Archive for the Java Category

The Making of an Eclipse Plug-in – Part 1

Posted in Eclipse, Flex, Flex Builder, Flex/AIR, Java with tags , , , , , , , , on May 4, 2009 by devgirl

I recently had the opportunity to write my first Eclipse plug-in as part of Tour de Flex for Adobe. We had a pretty short deadline for the project and I was a bit hesitant about entering the world of SWT and JFace without previous experience. I did have a good amount of experience coding in Java Swing/AWT previously, but it had been awhile and I had been coding UI’s in Flex/AIR with Java on the server side most recently. Moving back to this “widget-world” was certainly different! I discovered very quickly how spoiled I had been in the Flex/AIR world 😉 I ran into a few kinks along the way in my development that I believe could have easily been avoided and saved me oodles of time had I been able to find some quick information on the web. So now that I have been through the painful task of figuring out how to code, build, package and test an Eclipse plug-in, I decided to write a series of posts to explain the steps I took in creating my plug-in as a sort of quick reference and cut to the chase, as I found myself sifting through a lot of information to find the nuggets I needed.

Before I begin, there are two books I found particularly useful in tackling this project. They are:

Eclipse Building Commercial-Quality Plug-ins
The Definitive Guide to SWT and JFace

The View

An Eclipse ‘View’ is basically any of the UI tabs within your Eclipse environment, so for instance your Project Explorer, the Console, or the Problems window, that you can drag around to customize your environment. My Tour de Flex plug-in was all contained within one view, so the main things I needed to figure out were all the events and behaviors around showing, closing and sizing a custom Eclipse View panel. A screenshot of my Tour de Flex plug-in view is shown below.

tourdeflexPlugin

And by the way, if you don’t know about Tour de Flex or what the plug-in does, I HIGHLY recommend checking it out! Tour de Flex is a great tool for developers, full of code samples that showcase the language and how to use it. The plug-in can run in either FlexBuilder or Eclipse, and allows you to search code samples provided by Tour de Flex. Double-clicking on a search result will open the Tour de Flex AIR app right to that particular code sample where you can then find out more info or copy/paste code right into your IDE. Instructions for downloading the Tour de Flex plug-in and more information about this useful application can be found here.

Coding a Sample View

Fortunately Eclipse makes it pretty easy to get started in building a plug-in via a wizard. Using this wizard ensures the necessary base packages needed for a view are included, and includes some sample code to help get you started. To use this in Eclipse, click File | New | Project, and then find the Plug-in Development folder and select ‘Plug-in Project’ from the drop-down menu.

picture-383

You will then be prompted with the following screen, where you will enter the project name and location desired and leave the default selections unless you need to change the required Eclipse base version etc and hit ‘Next’.

pluginSettings1

The next button will take you to the ‘Plug-in Content’ dialog, where you will stick to defaults once again (except name changes as desired), and leave the default boxes checked. From here you will again click the ‘Next’ button.

pluginContent

On the following screen select the ‘Plug-in with a view’ option and go through the resulting panels indicating any names changes you might want for your plug-in, otherwise sticking with defaults. For the viewer type, you have two options which apply to the sample code that is contained within your view. You can choose a Table View or Tree View, and this will depend on your own personal view needs. In my case I used the table view and modified it as needed. Lastly hit ‘Finish’ and you will see a new project created with various files and folders needed for your plug-in. Screen shots of those wizard dialogs are shown below for my sample:

pluginSettings3
pluginSettings4

To see what the sample plug-in you just created looks like, or to test any plug-in for that matter, you can right click on the project in the Package Explorer and select the ‘Run as… Eclipse Application’. This will actually open a new running instance of Eclipse with your plug-in activated in that instance. Another way to test/run it is from the ‘Overview’ page of the plug-in that was created, under the ‘Testing’ section, via the option that says ‘Launch an Eclipse Application’. This page is your entry into all of your plug-in settings, and you will see tabs at the bottom that allow you to flip through each page of settings. More about these settings and how to use them will be explained in Part 2 of this series.

pluginOverview

So now that we know how to launch an Eclipse application for testing our plug-in, we need to go into that instance to find our new view. Once in the test Eclipse instance, go to the ‘Window’ menu and find the ‘Show View’ option. This will bring up a list of all the view categories, and you should now see your new category in the list, and under it your sample view. Once you find your newly created view, select it and hit the ‘OK’ button.

newView

The new sample view will be opened immediately for you to see with a basic table as shown in the screenshot below.

finalViewSample

Congratulations! You have just learned how to create your first basic plug-in! In Part 2 I will take a deeper dive into the files that were generated as a result of the above, discuss some caveats to watch out for during coding, and also take a closer look at the plug-in settings tabs.

Flex/AIR to Java Communication Using Merapi

Posted in Adobe Flex, Flex/AIR, Java with tags , , , , on November 13, 2008 by devgirl

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!