ParalleljRuntime_1-5-x.WebHome » Tutorials » 5 Minutes Example

5 Minutes Example

Goal

In this tutorial, we aim at discovering some basic ParallelJ's features in less than 5 minutes. For this example, we won't use ParallelJ studio, so as to illustrate that ParallelJ can be used completly programmatically, without any IDE integration. We'll see in another tutorial that we can still save some time by using ParallelJ studio.

Prerequisites

For this tutorial, I suppose you should know how to develop in Java, you should have some knowledge about Maven too, and I suggest you also to set up a ParallelJ development environment.

Let's start

Project creation

First of all, we need to create a project, we'll use one of the ParallelJ archetypes to make it easily. For this example, as we don't want the deployment of our project tricky, we will use the web archetype of parallelj, so in a command line, just type:

mvn archetype:generate -DarchetypeGroupId =org.parallelj -DarchetypeArtifactId =parallelj-archetype-web -DarchetypeVersion =LATEST

Then you'll be asked about some basic information related to the project. Let's provide these:

Define value for property 'groupId': : org.parallelj.tutorials
Define value for property 'artifactId': : 5minutes
Define value for property 'version':  1.0-SNAPSHOT: :
Define value for property 'package':  org.parallelj.tutorials: : org.parallelj.tutorials.5minutes
Confirm properties configuration:
groupId: org.parallelj.tutorials
artifactId: 5minutes
version: 1.0-SNAPSHOT
package: org.parallelj.tutorials.5minutes

At this point, we should have a project structure to work on:

ls -Al
total 3
-rw-r--r--    1 a183276  Administ     4141 Mar  1 14:53 pom.xml
drwxr-xr-x    4 a183276  Administ        0 Mar  1 14:53 src

Choosing the Bouncy Castle version

Please navigate to this link for deciding the bouncy castle version you want to choose.

Creating our first flow

Now, let's create a first simple flow. We'll try to enhance it in the second part of this tutorial. The flow we want to create will in fact execute two procedures.

  • The first one will generate a collection of strings. For our example, we should provide to the procedure how many strings it should generate.
    This first Procedure will implement the interface java.util.concurrent.Callable
  • The second one will get the datas generated by the first Procedure and then print these datas on the output console.
    This second Procedure will implement the interface java.lang.Runnable 

Define a first Procedure implementing Callable

So, let's begin with the first Procedure implementing Runnable which generate the strings:

package org . parallelj . tutorials ;

import java.util.ArrayList ;
import java.util.Collection ;
import java.util.concurrent.Callable ;

public class Generator implements Callable <Collection <String >> {

private Collection <String > data ;
private int size ;

public Generator ( int size ) {
  this . size = size ;
  this . data = new ArrayList <String >();
}

@Override
public Collection <String > call () throws Exception {
  for ( int i = 0 ; i < size ; i ++) {
   this . data . add ( "data" + i );
  }
  return this . data ;
}
}

This piece of code is quite easy to understand: you provide it a number of strings to generate.
The call method returns the generated strings.

Define a second Procedure implementing Runnable

Let's continue with the Procedure implementing java.lang.Runnable which print the datas generated by the first Procedure:

package org . parallelj . tutorials ;

import java.util.Collection ;

public class Viewer implements Runnable {

private Collection <String > datas ;

public Viewer (Collection <String > datas ) {
  this . datas = datas ;
}

@Override
public void run () {
  for (String data: this . datas ) {
   System . out . println (data );
  }
}
}

This piece of code just get the list of datas in the contructor. When the Tread is started, the datas are print to the output console.

Define the Flow of the Program

At this point, let's implement a simple flow to manage this executable:

package org . parallelj . tutorials ;

import java.util.Collection ;

import org.apache.log4j.Logger ;
import org.parallelj.AndJoin ;
import org.parallelj.AndSplit ;
import org.parallelj.Begin ;
import org.parallelj.Program ;

@Program
public class Example {

private Collection <String > datas ;
private static final Logger logger = Logger . getLogger (Example . class );

/*
  * Begin of Program
  * Entry method for Procedure generateDatas
  */

@Begin
public Generator generateDatas () {
  logger . info ( "Start..." );
  return new Generator ( 10 );
}

/*
  * Exit method for Procedure generateDatas
  */

@AndSplit ({ "view" })
public void generateDatas (Generator executable , Collection <String > value ) {
  this . datas = value ;
  logger . info ( "Stop... Generated data: " + this . datas . size ());
}

/*
  * Entry method for Procedure view
  */

@AndJoin
public Viewer view () {
  return new Viewer ( this . datas );
}

/*
  * End of Program
  * Exit method for Procedure view
  */

@AndSplit ({ "end" })
public void view (Viewer executable ) {
  logger . info ( "End..." );
}
}

As you can see, a ParallelJ program is something really easy to write, as it only consists in a Java class with some annotations. Here, we use the @Program annotation to say that we develop a ParallelJ program. Then, we just define the flow using annotations: @Begin for the beginning of the flow, and @AndSplit for the output of the procedure. Here, the output will be the end of the process.

As you can see, the signature of the exit methods are different depending of the type of procedure used: Runnable or Callable...
In fact, when we use Callable, the return type of the Callable is add as a parameter of the exit method of the procedure. This allows to be able to get the corresponding Object returned by the call method of this Callable.

Executing this simple flow

Now, we'd like to run this first example to saw if it works.
We just have to add this annotation at the top of our program:

package org . parallelj . tutorials ;

import java.util.Collection ;

import org.apache.log4j.Logger ;
import org.parallelj.AndJoin ;
import org.parallelj.AndSplit ;
import org.parallelj.Begin ;
import org.parallelj.Program ;

@Program
public class Example {
  .....
}

That's all, we can now use the lauching API to launch our program. Create a new class in src/test/java so as to execute it like a unit test:

package org . parallelj . tutorials ;

import junit.framework.Assert ;

import org.junit.Test ;
import org.parallelj.launching.LaunchException ;
import org.parallelj.launching.Launcher ;
import org.parallelj.launching.Launch ;

public class ExampleTest {

@Test
public void testExampleProgram () {
  Launcher launcher = null ;
  try {
   launcher = Launcher . getLauncher ();
   Launch <Example > launch = launcher . newLaunch (Example . class );
   launch . synchLaunch ();
  } catch (LaunchException e ) {
   Assert . fail ();
  }
}
}

As you can see, launching a ParallelJ program is really easy, as it uses a clear API, and a few annotations. Last step: let's execute the test !

mvn clean test

In the output, we can read:

INFO  16-08 11:34:49,515 (Example.java:generateDatas:35 )  -Stop... Generated data: 10
data0
data1
data2
data3
data4
data5
data6
data7
data8
data9
INFO  16-08 11:34:49,515 (Example.java:view:52 )  -End...
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.301 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

Remote control

Finally, for the end of this tutorial, it could be interesting to: receive the number of strings from the outside, deploy the program on an application server, make it available through ssh, use it remotely.

I guess you'll think this is too much for a five minutes example... So let's see how ParallelJ can help us with this:

First, we'd like to receive the parameter from the outside, so let's add it in our program:

@In
public int size ;

public void setSize ( int size ) {
this . size =size ;
}

It's quite easy, isn't it ? You just have to declare a new variable, and add the @In annotation on it. Then, we just need to provide it to the executable:

@Begin
public Generator generateData () {
  logger . info ( "Start..." );
  return new Generator (size );
}

Now, let's try to deploy our program remotely, and access it through ssh... In order to do this, we need to modify the configuration file, located in src/main/resources and add this:

<beans>
     <bean class= "org.parallelj.tutorials.Example" />
</beans>

And... That's all. Now we just need to run it on an application server. Let's use the t7 plugin, which is already configured in the pom.xml coming from the archetype:

mvn clean install t7:run

Now, we can access it though ssh:

ssh localhost

We can now use some commands to interact with ParallelJ server, like the help one, which will display you all the available ones. Using ll, we can see the list and the signatures of all the available programs:

Shell>ll
id:0 org.parallelj.tutorials.Example args: [size:int ]

Now, we can launch the program and specify it the arguments:

Shell>sl -i 0 -a size =15
Program org.parallelj.tutorials.Example with jobId 1330614408203 is terminated with status SUCCESS! Return code: []

And on the server side, you'll see something like:

INFO  16-08 11:55:40,192 (Example.java:generateDatas:42 )  -Stop... Generated data: 15
data0
data1
data2
data3
data4
data5
data6
data7
data8
data9
data10
data11
data12
data13
data14
INFO  16-08 11:55:40,192 (Example.java:view:58 )  -End...

Report

Here it is for this 5 minutes example, during this tutorial, we created a simple ParallelJ program, and saw how ParallelJ let us deploy it remotely easily ; finally, we accessed it through SSH, and saw how to provide it some parameters from the outside.

In another tutorial, we'll see how to deal with multi-threading execution, but also remote access through REST, Telnet or JMX.