Aranea CVS repository moved to SVN

January 19th, 2007 by

Migrating our CVS repository to Subversion has been completed. CVS write access is now disabled. CVS repository will remain accessible, but in read-only mode.

Converting CVS repository contents to SVN using cvs2svn script took 2.5 hours. SVN repository is now up and running, so development can continue normally. We also upgraded Changelogic to a newer version, that supports Subversion repositories. Developers will need to grab changelogic-personal.properties file from Changelogic -> Supporting files. Additionally, one of the following lines will need to be inserted to changelogic-personal.properties:

# When using Changelogic remotely, e.g. from your workstation
cl.vcs.repository=svn+ssh://araneaframework.org/var/svnroot

# When using Changelogic on araneaframework.org server
cl.vcs.repository=file:///var/svnroot

The dependencies that previous Changelogic version needed in your $ANT_HOME/lib folder are no longer necessary, you may delete them: apache-bsf.jar, changelogic-ant.jar, commons-httpclient.jar, commons-logging.jar, js.jar.

ViewVC for the new SVN repository will be available on the following URL: http://svn.araneaframework.org/viewvc/. Previous ViewCVS for the old CVS repository remains accessible on the following URL: http://www.araneaframework.org/cgi-bin/viewvc.cgi/.
Read-only access to SVN repository for anonymous users will be available on the following URL: http://svn.araneaframework.org/repos/aranea. For example, to check out a copy of the latest Aranea:
svn co http://svn.araneaframework.org/repos/aranea/branches/latest aranea Read-only access to the old CVS repository remains accessible in the same way as before.
Developer access to SVN repository will be available on the following URL: svn+ssh://araneaframework.org/var/svnroot. You will probably want to start with:
svn co svn+ssh://araneaframework.org/var/svnroot/aranea/branches/latest aranea

New Year, New Horizons

January 7th, 2007 by

Although most of the the team is still on vacation after the holidays, next week we will finally unveil the integration project to the general public. It will first be available via version control, as the first milestone release is planned for end of January. Integration will be our main priority in the near future and we are preparing some very nice surprises for you :) More on that next week.

1.0.4 Released

December 23rd, 2006 by

This release includes bugfixes and AJAX Action API backported from 1.1 branch. See Actions in action (pun intended) in a live AJAX demo included with the distribution (Demos->Advanced->Form With Actions). Also included is an advanced demo for popup management. Feel free to download it now!

Goodbye, JavaPolis…

December 14th, 2006 by

JavaPolis is almost over and the Aranea team has had a great time! Thanks to all who came to listen to our talk or came up to us in the booth, it was really great to see your interest and to help you out. Thanks a lot to Stephan and the organizers for a great job and we are looking forward to the next time we can met everyone in Antwerp!

In other news we announced integration with Struts, JSF and GWT during the conference and in the next couple of weeks we will setup the subprojects and make them available for testing. The stable releases are expected during January-February, so stay tuned for updates.

Aranea at JavaPolis 2006

December 8th, 2006 by

Everyone who will be at JavaPolis 2006 in Antwerp, Belgium from Tuesday, 12th to Friday, 15th December is very welcome to attend both the talk on “Object-Oriented Web Development with Aranea” and visit the booth that we share with ChangeLogic configuration management guys. We will have two of the core Aranea developers on place, so if you have any questions, troubles, comments and offers of help we will be more than glad to hear you out (and help if needed).

One week until JavaPolis

December 5th, 2006 by

Exactly seven days are left before the largest European Java conference kicks in! As it happens we have both a talk and a booth there, so anyone in the vicinity is very welcome to come by, listen and tell of your experiences with Aranea (even if they are not the best :) ).

As you may remember we promised to announce integration with Struts, JSF and GWT during that time. It seems we will just have to keep our word, as the work is almost complete. Struts integration is up and running, while JSF and GWT are right behind it. This means we’ll be able to demo a working app composed of legacy Struts, standard JSF and cutting-edge GWT right before your eyes during the talk (and during any other time in the booth, if you are interested). The official announcement will come right after JavaPolis, since we have to setup subprojects first.

Aranea 1.0.3 Released

December 1st, 2006 by

Another maintenance release from Aranea 1.0 series. See changelog for details.

We also have first changes integrated into our upcoming 1.1 branch, and hope to present some nice surprises before christmas season.

Zero Turnaround, Revisited

November 22nd, 2006 by

There has been some amount of discussion on the previous post. What was a bit surprising for me, is that a lot of people think that this isn’t really an issue for Java EE (they should really look at the comments here).

First of all let’s clear up some misunderstandings — we are talking about a development time approach, that allows to see the results of changes to code reflected instantly in the web application. This has nothing to do with production time hot swapping.

Secondly, nowadays compiling isn’t much of a bottleneck, since Eclipse (and similar IDEs) compile application incrementally on-the-fly. So the only thing we need is to actually reload this code in the JVM and we will get instant feedback that speeds up development.

Thirdly, web containers had for quite some time supported reloading classes while preserving the session state. However they do it by restarting the web application, which means all state outside the session (including business and persistence layer configuration, cache, stateful application-level services, compiled statements and so on) will be lost. To speak more specifically in a typical application based on Spring and Hibernate that is deployed to Weblogic (or Tomcat, or whatever else) such restart will take 30s to several minutes depending on the size of the application.

Now this is a really big issue — it means that averaging a restart every five minutes we get 96 restarts a day, which even 30s each gives us 48 minutes spent waiting for the application to reload. And the real numbers are even bigger, both because I chose optimistic numbers and because a developer who waits for a minute loses the context and might easily start reading Slashdot out of boredom. Thus companies are losing hell-of-a-lot of money on their developers just waiting for the application to restart.

So, to get back to the solution proposed in the original post. This was a way to get all of your web layer stuff to reload instantly. This by no means solves all problems, as the business and persistence layer are not covered by this approach. However since a lot of development happens in the web layer it does give a good boost to that (I don’t think I’d lie too much if I say that at least half of the restarts become unnecessary). Moreover there are some possibilities to get the rest of the stuff to reload as well, and Aranea team is working on them as well as some others.

Zero turn-around in Java?

November 21st, 2006 by

Zero turn-around is one of the selling points of PHP, Ruby, Python and other interpreted languages. Turns out it also works out-of-the-box with Aranea and here we’ll describe how we did it, what are the limitations and show off the compositional nature of Aranea. If you just want to get it to work see the reference manual entry on the topic.

Zero turn-around usually refers to the way changes made to the code are immediately visible in most interpreted languages. Indeed, since there is no compilation and almost no deployment, the time from making a change to seeing it in the browser is a fast as pressing Ctrl + S, Alt + Tab and F5. The situation in the JEE world is different — although compilation is relatively fast, together with deployment, cache reloads and framework initialization it might easily take up to a minute to see a change propagate in a large application.

The problem is that JVM spec clearly states that we can’t just reload code of a single class after it has been loaded into the JVM. HotSpot JVM offers some way by allowing to replace the code of the methods, but so far it forbids to anyhow alter structure and signatures, so it’s only of limited use. What we can do is to load classes using a particular (possibly our own) classloader, and then let it to be garbage collected among with all loaded classes. Then next time an instance is created the class will be loaded anew.

However even this won’t give us the desired result, as any existing instance of a class will still hold on to its previous definition (with the old classloader) and now we might actually have two conflicting class definitions in two different classloaders which can lead to all sorts of trouble. So we also need to somehow reload the object state in a new classloader.

Turns out that we can archive this with serialization — we just need to modify the ObjectInputStream to take a classloader parameter and load the instances using its classes. Thus what we have to do is:

  1. Load the classes using our classloader.
  2. Serialize the state of the instances
  3. Drop the old classloader and create a new one
  4. Deserialize state of the instances in the new classloader

Of course if some objects cannot be serialized (e.g do not implement Serializable or contain non-serializable fields) the whole scheme fails, since we cannot preserve their state.

Before we get to the actual Aranea stuff let’s try to implement the reloading procedure, that takes an object and reloads it using a fresh classloader. We know it should work through serialization, so it should look something like this:

...
private Serializable reload(Serializable child)
  throws Exception {
  return deepCopy(newClassLoader(), child);
}
...

deepCopy should just serialize and deserialize the object. There is one catch though — it should also resolve the classes using our own classloader, so we have to make a subclass of ObjectInputStream:

...
private static class ReloadingObjectInputStream
extends ObjectInputStream {
  private ClassLoader cl;

  public ReloadingObjectInputStream(
      ClassLoader cl,
      InputStream in)
    throws IOException {
    super(in);
    this.cl = cl;
  }

  /*
   * This method is used to resolve the classes
   * when creating object instances.
   */
  protected Class resolveClass(ObjectStreamClass desc)
    throws IOException, ClassNotFoundException {
    String name = desc.getName();
    return cl.loadClass(name);
  }
}
...

The deepCopy() method itself is straightforward and we could have used Apache SerializationUtils methods if it weren’t for the custom ObjectInputStream:

...
private  Serializable deepCopy(
    ClassLoader cl,
    Serializable original) throws Exception {
  //Serialize to a byte array
  ByteArrayOutputStream baos =
    new ByteArrayOutputStream(512);
  ObjectOutputStream out =
    new ObjectOutputStream(baos);
  try {
    out.writeObject(original);
  }
  finally {
    out.close();
  }

  byte[] serialized = baos.toByteArray();

  //Deserialize to an instance
  ByteArrayInputStream bais =
    new ByteArrayInputStream(serialized);

  ReloadingObjectInputStream in =
    new ReloadingObjectInputStream(cl, bais);
  Object obj = in.readObject();

  return (Serializable) obj;
}
...

We could have used just a usual classloader (most common is URLClassLoader) and just point its classpath to the “/WEB-INF/classes”. However there is also a trouble that the same classes are in the classpath of the web application classloader. The Java specification instructs classloaders to try loading classes with the parent classloader first, however in our case we would be able to reload those classes, so we need to invert this preference by delegating to parent only if we cannot find the class in the classpath:

...
private static class ReloadingClassloader
  extends URLClassLoader {

  public ReloadingClassloader(
      URL[] urls,
      ClassLoader parent) {
    super(urls, parent);
  }

  public Class loadClass(String name)
    throws ClassNotFoundException {
    //If already loaded just return
    Class c = findLoadedClass(name);
    if (c != null)
      return c;

    //First try own classpath
    //then delegate to parent
    try {
      return findClass(name);
    }
    catch (ClassNotFoundException e) {
      return super.loadClass(name);
    }
  }
}
...

We create the classloader by putting “/WEB-INF/classes” into the classpath. getEnvironment().getEntry() is just a way in Aranea to look up services, in this case we need a ServletContext:

...
private ClassLoader newClassLoader()
  throws MalformedURLException {
  //Get the ServletContext
  ServletContext sctx =
    (ServletContext) getEnvironment().getEntry(
        ServletContext.class);
  //Return a classloader for "/WEB-INF/classes"
  return new ReloadingClassloader(
      new URL[] {sctx.getResource("/WEB-INF/classes")},
      getClass().getClassLoader());
}
...

Now we have most of the machinery in place and before we move on to Aranea filter implementation we can spare a thought on the limitations of the solution. Obviously it will only work on serializable classes. What’s more, to get actual gain from it all classes should have serialVersionUID set to some fixed number (e.g. “0″). This should be done so that small changes in the method and class signatures wouldn’t cause a deserialization failure. Even then removing a class (even an inner or anonymous class) will cause serialization to fail as well as changing the field types or order. However it is still much more than HotSwap would allow (at least at the moment).

Now we can go on with implementing the Aranea filter that will do the work. There are several reasons why this solutions suits Aranea so well:

  • Aranea is originally assembled from independent components by containment. Therefore one filter can define the classloader to load its children and do the rest of the tricks.
  • All application widgets in Aranea are serializable and loaded by the parent classloader (most of the filters are configured by Spring and loaded by its classloader).
  • Aranea components can only access their parents through the environment, which can be taken away at any given moment. Moreover parents have references only to their direct children, and can communicate with the indirect children only through messages.

Thus we can create a filter and put it in appropriate place just above the application widgets and we will be able to seamlessly reload all application widgets code.

At the moment we will assume that creating a new classloader and serializing/deserializing does not visibly affect response time in development, so we will just reload all classes before every request. Thus we do not need to check exactly which classes have changed, since any possible changes will be reloaded.

Let’s start by creating the filter service itself. It will have to take the child class name as a string, since we will need to load it reflectively in a freshly created classloader.

public class StandardClassReloadingFilterWidget
    extends BaseApplicationWidget {

  private String childClassName;
  private RelocatableWidget child;

  public void setChildClass(String childClass) {
    this.childClassName = childClass;
  }

  protected void init() throws Exception {
    //Create the classloader and use it
    //to load the child class
    ClassLoader cl = newClassLoader();
    Class childClass = cl.loadClass(childClassName);

    //Create an instance of child class and
    //attach it to the filter
    child =
      new RelocatableDecorator(
          (Widget) childClass.newInstance());
    addWidget("c", child)'
  }
...

Here we create the child widget reflectively in the classloader and add it under a name “c”. The only interesting part is that we also wrap it into a RelocatableDecorator, which we will return to later. Now the next method is called before every request and will do the actual reloading:

...
protected void update(InputData input)
  throws Exception {
  try {
    //Remove all references to parents and
    //reload the child classes
    child._getRelocatable().overrideEnvironment(null);
    child = (RelocatableWidget) reload(child);
  }
  catch (ClassNotFoundException e) {
    log.error("Failed to reload widget classes", e);
  }
  finally {
    //Restore the references to parents
    child._getRelocatable()
      .overrideEnvironment(getEnvironment());
  }

  //Reattach the child new instance to the filter
  _getComposite().attach("c", child);
}
...

Here the point of wrapping the child into the RelocatableDecorator comes out — as all references from children to parents in Aranea have to go through the environment, by removing the environment from the child we also remove all possible links up allowing to serialize children only.

Now the filter is complete (except for the trivial render() method which we leave as an exercise for the reader) and can be tested in e.g. main example or any other Aranea application by adding a similar configuration entry:

<bean id="araneaApplicationStart" singleton="false"
  class="org.araneaframework.framework.filter.StandardClassReloadingFilterWidget">
  <property name="childClass" value="org.araneaframework.example.main.web.DevelWidget"/>
</bean>

Instead of the usual:

<bean id="araneaApplicationStart"
  class="org.araneaframework.example.main.web.LoginWidget"
  singleton="false"/>

You will most probably want to define a different root widget class (in this case DevelWidget), which will start the usual LoginWidget in a StandardFlowContainerWidget. Otherwise you will lose the reloading filter on login.

So, on the plus side we managed to build a useful feature that will save countless developer hours by adding just one filter in a correct place. We also worked through a nice enough example of how to add framework features to Aranea (there definitely are a couple of gotchas here, but they are few and described in the reference manual). The filter can be used to reload widgets and all their helper classes, which makes up basically all of the Aranea application web layer. Since JSPs and most other templating engines can also reload their code easily we get to see all of the changes to the web almost instantly.

On the minus side we are reloading all of the classes in the web layer and serializing/deserializing all of the state on every request, which may become costly for a large application. We could somewhat remedy it by checking that classes have changed before reloading them. Also this trick won’t work for the business layer, since it is usually not serializable and can be referenced from many different places. There are some possible ways around it by they need much more effort and deserve a separate post in the future :)

Aranea 1.0.2 Released

November 17th, 2006 by

A bugfix stable release, for detailed description see changelog.

Aranea 1.1M1 is delayed since we are working hard on integration with JSF, GWT and Struts. There is still hope to get at least most of them working by Javapolis and demo it during the presentation.