Intro
The contract furniture industry like many others features ever-changing requirements that must be reflected in the software used by companies in the industry. RPC Software of Chicago, Illinois has found success in this market by using a foundation of open source software in their products. The company is making use of technologies such as Eclipse RCP, DotProject, and SugarCRM to deliver quicker more cost effective solutions than their competitors. This case study takes a look under the hood of these technologies, the development knowledge gained in their use, and lessons learned.
Domain
RPC Software develops ERP order management software used by the furniture industry. Before RPC's product offerings, companies in the industry frequently used proprietary software written in Microsoft Visual Studio languages such as Visual Basic and DOS based solutions and CA's Visual Objects. Companies today are looking for broad solutions that handle many different business activities such as sales, quotes, order entry, time tracking, warehousing, accounting and reporting. As a result, software to satisfy such requirements needs to not only be scalable and robust but also modular in nature.
Like many other industries there has also been a drive in recent years to make information more transparent and accessible to vendors and customers that furniture dealerships interact with on a regular basis. This change is being driven in two main ways. First companies in the industry are moving to open data exchange formats such as OFDA-XML. Second, business processes such as project tracking are reporting and being exposed via web applications to allow cooperating companies to share information.
Solution Overview
RPC Software's customers require software that can be adapted quickly and specifically to their business needs. They also require the ability to have both robust client functionality for employees using the application on a daily basis, as well as the ability to expose reporting functionally to other levels of their business and to partners. Given these requirements of clients in their industry RPC decided to leverage open source software to provide a basis for their solutions. RPC's product lineup features a rich client ERP client/server component using Eclipse RCP and Apache Tomcat, a web based project management solution based on the open source DotProject PHP application, and a soon to be released web based CRM product that uses the open source SugarCRM as its foundation.
Web based solutions were chosen for the project management and CRM products due to the need share between dealerships, customers, and vendors without having to install a thick client. For the ERP product, Eclipse RCP was chosen based on the rich functionality of the SWT/JFace widget set as well as the modular infrastructure provided by its OSGi underpinnings.
At the center of Eclipse RCP is the OSGi specification it is built on. As defined by wikipedia OSGi framework provides:
The Framework implements a complete and dynamic component model - something that is missing in standalone Java/VM environments. Applications or components (coming in the form of bundles for deployment) can be remotely installed, started, stopped, updated and uninstalled without requiring a reboot - management of Java packages/classes is specified in great detail. Life cycle management is done via APIs which allow for remote downloading of management policies. The service registry allows bundles to detect new services, or the going away of services, and adapt accordingly. (http://en.wikipedia.org/wiki/OSGi)
The CORE product consists of client and a server. Both make extensive use of OSGi for the organization of code into functional components and the reuse of that code on both the server and client tiers. Eclipse RCP allows for the modularization of classes and resources into jar files called plugins which are a superset of OSGi bundles. The RCP Software client is divided into core business plugins for each of its functional areas. It also makes uses of plugins for third party API's such as Hibernate and Jasper Reports. The CORE Business server is also structured as a set of plugins. This allows reuse of business logic plugins easily on both the client and server.
To further simplify the deployment of their applications RPC has structured both the client and server to be included as the same installation. Eclipse RCP defines the concept of an entry point defined via a combination of XML and config files in a plugin. The framework uses dependency meta data between plugins to determine which ones need to be started for a specific entry point. For the client a normal exe based Eclipse RCP startup process is performed using a client entry point. This client startup excludes those plugins that provide server based functionality. Comparatively when running as a server, a Windows service is created using the open source JNIWrapper product that launches the Eclipse RCP installation using a different entry point which includes a Tomcat server instance packages as a plugin but does not include plugins containing UI specific logic or that are client dependencies such as the SWT plugin.
The CORE Business client handles common ERP related tasks such as the creation of proposals, loading of bills of material, and accounting. The server component provides web based reports of the data entered that allow members of the each company's organization to see high level summaries of activity. When orders are entered through the CORE Business client a product id is also automatically created in the database of Core Vision product. As timeline changes are made in CORE Vision, they can be viewed in Core Business. Similarly CRM changes made in Core Business will be reflected in CORE CRM and vice versa. RPC handles the integration of the two databases. A company using products such as DotProject and SugarCRM separately would not have access to such integration.
Eclipse RCP Client
At center of the CORE Business product is its use of the Eclipse RCP rich client framework. Customers use the CORE Business client on a daily basis for the ERP needs such as accounting, management reporting, project pricing, creation or proposals, etc. Eclipse RCP was chosen for a number of reasons over other technologies. Due to the information entry and data size demands of clients, a web based application was not a viable option. Rich client widget frameworks such as C# and Swing were considered in addition to Eclipse RCP and SWT. The native look and feel fidelity of SWT was a key selling point however. The out of the box functionality included with Eclipse RCP such as windowing, menus, and preferences was also attractive to RPC Software.
The modularization provided by OSGi and Eclipse RCP has used extensively by RPC Software in the CORE Business client. Customers often need such items as custom reports and calculation logic. There are also cases where functionality such as Time Entry is not needed by all clients. The plugin based infrastructure of Eclipse RCP allows RPC Software to solve these requirements by distributing a set of core application plugins along with custom ones for specific client needs.
The Eclipse RCP framework features an xml based format that plugins can use to notify the core application about features that they provide. One example where RPC makes use of this functionality is custom reports. The following XML snippet shows how a custom purchase order report is added at runtime via a client specific custom.plugin.*.core style plugin.
<extension id="xsltTransforms" point="com.rpc.core.xsltTransforms">
<xsltTransform id="com.rpc.core.vendor.model.PurchaseOrder.pdf">
<run class="com.rpc.core.reporting.DefaultTransformSourceProvider">
<parameter name="location" value="reports/PurchaseOrder.xsl" />
</run>
</xsltTransform>
</extension>
The value in this style of control is that all configuration changes and meta information needed to include the functionality in the running application is contained in the custom plugin. No changes are needed to make the core plugins or the menuing system of the application aware of the new functionality. It is all discovered and wired together at runtime by the Eclipse RCP framework.
Eclipse Server
RPC Software makes use of the plugin structure of Eclipse RPC not only in the CORE Business client but also in the Tomcat based CORE Business server. The CORE Business server exposes reporting functionality related to data entered through the CORE Business Eclipse RCP based client. In designing the CORE Business Server it became apparent that there was a need to reuse much of the same logic and components that also existed on the client such as Hibernate and Jasper Reports. The most obvious solution to the requirement of reuse is to repackage the classes need on the sever as jars included in a WAR file. This solution would have required complicated build scripts that would need to be continually modified as class structure changed. Instead it seemed far easier to make Tomcat "plugin aware".
The Eclipse IDE uses an embedded version of Tomcat for its help system. RPC was able to use this as a starting point for the functionality they desired. At this point they moved the servlet.jar file into its own plugin so it could be used by other plugins they had created which required the servlet API's. They also modified the existing Tomcat plugin to use the Eclipse JDT compiler instead of the standard Java compiler. This allowed CORE Business to only need the JRE bundled instead of the JDK. Finally, the classloader used by the plugin containing JSP pages was modified to load needed system plugins such as org.eclipse.core.runtime.
package org.eclipse.help.internal.appserver;
public class PluginClassLoaderWrapper extends URLClassLoader {
...
/**
* This is a workaround for the jsp compiler that needs to know the
* classpath.
*/
public URL[] getURLs() {
Set urls = getPluginClasspath(_plugin);
return (URL[]) urls.toArray(new URL[urls.size()]);
}
private Set getPluginClasspath(String pluginId) {
// Collect set of plug-ins
Set plugins = new HashSet();
addPluginWithPrereqs(pluginId, plugins);
// Collect URLs for each plug-in
Set urls = new HashSet();
for (Iterator it = plugins.iterator(); it.hasNext();) {
String id = (String) it.next();
try {
Bundle b = Platform.getBundle(id);
if (b != null) {
// declared classpath
String headers = (String) b.getHeaders().get(Constants.BUNDLE_CLASSPATH);
ManifestElement[] paths =ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, headers);
if (paths != null) {
for (int i = 0; i < paths.length; i++) {
String path = paths[i].getValue();
addBundlePath(urls, b, path);
}
} else {
// RPC custom code:
try { String bundleJarPath = b.getLocation();
if (bundleJarPath.equals(Constants.SYSTEM_BUNDLE_LOCATION)) {
SystemBundle systemBundle = (SystemBundle) b;
bundleJarPath = ((SystemBundleData) systemBundle.getBundleData()).getBundleFile().getBaseFile().toURL().getPath();
bundleJarPath =bundleJarPath.substring(bundleJarPath.lastIndexOf("plugins/"));
} else if(bundleJarPath.startsWith("initial@reference:file:")) {
bundleJarPath =b.getLocation().replaceFirst("initial@reference:file:", "");
} else {
bundleJarPath =b.getLocation().replaceFirst("update@", "");
}
if (bundleJarPath.endsWith("/")) {
bundleJarPath = bundleJarPath.substring(0, bundleJarPath.lastIndexOf("/"));
}
if (bundleJarPath.startsWith("plugins/") && bundleJarPath.endsWith(".jar")) {
URL installURL = Platform.getInstallLocation().getURL();
bundleJarPath = installURL.getPath() + bundleJarPath;
urls.add(new URL(installURL.getProtocol(), installURL.getHost(), bundleJarPath));
}
} catch (Exception ex) {
}
// RPC custom code:
}
// dev classpath
String[] devpaths =DevClassPathHelper.getDevClassPath(pluginId);
if (devpaths != null) {
for (int i = 0; i < devpaths.length; i++) {
addBundlePath(urls, b, devpaths[i]);
}
}
}
} catch (BundleException e) {
}
}
return urls;
}
// RPC custom code:
private void addBundlePath(Set urls, Bundle b, String path) {
URL url = b.getEntry(path);
if (url != null) {
try {
urls.add(FileLocator.toFileURL(url));
} catch (IOException ioe) {
}
}
}
// RPC custom code:
...
}
This solution provided a number of advantages over a tradition Java WAR deployment setup. First, RPC is now able to use the exact same plugins on both the client and server tiers promoting reuse and reducing maintenance. Secondly, the deployment setup is also much less complicated in nature. As a war file RPC would have to install Tomcat at each client site and configure the WAR for deployment. By bundling their server as a turnkey set of Eclipse RCP plugins they save a considerable amount of configuration and testing at each client installation while gaining reliability.
Browser Integration
Another interesting element of the Core Business application is its evolution of reporting capabilities. As the application has grown a number of reporting options have been used for customer requirements such as Apache FO, Jasper Reports, and standard Java printing API's. While some reports are server based and others can be run directly in the client, customers wanted the ability to view server based based reports without having to switch to a browser. RPC was able to address this need by making used of the SWT embedded browser component. With a few lines of code similar to that shown below, they were able to render HTML based reports from the server directly in the Eclipse RPC based client.
final Browser browser = new Browser(shell, SWT.NONE);
browser.setUrl("http://eclipse.org");
In addition to presenting reports from the server, the client also includes ease of use features such as a drop down combo box to select report view types directly in the client. A dynamic url is then generated and the request is sent to the server.
Lessons Learned
Overall, RPC Software has found Eclipse RCP to be a very robust framework for their development needs. It has allowed them to meet the different needs of clients while maintaining a single code base. Being open source in nature has also allowed them to enhance missing functionality as needed. Java in general has allowed for more rapid application development through the use of API's such as Hibernate, Apache FO, and Jasper Reports. They estimate that initial application development would have taken 30 months instead of 14 if Eclipse RCP had not been used.
RPC Software has also been pleased with Eclipse as an IDE for Eclipse RCP development. The PDE development environment makes RCP development a first class activity on par with Java development in general. The many custom editors for plugin functionality support files has lowered the barrier of entry that would have existed if manual editing of configuration files would have been required. They have also been able to take advantage of Eclipse IDE plugins such as the Jasper Report Generator and the Eclipse TPTP plugin to speed up development activities.
Future Directions
RPC is planning to continue leveraging open source software to enhance their products in the future. As previously mentioned, their upcoming CORE CRM product will provide web based CRM access into their solution suite through SugarCRM. They are also looking at migrating the various reporting technologies used in the CORE Business product to the Eclipse BIRT product. Finally, work is being done in the next version of the product to distribute product updates and vendor catalogs via the Eclipse Update site functionality to CORE Business client installs.