Summary: This tutorial explains JavaSpaces basics and shows how to build a pure JavaSpaces application with GigaSpaces.
Overview
This basic tutorial will introduce you to the JavaSpaces standard and the JavaSpaces API. Throughout the tutorial, you will implement a simple, pure JavaSpaces application that could run on any JavaSpaces implementation. The tutorial will show you how to lookup a space, write Entries to the space and then read and take those Entries, using leases and transactions. JavaSpaces is a service specification from Sun Microsystems that provides a simple yet powerful infrastructure for building distributed applications. The JavaSpaces specification defines the space – a distributed, shared, memory-based repository for objects – and provides support for distributed transactions, events and leasing. In the JavaSpaces programming model, applications are viewed as a group of processes, cooperating via the flow of objects into and out of spaces. The JavaSpaces APIThe JavaSpaces API consists of four main methods:
In addition, the snapshot allows applications to provide optimization hints to the space. This minimal API set reduces the learning curve when adopting JavaSpaces. The API is also natural to Jini developers, since it is built on top of Jini specifications (Entries, leases, service, etc.). Jini itself is built on Java and RMI, so there is no need to understand complex distributed Java technologies, like EJB or CORBA. Some JavaSpaces TermsIn order to understand the basics of JavaSpaces, you will need to understand a few terms first:
Writing the Code
To start with, you'll need to implement an Entry object, which the application will write to the space. You'll also need to write mechanisms to discover a space and to create transactions. Finally, you can write Entries to the space and read them back, under a Jini distributed transaction. Entry ObjectThis is the Entry object that the application will write to the space. For the sake of simplicity, create a Message object that implements the Entry interface, with two attributes, an integer ID and a string for the content of the message. Remember that according to the standard your Entry implementation must have a public, no-args, constructor and all its fields should be public and non-primitive. Your object should look something like this: package com.gigaspaces.examples.tutorials.plainjavaspaces; import net.jini.core.entry.Entry; public class Message implements Entry { public String content; public Integer ID; public String toString(){ return "Message ID:" + ID + " ,Message content: " + content; } public Message(){} // No args constructor is mandatory in an Entry class } Note that all you need to import is net.jini.core.entry.Entry. Discovering the SpaceThe standard Jini approach to discovering a space is much more cumbersome than the way we do it at GigaSpaces (as you'll see in the next tutorial) but to stick to the standard, we'll now do it the hard way. A method that receives the space name, performs the lookup and returns a reference to a space might look like this: import java.rmi.RMISecurityManager; import net.jini.core.discovery.LookupLocator; import net.jini.core.entry.Entry; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceTemplate; import net.jini.lookup.entry.Name; import net.jini.space.JavaSpace; [...] static public JavaSpace findSpace(String spaceName) throws Exception { // Get a RMI security manger, if doesn't exist set a new one. // The security policy is passed to this security manager using the -Djava.security.policy flag. if ( System.getSecurityManager() == null ) System.setSecurityManager( new RMISecurityManager() ); //Create a template to lookup the JavaSpaces service. Class [] classes = new Class[]{net.jini.space.JavaSpace.class}; Name sn = new Name( spaceName ); ServiceTemplate tmpl = new ServiceTemplate(null,classes,new Entry[] { sn } ); // Locate the JavaSpaces service and create a JavaSpace proxy attached to it. LookupLocator locator = new LookupLocator("jini://localhost"); ServiceRegistrar sr = locator.getRegistrar(); JavaSpace space = (JavaSpace)sr.lookup(tmpl); return space; } Transactions MechanismCreating Jini transactions can be implemented as the class below: package com.gigaspaces.examples.tutorials.plainjavaspaces; import java.io.IOException; import java.net.MalformedURLException; import java.rmi.RMISecurityManager; import java.rmi.RemoteException; import net.jini.core.discovery.LookupLocator; import net.jini.core.entry.Entry; import net.jini.core.lookup.ServiceRegistrar; import net.jini.core.lookup.ServiceTemplate; import net.jini.core.transaction.Transaction; import net.jini.core.transaction.TransactionFactory; import net.jini.core.transaction.server.TransactionManager; public class TransactionHelper { private static TransactionHelper me = null; private TransactionManager trManager=null; public TransactionHelper() { } public static TransactionHelper getInstance(){ if(me==null){ me = new TransactionHelper(); } return me; } // getJiniTransaction // Returns a transaction manager proxy. // Args: // timeout - The length of time our transaction should live before timing out. // public Transaction.Created getJiniTransaction(long timeout) throws Exception { if (null == trManager) { trManager = findTransactionManager(); } Transaction.Created tCreated = TransactionFactory.create(trManager,timeout); return tCreated; } private TransactionManager findTransactionManager(){ if ( System.getSecurityManager() == null ){ System.setSecurityManager(new RMISecurityManager()); } // Creating service template to find transaction manager service by matching fields. Class [] classes = new Class[]{net.jini.core.transaction.server.TransactionManager.class}; ServiceTemplate tmpl = new ServiceTemplate(null,classes,new Entry[] { } ); // Creating a lookup locator. LookupLocator locator = null; try { locator = new LookupLocator("jini://localhost"); } catch (MalformedURLException ex) { System.out.println(ex.getMessage()); ex.printStackTrace(); } ServiceRegistrar sr = null; try { sr = locator.getRegistrar(); } catch (ClassNotFoundException ex1) { ex1.printStackTrace(); } catch (IOException ex1) { ex1.printStackTrace(); } TransactionManager tm = null; try { tm = (TransactionManager) sr.lookup(tmpl); } catch (RemoteException ex2) { ex2.printStackTrace(); } return tm; } } Writing Entries to the SpaceOnce you discover the space (as shown above), you can create instances of your Entries and write them into the space. Using the Message Entry showed above, writing Entries to the space might look like this: [...] Message message = new Message(); message.ID = 1; message.content = "My first PlainJavaSpaces Message!"; space.write(message, null, Lease.FOREVER); [...] Note that the write method receives three parameters – Entry to write to the space, transaction (no transaction in this case) and a Lease in milliseconds. In the code above the message Entry is written to the space, and stays there indefinitely or until it is explicitly removed. Reading or Taking Entries from the SpaceOnce you have written Entries to the space, you can read or take those Entries, one by one. To do this, you must define a template, which will be used to look for relevant Entries. A template is just an instance of your Entry implementation; matching is done by the type of the template as well as its field values. For example, assume there are two Message objects in the space, one with ID = 1 and the other with ID = 2. Before you call the read or take operations, you must instantiate another Message object and set the ID of the Entry that you want to find in the space. Leaving the content field null means that this field is used as a wildcard – the space returns Entries of this type regardless of the value in the field. Message template = new Message(); template.ID = 1; Message result = (Message)space.read(template, null, JavaSpace.NO_WAIT); [...] template.ID = 2; result = (Message)space.take(template, null, JavaSpace.NO_WAIT); Again, the read and take methods take three parameters – the template to match, transaction (none in this case) and a timeout value that indicates the maximum amount of time to wait when no matching Entries are found. When the timeout value is greater than 0, the thread is blocked until the timeout expires or a matching Entry enters the space and is caught by this thread. Writing or Reading Under TransactionTry performing operations on the space under a transaction. Using the TransactionHelper shown above, you can do this as follows: [...] Transaction.Created txn = TransactionHelper.getInstance().getJiniTransaction(60 * 1000); space.write(message, txn.transaction, Lease.FOREVER); Message result = (Message)space.read(template, txn.transaction, JavaSpace.NO_WAIT); txn.transaction.commit(1000); [...] Reference Source Code
Compiling the Code
To compile this code you will need to include two JAR files in your classpath. Assuming %JSHOMEDIR% is defined as your GigaSpaces installation root directory, the two JARs are:
If you keep your sources under the src folder and put your generated classes under the classes folder, your compilation command would then be similar to this (when executed from the application folder): javac -classpath %JSHOMEDIR%/lib/jini/jsk-lib.jar;%JSHOMEDIR%/lib/jini/jsk-platform.jar -d .\classes .\src\com\gigaspaces\examples\tutorials\plainjavaspaces\*.java Running Your Application
Starting the Space – a JavaSpaces ServiceBefore you can run your application, you need to start a JavaSpaces service. This service is the space on which your application performs its operations. %JSHOMEDIR%\bin\gsInstance "/./myspace?schema=javaspace"
In the command above the gsInstance script starts the GigaSpaces server. In GigaSpaces every space runs within and a container and the /./myspace argument instructs the server to start a new space with the name myspace and a default container name (in this case myspace_container). Starting the Jini Transaction Manager (Mahalo)If you wish to use Jini transactions in your application, you must also run the Jini Transaction Manager, called Mahalo. To start it, execute: %JSHOMEDIR%\bin\startJiniTX_Mahalo Running the ApplicationOnce the space is up (and optionally the Transaction Manager) you can run your application. Running our own example would look like this (one line): java -Djava.security.policy=%JSHOMEDIR%\policy\policy.all -classpath %JSHOMEDIR%/lib/jini/jsk-lib.jar;%JSHOMEDIR%/lib/jini/jsk-platform.jar;.\classes com.gigaspaces.examples.tutorials.plainjavaspaces.PlainJavaSpaces myspace Note that now, besides the jars, the classpath also includes our compiled classes. You also need to set a system property for the policy that the RMI Security Manager uses. Finally, the last argument is the space name you wish to connect to; it should be identical to the space name you chose when you started the space. That's it! What's Next?
Further Reading
|
![]() |
GigaSpaces.com - Legal Notice - 3rd Party Licenses - Site Map - API Docs - Forum - Downloads - Blog - White Papers - Contact Tech Writing - Gen. by Atlassian Confluence |