OpenJPA
  1. OpenJPA
  2. OPENJPA-1490

ClassNotFoundExceptions in an OSGi environment

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: 2.0.0-beta
    • Fix Version/s: None
    • Component/s: diagnostics, osgi
    • Labels:
      None
    • Environment:
      OSGi

      Description

      OpenJPA is available packaged as an OSGi bundle, and specifies several optional package imports, for example the serp packages.

      When calling createContainerEntityManagerFactory() these imports are no longer optional, and NoClassDefFoundErrors are generated. These exceptions should be handled more gracefully, rather than simply being thrown back to the user.

      Examples follow:

      java.lang.NoClassDefFoundError: javax.transaction.Synchronization
      at java.lang.ClassLoader.defineClassImpl(Native Method)
      at java.lang.ClassLoader.defineClass(ClassLoader.java:265)
      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:376)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:452)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:405)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:393)
      at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:105)
      at java.lang.ClassLoader.loadClass(ClassLoader.java:609)
      at java.lang.ClassLoader.defineClassImpl(Native Method)
      at java.lang.ClassLoader.defineClass(ClassLoader.java:265)
      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:376)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:452)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:405)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:393)
      at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:105)
      at java.lang.ClassLoader.loadClass(ClassLoader.java:609)
      at java.lang.J9VMInternals.verifyImpl(Native Method)
      at java.lang.J9VMInternals.verify(J9VMInternals.java:72)
      at java.lang.J9VMInternals.initialize(J9VMInternals.java:134)
      at org.apache.openjpa.conf.OpenJPAConfigurationImpl.<init>(OpenJPAConfigurationImpl.java:221)
      at org.apache.openjpa.conf.OpenJPAConfigurationImpl.<init>(OpenJPAConfigurationImpl.java:195)
      at org.apache.openjpa.conf.OpenJPAConfigurationImpl.<init>(OpenJPAConfigurationImpl.java:186)
      at org.apache.openjpa.persistence.PersistenceProviderImpl.newConfigurationImpl(PersistenceProviderImpl.java:230)
      at org.apache.openjpa.persistence.PersistenceProviderImpl.createContainerEntityManagerFactory(PersistenceProviderImpl.java:166)
      at org.apache.openjpa.persistence.PersistenceProviderImpl.createContainerEntityManagerFactory(PersistenceProviderImpl.java:62)
      at org.apache.aries.jpa.container.impl.EntityManagerFactoryManager.createEntityManagerFactories(EntityManagerFactoryManager.java:227)
      at org.apache.aries.jpa.container.impl.EntityManagerFactoryManager.bundleStateChange(EntityManagerFactoryManager.java:121)
      at org.apache.aries.jpa.container.impl.PersistenceBundleManager.modifiedBundle(PersistenceBundleManager.java:197)
      at org.apache.aries.util.tracker.MultiBundleTracker$InternalBundleTracker.modifiedBundle(MultiBundleTracker.java:108)
      at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:453)
      at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:237)
      at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:413)
      at org.eclipse.osgi.framework.internal.core.BundleContextImpl.dispatchEvent(BundleContextImpl.java:916)
      at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:220)
      at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:149)
      at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEventPrivileged(Framework.java:1350)
      at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEvent(Framework.java:1301)
      at org.eclipse.osgi.framework.internal.core.BundleHost.stopWorker(BundleHost.java:490)
      at org.eclipse.osgi.framework.internal.core.AbstractBundle.suspend(AbstractBundle.java:546)
      at org.eclipse.osgi.framework.internal.core.Framework.suspendBundle(Framework.java:1098)
      at org.eclipse.osgi.framework.internal.core.PackageAdminImpl.suspendBundle(PackageAdminImpl.java:314)
      at org.eclipse.osgi.framework.internal.core.PackageAdminImpl.processDelta(PackageAdminImpl.java:460)
      at org.eclipse.osgi.framework.internal.core.PackageAdminImpl.doResolveBundles(PackageAdminImpl.java:241)
      at org.eclipse.osgi.framework.internal.core.PackageAdminImpl$1.run(PackageAdminImpl.java:176)
      at java.lang.Thread.run(Thread.java:735)
      Caused by: java.lang.ClassNotFoundException: javax.transaction.Synchronization
      at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:489)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:405)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:393)
      at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:105)
      at java.lang.ClassLoader.loadClass(ClassLoader.java:609)
      ... 59 more

      java.lang.NoClassDefFoundError: serp.util.Strings
      at org.apache.openjpa.lib.conf.Configurations.newInstance(Configurations.java:200)
      at org.apache.openjpa.lib.conf.ObjectValue.newInstance(ObjectValue.java:124)
      at org.apache.openjpa.lib.conf.PluginValue.instantiate(PluginValue.java:103)
      at org.apache.openjpa.lib.conf.ObjectValue.instantiate(ObjectValue.java:83)
      at org.apache.openjpa.lib.conf.ConfigurationImpl.getLogFactory(ConfigurationImpl.java:209)
      at org.apache.openjpa.lib.conf.ConfigurationImpl.getLog(ConfigurationImpl.java:226)
      at org.apache.openjpa.conf.OpenJPAConfigurationImpl.getConfigurationLog(OpenJPAConfigurationImpl.java:1600)
      at org.apache.openjpa.lib.conf.ConfigurationImpl.loadGlobals(ConfigurationImpl.java:191)
      at org.apache.openjpa.conf.OpenJPAConfigurationImpl.<init>(OpenJPAConfigurationImpl.java:584)
      at org.apache.openjpa.conf.OpenJPAConfigurationImpl.<init>(OpenJPAConfigurationImpl.java:195)
      at org.apache.openjpa.conf.OpenJPAConfigurationImpl.<init>(OpenJPAConfigurationImpl.java:186)
      at org.apache.openjpa.persistence.PersistenceProviderImpl.newConfigurationImpl(PersistenceProviderImpl.java:230)
      at org.apache.openjpa.persistence.PersistenceProviderImpl.createContainerEntityManagerFactory(PersistenceProviderImpl.java:166)
      at org.apache.openjpa.persistence.PersistenceProviderImpl.createContainerEntityManagerFactory(PersistenceProviderImpl.java:62)
      at org.apache.aries.jpa.container.impl.EntityManagerFactoryManager.createEntityManagerFactories(EntityManagerFactoryManager.java:227)
      at org.apache.aries.jpa.container.impl.EntityManagerFactoryManager.bundleStateChange(EntityManagerFactoryManager.java:121)
      at org.apache.aries.jpa.container.impl.PersistenceBundleManager.modifiedBundle(PersistenceBundleManager.java:197)
      at org.apache.aries.util.tracker.MultiBundleTracker$InternalBundleTracker.modifiedBundle(MultiBundleTracker.java:108)
      at org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:453)
      at org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:237)
      at org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:413)
      at org.eclipse.osgi.framework.internal.core.BundleContextImpl.dispatchEvent(BundleContextImpl.java:916)
      at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:220)
      at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:149)
      at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEventPrivileged(Framework.java:1350)
      at org.eclipse.osgi.framework.internal.core.Framework.publishBundleEvent(Framework.java:1301)
      at org.eclipse.osgi.framework.internal.core.BundleHost.stopWorker(BundleHost.java:490)
      at org.eclipse.osgi.framework.internal.core.AbstractBundle.suspend(AbstractBundle.java:546)
      at org.eclipse.osgi.framework.internal.core.Framework.suspendBundle(Framework.java:1098)
      at org.eclipse.osgi.framework.internal.core.PackageAdminImpl.suspendBundle(PackageAdminImpl.java:314)
      at org.eclipse.osgi.framework.internal.core.PackageAdminImpl.processDelta(PackageAdminImpl.java:460)
      at org.eclipse.osgi.framework.internal.core.PackageAdminImpl.doResolveBundles(PackageAdminImpl.java:241)
      at org.eclipse.osgi.framework.internal.core.PackageAdminImpl$1.run(PackageAdminImpl.java:176)
      at java.lang.Thread.run(Thread.java:735)
      Caused by: java.lang.ClassNotFoundException: serp.util.Strings
      at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:489)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:405)
      at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:393)
      at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:105)
      at java.lang.ClassLoader.loadClass(ClassLoader.java:609)
      ... 34 more

      Obviously there is no problem if the package imports are satisfied, but it would be nice to have a clear error message indicating that no container-managed JPA is possible without these packages.

        Activity

        Hide
        Donald Woods added a comment -

        Here is a potential fix, but not one I'm going to commit as it changes the existing behavior of createContainerEMF(), which could break upstream projects/products that use OpenJPA.

        Most Java EE containers use Errors to denote critical failures that should cause the container to stop loading.

        Why is Aries or Felix/Equinox OSGi container not catching a NoClassDefFoundError to mean a required bundle could not be found/loaded and cause the bundle being loaded (openjpa in this case) to stop loading??? Requiring providers to implement special error code for OSGi containers should either be handled by RFC143 or the OSGi framework.

        Show
        Donald Woods added a comment - Here is a potential fix, but not one I'm going to commit as it changes the existing behavior of createContainerEMF(), which could break upstream projects/products that use OpenJPA. Most Java EE containers use Errors to denote critical failures that should cause the container to stop loading. Why is Aries or Felix/Equinox OSGi container not catching a NoClassDefFoundError to mean a required bundle could not be found/loaded and cause the bundle being loaded (openjpa in this case) to stop loading??? Requiring providers to implement special error code for OSGi containers should either be handled by RFC143 or the OSGi framework.
        Hide
        Timothy Ward added a comment -

        I'm not looking for a PersistenceException, but it would be nice if the container could catch a RuntimeException rather than an Error as that is much easier (and safer) for the caller to handle.

        It would also be nice if the thrown Exception had an error message that said something like "The package xxxx is required when using OpenJPA with a container in OSGi, but this package was not available". It should be relatively simple to check that packages are available when in an OSGi framework, so this could potentially be done ahead of time rather than waiting for the NoClassDefFoundError.

        As this is primarily a consumability problem, I made sure to raise it as a minor bug and understand that it may not be fixed immediately. My main concerns were (in order):

        a) to let you know about the restriction for any future OSGi work in OpenJPA
        b) to get a change to the code so that a RuntimeException is thrown rather than a NoClassDefFoundError
        c) to get a better error message when a package is unavailable

        If throwing a RuntimeException is a reasonably simple solution then I'm happy with that, if not then I'm open to other solutions.

        Show
        Timothy Ward added a comment - I'm not looking for a PersistenceException, but it would be nice if the container could catch a RuntimeException rather than an Error as that is much easier (and safer) for the caller to handle. It would also be nice if the thrown Exception had an error message that said something like "The package xxxx is required when using OpenJPA with a container in OSGi, but this package was not available". It should be relatively simple to check that packages are available when in an OSGi framework, so this could potentially be done ahead of time rather than waiting for the NoClassDefFoundError. As this is primarily a consumability problem, I made sure to raise it as a minor bug and understand that it may not be fixed immediately. My main concerns were (in order): a) to let you know about the restriction for any future OSGi work in OpenJPA b) to get a change to the code so that a RuntimeException is thrown rather than a NoClassDefFoundError c) to get a better error message when a package is unavailable If throwing a RuntimeException is a reasonably simple solution then I'm happy with that, if not then I'm open to other solutions.
        Hide
        Donald Woods added a comment -

        What exactly are you looking for? The spec doesn't allow for wrapping exceptions in a PersistenceException for createCEMF() -

        /**
        Called by the container when an EntityManagerFactory is to be created.
        @param info metadata for use by the persistence provider
        @param map a Map of integration-level properties for use by the persistence provider (may be null if no properties are specified).
        If a Bean Validation provider is present in the classpath, the container must pass the ValidatorFactory instance in the map with the key "javax.persistence.validation.factory".
        @return EntityManagerFactory for the persistence unit specified by the metadata
        */
        public EntityManagerFactory createContainerEntityManagerFactory(
        PersistenceUnitInfo info, Map map);

        but does allow RuntimeExceptions to be thrown.

        Show
        Donald Woods added a comment - What exactly are you looking for? The spec doesn't allow for wrapping exceptions in a PersistenceException for createCEMF() - /** Called by the container when an EntityManagerFactory is to be created. @param info metadata for use by the persistence provider @param map a Map of integration-level properties for use by the persistence provider (may be null if no properties are specified). If a Bean Validation provider is present in the classpath, the container must pass the ValidatorFactory instance in the map with the key "javax.persistence.validation.factory". @return EntityManagerFactory for the persistence unit specified by the metadata */ public EntityManagerFactory createContainerEntityManagerFactory( PersistenceUnitInfo info, Map map); but does allow RuntimeExceptions to be thrown.

          People

          • Assignee:
            Unassigned
            Reporter:
            Timothy Ward
          • Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:

              Development