Wednesday, December 06, 2006

Java: How to Create a Basic RCP Application

So, at the gentle nudging of my new boss, I have been looking into building applications with RCP. In theory, it seems like a sound framework. In practice, I have run into quite a few pitfalls. Much of it is a major philosophy shift on my part, or rather the difficulty dealing with the Eclipse plug-in paradigm. So, over the next few articles, I will share my experiences in building what I hope is a simple RCP application.

The application I will build here is a simple web service communication program that will use the Google web service to query Google and retrieve the results. I decided to build this application for several reasons. First, it somewhat mirrors the application I am currently building for work, in terms of getting information, using a web service, and using JAR files external to the RCP framework. I will use Apache Axis to generate proxy classes to use with Google. Requirements for this series are Eclipse, Java 5, and Apache Axis. As an added bonus, for no apparent reason, I will also have a Tree List that displays all files in the root of the drive. So in this article, I will demonstrate a few things. First, I will demonstrate how to create an RCP application in Eclipse. I will also demonstrate how to modify a view, add visual components, and I will demonstrate how to retrieve a file list and directory listing in Java, using a recursive function to populate an SWT Tree component.

The first step is to create the RCP project itself. Here are the steps.

First, open Eclipe. Once Eclipse is open, open the Java Perspective. You do this by going up to Window / Open Perspective /Java (Or if Java is not there, go to Other / Java). Now, we need to start a new Plug-in Project. Go to File / New / Project. When the wizard opens up, choose Plug-In Development / Plug-In Project.


Figure 1. New Plug-In project.

On the next screen of the wizard, enter in a project name (in my case, I am naming it com.digiassn.blogspot.RCPTutorial). Make sure the Create a Java Project option is checked, and set the Eclipse version you are targeting. I set mine to version 3.2.

On the next screen, be sure to check the option to create a Rich Client Platform Application. Enter the other parameters (I left mine default). On the next screen there is a series of templates. I chose the RCP Application with a View template. Once done, I just hit Finish, and my initial project has been created.

That’s all there is to it to create an RCP application. Now, I can test run the application by clicking on the Launch an Eclipse Application item in the editors Overview tab, under Testing.


Figure 2. Project Editor


Now, with the new project created, I want to modify it to provide the interface I want to use. Since I used the above template, I can modify the src/com.digiassn.RCPTutorial/View.java file. What I want is to clean up some of the junk that the Eclipse wizard threw in, remove the wizard generated objects in the view since they do not coincide with my goal for this program, and add the necessary components to my view. I also need to put in the code to initialize my TreeView object with my file listing. For run-times sake, I choose to just display a list of directories. In order to do this, I use the Java File object, and create a recursive function that will populate the list for me. The way it works, is it gets a list of files, if the current file is a directory, it creates a new tree item, and then recalls itself using itself as the root value. I was kind of stoked; I haven’t had to write a recursive function since high school. The code for the View.Java file is below.


View.java
package com.digiassn.blogspot.rcptutorial;

//Necessary imports for SWT components
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import java.util.Date;

import java.io.File;

public class View extends ViewPart {
//The tree list displaying files
private Tree treFileList;
//String generated by wizard to identify the component
public static final String ID = "com.digiassn.blogspot.RCPTutorial.view";
private Shell this_shell;

private void populateTargetTree(Tree parent, File root)
{
File []listOfFile = root.listFiles();

//For each of the files, check if it is a directory, and add
//to the tree object
for (File f : listOfFile)
{
//Try statement added. Reason being, if the current file has
//special access permissions, Java does not handle correctly
//and causes a runtime exception and causes a stop in processing
try {
//Check if it is a directory
if (f.isDirectory())
{
//create new tree item, setting the data to the current file for
//later use
TreeItem t = new TreeItem(parent, SWT.NULL);
t.setText(f.getName());
t.setData(f);

//Make a recursive call, populating TreeItem with
//all child directories
populateTargetTree(t, f);
}
} catch (RuntimeException e) {
//Do nothing
}
}
}

/**
* populateTargetTree
*
* @param parent (The Main treeItem)
* @param root (The Root folderr in the file system
*
* A recursive call, similar to the populateSourceTree function, but
* populataes with the local file system instead of the Actuate encyclopedia
*/
private void populateTargetTree(TreeItem parent, File root)
{
File[] listOfFile = root.listFiles();

for (File f : listOfFile)
{
try {
if (f.isDirectory())
{
TreeItem t = new TreeItem(parent, SWT.NULL);
t.setText(f.getName());
t.setData(f);

populateTargetTree(t, f);
}
} catch (RuntimeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
public void createPartControl(Composite parent) {
this_shell = parent.getShell();

//Create a group component, this will house the components related to the
//Google portion of the program. Use the veritcle layout Fill for layout management
final Group grpGoogle = new Group(parent, SWT.NONE);
grpGoogle.setText("Google Stuff");
grpGoogle.setLayout(new FillLayout(SWT.VERTICAL));

//Now create the group for the file system component
final Group grpFileSystem = new Group(parent, SWT.NONE);
grpFileSystem.setText("File System");
grpFileSystem.setLayout(new FillLayout(SWT.VERTICAL));

//Add the tree list that will display the files on the hard drive
treFileList = new Tree(grpFileSystem, SWT.BORDER);

//Add a listener to the tree that will display the information about the directory
//stored
treFileList.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
MessageBox m = new MessageBox(this_shell, SWT.OK);
String message_to_display = "File: " + ((File) treFileList.getSelection()[0].getData()).getName() + '\n' +
"Path: " + ((File) treFileList.getSelection()[0].getData()).getPath() + '\n' +
"Last Modified: " + new Date(((File) treFileList.getSelection()[0].getData()).lastModified()).toString() + '\n' +
"Number of Subs: " + String.valueOf(((File) treFileList.getSelection()[0].getData()).list().length);
m.setMessage(message_to_display);
m.setText("File Selected");

m.open();
}
});

this.populateTargetTree(treFileList, new File("C:/"));
}

/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
}
}

Next article I will create the proxy classes for Googles web services, then show how to import them into the project. This can be a problem, as I found, since Eclipse RCP projects require that JAR files be part of a plug-in. I will show a workaround for this.

Having worked with this for a little bit, I can say this had suprisingly a lot of pitfalls. Documentation was incredibly sparse, and I had a lot of difficulty finding solutions to issue, such as the external JAR issue I mentioned. Most answers I found were in news group posts. This, to me, is not good, especially for younger programmers who are learning. Shame on Eclipse for not having better documentation on these kinds of things. While I do like the RCP framework, I think it has a long way to go. I did come across the RCP Developer from Instantiations that provides some better wizards, and a decent visual designer.

2 comments:

Phil said...

I certainly agree, there very little documentation freely available, not what I expected from Eclipse.

Nora said...

Thank you so much for posting this.
I learnt a lot.