jdo/OSGi: error building JDO PersistenceManagerFactory after bundle update

帅比萌擦擦* 提交于 2019-12-08 11:06:09

问题


I'm using JDO with datanucleus-mongodb 3.2.3 and spring 3.0.7 on top of karaf 2.2.10.

On a fresh OSGi bundle install I'm able to persist on mongodb without issues, but after a bundle reinstall, I get the following error while building a new JDO PersistenceManagerFactory:

ERROR: Bundle [my_bundle] [242] Unable to get module class path.
(java.lang.IllegalStateException: zip file closed)      

Where the ID (242) refers to the first assigned ID to the bundle (in other words, the ID of the old bundle).

The context of the previous bundle seems to be properly closed, as well as the "old" JDO PersistenceManagerFactory.

My local persistence manager factory bean class (based on the example provided in the dn site):

public class OSGiLocalPersistenceManagerFactoryBean
    extends LocalPersistenceManagerFactoryBean implements BundleContextAware {

    public static final String JDO_BUNDLE_NAME    = "org.datanucleus.api.jdo";
    public static final String JDO_PMF_CLASS_NAME = "org.datanucleus.api.jdo.JDOPersistenceManagerFactory";

    private BundleContext bundleContext;

    @Override
    protected PersistenceManagerFactory newPersistenceManagerFactory(String name) {
        return JDOHelper.getPersistenceManagerFactory(name, getClassLoader());
    }

    @Override
    protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) {
        ClassLoader classLoader = getClassLoader();

        props.put("datanucleus.primaryClassLoader", classLoader);

        if (FrameworkUtil.getBundle(this.getClass()) != null) { // running in OSGi
            props.put("datanucleus.plugin.pluginRegistryClassName", "org.datanucleus.plugin.OSGiPluginRegistry");
        }

        PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props, classLoader);

        return pmf;
    }

    private ClassLoader getClassLoader() {
        ClassLoader classLoader = null;
        Bundle thisBundle = FrameworkUtil.getBundle(this.getClass());

        if (thisBundle != null) { // on OSGi runtime
            Bundle[] bundles = bundleContext.getBundles();

            for (Bundle bundle : bundles) {
                if (JDO_BUNDLE_NAME.equals(bundle.getSymbolicName())) {
                    try {
                        classLoader = bundle.loadClass(JDO_PMF_CLASS_NAME).getClassLoader();
                    } catch (ClassNotFoundException e) {
                        // do something fancy here ...
                    }
                    break;
                }
            }
        } else { // somewhere else
            classLoader = this.getClass().getClassLoader();
        }
        return classLoader;
    }

    @Override
    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }
}

Some persistence related excerpts from the context:

<!-- persistence manager factory -->
<bean id="pmf" class="[my_package].OSGiLocalPersistenceManagerFactoryBean">
    <property name="configLocation" value="classpath:datanucleus.properties" />
</bean>

<!-- persistence manager factory proxy -->
<bean id="persistenceManagerFactoryProxy"
      class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
    <property name="targetPersistenceManagerFactory" ref="pmf" />
</bean>

<!-- transactions -->
<bean id="transactionManager" class="org.springframework.orm.jdo.JdoTransactionManager">
    <property name="persistenceManagerFactory" ref="persistenceManagerFactoryProxy" />
</bean>

<tx:annotation-driven />

The error message seems to point to a classloading issue, but then, why does it fail only during re-deployment?

Any hint would be appreciated!


回答1:


Make sure you also refresh the depending bundles, cause those usually stick to the old uninstalled bundle. It's still there until all references are cleared. In the Karaf shell you'll just need to issue refresh or simple refresh without the ID, this will cause the complete container to do a re-wiring :)




回答2:


For those who cannot simply refresh javax.jdo make sure you recreate your custom ClassLoader while recreating the PersistenceManagerFactory. Datanucleus will not try to load the same class twice if the ClassLoader has not changed. You will end up having ClassCastExceptions saying Entity.class cannot be cast to Entity.class.



来源:https://stackoverflow.com/questions/19524534/jdo-osgi-error-building-jdo-persistencemanagerfactory-after-bundle-update

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!