/* * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net> * Distributed under the terms of either: * - the common development and distribution license (CDDL), v1.0; or * - the GNU Lesser General Public License, v2.1 or later */ package winstone.jndi; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.naming.CompositeName; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Name; import javax.naming.NamingException; import winstone.JNDIManager; import winstone.Logger; import winstone.WinstoneResourceBundle; import winstone.jndi.resourceFactories.WinstoneDataSource; /** * Implements a simple web.xml + command line arguments style jndi manager * * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a> * @version $Id: ContainerJNDIManager.java,v 1.3 2006/02/28 07:32:48 rickknowles Exp $ */ public class ContainerJNDIManager implements JNDIManager { public static final WinstoneResourceBundle JNDI_RESOURCES = new WinstoneResourceBundle("winstone.jndi.LocalStrings"); protected Map objectsToCreate; /** * Gets the relevant list of objects from the args, validating against the * web.xml nodes supplied. All node addresses are assumed to be relative to * the java:/comp/env context */ public ContainerJNDIManager(Map args, List webXmlNodes, ClassLoader loader) { // Build all the objects we wanted this.objectsToCreate = new HashMap(); Collection keys = new ArrayList(args != null ? args.keySet() : (Collection) new ArrayList()); for (Iterator i = keys.iterator(); i.hasNext();) { String key = (String) i.next(); if (key.startsWith("jndi.resource.")) { String resName = key.substring(14); String className = (String) args.get(key); String value = (String) args.get("jndi.param." + resName + ".value"); Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.CreatingResourceArgs", resName); Object obj = createObject(resName.trim(), className.trim(), value, args, loader); if (obj != null) this.objectsToCreate.put(resName, obj); } } } /** * Add the objects passed to the constructor to the JNDI Context addresses * specified */ public void setup() { try { InitialContext ic = new InitialContext(); for (Iterator i = this.objectsToCreate.keySet().iterator(); i.hasNext();) { String name = (String) i.next(); try { Name fullName = new CompositeName(name); Context currentContext = ic; while (fullName.size() > 1) { // Make contexts that are not already present try { currentContext = currentContext .createSubcontext(fullName.get(0)); } catch (NamingException err) { currentContext = (Context) currentContext .lookup(fullName.get(0)); } fullName = fullName.getSuffix(1); } ic.bind(name, this.objectsToCreate.get(name)); Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.BoundResource", name); } catch (NamingException err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorBindingResource", name, err); } } Logger.log(Logger.DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.SetupComplete", "" + this.objectsToCreate.size()); } catch (NamingException err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorGettingInitialContext", err); } } /** * Remove the objects under administration from the JNDI Context, and then * destroy the objects */ public void tearDown() { try { InitialContext ic = new InitialContext(); for (Iterator i = this.objectsToCreate.keySet().iterator(); i .hasNext();) { String name = (String) i.next(); try { ic.unbind(name); } catch (NamingException err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorUnbindingResource", name, err); } Object unboundObject = this.objectsToCreate.get(name); if (unboundObject instanceof WinstoneDataSource) ((WinstoneDataSource) unboundObject).destroy(); Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.UnboundResource", name); } Logger.log(Logger.DEBUG, JNDI_RESOURCES, "ContainerJNDIManager.TeardownComplete", "" + this.objectsToCreate.size()); } catch (NamingException err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorGettingInitialContext", err); } } /** * Build an object to insert into the jndi space */ protected Object createObject(String name, String className, String value, Map args, ClassLoader loader) { if ((className == null) || (name == null)) return null; // Set context class loader ClassLoader cl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(loader); try { // If we are working with a datasource if (className.equals("javax.sql.DataSource")) { try { return new WinstoneDataSource(name, extractRelevantArgs(args, name), loader); } catch (Throwable err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorBuildingDatasource", name, err); } } // If we are working with a mail session else if (className.equals("javax.mail.Session")) { try { Class smtpClass = Class.forName(className, true, loader); Method smtpMethod = smtpClass.getMethod("getInstance", new Class[] { Properties.class, Class.forName("javax.mail.Authenticator") }); return smtpMethod.invoke(null, new Object[] { extractRelevantArgs(args, name), null }); //return Session.getInstance(extractRelevantArgs(args, name), null); } catch (Throwable err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorBuildingMailSession", name, err); } } // If unknown type, try to instantiate with the string constructor else if (value != null) { try { Class objClass = Class.forName(className.trim(), true, loader); Constructor objConstr = objClass .getConstructor(new Class[] { String.class }); return objConstr.newInstance(new Object[] { value }); } catch (Throwable err) { Logger.log(Logger.ERROR, JNDI_RESOURCES, "ContainerJNDIManager.ErrorBuildingObject", new String[] { name, className }, err); } } return null; } finally { Thread.currentThread().setContextClassLoader(cl); } } /** * Rips the parameters relevant to a particular resource from the command args */ private Properties extractRelevantArgs(Map input, String name) { Properties relevantArgs = new Properties(); for (Iterator i = input.keySet().iterator(); i.hasNext();) { String key = (String) i.next(); if (key.startsWith("jndi.param." + name + ".")) relevantArgs.put(key.substring(12 + name.length()), input .get(key)); } return relevantArgs; } }