问题
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