Thursday, December 19, 2013

From Node.js back to Java, Part 1: EventEmitter and Callbacks

There were a lot of features of Node.js and JavaScript that I liked.  Why not bring them to Java?  That's what I'm working on with Nava, "Bringing good ideas from node.js into Java".  So far, I have implemented a fair amount.  The code can be compiled against Java 6, Java 7, and Android 2.2, and presumably later versions of Android.

The emit package is a pretty direct port of a node.js EventEmitter to Java, and can be used in a very similar manner as in node.js.  The main difference is that the event handler cannot be a closure, (cause we don't have closures!) it must implement a simple interface, Emit.IListener, with one method, handleEvent().  Producers of events would subclass or delegate to Emitter, much like the node class would extends or delegate to EventEmitter.  This code essentially replaces Java's EventListenerList and associated classes and interfaces.  There are several major advantages:

  1. The code does not depend on Swing, so it could be used in Android. 
  2. The "events" that get fired need not extend EventObject.  They could be Strings or voids.  However, in many cases, subclassing EventObject makes sense.
  3. Generics are used to obviate the need for a lot of boilerplate, such as declaring a bunch of Listener subclasses and their respective delegation methods addFooListener(), removeFooListener(), etc...
There are also a few disadvantages, noted in the documentation. The main one is that everything is more loosely typed, as you'd expect as this is based upon JavaScript.  Underneath, there are unchecked casts.


The callback package is a rough port of JavaScript / node.js style callbacks.  Your callback "closures" must implement the Callback interface, or extend from AbstractCallback.  Callbacks can be "chained together", either manually using setNextCallback(), or programatically with the utility method Callbacks.chainUp().

You could then "submit" the callback directly by calling the first one, but that would happen synchronously, in-line, and, other than for initial testing, probably isn't worth it.  The more "node-like" technique would be to create a CallbackExecutor (probably application-wide) and use submitCallback(), passing the first callback and it's data.  Your thread will then continue, just like in node, with no need to await the completion (good) and no knowledge of the result (sometimes annoying).

For example, if you had a Reader that read a File into a String, and a Counter that counted words, the skeleton Java code would be:

      Reader reader = new Reader();
      Counter counter = new Counter();
      Callbacks.chainUp(reader, counter );
      CallbackExecutor cex = new CallbackExecutor(2,1);
      cex.submitCallback(reader, theFile);
      // your code then moves on (or just stops...)

As opposed to actual JavaScript/Node, which would look something like:

      fs.readFile(theFile, function(err, data) {
         if (err) throw err;
         // normally the counting code would be in-line here
         // but for modularity similar to the Java
         countWords(data);
       });
       // your code then moves on (or just stops...)


There's more, but that's a start for today.  Check out the readme file, javadocs, and JUnit tests for more information.

Thursday, December 5, 2013

Javadocs on GitHub for Dummies

GitHub has a feature to allow you to upload supporting documents, such as Javadocs, into a gh-pages branch, for easy access by people browsing your project.  The problem is that it's a huge PITA to configure, especially if you are new to git.  Here's how I did it.  This is for a Windows machine and a typical java project.  YMMV.

For example, if you are working on ProjectFoo in GitHub, somewhere there will be a ProjectFoo folder on your local disk that contains a README.me, .gitignore, and folders such as src and test.  I will assume that this has been done, plus your project, in this state, already exists on GitHub as github.com/UserName/ProjectFoo.git.

You want your javadocs to go into a completely separate folder from your main project.  Otherwise you are constantly switching back and forth.  I have organized my projects as follows, splitting my "master" GIT_FOLDER into master and gh-pages subfolders:

  GIT_FOLDER   (all git projects go here)
    master
      ProjectFoo
      ProjectSomeOther
    gh-pages
      ProjectFoo
      ProjectSomeOther

You don't have to follow this arrangement.  But the important thing is to get the javadocs separated from the main project so the branches don't keep stepping on each other.

Initial Setup

cd to GIT_FOLDER/gh-pages  (or, if you have a different setup for the gh-pages branch, to the corresponding folder) and open a Command Window.

Checkout your main branch there

>git clone https://github.com/UserName/ProjectFoo.git

This will create a folder GIT_FOLDER/gh-pages/ProjectFoo.  CD there and check your branch.

>cd ProjectFoo. 

>git branch
* master

Do not create a gh-pages branch yet!  Instead, checkout a new orphan branch named gh-pages

>git checkout --orphan gh-pages
Switched to a new branch 'gh-pages'

In my experience, git still says you are on master if you go git branch, but ignore that for now, it will eventually figure things out.

A directory command (dir /A /B) should show your Java code, with src and possibly test folders, something like:

.git
.gitignore
LICENSE
README.md
src
test

All you want here are the javadocs.
  1. Delete the LICENSE file, and the src and test folders.
  2. Create (or copy) the javadocs to a folder named javadocs.
  3. Double check that .gitignore isn't doing anything too goofy
Your folder should now contain:

.git
.gitignore
javadocs
README.md

Check your git status.  It should now have the correct branch.  Your list of deleted files will vary.

>git status
# On branch gh-pages
# Changes not staged for commit:
#   (use "git add/rm ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#       deleted:    LICENSE
#       deleted:    src/com/company/package/SomeFile1.java
#       deleted:    src/com/company/package/SomeFile2.java
#       deleted:    src/com/company/package/package-info.java
#       deleted:    test/com/company/package/SomeFile1Test.java
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#       javadocs/

Add javadocs to the repository.  You may see warnings about line endings.

>git add javadocs

Commit them.  You may see warnings about line endings.

>git commit -m "1st checkin of javadocs"

Now, commit everything else to delete the src and test folders

>git commit -a -m "deleted src from gh-pages"

As a final check, git status should now be clean and git branch shows the new branch:

>git status
# On branch gh-pages
nothing to commit, working directory clean

>git branch
* gh-pages
  master

Finally, push to GitHub.  

>git push origin gh-pages
Username for 'https://github.com': UserName
Password for 'https://UserName@github.com':
Counting objects: ...
... reused 0 (delta 0)
To https://github.com/UserName/project.git
 * [new branch]      gh-pages -> gh-pages

Now, you can login to GitHub with your browser, and you should see the new branch.  Assuming you want a prominent link to these javadocs, go to the main branch and add this line somewhere in the README file:

[JavaDocs are here](http://UserName.github.io/ProjectFoo/javadocs/)

For an example, see my Nava project.

Later on, how to update the JavaDocs:


  1. Generate (or copy) them into that javadocs folder
  2. Open a command window there
  3. git status to see whats going on.  You should be on the gh-pages branch!
  4. You will probably need to add some new docs:  git add .
  5. git commit -m "some comment"
  6. git status   (if you are paranoid)
  7. git push origin gh-pages
  8. git status  Everything should be clean.