Flex/AIR to Java Communication Using Merapi

If you’re looking for a way to communicate between Flex and Java, there’s a great API available for doing just that. It’s called Merapi and is basically a bridge for sending messages between Java applications and Flex/AIR apps. I recently worked on a project for Adobe (shhh, until MAX!) where I used Merapi to communicate between an Eclipse plugin and an AIR app and found it extremely cool! One of the greatest things I found with it is the fact that it is written on top of the AMF3 libraries so passing objects between the two is a piece of cake!

In this post I will show how I was able to use Merapi to suit my needs of communication. I started with Merapi on the Java side by creating a Merapi Bridge instance and registering the various messages I wanted to listen to along with the handler object. The object specified as the handler needs to implement the handleMessage() method and gets called when a message being listened to is received. Each message has a name to identify it between the Java and ActionScript/Flex side. The code to register the messages in Java looks like the following:

          Bridge br = Bridge.getInstance();
          br.registerMessageHandler(MSG_FINDCOMPS, this);      // MSG_FINDCOMPS is a static String with value FindComponents
          br.registerMessageHandler(MSG_FINDFEATCOMPS, this);  // MSG_FINDFEATCOMPS is a static String with value FindFeaturedComponents

and the code to handle those messages when they are received on the Java side looks like the following:

          public void handleMessage( IMessage message ) {
		// Check message type and handle accordingly
		if (message.getType().equals(MSG_FINDCOMPS)) {
			final IMessage m = message;
			resultTableDisplay.syncExec(new Runnable() {
		        public void run() {
		            final ArrayList<Component> al = (ArrayList<Component>)m.getData();
		        	compList.setComponents(al);
			    }
		        });
		}
		if (message.getType().equals(MSG_FINDFEATCOMPS)) {
		    // In this case, we want to go ahead and reply with a message containing the Plugin Transfer
		    // Object so we have the Eclipse workspace path etc... back in the AIR app
		    TDFPluginTransferObject tpto = new TDFPluginTransferObject();
		    tpto.setSelectedComponentId(null);
		    try {
	                IPath path = (IPath) org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getRawLocation();
			tpto.setPluginDownloadPath(path.toString());
			this.sendMessage(MSG_SENDINFO,tpto);
		    }
		    catch (IllegalStateException ex) {
			System.out.println("IllegalStateException:" + ex);
		    }

		    final IMessage m = message;
		    featuredTableDisplay.syncExec(new Runnable() {
		    public void run() {
		        final ArrayList<Component> al = (ArrayList<Component>)m.getData();
		             featuredCompList.setComponents(al);
		        }
		    });
		}
	}

Notice in the code shown above, I am also sending a message to the AIR side with a custom object containing data I need there as a response to a message I had received. That object is represented by a class on both the the AIR and Java side and all serializing/deserializing of it is done for me underneath, which is awesome! More about that again shortly. My sendMessage() method is where I actually do all the sending from the Java side to the AIR side and looks like the following:

        public void sendMessage(String msgType, Object msgData) {
		try {
			Bridge.getInstance().sendMessage(new Message(msgType,null, msgData));
		}
		catch(Exception ex) {
			System.out.println("Exception " + ex);
		}
	}

So now we need to head over to the AIR side to see how this all fits together. First I need to make sure that the app was called from my plugin since I have specific behavior that is needed in that case. So to do this I check for an invoke argument that I pass from the Eclipse side when I invoke the AIR app. If found, then I want to create a Merapi Bridge instance and listener, along with a specified handler method for the responses. As you have probably noticed, the Bridge object is implemented as a Singleton, so you always get that one instance.

	if (invokeEvt.arguments[0] == "plugin") {
	        isPlugin = true;
		bridge = Bridge.instance;
	  	bridge.addEventListener(ResultEvent.RESULT,handleResponse);
	}

The handleResponse() method to specified above is called when a response is received from Java and that handler looks like the following:

       private function handleResponse(event:Event):void
       {
            var ev:ResultEvent = ResultEvent(event);
		var msg:Message = Message(ev.result);
		if (msg.type == "FindComponents") {
			if (msg.data != null) {
				var msgType:String = msg.type;
				comps = objectData.getFilteredComponents(String(msg.data));

	    		}
			var m : Message = new Message();
           		m.type = "FindComponents";
               		m.data = comps;
               		bridge.sendMessage(m);
		}
		else if (msg.type == "SendPluginTO") {
		        pluginTransferObject = TDFPluginTransferObject(msg.data);
		}
		else if (msg.type == "Minimize") {
			this.minimize();
		}
		else if (msg.type == "Dock") {
			this.dock();
		}
		else if (msg.type == "Undock") {
			// We need to figure out what the download path is from the returned message and set it
			pluginTransferObject = TDFPluginTransferObject(msg.data);
			this.objectList_change(null); // Fire the navigation to the component double-clicked from plugin
			this.undock(event);
		}
		else if (msg.type == "Exit") {
			isPlugin = false;
			onExiting(event);
		}
     }

The Java side is the ‘initiator’ of the communication, and the AIR app handles it’s requests via the above method, however the AIR side can also send a message to the Java side once the bridge has been established. An example of that is shown below, were we specify the component type name and its data before sending.

                var m : Message = new Message();
	       	m.type = MSG_FINDCOMPS;  // where MSG_FINDCOMPS is a static variable string with value FindComponents
	        m.data = featuredComps;
	        bridge.sendMessage(m);

There is one line of code from the handleResponse() method I’d like to point out in particular, where I’m creating the custom object below:

        pluginTransferObject = TDFPluginTransferObject(msg.data);

This is the other side of the object serialization that occurs automatically for me so my object is ready to go upon receipt. Two main things to be noted here… 1) you MUST put the remote path of the Java side object to be mapped to inside your custom ActionScript object (such as in my TDFPluginTransferObject in this case). That statement looks like the following:

[RemoteClass(alias="com.adobe.tourdeflex.core.TDFPluginTransferObject")]

and 2) all properties of the object must match exactly to the fields on the Java side, names, capitalization, everything.

So that about sums it up. The use of Merapi in this application definitely added that ‘WOW’ factor, and is still super cool to me and everyone that sees it so I highly recommend checking it out! The Merapi project is currently in private beta and about to be released soon. The guys behind it, namely Adam Flater and Dave Meeker, have been working very hard to support it and were extremely helpful in making sure we were able to use it for our needs. Thanks Adam & Dave :)!! They will also be at Adobe MAX, so be sure and check out all the cool stuff they’re doing!

Advertisements

14 Responses to “Flex/AIR to Java Communication Using Merapi”

  1. asadsiddiqi Says:

    Fabulous article . That does show the usage of API and I love it …. Since Java is my new love now ( hehe ) I really enjoy reading JAVA code !! U have a great blog !! keep it going and the good words coming !!
    Thank you

  2. […] Devgirl’s Weblog Trials and tribulations of software development « Flex/AIR to Java Communication Using Merapi […]

  3. First, thanks for your great article!

    But I have a serious problem while implementing my application.
    That is, I can send custom object from Java to AIR.
    And I can send primitive data type from AIR to Java.
    However, I can not send “custom object” from AIR to Java.
    Actually, I got the java.lang.ClassCastException!

    I found it in your code here:
    final ArrayList al = (ArrayList)m.getData();
    Could you show me more details about it?

    I also found an article here, but still have no idea.
    http://www.merapiproject.net/index.php?option=com_fireboard&Itemid=58&func=view&id=69&catid=8&limitstart=6

    Thank you very much. 🙂

  4. The way that I passed my custom objects was via a Flex ArrayCollection – to a Java ArrayList. So on my Flex/AIR side, I have custom class called Component with the [RemoteClass(alias=”com.adobe.tourdeflex.core.Component”)] declaration in it, which specifies the remote class on the Java side to map to. I need to make sure my Java side has this same package name and the same exact properties and methods so they map correctly. Then, on my AIR side I put a all of my custom Component objects in an ArrayCollection, and then actually pass the ArrayCollection object. So in this case, the comps objects is an ArrayCollection:

    m.data = comps;
    bridge.sendMessage(m);

    And on the Java receiving side, it would be handled with:
    final ArrayList al = (ArrayList)m.getData();

    where that Component class matches the component class on the AIR side.

    I hope this helps!!
    Holly

  5. Thanks for the quick response!

    Finally the problem was solved by upgrading the Merapi framework to the newest version (0.0.90).
    But, anyway, your tutorial really helps!
    Thanks again! 🙂

  6. Hi,
    does it thinkable that Air and Java communication could be developt/use on a synchronus way.

    Best regards
    Julien

  7. When used merapi had problems such as CPU 100%
    processing, fixed TCP port, then developed my
    own classes, java and flex. Are available
    projects for download in my blog

  8. is there is any sample application for this
    i am new to java so need help how actually flex and java work together

  9. Very nice,

    helped me a lot of lot…

    thanks devgirl

  10. […] Flex/AIR to Java Communication Using Merapi « Devgirl’s Weblog. Filed under: Uncategorized Comments Off Comments (0) Trackbacks (0) ( subscribe to comments on this post ) […]

  11. this is nice… thanks devgirl. smart lady developers are so rare. 🙂

  12. Guys, I am having a big problem.
    My Java App has many threads, and sometimes when these threads send many messages at the same time, I lose some of these messages on the flex side.
    I am using the version 0.1.8.
    Can anyone help me please?
    Thanks

  13. hey, surfing 2 mins on web and have to say very
    good site and I’m gonna like it.

    look forward to surfing around and reading alot of topics here.

    figured I say what’s up!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: