222 lines
12 KiB
Java
222 lines
12 KiB
Java
package net.openesb.standalone.naming.jndi.impl;
|
|
|
|
import net.openesb.standalone.naming.jndi.tomcat.TomcatDataSourcePoolFactory;
|
|
import java.net.MalformedURLException;
|
|
import java.net.URL;
|
|
import java.util.HashMap;
|
|
import java.util.Hashtable;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.ResourceBundle;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import javax.naming.Context;
|
|
import javax.naming.InitialContext;
|
|
import javax.naming.NamingException;
|
|
|
|
import javax.naming.spi.InitialContextFactory;
|
|
import javax.sql.DataSource;
|
|
import javax.sql.XADataSource;
|
|
import javax.xml.bind.JAXBContext;
|
|
import javax.xml.bind.JAXBElement;
|
|
import javax.xml.bind.JAXBException;
|
|
import javax.xml.bind.Unmarshaller;
|
|
import net.openesb.standalone.naming.jaxb.DataSourcePoolPropertiesComplexType;
|
|
import net.openesb.standalone.naming.jaxb.JdbcResourceComplexType;
|
|
import net.openesb.standalone.naming.jaxb.OeContextComplexType;
|
|
import net.openesb.standalone.naming.jndi.DataSourcePoolFactory;
|
|
import net.openesb.standalone.naming.utils.I18NBundle;
|
|
|
|
/**
|
|
*
|
|
* @author Paul PEREZ (paul.perez at pymma.com)
|
|
* @author OpenESB Community
|
|
*/
|
|
public class InitialContexFactoryImpl implements InitialContextFactory {
|
|
|
|
public static final String DATASOURCE_TYPE = "Datasource";
|
|
public static final String XADATASOURCE_TYPE = "XADatasource";
|
|
private static final Logger sLogger = Logger.getLogger("net.openesb.standalone.naming");
|
|
private final Map<String, DataSourcePoolPropertiesComplexType> mDSPMap = new HashMap<String, DataSourcePoolPropertiesComplexType>();
|
|
private final DataSourcePoolFactory mDSPFactory = new TomcatDataSourcePoolFactory();
|
|
private final String mClassName = "InitialContexFactoryImpl";
|
|
private final ResourceBundle mResourceBundle;
|
|
private String mMessage;
|
|
|
|
// Constructor
|
|
public InitialContexFactoryImpl() {
|
|
|
|
I18NBundle nBundle = new I18NBundle("net.openesb.standalone.naming.utils");
|
|
mResourceBundle = nBundle.getBundle();
|
|
}
|
|
|
|
/* Regarding the exception management, If the context file if not correct,
|
|
* I choosed to return an initial context in any case even empty. So if input data
|
|
is not correct, I log this information but catch the exception in order to return
|
|
an initial context. Another policy would be to stop at any exception. I did not choose
|
|
it. Naming exception will be thrown only if I cannot create the initial context */
|
|
/* The initial context I use is the one found in Tomcat 7 */
|
|
@Override
|
|
public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
|
|
Map<String, DataSource> datasourceMap = new HashMap<String, DataSource>();
|
|
String methodName = "getInitialContext";
|
|
/*Context initialisation Just set the system properties and use the class InitialContext*/
|
|
System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
|
|
System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
|
|
Context initialContext = new InitialContext();
|
|
mMessage = mResourceBundle.getString("context.created");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage);
|
|
|
|
/* Second step read the XML file URL where context configuration is described
|
|
* The URL can be file:// http:// ...
|
|
* The XML File URL must be in environement hashmap and read the key URL must be equal to
|
|
* CONTEXT_URL*/
|
|
String urlValue = null;
|
|
if (environment.containsKey(Context.PROVIDER_URL)) {
|
|
urlValue = (String) environment.get(Context.PROVIDER_URL);
|
|
mMessage = mResourceBundle.getString("context.url.read");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{urlValue});
|
|
} else {
|
|
mMessage = mResourceBundle.getString("context.url.not.provided") + " " + mResourceBundle.getString("context.url.not.provided.ID");
|
|
sLogger.logp(Level.SEVERE, mClassName, methodName, mMessage);
|
|
}
|
|
|
|
/* Read the context from the URL */
|
|
@SuppressWarnings("UnusedAssignment") JAXBElement<OeContextComplexType> root = null;
|
|
try {
|
|
JAXBContext jc = JAXBContext.newInstance("net.openesb.standalone.naming.jaxb");
|
|
Unmarshaller unmarshaller = jc.createUnmarshaller();
|
|
root = (JAXBElement<OeContextComplexType>) unmarshaller.unmarshal(new URL(urlValue));
|
|
} catch (MalformedURLException ex) {
|
|
mMessage = mResourceBundle.getString("url.context.name.malformed") ;
|
|
sLogger.logp(Level.SEVERE, mClassName, methodName, mMessage, new Object[] {urlValue});
|
|
mMessage = mResourceBundle.getString("catch.exception");
|
|
sLogger.logp(Level.SEVERE, mClassName, methodName, mMessage, ex);
|
|
return initialContext ;
|
|
} catch (JAXBException ex) {
|
|
mMessage = mResourceBundle.getString("jaxb.unmarshalling.failed");
|
|
sLogger.logp(Level.SEVERE, mClassName, methodName, mMessage, new Object[] {urlValue});
|
|
mMessage = mResourceBundle.getString("catch.exception");
|
|
sLogger.logp(Level.SEVERE, mClassName, methodName, mMessage, ex);
|
|
return initialContext ;
|
|
}
|
|
|
|
// This must be made with the xml file has an element root
|
|
// Log level Fine Unmarshalling ok
|
|
OeContextComplexType oeContext = root.getValue();
|
|
mMessage = mResourceBundle.getString("context.binding.ok");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage);
|
|
|
|
/* OeContext contains the complete context */
|
|
/* I create a map with the datasourcePool Name as key and datasourcePool as Value
|
|
* This will be useful to instanciate the db connector later.
|
|
*/
|
|
List<DataSourcePoolPropertiesComplexType> dataSourcePoolList = oeContext.getDataSourcePoolProperties();
|
|
int listSize = dataSourcePoolList.size();
|
|
mMessage = mResourceBundle.getString("number.dataSourcePoolProperties.found");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{listSize});
|
|
|
|
|
|
//Loop on dataSourcePoolList iterator
|
|
for (DataSourcePoolPropertiesComplexType dspComplexType : dataSourcePoolList) {
|
|
mDSPMap.put(dspComplexType.getDbConnectorName(), dspComplexType);
|
|
mMessage = mResourceBundle.getString("datasourcepoolproperties.found.in.context");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{dspComplexType.getDbConnectorName()});
|
|
}
|
|
|
|
// Now Let's read JdbcResource
|
|
List<JdbcResourceComplexType> jdbcResourceList = oeContext.getJdbcResources();
|
|
listSize = jdbcResourceList.size();
|
|
mMessage = mResourceBundle.getString("number.jdbcResource.declaration.found");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{listSize});
|
|
|
|
//Loop on JDBCResourceList iterator
|
|
for (JdbcResourceComplexType jdbcResource : jdbcResourceList) {
|
|
/* For each jcbc resource I want to associate a dbConnector.
|
|
* DBConnector provide a connectionPool or a XAConnectionPool
|
|
* I instanciate the dbConnetor in a lazy mode (when needed)
|
|
* Once instanciated dbConnector are put in a map for reusing purpose
|
|
* ex: when two JNDI names target the same dbConnector
|
|
*/
|
|
|
|
// Get JNDI Name
|
|
String jndiName = jdbcResource.getJndiName();
|
|
mMessage = jndiName + " " + mResourceBundle.getString("in.process");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage);
|
|
|
|
|
|
/* Check if this JNDI name is already in the context. In that case the
|
|
* second instance is not taken into account
|
|
*/
|
|
try {
|
|
initialContext.lookup(jndiName);
|
|
mMessage = mResourceBundle.getString("jndi.value.already.defined");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{jndiName});
|
|
continue;
|
|
} catch (NamingException ex) {
|
|
// Nothing else to do. Having an exception is the normal process
|
|
}
|
|
|
|
|
|
/* Create datasource or XA Datasource thanks to the underlying dbConnector
|
|
* DBConnector refeence is in the DataSourcePoolProperties. DBConnector are instanciated
|
|
* dynamically and must be present in the classpath
|
|
* */
|
|
String dbConnectorName = jdbcResource.getDbConnectorName();
|
|
/* check if the datasource has been created already for a previous
|
|
* JNDI Name. In that case we reuse it.
|
|
*/
|
|
if (datasourceMap.containsKey(dbConnectorName)) {
|
|
if (datasourceMap.get(dbConnectorName) instanceof XADataSource) {
|
|
initialContext.rebind(jndiName, (XADataSource) datasourceMap.get(dbConnectorName));
|
|
} else {
|
|
initialContext.rebind(jndiName, datasourceMap.get(dbConnectorName));
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Retrieve DataSourcePoolPropertie
|
|
DataSourcePoolPropertiesComplexType dspProperties = mDSPMap.get(dbConnectorName);
|
|
// Check if Datasourse or XA Datasource
|
|
if (dspProperties.getResourceType().equals(InitialContexFactoryImpl.DATASOURCE_TYPE)) {
|
|
mMessage = mResourceBundle.getString("datasource.in.process");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{jndiName});
|
|
DataSource dataSource = mDSPFactory.getDataSource(dspProperties);
|
|
/* Check if datasource is not null then put in the context since exception are catch */
|
|
if (null != dataSource) {
|
|
datasourceMap.put(dbConnectorName, dataSource);
|
|
try {
|
|
initialContext.rebind(jndiName, dataSource);
|
|
} catch (NamingException ex) {
|
|
initialContext.bind(jndiName, dataSource);
|
|
}
|
|
mMessage = mResourceBundle.getString("datasource.processed.bind.success");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{jndiName});
|
|
}
|
|
|
|
} else if (dspProperties.getResourceType()
|
|
.equals(InitialContexFactoryImpl.XADATASOURCE_TYPE)) {
|
|
mMessage = mResourceBundle.getString("xadatasource.in.process");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{jndiName});
|
|
XADataSource xaDataSource = mDSPFactory.getXADataSource(dspProperties);
|
|
if (null != xaDataSource) {
|
|
/* Store the XAdatasource in a map for reusing purpose see above */
|
|
datasourceMap.put(dbConnectorName, (DataSource) xaDataSource);
|
|
initialContext.rebind(jndiName, xaDataSource);
|
|
mMessage = mResourceBundle.getString("xadatasource.processed.bind.success");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{jndiName});
|
|
}
|
|
} else {
|
|
mMessage = mResourceBundle.getString("bad.resource.type");
|
|
sLogger.logp(Level.FINE, mClassName, methodName, mMessage, new Object[]{dspProperties.getResourceType(), dspProperties.getDatabaseName()});
|
|
|
|
}
|
|
}
|
|
|
|
/* the context contains the binding and the datasource or xaDatasource links
|
|
* Return the context
|
|
*/
|
|
return initialContext;
|
|
}
|
|
}
|