1 2 3 Previous Next

fabriziogiudici

349 posts

As I said in my previous post, a few months ago I've put under my CI a number of projects of mine to be tested in parallel with JDK 6 and JDK 7. After a few minor issues, they were ok and have been working even in production under (Open)JDK 7 since the end of the past year. Given that now Oracle has started releasing JDK 7 for Mac OS X too and that the latest NetBeans 7.1.2 works fine under Mac OS X and JDK 7, I'm going to start dropping support for JDK 6 and gradually move all my projects to JDK 7. This means to set -source 1.7 and -target 1.7, so I'll be able to start using the new Java 7 features.

But yesterday night the new -source and -target options gave me a strange result: all of a sudden, some tests failed with funny messages such as:

Failed tests:   setUp(it.tidalwave.northernwind.core.impl.filter.NodeLinkMacroFilterTest):
Expecting a stackmap frame at branch target 94 in method
it.tidalwave.northernwind.core.impl.filter.MacroFilter.filter(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
at offset 22   setupFixture(it.tidalwave.northernwind.core.impl.filter.XsltMacroFilterTest):
Expecting a stackmap frame at branch target 21 in method it.tidalwave.northernwind.core.impl.filter.XsltMacroFilter.filter(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
at offset 6   setupFixture(it.tidalwave.northernwind.core.impl.model.DefaultSiteProviderTest):
Expecting a stackmap frame at branch target 14 in method it.tidalwave.northernwind.core.impl.model.DefaultSite.r(Ljava/lang/String;)Ljava/lang/String;
at offset 6
...

Turns out they are error from the bytecode verifier. Now, before starting the migration to JDK 7 you should read the document prepared by Oracle: at section 4.1.1 there's something about the new bytecode format and bytecode verifier. Trying to keep the things simple, the new bytecode verifier performs stricter checks and relies upon changed data format in the bytecode. The VM in JDK 7 uses the new verifier for code compiled in Java 7 mode, but falls back to the old one for code compiled in Java 6 mode. Thus, in theory there should be no problem.

Problems actually arise if you're using bytecode manipulating tools, such as AspectJ in static weaving mode - I do - that haven't been updated yet. They basically read the bytecode, tagged as Java 7 bytecode, and perform changes in Java 6 mode, saving the results still tagged in Java 7 mode. Thus, the VM in JDK 7 sees Java 7 bytecode and activates the new Java 7 verifier, which fails (or can fail) when it meet the bytecode manipulated in Java 6 mode.

It seems complicated, but the simple solution is to force the use of the old verifier in JDK 7 by adding this VM runtime option: -XX:-UseSplitVerifier.

When AspectJ is updated (AspectJ 1.7.0.M1 is the first release targeted at JDK 7, but it's still a milestone so it's probably not a good idea to try it in production) everything will be fine again and there will be no more need for the -XX option.

 

With the first release ever of a Java VM by Oracle for Mac OS X, a long, long time problem has probably been solved. Now we have a single producer of VM, Oracle, that can produce bits for all the major operating systems (Windows, Linux, Mac OS X) and release in the same moment. In the past Apple was entirely responsible for bits on Mac OS X with a chronical delay with respect to the other operating systems.

This is also the first official, non early-access release of a JDK 7 for Mac OS X and makes it possible to get aligned to Java 7 for our projects. Java 6 is going to end its life in a few months and my intention is to have all my projects relying on Java 7 within this Summer. Some of them has been already put under CI with parallel Java 6 and Java 7 builds since a few time, as well as running in production with JDK 7. Now that I can compile them in Java 7 also on my Mac OS X laptop (NetBeans 7.1.2 also runs fine with JDK 7 on Mac OS X), I can start dropping support for Java 6, setting -source and -target 1.7. Which also means that I can start using the new Java 7 features.

The process is not necessarily without problems, and I'll blog about one that I faced with (and solved) yesterday in my next post.

Java is great. But sometimes you get caught in a trap of mud and you don't see it coming.

Context: I'm working with XSLT for manipulating XHTML and it works great. Well, 99% of it works great. The remainder 1% is problematic. Xalan (the XSLT processor in the JDK) knows how to produce output in HTML and XML modes, by means of the <xsl:output .../> directive. HTML mode doesn't work, because XHTML is not HTML. XML should work, because XHTML is XML. Really? Not, indeed. XHTML differs from XML for some details in serialization. In particular, while empty elements in XML are always serialized with a shortcut (e.g. <element/>), this is not the case for XHTML. Some elements, such as <br/> must be serialized with shortcuts. Some must not, such as <a>, <p>, <script>, <textarea>, etc... This means that an empty anchor must be always serialized with <a></a>.

Such empty elements are frequent when a JavaScript library is used, since they are usually placeholders to be dinamically populated. Even recent browsers screw up things when they see a <script href="..."/> element, and some JavaScript tools which manipulate the DOM screw up things when they see something such as <a/>.

In spite of this, Xalan is not able to deal with proper XHTML serialization. There are a number of blog posts from annoyed people and an official Xalan bug opened ... in 2004 and never fixed. Clearly at the Xalan community they think that manipulating XHTML is a niche activity (Sun has been bashed for years because of relevant bugs not fixed after a long time, but clearly they weren't alone).

Trying to patch the internal serialization classes of Xalan didn't work, as they are tightly coupled with a lot of stuff in the com.sun.* packages. Apache used to provide a number of serializes for XML, but they were deprecated in favour or TrAX (that is, Xalan), or LSSerializer. Unfortunately the latter doesn't seem to provide any flexibility in XML serialization and can't be used for proper XHTML serialization.

So, the only solution I've found so far is to resume an old deprecated class named XHTMLSerializer which does almost everything good (the missing parts can be easily fixed by subclassing). Actually, looking at the source, specific care to the XHTML issues were paid, demonstrating that among the Xalan authors the problem was well understood. Somebody was probably too quick on the trigger when he decided to deprecate some stuff without ensuring that all the features had found their way to the new classes.

Done? Not at all. XHTMLSerializer works fine with JDK6 but miserably fails with JDK7. It seems that the JRE7 misses a resource used by some of the inner classes. Probably these classes have not been tested in JDK7 since they are deprecated (but, then, what's the point in including them in the runtime?).

Second attempt, and I copied three other classes from JDK6 into my application, together with the missing resource. Fortunately they are not tightly coupled with other stuff and they can live on their own. 

Hours wasted for such a silly thing.

If this can be helpful to you, the details are filed in my project's issues NW-96 and NW-99 (they include links to patches).

gt;.

I think that Maven is a great tool for development. But it can be used for more. For instance, I've just prepared things so that starting from a clean room you can try out my lightweight CMS, NorthernWind, by just invoking a couple of commands. They will install and run NorthernWind, an embedded server and an example site. More information at the NorthernWind blog.

fabriziogiudici

Actors in Java Blog

Posted by fabriziogiudici Jan 4, 2012

Recently there has been a renewed interest into the Actor programming model. The Actor Model actually comes from the '70s, but as far as I'm aware it has been used only in a very limited subset of industrial projects outside the area of telecoms. Erlang (not by chance developed at Ericsson, a telecom industry), which is a language whose concurrency model is actor oriented, is getting some attention but it's definitely a niche kind of a language. More interesting is the fact that the Scala language developed its own actor-based platform, Akka, which is also available to Java (and, generally speaking, to JVM-based languages). While there might (a-hum) be a lot of hype about Scala and I'm pretty oriented to apply a big low-pass filter on trendy and cool stuff, actors have definitely their place in the world when you're involved with complex concurrency. Once upon a time complex concurrency was a matter only for specific industrial segments (e.g. the previously cited telecom industry), but since things such as multi-cores and "the cloud" are invading our battlefields it's better to get prepared.
 

BTW, cloud and multi-core apart, I've already seen a lot of production code with scattered synchronized sections that "perhaps shouldn't be there, but the thing works and it's better to let them stay". Note that this argument is the typical smell of lack of testing, but concurrency is such a complex thing to test that even when the customer is a good guy and achieves a very high coverage, often he can't be sure. The risk is to have some unprotected section that sooner or later will lead to some inconsistency or raise an exception, up to the scary possibility that a deadlock occurs. The better way to deal with concurrency is to pick a programming model that avoids problems by costruction, and actors can be a good choice.
 

I've started doing some coding in the area and while I'm still far from a conclusion it's high time I posted some considerations.
 


Actors and Akka
 

So, what are actors about? These are the basic principles:
 

       
  1. No shared (mutable) data. Each actor manages its own slice of data and there's nothing shared with others. Thus no need for synchronized.
         
  2.    
  3. Lightweight processes. Threads are still good, since they scale well; but, as per the previous point, they must be isolated.
         
  4.    
  5. Communicate through Asynchronous Messages. What is traditionally done by invoking a method from an object to another now is done by sending an asynchronous message. The sender is never blocked, and the receiver gets all inbound messages enqueued into a 'mailbox', from which they will be consumed one at a time per each actor instance.
         
  6.    
  7. Messages are immutable. This should be inferred by the previous points (otherwise bye bye "no shared mutable data"), but it's a good advice to stress the point.
         

With actors the contract of a computational entity is no more represented by an interface (that is an enumeration of methods) and behaviour, but by the set of messages that the actor can receive and send, and behaviour. Copying the first example in the Java API for Akka, a simple actor can be:

import akka.actor.UntypedActor;
import akka.event.EventHandler;

public class SampleUntypedActor extends UntypedActor
  {
    public void onReceive (Object message) throws Exception
      {
        if (message instanceof String)
          {
                         getContext().replyUnsafe("Hello " + message);
          }
        else
          {
            throw              new IllegalArgumentException("Unknown message: " + message);
          }
      }    
  }

Actors, being managed objects (and possibly distributed on a network), can't be directly accessed, but must be handled by references. For instance, to send a message to the previous actor:

import static akka.actor.Actors.*;
final ActorRef myActor = actorOf(SampleUntypedActor.class);
actor.start();
...
actor.tell("world");

Now Akka has a considerable value in being tested and optimized - performance is one of the reasons for which you might want to use actors and it's not easy to achieve and Akka is known to scale to impressive numbers. But while messages can be delivered in different fashions, unfortunately Akka seems not to be supporting publish & subscribe which is my preferred way to go (I've seen references to extensions and possibly this feature could be introduced in future). This is a first showstopper for me. Furthermore, basic concepts are simple but, as it unfortunately often occurs, things get more complicated as you start digging into details. Also, you note the total lack of syntactic sugar, as the incoming message is a vanilla Object and you need a cascade of if (message instanceof ...) to deal with multiple messages. At least, for the things Akka calls untyped actors: there are typed actors too, which can be even defined again by an interface to mimic method calling, that Akka will manipulate through AOP to transform method invocation in message passing. An approach that I don't like, because I think that in a message-passing software the approach must be evident in source code, not masked under something that pretend to be method invocation; furthermore, method invocation semantics are incompatible with publish & subscribe. So, I'd say that with Akka either you have no sugar or you're going to sink into honey.
 

Anyway, just before publishing this blog post, I've learned that Akka 2.0 is going to have publish & subscribe. Excellent news. In the meantime?
 


Understanding what I want
 

In the meantime, I've started sketching some code on my own, to understand how I'd like to use actors. The idea is to learn things and then try to converge to Akka, eventually with a thin layer of syntactic sugar. There's enough work so far that's worth while a blog post, both for my personal need of writing down things and to discuss with others.
 

Since things must be given a real context I've started thinking of desktop applications, in particular two simple tools that I need: SolidBlue computes the fingerprint of the files contained in a directory (I use it for periodically checking the sanity of my photos and related backups) and blueArgyle blueShades provides a GUI for Argyll, a tool for color management, suited to my needs. Both are being implemented with the NetBeans   Platform.
 

So let's focus on SolidBlue and its main feature. The scenario is:
 

       
  1. You select a directory.
  2.    
  3. The application scans the directory recursively.
  4.    
  5. For each discovered file, contents are loaded and the MD5 fingerprint is computed.
  6.    
  7. Each MD5 computed fingerprint is stored into a flat file.
  8.    
  9. A UI monitors the workflow displaying the current status on the screen.

The flow can be parallelized. For instance, directory recursive inspection can be performed by multiple threads, as well as the MD5 computation, which only involves the CPU. On the other hand, loading from the disk is something that it's better to serialize (that is, reading only one file at a time) in order to maximize the disk throughput (which it's the true bottleneck of the application). Indeed, things are a bit more complex than I've just said, but I'll be back on the issue later.
 


Primary message flows in SolidBlue
 

Note: in the following code samples, I'm making use of Lombok annotations for some plumbing. This is not only great for everyday's work, but it also makes code samples much easier to read. Also, I'm only listing significant import statements, as well as skipping some non relevant code chunks.
 

Everything starts by sending to the system a message asking for a scan:
 

FileScanRequestMessage.forFolder("/Volume/Media/Photos")
                                  .withFilter(withExtensions("NEF", "JPG", "TIF"))
                                  .send();

As you can see, there's no target actor, but according to the "publish and subscribe" approach the message just sends itself. The listing for FileScanRequestMessage is below:
 

package it.tidalwave.integritychecker;

import it.tidalwave.actor.MessageSupport;
import it.tidalwave.actor.annotation.Message;

@Message @Immutable @RequiredArgsConstructor(access=PRIVATE) @EqualsAndHashCode @ToString(callSuper=false)
public class FileScanRequestMessage extends MessageSupport
  {
    public static interface Filter
      {       
        public boolean accepts (@Nonnull FileObject fileObject); 
      }
     
    @Nonnull @Getter
    private final FileObject folder; 
   
    @Nonnull @Getter
    private final Filter filter; 
   
    @Nonnull
    public static FileScanRequestMessage forFolder (final @Nonnull FileObject fileObject)
      {
        return new FileScanRequestMessage(fileObject, Filter.ANY);
      }   
   
    @Nonnull
    public FileScanRequestMessage withFilter (final @Nonnull Filter filter)
      { 
        return new FileScanRequestMessage(folder, filter); 
      }
  }


Somewhere there's a FileObjectDiscoveryActor that listens to that message:

package it.tidalwave.integritychecker.impl;

import it.tidalwave.actor.annotation.Actor;
import it.tidalwave.actor.annotation.ListensTo;

@Actor @ThreadSafe
public class FileObjectDiscoveryActor
  {
    public void onScanRequested (final @ListensTo FileScanRequestMessage message)
      {
        for (final FileObject child : message.getFolder().getChildren())
          {
            if (message.getFilter().accepts(child))
                         {
                           (child.isFolder() ? FileScanRequestMessage.forFile(child).withFilter(message.getFilter())
                                             : FileDiscoveredMessage.forFile(child)).send();
                         }
          }
      }
  }

You can see here my syntactic sugar: the actor is a POJO and methods designated to receive messages are annotated by @ListensTo. Multiple methods can listen to multiple messages. The annotation is similar to @Observes by CDI (JSR-299) - actually I'd love to reuse it, but it seems to have different semantics (e.g. by default it can activate managed objects that are the target of an inbound message; furthermore there are multiple delivery options related to transactionality that at the moment I'm not interested into).
 

Recursive directory navigation is implemented by sending another FileScanRequestMessage. When a regular file is detected, a FileDiscoveredMessage is fired (there's no need to see its listing, as it's straightforward).
 

Inbound messages are first enqueued and then dispatched in a FIFO fashion (with exceptions explained later). If the actor is not thread safe, there's the guarantee that it can be engaged by a single thread at any time (thus, messages are processed one per time). In this way there's no need to have synchronized sections. If the actor is thread safe (the default), as FileDiscoveredMessage that's even stateless, it can be engaged by multiple threads at the same time. The thread safety property is specified as an attribute of @Actor (unfortunately @ThreadSafe can't help since its retention is compile time).
 

The second actor is the one that reads data from files:
 

package it.tidalwave.integritychecker.impl;

import it.tidalwave.actor.annotation.Actor;
import it.tidalwave.actor.annotation.ListensTo;

@Actor(initialPriority=Thread.MAX_PRIORITY) @ThreadSafe
public class FileLoaderActor
  {
    public void onFileDiscovered (final @ListensTo FileDiscoveredMessage message)
      {
        final FileObject fileObject = message.getFileObject();

        try
          {
            final File file = FileUtil.toFile(fileObject);
            final @Cleanup RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
            final MappedByteBuffer byteBuffer = randomAccessFile.getChannel().map(READ_ONLY, 0, file.length()); 
            byteBuffer.load();
            randomAccessFile.close();
            new FileContentsAvailableMessage(fileObject, byteBuffer).send();
          }
        catch (Exception e)
          {
            FileDamageDetectedMessage.forFile(fileObject).withCause(e).send();
          }
      }
  }

It uses memory-mapped I/O for speed and fires a FileContentsAvailableMessage carrying the bytes, or a FileDamageDetectedMessage in case of error.
 

The next stage is the actor that computes the fingerprint:
 

package it.tidalwave.integritychecker.impl;

import it.tidalwave.actor.annotation.Actor;
import it.tidalwave.actor.annotation.ListensTo;

@Actor @ThreadSafe
public class FingerprintComputerActor
  {
    public void onFileContentsAvailable (final @ListensTo FileContentsAvailableMessage message)
      throws NoSuchAlgorithmException
      {
        final String algorithm = "MD5";
        final MessageDigest digestComputer = MessageDigest.getInstance(algorithm);
        digestComputer.update(message.getContents());
        final Fingerprint fingerprint = new Fingerprint(algorithm, toString(digestComputer.digest()));
        FingerprintComputedMessage.forFile(message.getFileObject()).withFingerprint(fingerprint).send();
      }
  }

Again, a FingerprintComputedMessage message carrying the result is fired. The last stage is the persistence actor:
 

package it.tidalwave.integritychecker.impl;

import it.tidalwave.actor.CollaborationStartedMessage;
import it.tidalwave.actor.MessageSupport;
import it.tidalwave.actor.annotation.Actor;
import it.tidalwave.actor.annotation.ListensTo;
import it.tidalwave.actor.annotation.Message;
import it.tidalwave.actor.annotation.OriginatedBy;

@Actor(threadSafe=false) @NotThreadSafe
public class PersistenceManagerActor
  {
    @Message(outOfBand=true) @ToString
    static class FlushRequestMessage extends MessageSupport
      {
      }
   
    private final Map<String, Object> map = new TreeMap<String, Object>();
   
    private File persistenceFile;
   
    private boolean flushPending;
   
    public void onScanStarted (final @ListensTo CollaborationStartedMessage cMessage,
                                       final @OriginatedBy FileScanRequestMessage message)
      {
        final File folder = FileUtil.toFile(message.getFolder());               
        final String fileName = new SimpleDateFormat("'fingerprints-'yyyyMMdd_HHmm'.txt'").format(new Date());
        persistenceFile = new File(folder, fileName);
        map.clear();
      }
   
    public void onFileDiscovered (final @ListensTo FileDiscoveredMessage message)
      {
        final String name = message.getFileObject().getNameExt();
       
        if (!map.containsKey(name)) // message sequentiality is not guaranteed
          {
            map.put(name, "unavailable"); 
            requestFlush();
          }
      }

    public void onFingerprintComputed (final @ListensTo FingerprintComputedMessage message)
      {
        final String name = message.getFileObject().getNameExt();
        final Fingerprint fingerprint = message.getFingerprint();
        map.put(name, fingerprint);
        requestFlush();
      }
   
    private void onFlushRequested (final @ListensTo FlushRequestMessage message)
      throws InterruptedException, IOException
      {
        flushPending = false;
        // writes data to file
     }
   
    private void requestFlush()
      {
        if (!flushPending)
          {
            new FlushRequestMessage().sendLater(5, TimeUnit.SECONDS);
            flushPending = true;
          }
      }
  }

The basic idea is not to write to disk every piece of data as it's generated, since it might be expensive (well, perhaps writing to a relational database wouldn't be, but for a simple tool such as SolidBlue it makes more sense to write to a flat file). So, data are first put into an in-memory map (a record is generated as soon as a file has been discovered and later overwritten with the final result) that is periodically flushed to disk. So, the actor is stateful, hence it's not thread safe (there must be only one instance). Whenever the map is changed, it's marked 'dirty' and a request to flush it to the disk is generated. The flush will happen within 5 seconds, but it's not a good idea to use a Java Timer as I'd run into the threading problems that I want to avoid. Instead, a private FlushRequestMessage is sent back to itself with some delay, triggering the write to the disk. This message is annotated as 'out-of-band', it means that must delivered with high priority (in practice, it's placed at the head of the incoming message queue rather than the tail). Since the runtime guarantees that only a single message can be processed by any actor instance at any time, there's no need to protect the map, or the flushPending flag, by synchronized sections.

The onScanStarted() method is interesting, because it introduces the concept of collaborations.

 

Collaborations
 

Actually, asynchronicity is excellent for massively concurrent system (as well as, not to say, to model things that are asynchronous in nature, and there are many). But it's nice to know, in some way, that a sequence of things that happened in response to a message of yours has been completed. In my code I've called this concept "Collaboration":
 

       
  1. Any message is always part of a Collaboration.
  2.    
  3. If the thread creating a certain message is not bound to a Collaboration, a new Collaboration is created and the message will be considered its originator.
  4.    
  5. The originator message will be delivered in threads bound to its Collaboration. This means that any further message, created as a consequence of the reception of the originator message, will share its Collaboration.
         
  6.    
  7. A Collaboration keeps tracks of all the related messages and threads by means of reference counting.
         
  8.    
  9. When there are no more pending messages or working threads for a Collaboration, it is considered completed.
  10.    
  11. Two special messages, CollaborationStartedMessage and CollaborationTerminatedMessage, are fired by the runtime to notify of the creation and completion of collaborations.

When a message is sent, you can get its Collaboration object:
 

final Collaboration collaboration = new MyMessage().send();

and any listening method can get the Collaboration as well:
 

public void onMyMessage (final @ListensTo MyMessage message)
  {
    final Collaboration collaboration = message.getCollaboration();
    ...
  }

By construction, thus, a Collaboration is attached to all the threads that are directly or indirectly triggered by the originating message. This could be used for managing regular transactions (for instance, attaching a javax.transaction.UserTransaction to the Collaboration).   But actors seem to be better dealing with Software Transactional Memory, so I drop this argument for now.
 

It's even possible to synchronously waiting for a Collaboration to complete:
 

collaboration.waitForCompletion();
 

even though I think it's only useful for tests.  More interesting is the case in which a Collaboration includes bidirectional interactions with a user: for instance, making a dialog box to pop up and wait for a selection.
In this circumstances, a Collaboration can be suspended (this means it is not considered to be terminated even though there are no pending messages or working threads) and later resumed. More details in a further post.
 

Collaborations is something that I don't expect to find in platforms such as Akka, since I'm not sure it's feasible to have them working in an efficient way in a distributed context (I mean: maybe yes, maybe not, I haven't studied the problem yet). But they are a nice feature to have if possible and perhaps it's possible to implement it on top of an existing actor platform.
 

Back to the method onScanStarted(), it is clear now that it listens to the CollaborationStartedMessage messages originated by a FileScanRequestMessage to initialize the storage of the fingerprints, which must be located in the top scanned directory.
 

In a similar way, the IntegrityCheckerPresentationControllerActor listens to the various messages being delivered, including those notifying the beginning and the end of the Collaboration, to update the user interface:
 

package it.tidalwave.integritychecker.ui.impl;

import it.tidalwave.actor.MessageSupport;
import it.tidalwave.actor.Collaboration;
import it.tidalwave.actor.CollaborationCompletedMessage;
import it.tidalwave.actor.CollaborationStartedMessage;
import it.tidalwave.actor.annotation.Actor;
import it.tidalwave.actor.annotation.ListensTo;
import it.tidalwave.actor.annotation.Message;
import it.tidalwave.actor.annotation.OriginatedBy;

@Actor(threadSafe=false) @NotThreadSafe
public class IntegrityCheckerPresentationControllerActor
  {
    private static final double K10 = 1000;
    private static final double M10 = 1000000;
   
    @Message(outOfBand=true, daemon=true) @ToString
    private static class RefreshPresentationMessage extends MessageSupport
      {
      }
                 
    private final IntegrityCheckerPresentationBuilder presentationBuilder = Locator.find(IntegrityCheckerPresentationBuilder.class);
   
    private final IntegrityCheckerPresentation presentation = presentationBuilder.createPresentation();
   
    private final Statistics statistics = new
Statistics();
   
    private boolean refreshing = false;
   
    private int totalFileCount;
   
    private long totalDataSize;
   
    private int processedFileCount;
   
    private long processedDataSize;
   
    public void onScanStarted (final @ListensTo CollaborationStartedMessage cMessage,
                                     final @OriginatedBy FileScanRequestMessage message)
      {
        totalFileCount = 0;
        totalDataSize = 0;
        processedFileCount = 0;
        processedDataSize = 0;
        refreshing = true;
        new RefreshPresentationMessage().send();
      }
   
    public void onScanCompleted (final @ListensTo CollaborationCompletedMessage cMessage,
                                       final @OriginatedBy FileScanRequestMessage message)
      {
        refreshing = false;
        presentation.setProgressLabel("done");
        new RefreshPresentationMessage().send();
      }
   
    public void onFileDiscovered (final @ListensTo FileDiscoveredMessage message)
      {
        totalFileCount++;
        totalDataSize += message.gnbsp;nbsp;nbsp;nbsp; nbsp; }etFileObject().getSize();
      }
   
    public void onFingerprintComputed (final @ListensTo FingerprintComputedMessage message)
      {
        processedFileCount++;
        processedDataSize += message.getFileObject().getSize();
        final Collaboration collaboration = message.getCollaboration();
        final long elapsedTime = collaboration.getDuration().getMillis();
        final double speed = (processedDataSize / M10) / (elapsedTime / K10);
        final int eta = (int)(((totalDataSize - processedDataSize) / M10) / speed);
        ... // and update the statistics object
      }
   
    private void updatePresentation (final @ListensTo RefreshPresentationMessage message)
      {
        presentation.updateStatistics(statistics);
       
        if (refreshing)
          {
                  new RefreshPresentationMessage().sendLater(1, TimeUnit.SECONDS);
          }
      }
  }

Actually another advantage of message-based designs is that a user interface can be easily updated without having to know a large number of listeners.
 


Activation
 

Actors are managed objects and must be never directly accessed. To accomplish this, they are declared by means of activators, which typically are grouped together such as in:
 

package it.tidalwave.integritychecker.impl;

import org.openide.util.lookup.ServiceProvider;
import it.tidalwave.actor.spi.ActorGroupActivator;
import static it.tidalwave.actor.spi.ActorActivator.*;

@ServiceProvider(service=IntegrityCheckerActivator.class)
public class IntegrityCheckerActivator extends ActorGroupActivator
  {
    public IntegrityCheckerActivator()
      {
        add(activatorFor(FileObjectDiscoveryActor.class).withPoolSize(8));
        add(activatorFor(FileLoaderActor.class).withPoolSize(1));
        add(activatorFor(FingerprintComputerActor.class).withPoolSize(4));
        add(activatorFor(PersistenceManagerActor.class).withPoolSize(1));
      }
  }

Activators specify the pool size of each actor. Given that, it's possible to activate and deactivate the group:

Locator.find(IntegrityCheckerActivator.class).activate();
Locator.find(IntegrityCheckerActivator.class).deactivate();

 

For people not used to the NetBeans Platform, @ServiceProvider is a compile-time annotations that generates a service declaration into META-INF/services, while Locator is a facility that retrieves the reference at runtime.
 

Actors can have methods annotated with @PostConstruct and @PreDestroy, which will be called just before activation and just after deactivation, of course in a thread-safe way. There's the guarantee that messages can't be delivered before activation is completed and after deactivation.
 


Simpler than Akka... for how long?
 

This works, I enjoy the fact that I can avoid synchronized blocks and so far I don't miss the fact that that thing is clearly much less performant than Akka. Everything fits into less than 40k of jar file and it's much simpler than Akka (whose complexity is justified by the fact that it offers many more features). So what? Distributing to a network is something that we can't ignore in a cloud oriented world. So it's likely that going on I'll see the need for more features: often you discover that you need new features as you go on. Smell of reinventing the wheel ahead!
 

For instance, consider the FileLoadActor. I've previously said that experimental evidence demonstrates that it makes sense (at least with large files) to have it instantiated in a single instance, thus serializing data access to the disk. This makes sense given the physical nature of a magnetic disk. But this happens with a single disk: if you have more than one, it probably makes sense to have one instance per disk. Having a Solid State Drive (SSD) changes the rules. This means that you must have some more complex way to dispatch messages, a form of routing. Akka offers it, and it would be unwise to rewrite this feature from scratch.
 

So now I'm going to start phase two, that is to reimplement this stuff upon Akka (using the 2.0 milestone that's already available). In a few weeks I'll let you know how the story goes on.

The code that I described in this blog post are available at the Mercurial repository http://bitbucket.org/tidalwave/solidblue-src, tag 1.0-ALPHA-4.
 

In a further post I'll talk about how Collaborations are used by blueArgyll, which features more complex interactions with the user. See you later.

I might be wrong, but Google just published what appears to be, at least to my knowledge (I could have missed some other in the past) the first interactive Doodle. It's in honor of Stanis?aw Lem, sci-fi writer of Solaris fame (please, if you have time, watch the  Tarkovskij's movie rather than - or in addition to - the Soderberg one, even though  Tarkovskij is harder to follow) and at a certain point during an animation a robot appears. It challenges you with a math quiz and you can interact with it to go on. Then a further challenge appears... but at this point I have to go back to a meeting. ;-)

Monday evening I was back home from Devoxx '11. Excellent conference and excellent people, I'm so happy I was back to it after two years. I'm full of sensations and things to think about for the next weeks. Also for the non technical part of the journey: I drove for more than 2.800 kilometers full of beauty, from the magnificent Brugge, to the chatedral of Reims, passing through the Lac du Der-Chantecoq filled with cranes, and the ever beautiful Bourgogne: this made for 1536 photo shoots and videos, whose postprocessing will keep me busy for some time. 

I even survived a disk crash just the evening before my talk - fortunately I recently fitted two disks into my laptop, and the backup was fine. I'll post more about this later, just in case the setup tips are interesting for somebody.

This long introduction :o) just to say that my slides about "Bulding Android apps with Maven" are available at SlideShare.

fabriziogiudici

Back to Devoxx! Blog

Posted by fabriziogiudici Nov 15, 2011

2011, and I'm back to my favourite conference. In the past two years I attended JavaOne and Jazoon, but for different reasons I wasn't able to go to Antwerpen. A number of things have changed in the meantime. Sun is no more here, but I already absorbed the shock at JavaOne 2010. Devoxx is held in November since a couple of years (previously it was in December). For my desire to match a photographic trip to France this is definitely a plus: the landscape looks better one month in advance and it seems that the weather is definitely better too (or maybe is it just a chance?): four days for the trip to Antwerpen and four days of excellent weather in a row (with just a few hours of fog through Picardie). 

Now, the conference. As usual, everything is smooth and well organized. The speakers' dinner, yesterday, was excellent to meet (again) some people whom you usually interact with only by means of the internet (the food was fine too, BTW). There are differences, through the years. My first Devoxx's (JavaPolis at the time) were packed with italians, especially JUG leaders. For a number of reasons, this is no more happening. I also recall a large pack of brazilians, lead by Bruno - well, this morning Stephan Janssen is trying to deceive me, as he's wearing the large brazilian flag on his back (I suppose I'll figure out why now that he's starting the introductory talk).

The technical thing for getting in this year is a wristband, a plastic band that is wrapped around your wrist carrying on identification information. I suppose it's better for the management - what I don't like is that you should keep it all the time until the conference is over. Well, it's waterproof (no problems with the shower), but I really hate to have something at my wrist when I go to sleep. Fortunately, with a little trick, it's possible to remove and re-attach it (working around a design of the junction that is supposed to self-destroy when detached). 

Yesterday I also met some guys from the NetBeans Dream Team (and Geertjan of course). In front of a beer offered at the Oracle stand there has been a quick discussion about Swing, JavaFX 2.0, HTML 5 and the tablets. More about this in a upcoming blog post. 

So big is my excitement that I even managed in waking up at the proper time this morning and I'm ready to attend the first keynote speech (usually I miss those at the first time slot). Some numbers: Devoxx celebrates its tenth birthday with 3350 attendees from 40 countries; 150 sessions, 200 hours and 170+ Rock Star speakers. 60 JUGs endorsed the event. Google is for the first time a sponsor. And an announcement: we have a spin off in Paris: Devoxx France! 18th to 20th April 2012. As far as I understand, there will be a relevant percentage of presentations held in french language. 

Enough for this morning. Oh, of course, let's not forget my speech: "Building Android apps with Maven", which is scheduled tomorrow afternoon (Nov 17) at 14:00. 

PS Ok, the brasilian flag is in honour to Bruno, that wasn't able to be there. Bruno is even depicted in the large "map of the world" that is this year's official graphics of the conference (it has been on the home page of the conference for months). The graphics itself, BTW, is something allegoric with a lot of details inside, much in the same way the flemish famous painter Hieronymus Bosch made his masterworks. Only a bit less worrying.     

The past summer I announced that I was going to move all my websites to a new CMS, and actually blueBill has been moved since that. Unfortunately I had some trivial problems while migrating the others, and then a number of accidents, the latest one being a major flood in the town where I live, stole me the time to complete the operation. Thus, you'll see that blueMarine and forceTen at the moment are broken (pointing to an error page or a Jetty welcome page) and jrawio has got some broken links and missing CSS/media. Please bear with me for still some time, until I fix everything.

The last page on the latest issue of IEEE Spectrum attracted my attention since it was about the popularity of programming languages. The page was made of four pictures taken from langpop.com, which makes popularity figures out of multiple sources:

       
  • Yahoo Search
  •    
  • Craigslist
  •    
  • Powell's Books
  •    
  • Freshmeat
  •    
  • Google Code
  •    
  • Del.icio.us
  •    
  • Ohloh
  •    
  • programming.reddit.com
  •    
  • Slashdot
  •    
  • IRC

This is different than TIOBE, that looks at some of the same sources, but then provides a weighted average (langpop.com offers a form to compute a weighted average with equal coefficients - useless - and with your favourite coefficients - useful only to tweak the statistics to accomplish your desires).     Java performs very well in all cases (being mostly in the first or top three places); Craigslist gives a lower figure, and one might thing it's relevant since it's about job offerings. But AFAIK Craigslist is popular in the US, not in Europe (perhaps a query on LinkedIn or Monster would be more interesting). In most cases, Java, C and C++ are at the top three positions, while some sites gives the first position to JavaScript or Python.     The funny thing is that probably the best result is with Slashdot, which is a site mostly hostile to Java. This recalls me a popular motto in my country: "good or bad, it's mostly about being talked on". Who knows.     It's difficult to compare all that stuff. Too bad langpop.com doesn't provide trends for each source (there's a timeline view, but it's only aggregated and the web owners say that they don't have a big deal of historic data; in any case, if you try it, Java is substantially stable since 2008). They would be much more interesting when compared over time.      

fabriziogiudici

Thanks, Vaadin Blog

Posted by fabriziogiudici Oct 28, 2011

I've just left a meeting where the PM congratulated the team because the customer accepted a product release that was made with three weeks in advance of the original plan. First, thank to the developers' team. Second, thank to the good development process (people and process are always the important things, more than technology). Third, thank to libraries and software factory, including Maven, Spring, NetBeans, TestNG, Nexus, Hudson, Jira - with an explicit mention for Vaadin.

It's my first web project after a few years in which I've been primarily involved with destkop apps and applets. My customer too, just because it's doing stuff which couldn't be made with a web UI. This new project has got a simpler UI and the specific requirement of being a webapp, so it went that way. It's also my first business with Vaadin, which entered my radar a few years ago, but I got acquainted with only at the beginning of this year (not because it's hard, but because only recently I found some time for it). 

Vaadin makes you able to work exclusively with Java and automatically generates a UI running JavaScript, based on components from the Google Web Toolkit. You don't have to run code translators or such, you just program in regular Java, write regular Java tests, JavaScript is generated for you at runtime. A piece of cake. And JavaScript is how my customer and I like it: a bytecode to run in a VM, not a programming language.

You can use Vaadin in many ways. With Maven is pretty easy if you start with an archetype. Vaadin offers a number of model classes which can be used to design your application on. I drove a different design: abstract MVC with interfaces and default controllers, so you can test everything with JUnit / TestNG (*). Views are completely dummy objects, only mocked in tests. Then you have Vaadin UI components implementing them. In this way you have the additional benefit of not depending on a specific UI technology. Not that we don't trust Vaadin: it's version 6, with ten years of history. Not that we plan to change Vaadin: I don't see anything like it for the web. It's just that I consider a Good Practice to reduce dependencies on specific technologies as much as possible.

PS It's also the first time I'm using TestNG and Lombok with a business project. The former made our tests much better, the latter our code  terser. Thanks.

 

(*) You can see some examples about my way to MVC in a series of DZone posts - the first one being available, the next one coming soon.

 **** Edited to add:

At DZone they have just blogged about a book about Vaadin. I've just bought it.

A number of things are being changed in the infrastructure of Tidalwave projects:

  • Moving websites of projects to a new software and server is going on: the latest involved project is jrawio. blueMarine and forceTen will follow.
  • Jira and a supporting Nexus repository which is needed for some projects (it hosts a few third parties' artifacts that aren't on Maven Central) have been also moved to a new server.
  • Jira has been upgraded from the old 3.12 to the latest 4.4.1.
  • Mailing lists and other parts of the infrastructure are also being consolidated to Java.Net, coming from Kenai.
  • Mercurial repositories have been moved to BitBucket, since it offers the same cool "fork and pull" way of working of GitHub.

Please understand that this process implies some temporary disruption of service, in particular when a server is moved and a DNS change is implied.

Geertjan Wielenga (Oracle) and Toni Eppleton (NetBeans Dream Team) are going to give a certified training course about the NetBeans Platform. Please have a look here for more information and online registration.

The past week Markus Eisele notified that on Aug 31 an new release of JDK 1.7.0 was released, fixing the bugs that caused so much noise a few months ago. One month ago I started adding JDK 7-based jobs to my Hudson, to check compatibility of my projects. So far, so good (I only had to upgrade a dependency to Lombok to get the fix for an incompatibility with the Java 7 compiler). So, after a further week of manual tests at home, I've decided to move my new site hosting to Java 7. It's a very simple setup, with Jetty directly serving my websites by means of my new, ultraweight CMS - it sounds as the good, first small step for using JDK 7 in production. It already handles blueBill Mobile, Stopping Down, the revived Tidalwave website (whose contents are being redesigned from scratch) and my new personal blog; further sites will be moved in the week end.

So far so good. I've only seen a PermGen OOM, which could have probably occurred with JDK 6 too (I didn't do any tuning of the JVM so far).

PS For what concerns my new personal blog, I'm not moving away from here. It's just a place for things that aren't Java or photography.

Filter Blog

By date: