Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-users] Bytecode-weaving in equinox/eclipse-rcp-applications

Hi,

I was trying to set up bytecode weaving within an eclipse-rcp-application. It was not as straightforward as I thought, so I'd like to share my experiences.

First I checked out the rcp-example from the eclipselink-svn-repository:
svn export http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.derby/
svn export http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.comics.model.annotated/
svn export http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.comics.setup/
svn export http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.rcp.comics/
Next, I downloaded the EclipseLink 2.1.0 M7 zip and placed all contained files into the plugin-dir of my eclipse installation.
I started eclipse and imported the checked-out projects into the workspace. Then I copied the derbyclient.jar into org.eclipse.persistence.derby and replaced the external classpath reference with the local jar. So far so good.

Called "Clean project" and still 45 missing-type-errors to resolve: The problem here is, that Import-Package: javax.persistence;version="[1.99.0,2.0.0)" has obviously an unsatisfiable version range. Although you can still find the interim javax.persistence_2.0_preview.jar in the eclipse-plugins folder, it seems to be not considered here.

After changing the MANIFEST.MF of  "org.eclipse.persistence.example.jpa.comics.model.annotated", "org.eclipse.persistence.example.jpa.comics.setup" and "org.eclipse.persistence.example.jpa.rcp.comics" to Import-Package: javax.persistence;version=2.0.0 , all errors are gone.

Next I started the derby-db (bin/startNetworkServer) and ran ComicsExampleDBSetup.launch as described in http://dev.eclipse.org/svnroot/rt/org.eclipse.persistence/trunk/examples/org.eclipse.persistence.example.jpa.rcp.comics/ReadMe.txt. No luck. This program terminates immediately without any logging output. Looking at the launch configuration, there is hardly any bundle selected (probably due to the fact that in the originating workspace the required bundles were part of the workspace and not part of the target platform). So I add all bundles as described in http://wiki.eclipse.org/EclipseLink/Examples/OSGi/Equinox_Byte_Code_Weaving#Equinox_Configuration. Now the program runs with a lot of debug output and without any errors.

Next step is to make the RCP application run: Launching ComicsRCP.launch brings up a dialog with unsatisfied constraints. So I edited the launch configuration to include all missing imports: org.eclipse.core.databinding.observable, org.eclipse.core.databinding.property, javax.persistence, org.eclipse.persistence.jpa, org.eclipse.persistence.antlr, org.eclipse.persistence.core and org.eclipse.persistence.asm. The RCP application starts up.

Besides from having to edit the launch configurations, this all worked pretty much out of the box :-).


No comes the tough part: Getting bytecode weaving to work.

First I revised "ComicsRCP.launch" to set up the the start order and bundle activations as described in http://wiki.eclipse.org/EclipseLink/Examples/OSGi/Equinox_Byte_Code_Weaving#Equinox_Configuration. I also added "-Dosgi.framework.extensions=org.eclipse.persistence.jpa.equinox.weaving" as a VM-start-parameter.

On starting the RCP application there is now a new validation error saying plug-in "org.eclipse.persistence.jpa.equinox" requires Import-Package "org.eclipse.persistence.jpa.equinox.weaving". Proceeding with OK, the application starts up as before. However, no output of that something has been woven. The litmus test of http://wiki.eclipse.org/EclipseLink/Examples/OSGi/Equinox_Byte_Code_Weaving#Confirming_Byte_Code_Weaving_is_Working confirms my concerns.

So I started to pull in eclipselink bundles into my workspace - first "org.eclipse.persistence.jpa.equinox.weaving". This plugin has a class "WeaverRegistry" were I put a first breakpoint into processClass(...). The breakpoint is hit, however "this.weaverServices" is always empty, so nothing is executed in this method. Later on in this method, you can read System.out.println(name + " woven") , so there must be some output if everything goes right. The variable weaverServices is a list of ServiceReferences of type IWeaver, so there must be someone that is registering IWeaver-services. And there is one: EquinoxInitializer in method registerTransformer(...). This class is in "org.eclipse.persistence.jpa.equinox" (this is a fragment-bundle of "org.eclipse.persistence.jpa"). The manifest of that fragment-bundle contains a line:
JPA-Initializer: org.eclipse.persistence.internal.jpa.deployment.osgi.equinox.EquinoxInitializer
So next I searched for "JPA-Initializer" in the EclipseLink code base. One single hit in class "Activator" in "org.eclipse.persistence.jpa" in method start(BundleContext). This method seems to be work-in-progress. All that is done with "JPA-Initializer" is to get out a debug message. Ironically, the chosen log level is CONFIG, so nothing will be printed out in any case (the default threshold is INFO and at this early stage the log-system is yet to be initialized).

So next I took a look at how the EntityManagerFactory is created in the RCP sample: class "Model" in "org.eclipse.persistence.example.jpa.rcp.comics", method getEntityManagerFactory(). Stepping into the class "PersistenceProvider" you can see two constructors: one default-constructor and one with a String parameter and a helpful comment. Obviously, you have to chose the latter constructor to get weaving to work. But what to provide as parameter "initializerClassName"? From looking at the code, this must be a class of type "JPAInitializer". And, guess what, "EquinoxInitializer" is such a class. So I changed the initialization-code to
emf = new PersistenceProvider("org.eclipse.persistence.internal.jpa.deployment.osgi.equinox.EquinoxInitializer")
.createEntityManagerFactory(PU_NAME, properties);
The application starts up as before, but there is a ClassNotFoundException of EquinoxInitializer at the beginning of the log output. This seems to be a weird eclipse-tooling bug. Refreshing any MANIFEST.MF file in the workspace and the CNFE is gone. But still no weaving in sight.

http://wiki.eclipse.org/EclipseLink/Examples/OSGi/Equinox_Byte_Code_Weaving#Equinox_Configuration says, that weaving has to be turned on explicitly in the persistence.xml. So I put this line into it:
<property name="eclipselink.weaving" value="true"/>
Restarting the application, there is now a debug-line saying: org.eclipse.persistence.example.jpa.comics.model.annotated.Issue woven . But there is also an error message in the RCP-application:
java.lang.ClassNotFoundException: org.eclipse.persistence.internal.weaving.PersistenceWeaved
    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:494)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:410)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:398)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:105)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.defineClass(DefaultClassLoader.java:183)
    at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.defineClass(ClasspathManager.java:576)
    at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findClassImpl(ClasspathManager.java:546)
    at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClassImpl(ClasspathManager.java:477)
    at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass_LockClassLoader(ClasspathManager.java:465)
    at org.eclipse.osgi.baseadaptor.loader.ClasspathManager.findLocalClass(ClasspathManager.java:445)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.findLocalClass(DefaultClassLoader.java:211)
    at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:381)
    at org.eclipse.osgi.internal.loader.SingleSourcePackage.loadClass(SingleSourcePackage.java:33)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:454)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:410)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:398)
    at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:105)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
    at org.eclipse.persistence.internal.jpa.deployment.osgi.CompositeClassLoader.loadClass(CompositeClassLoader.java:137)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at org.eclipse.persistence.internal.security.PrivilegedAccessHelper.getClassForName(PrivilegedAccessHelper.java:88)
    at org.eclipse.persistence.descriptors.ClassDescriptor.convertClassNamesToClasses(ClassDescriptor.java:1221)
    at org.eclipse.persistence.sessions.Project.convertClassNamesToClasses(Project.java:362)
    at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:325)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:157)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:214)
    at org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:202)
    at org.eclipse.persistence.example.jpa.rcp.comics.Model.getEntityManager(Model.java:75)
    at org.eclipse.persistence.example.jpa.rcp.comics.Model.begin(Model.java:39)
    at org.eclipse.persistence.example.jpa.rcp.comics.Model.<init>(Model.java:35)
    at org.eclipse.persistence.example.jpa.rcp.comics.View.initializeModel(View.java:75)
    at org.eclipse.persistence.example.jpa.rcp.comics.View.createPartControl(View.java:59)
So weaving is obviously working now, but there are still some osgi-classloader issues to be sorted out. Not sure about what might be the correct way, I added several Import-Packages to the "org.eclipse.persistence.example.jpa.comics.model.annotated"-plugin as required by the CNFE-messages:  org.eclipse.persistence.descriptors.changetracking,  org.eclipse.persistence.indirection,  org.eclipse.persistence.internal.descriptors,  org.eclipse.persistence.internal.weaving,  org.eclipse.persistence.queries, org.eclipse.persistence.sessions. There is no guaranty that there are no more required import-packages.

So finally the applications starts up (after a day of excessive debugging) :-).


So, to cut a long story short: Some things could be changed to improve first user experience:
  • Please, align version numbers between the rcp-sample and the distribution (which I took both from trunk).
  • The interim javax.persistence_2.0_preview.jar could be probably removed from the EL-distribution.
  • Please have a look at the validation error for Import-Package "org.eclipse.persistence.jpa.equinox.weaving" in plug-in "org.eclipse.persistence.jpa.equinox". Perhaps it has to be declared as resolution:=optional.
  • Logging: There is a mixture of JUL (org.eclipse.persistence.javax.persistence.osgi.Activator), sysouts (org.eclipse.persistence.jpa.equinox.weaving.WeaverRegistry) and EL-logging (org.eclipse.persistence.jpa.osgi.Activator). Some log-messages will never make it to the console (e.g. "osgi_initializer").
  • Using org.eclipse.persistence.internal.jpa.deployment.osgi.equinox.EquinoxInitializer should be clarified in the documentation (or the look-up mechanism to be implemented).
  • In the comic-rcp sample it seems odd, that the persistence.xml is not placed in the bundle were the model classes lie.
  • The manifest header "JPA-PersistenceUnits" should not be required at all. org.eclipse.persistence.jpa.osgi.Activator already has all the things to query bundles for the presence of "META-INF/persistence.xml". A simple xpath-query would reveal the contained persistence-unit-names.
  • The additional import-packages for the woven bundle probably cannot be avoided. It should however be investigated, which packages are required. The best solution in the long run is probably to place those packages in a separate bundle. (The same issue should IMHO occur outside of OSGi when serializing and transferring woven classes.)

-- Frank


View this message in context: Bytecode-weaving in equinox/eclipse-rcp-applications
Sent from the EclipseLink - Users mailing list archive at Nabble.com.

Back to the top