torsdag 11 oktober 2012

Scrum: Poker planning cards to print

If you ever need fibonacci like plannings card.

http://www.pmtoolbox.com/project-management-news/print-your-own-planning-poker-cards.html

fredag 5 oktober 2012

Unit testing for classes using javax.mail.Transport

Found an interesting framework dumbster that simplifies unit testing of mail sending services and APIs. It basically creates a fake mail server that intercepts all SMTP commands.

Here is a simple example of a unit test for the class BasicMailHelper which has a method send that sends an email using SMTP.

private static final int PORT = 9966;
private static final String HOST = "localhost";
private static final String USER = "aUser";
private static final String FROM = "aFrom";

private static Session session;

@BeforeClass
public static void createSession()
{
   // create the mail session
   Properties props = new Properties();
   props.put("mail.smtp.host", HOST);
   props.put("mail.smtp.port", Integer.toString(PORT));
   props.put("mail.smtp.user", USER);
   props.put("mail.smtp.from", FROM);
   props.put("mail.smtp.auth", Boolean.toString(false));
   props.put("mail.transport.protocol", "smtp");
   session = Session.getInstance(props);
}

@Test
public void testSendTo()
     throws MessagingException, IOException
{
   // create the fake SMTP dumbster server
   SimpleSmtpServer server = SimpleSmtpServer.start(PORT);

   // send the email using the class that is to be tested
   MailHelper mailHelper = new BasicMailHelper.Builder().setSession(session).build();
   String subject = "aSubject";
   String body = "aBody";
   InternetAddress to = new InternetAddress("test@test.com");
   mailHelper.send(subject, body, to);

   // make sure all requests are processed by stopping the server
   server.stop();

   // evaluate the result by examining the emails in dumbster
   Assert.assertEquals(1, server.getReceivedEmailSize());
   SmtpMessage mail = (SmtpMessage) server.getReceivedEmail().next();
   Assert.assertEquals(subject, mail.getHeaderValue("Subject"));
   Assert.assertEquals(to.getAddress(), mail.getHeaderValues("To")[0]);
   Assert.assertTrue(mail.getBody().contains(body));
}

After some more testing of dumbster I needed to compensate for dead-lock (i.e. a timing related missing notify) and missing error handling. This is what I ended up with (would be nice to have an updated version of dumpster). I use a CountDownLatch to handle the dead-lock, reflection to get the state of the private field serverSocket to see if the server is correctly initialized (e.g. has not thrown port already in use).

private final static int PORT_MIN = 8000;
private final static int PORT_MAX = 9000;
private static final Logger LOGGER = LoggerFactory.getLogger(MailTest.class);

private void startDumbster()
{
   int port = PORT_MIN;
   final CountDownLatch[] startedLatch = {null};
   while (true)
   {
      if (port > PORT_MAX)
      {
         Assert.assertTrue("Unable to find free port", false);
      }
      // compensate for dead-lock in SimpleSmtpServer.start and missing status flags
      startedLatch[0] = new CountDownLatch(1);
      new Thread(new Runnable()
      {
         public void run()
         {
            server = SimpleSmtpServer.start(port); // might lock the thread, use a timeout
            startedLatch[0].countDown();
          }
      }).start();
      startedLatch[0].await(1, TimeUnit.MINUTES);
      Field socketField = SimpleSmtpServer.class.getDeclaredField("serverSocket");
      socketField.setAccessible(true);
      if ((startedLatch[0].getCount() == 0) && !server.isStopped() && (socketField.get(server) != null))
      {
         LOGGER.info("Successfully started dumpster on port {}", port);
         break;
      } else
      {
         port++;
      }
   }
}

torsdag 4 oktober 2012

JMX over HTTP with Jolokia and javascript

Using a combination of jolokia and jquery (with jstree) it is quite easy to create a jconsole like M-Bean handler application in javascript.

The basic idea is to search all M-Beans using jolokia and to create a navigation tree using jstree. When selecting a leaf node the corresponding M-Bean attributes and operations are presented.

Implementation

The AgenServlet from jolokia was added to a servletcontainer (tomcat) in web.xml

<servlet>
      <servlet-name>jolokia</servlet-name>
      <servlet-class>org.jolokia.http.AgentServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
      <servlet-name> jolokia </servlet-name>
      <url-pattern>/jolokia/*</url-pattern>
</servlet-mapping>

By using the javascipt API for jolokia to search for M-Beans it is possible to present a jconsole like tree structure using jstree.

NOTE: the keyorder:"constructionTime" is a patch to jolokia making it possible to get the M-Bean keys in construction order instead of cannonical. This feature makes the tree look like jconsole but is currently not available in jolokia (just omit it).

Disclaimer: I'm obviously not a javascript developer, sorry for the coding style :)

<div id="nav" class="jstree"></div>
<script type="text/javascript">
function extractDomainMap(mbeans) {
   var domains = {};
   for (var i = 0; i < mbeans.length; i++) {
      var mbean = mbeans[i];
      var domainEnd = mbean.indexOf(":");
      var domainName = mbean.substring(0, domainEnd);
      var domain = domains[domainName];
      if (domain == null) {
         domain = {"name": domainName, "entries": {}};
         domains[domainName] = domain;
      }
      var container = domain.entries;
      var tokens = mbean.substring(domainEnd + 1).split(",");
      for (var ii = 0; ii < tokens.length; ii++) {
         var token = tokens[ii];
         var typeEnd = token.indexOf("=");
         var name = token.substring(typeEnd + 1);
         var item = container[name];
         if (item == null) {
            item = {"name": name, "entries": []};
            container[name] = item;
         }
         if (ii == (tokens.length - 1)) {
            item.mbean = mbean;
         }
         container = item.entries;
      }
   }
   return domains;
}

function createJsTreeDataRecursive(entries, children) {
   var i = 0;
   for (var itemName in entries) {
      if (entries.hasOwnProperty(itemName)) {
         var item = entries[itemName];
         var node = {"data": item.name, "children": []};
         if (item.mbean != null) {
            node.metadata = {"mbean": item.mbean};
         }
         children[i] = node;
         createJsTreeDataRecursive(item.entries, node.children);
         i++;
      }
   }
}

function createJsTreeData(domains) {
   var data = {"data" : []};
   var i = 0;
   for (var domainName in domains) {
      if (domains.hasOwnProperty(domainName)) {
         var domain = domains[domainName];
         var node = {"data": domain.name, "children": []};
         data.data[i] = node;
         createJsTreeDataRecursive(domain.entries, node.children);
         i++;
      }
   }
   return data;
}

function searchAll() {
   var response = new Jolokia({"url": "jolokia"}).request(
     {type: "search", mbean:"*:*", keyorder:"constructionTime"}, 
     {method: "post"});
   response.value.sort();
   return createJsTreeData(extractDomainMap(response.value));
}

var data = searchAll();
$("#nav")
   .jstree ({
      "json_data" : data,
      "themes" : {
         "theme" : "classic",
         "dots" : false
      },
      "core" : {
         "animation" : 50
      },
         "plugins" : ["themes", "classic", "json_data","ui"]
   })
   .bind("select_node.jstree", function (event, data) {
      var mbean = data.rslt.obj.data("mbean");
      if (mbean != null) {
         listMbean(mbean);
      }
   });
</script>

The listMBean function is invoked when an leaf node is selected. It is quite easy to create a jquery tablesorter of all the attributes, operations and notifications using for example the cool javascript template framework handlebars. Here is the code that creates a table of the M-Bean attributes

<div id="attributes"></div>
<script id="attributes-template" type="text/x-handlebars-template">
<table id="attributes-table" class="tablesorter">
   <thead>
      <th>Name</th>
      <th>Value</th>
   </thead>
   <tbody>
   {{#attributes}}
      <tr>
         <td>{{name}}</td>
         <td id='{{name}}'>
         {{#if value.rw}}
            <input class="attr-input" id='attr-input-{{name}}' name='{{name}}' type='text' value=''>
            <input class="attr-submit" id='attr-submit-{{name}}' name='Save' type='submit' value='Save' onclick="updateAttribute('{{name}}')">
         {{/if}}
         </td>
      </tr>
   {{/attributes}}
   </tbody>
</table>
</script>

<script type="text/javascript">
var currentMbean;
function listMbean(mbean) {
   var path = mbean.replace(new RegExp("/", 'g'), "!/");
   path = path.replace(":", "/");
   var meta = new Jolokia({"url": "jolokia"}).request(
     {"type": "list", "path": path}, 
     {method: "post"});
   currentMbean = mbean;
   currentMeta = meta;
   $("#mbeanInfo").html("<h2 id='mbeanName'>" + mbean + "</h2><p>" + meta.value.desc + "</p>");
   var attributes = { 'attributes' : [] };
   for (var attr in meta.value.attr) {
      if (meta.value.attr.hasOwnProperty(attr)) {
         attributes['attributes'].push({
            'name' : attr,
            'value' : meta.value.attr[attr]
         });
      }
   }
   var source = $("#attributes-template").html();
   var template = Handlebars.compile(source);
   $("#attributes").html(template(attributes));
   $("#attributes-table").tablesorter({widgets: ['zebra']});
   // inject the values
   var values = new Jolokia({"url": "jolokia"}).request(
     {"type": "read", "mbean": mbean}, 
     {method: "post"});
   for (var attr in values.value) {
      if (values.value.hasOwnProperty(attr)) {
         var value = values.value[attr];
         if (meta.value.attr[attr].rw) {
            $("#attr-input-" + attr).val(value);
         } else {
            $("#" + attr).html(value);
         }
      }
   }
}


function updateAttribute(name) {
   var mbean = currentMbean;
   var value = $("#attr-input-" + name).val();
    new Jolokia({"url": "jolokia"}).request(
     {"type": "write", "mbean": mbean, "attribute": name, "value": value}, 
     {method: "post"});
   listMbean(mbean);
}
</script>

Similar tables can be created for the M-Bean operations and notifications.



torsdag 20 september 2012

onsdag 29 augusti 2012

tar: Skip directories when creating archive

Skip subversion / svn directories when creating a tar archive

>> tar -cvf patch.tar --exclude=.svn try2

where try2 is the directory that will be in the tar achive

tisdag 28 augusti 2012

Subversion: How do I create a svn tag / branch from a specific revision

Open a shell
>> svn copy -r r72664 http://svn.sitevision.net/repos/sitevision/trunk http://svn.sitevision.net/repos/sitevision/tags/STAGING_INIT
Subversion: What svn revision was this branch created in?
Open a shell in the project root

>> svn log --stop-on-copy .

Returns a list of revisions. The first will be at the end of the list


Staging: initial logging
------------------------------------------------------------------------
r72664 | mikael | 2012-05-28 09:44:57 +0200 (Mon, 28 May 2012) | 1 line