package org.atricore.idbus.bundles.datanucleus.core;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.atricore.idbus.kernel.common.support.osgi.OsgiBundleClassLoader;
import org.atricore.idbus.kernel.common.support.osgi.OsgiBundlespaceClassLoader;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean;
import org.springframework.osgi.context.BundleContextAware;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.util.Map;
/**
* @author <a href="mailto:sgonzalez@atricore.org">Sebastian Gonzalez Oyuela</a>
* @version $Id$
*/
public class OsgiJDOPersistenceManagerFactoryBean
extends LocalPersistenceManagerFactoryBean
implements BundleContextAware {
private static final String JNDI = "jndi:";
private static final String OSGI = "osgi:";
private static final Log logger = LogFactory.getLog(OsgiJDOPersistenceManagerFactoryBean.class);
private BundleContext bundleContext;
private String dataSourceUrl;
private DataSource dataSource;
@Override
protected PersistenceManagerFactory newPersistenceManagerFactory(Map props) {
if (logger.isDebugEnabled())
logger.debug("Creating new PersistenceManagerFactory based on properties");
ClassLoader osgiCl = new OsgiBundleClassLoader(bundleContext.getBundle());
if (props.get("datanucleus.primaryClassLoader") == null) {
if (logger.isDebugEnabled())
logger.debug("Setting primary Classloader to Osgi Bundle classloader for " +
bundleContext.getBundle().getLocation());
props.put("datanucleus.primaryClassLoader", osgiCl);
} else {
if (logger.isDebugEnabled())
logger.debug("Replacing primary Classloader to Osgi Bundle classloader for " +
bundleContext.getBundle().getLocation());
props.put("datanucleus.primaryClassLoader", osgiCl);
}
try {
if (dataSource == null) {
if (dataSourceUrl == null)
dataSourceUrl = (String) props.get("jdbc.dataSourceUrl");
dataSource = (DataSource) createDatasource(dataSourceUrl);
}
props.put("datanucleus.ConnectionFactory", dataSource);
} catch (Exception e) {
logger.error("Cannot locate DS for " + dataSourceUrl, e);
}
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(props, osgiCl);
if (logger.isDebugEnabled())
logger.debug("Using PMF ("+pmf.getName()+") " + pmf);
return pmf;
}
@Override
protected PersistenceManagerFactory newPersistenceManagerFactory(String name) {
/* DO NOT USE THE ENTIRE BUNDLESPACE, instead embed datanucleus in your own bundle.
ClassLoader osgiCl = new OsgiBundlespaceClassLoader(bundleContext,
new OsgiBundleClassLoader(bundleContext.getBundle()),
bundleContext.getBundle());
*/
ClassLoader osgiCl = new OsgiBundleClassLoader(bundleContext.getBundle());
if (logger.isDebugEnabled())
logger.debug("Creating new PersistenceManagerFactory based on name for " +
bundleContext.getBundle().getLocation());
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(name, osgiCl);
if (logger.isDebugEnabled())
logger.debug("Using PMF ("+pmf.getName()+")" + pmf);
return pmf;
}
public void setBundleContext(BundleContext bundleContext) {
if (logger.isDebugEnabled())
logger.debug("Recieved BundleContext " + bundleContext);
this.bundleContext = bundleContext;
setBeanClassLoader(Thread.currentThread().getContextClassLoader());
}
public String getDataSourceUrl() {
return dataSourceUrl;
}
public void setDataSourceUrl(String dataSourceUrl) {
this.dataSourceUrl = dataSourceUrl;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Looks up a datasource from the url. The datasource can be passed either as jndi name or osgi ldap filter.
* @param url
* @return
* @throws Exception
*/
public Object createDatasource(String url) throws Exception {
if (url == null) {
throw new Exception("Illegal datasource url format. Datasource URL cannot be null.");
} else if (url.trim().length() == 0) {
throw new Exception("Illegal datasource url format. Datasource URL cannot be empty.");
} else if (url.startsWith(JNDI)) {
String jndiName = url.substring(JNDI.length());
InitialContext ic = new InitialContext();
Object ds = ic.lookup(jndiName);
return ds;
} else if (url.startsWith(OSGI)) {
String osgiFilter = url.substring(OSGI.length());
String clazz = null;
String filter = null;
String[] tokens = osgiFilter.split("/", 2);
if (tokens != null) {
if (tokens.length > 0) {
clazz = tokens[0];
}
if (tokens.length > 1) {
filter = tokens[1];
}
}
ServiceReference[] references = bundleContext.getServiceReferences(clazz, filter);
if (references != null) {
ServiceReference ref = references[0];
Object ds = bundleContext.getService(ref);
bundleContext.ungetService(ref);
return ds;
} else {
throw new Exception("Unable to find service reference for datasource: " + clazz + "/" + filter);
}
} else {
throw new Exception("Illegal datasource url format");
}
}
}