Making Applications Work Together In Eclipse

1,152 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,152
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Making Applications Work Together In Eclipse

  1. 1. Eclipse as we know is a great implementation of plugin-architecture.We decouple different components of a system into bundles.plugin-architecture is very simplistic in nature, highly extensible and modular at thecost of a tricky class-loading policy.Actually Eclipse is a story of several class-loaders.It iniataites a chain of class loaders to load the plug-ins lazily as specified incomponent-specific manifest.mf files.If we understand its class-loading policy and learn some tricks, then we can makedifferent third-party jars talk to each other and avoid infamous ClassNotFoundException.The immediate parent of a plug-in class loader is the Eclipse Boot Class Loader(providing access to boot.jar). The parent is the standard java system class loaderwhich terminates the chain. The Application Class-loader which loads classes fromthe systems CLASSPATH is not part of the chain.Thats why while loading product components, Eclipse does not look into Classpathin contrast to any other java-based client applications.On start-up, the eclipse platform builds a shadow of all the plugins by reading all themanifest files into a plug-in registry.Whenever a plugin com.xyz.myProduct is started by Eclipse Application Class,the class-loader for com.xyz.myProduct takes-off.If com.myProduct.xyz tries to access any class from another plugincom.myProduct.abc,Eclipse invokes the Plug-in Class-loader coresponding to com.myProduct.abc.Thats the essence of Eclipse OSGi.Q1. How to use third-party applications while building and running myproduct ?Its of no use to specify third-party jars in classpath.While building the application com.myProduct, we should bundle all the required jarsin a single plugin (com.myProduct.library) and expose the apis of the bundled log4j,jpox, xstream etc.Q2. How a third-party jar (log4j.jar) can see the classes fromcom.myProduct.xyz.jar during runtime ?Lets assume com.abc.myProduct plugin logs messages using log4j.So during runtime, log4j needs to see the classes from com.myProduct.abc pluginThis can be achieved by registering log4j with Eclipse-Buddy Policy and specifyingcom.abc.myProduct as a buddy of log4j.# log4j Manifest.MFBundle-Name: org.apache.log4jBundle-Version: 1.2.13
  2. 2. ...Eclipse-BuddyPolicy: registered# myplugin Manifest.MFBundle-Name: com.abc.myProductBundle-Version: 1.0.0Requires-Bundle: org.apache.log4j,...Eclipse-RegisterBuddy: org.apache.log4jIf anyone registers with log4j as its buddy, and log4j needs to find a classcom.abc.myProduct.MyComponent then it will check all the buddies before throwing"ClassNotFound" ExceptionQ3. How can users integrate third-party jars with myProduct plugins on-the-fly ?Lets see how users can actually hack eclipse configuration files to integrate requiredjars on-the-fly.say user has installed a plugin com.magicScript which allows him to program usingany script including jruby. But the product plugin doesnt ship the jruby jars i.e. doesnot adopt any of the above mechanisms.So user have to add JRUBY_MOME in eclipse.ini. Now when eclipse will start up itwill set jruby home in the path.Lets assume the com.magicScript plugin already depends on a plugincom.magicScript.library containing a lib folder.Next the jruby.jar needs to be placed inside the lib folder and the location libjruby.jarneeds to be specified in the manifest.mf of com.magicScript.library.Finally, starting eclipse with -clean -Intialization option will automatically first setJruby path and then invoking magicScript perspective will trigger the classLoader forthe bundle com.magicScript.library which in turn will load jruby classes from the jar(as specified in manifest.mf).Thus user will be able to code/compile/run jruby.This same trick can be used if we want the user to dynamically specify a DB driverjar and connect to a db using a plugin already installed in his environment.Say com.myProduct.dbExplorer plugin will load classes from the jar to be specifiedby users during runtime.(4) So far we depend only on Eclipse Bundle-ClassLoader and we configure eclipsein such a way (either development-time / runtime) that all required jars will be loadedby the classloader of the bundle in which jars are packed.But what if we need to access a class which can not be loaded by the bundle-classloader ?
  3. 3. We need to set certain jars in custom classloader so the classes bundled in the jar canbe loaded on demand !A typical scenario is com.xyz.MyProduct.library contains scriptDebugger.jar (some3rdparty jar) whose api need to be invoked during runtime and the api class willaccess some class of jruby.jar (may be specified by user during runtime) which cantbe packed inside the product.//The follwoing piece-of-code should be part of thecom.xyz.myProduct.ScriptManager to load classes from jruby jar that user willspecify during runtime.// gather the names and loacation of jars as provided by user through preference pageafter product is deployed.String[] jarslist = DynamicJarLoader.getThirdPartyJars();URL[] jarURLs = new URL[jarslist.length];JarFileLoader newLoader = new JarFileLoader(jarURLs);for (int i = 0; i < jarslist.length; i++) {newLoader.addFile (jarslist[i]);}class JarFileLoader extends URLClassLoader{public JarFileLoader (URL[] urls){super (urls);}public void addFile (String path) throws MalformedURLException{String urlPath = "jar:file://" + path + "!/";addURL (new URL (urlPath));}}Now swap bundleclassloader with your classloader !ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();try {current.setContextClassLoader( newLoader);// Either Load reqd. classes and work with themnewLoader.loadClass ("org.jruby.JRubyClient");newLoader.loadClass ("org.hsqldb.jdbcDriver");newLoader.loadClass("oracle.jdbc.driver.OracleDriver");// Or invoke some other api (of scriptRunner.jar which will load JRuby classes tocompile/run jruby script)}catch(Exception exception) {
  4. 4. exception.printStackTrace();}finally { // Restore Eclipse Bundle Class-loadercurrent.setContextClassLoader(oldLoader);}further reading : http://www.eclipsezone.com/articles/eclipse-vms/

×