001: /*
002: * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: */
007: package winstone.jndi;
008:
009: import java.lang.reflect.Constructor;
010: import java.lang.reflect.Method;
011: import java.util.ArrayList;
012: import java.util.Collection;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Map;
017: import java.util.Properties;
018:
019: import javax.naming.CompositeName;
020: import javax.naming.Context;
021: import javax.naming.InitialContext;
022: import javax.naming.Name;
023: import javax.naming.NamingException;
024:
025: import winstone.JNDIManager;
026: import winstone.Logger;
027: import winstone.WinstoneResourceBundle;
028: import winstone.jndi.resourceFactories.WinstoneDataSource;
029:
030: /**
031: * Implements a simple web.xml + command line arguments style jndi manager
032: *
033: * @author <a href="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
034: * @version $Id: ContainerJNDIManager.java,v 1.3 2006/02/28 07:32:48 rickknowles Exp $
035: */
036: public class ContainerJNDIManager implements JNDIManager {
037: public static final WinstoneResourceBundle JNDI_RESOURCES = new WinstoneResourceBundle(
038: "winstone.jndi.LocalStrings");
039:
040: protected Map objectsToCreate;
041:
042: /**
043: * Gets the relevant list of objects from the args, validating against the
044: * web.xml nodes supplied. All node addresses are assumed to be relative to
045: * the java:/comp/env context
046: */
047: public ContainerJNDIManager(Map args, List webXmlNodes,
048: ClassLoader loader) {
049: // Build all the objects we wanted
050: this .objectsToCreate = new HashMap();
051:
052: Collection keys = new ArrayList(args != null ? args.keySet()
053: : (Collection) new ArrayList());
054: for (Iterator i = keys.iterator(); i.hasNext();) {
055: String key = (String) i.next();
056:
057: if (key.startsWith("jndi.resource.")) {
058: String resName = key.substring(14);
059: String className = (String) args.get(key);
060: String value = (String) args.get("jndi.param."
061: + resName + ".value");
062: Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES,
063: "ContainerJNDIManager.CreatingResourceArgs",
064: resName);
065: Object obj = createObject(resName.trim(), className
066: .trim(), value, args, loader);
067: if (obj != null)
068: this .objectsToCreate.put(resName, obj);
069: }
070: }
071: }
072:
073: /**
074: * Add the objects passed to the constructor to the JNDI Context addresses
075: * specified
076: */
077: public void setup() {
078:
079: try {
080: InitialContext ic = new InitialContext();
081: for (Iterator i = this .objectsToCreate.keySet().iterator(); i
082: .hasNext();) {
083: String name = (String) i.next();
084: try {
085: Name fullName = new CompositeName(name);
086: Context currentContext = ic;
087: while (fullName.size() > 1) {
088: // Make contexts that are not already present
089: try {
090: currentContext = currentContext
091: .createSubcontext(fullName.get(0));
092: } catch (NamingException err) {
093: currentContext = (Context) currentContext
094: .lookup(fullName.get(0));
095: }
096: fullName = fullName.getSuffix(1);
097: }
098: ic.bind(name, this .objectsToCreate.get(name));
099: Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES,
100: "ContainerJNDIManager.BoundResource", name);
101: } catch (NamingException err) {
102: Logger
103: .log(
104: Logger.ERROR,
105: JNDI_RESOURCES,
106: "ContainerJNDIManager.ErrorBindingResource",
107: name, err);
108: }
109: }
110: Logger.log(Logger.DEBUG, JNDI_RESOURCES,
111: "ContainerJNDIManager.SetupComplete", ""
112: + this .objectsToCreate.size());
113: } catch (NamingException err) {
114: Logger.log(Logger.ERROR, JNDI_RESOURCES,
115: "ContainerJNDIManager.ErrorGettingInitialContext",
116: err);
117: }
118: }
119:
120: /**
121: * Remove the objects under administration from the JNDI Context, and then
122: * destroy the objects
123: */
124: public void tearDown() {
125: try {
126: InitialContext ic = new InitialContext();
127: for (Iterator i = this .objectsToCreate.keySet().iterator(); i
128: .hasNext();) {
129: String name = (String) i.next();
130: try {
131: ic.unbind(name);
132: } catch (NamingException err) {
133: Logger
134: .log(
135: Logger.ERROR,
136: JNDI_RESOURCES,
137: "ContainerJNDIManager.ErrorUnbindingResource",
138: name, err);
139: }
140: Object unboundObject = this .objectsToCreate.get(name);
141: if (unboundObject instanceof WinstoneDataSource)
142: ((WinstoneDataSource) unboundObject).destroy();
143: Logger.log(Logger.FULL_DEBUG, JNDI_RESOURCES,
144: "ContainerJNDIManager.UnboundResource", name);
145: }
146: Logger.log(Logger.DEBUG, JNDI_RESOURCES,
147: "ContainerJNDIManager.TeardownComplete", ""
148: + this .objectsToCreate.size());
149: } catch (NamingException err) {
150: Logger.log(Logger.ERROR, JNDI_RESOURCES,
151: "ContainerJNDIManager.ErrorGettingInitialContext",
152: err);
153: }
154: }
155:
156: /**
157: * Build an object to insert into the jndi space
158: */
159: protected Object createObject(String name, String className,
160: String value, Map args, ClassLoader loader) {
161:
162: if ((className == null) || (name == null))
163: return null;
164:
165: // Set context class loader
166: ClassLoader cl = Thread.currentThread().getContextClassLoader();
167: Thread.currentThread().setContextClassLoader(loader);
168:
169: try {
170: // If we are working with a datasource
171: if (className.equals("javax.sql.DataSource")) {
172: try {
173: return new WinstoneDataSource(name,
174: extractRelevantArgs(args, name), loader);
175: } catch (Throwable err) {
176: Logger
177: .log(
178: Logger.ERROR,
179: JNDI_RESOURCES,
180: "ContainerJNDIManager.ErrorBuildingDatasource",
181: name, err);
182: }
183: }
184:
185: // If we are working with a mail session
186: else if (className.equals("javax.mail.Session")) {
187: try {
188: Class smtpClass = Class.forName(className, true,
189: loader);
190: Method smtpMethod = smtpClass
191: .getMethod(
192: "getInstance",
193: new Class[] {
194: Properties.class,
195: Class
196: .forName("javax.mail.Authenticator") });
197: return smtpMethod.invoke(null, new Object[] {
198: extractRelevantArgs(args, name), null });
199: //return Session.getInstance(extractRelevantArgs(args, name), null);
200: } catch (Throwable err) {
201: Logger
202: .log(
203: Logger.ERROR,
204: JNDI_RESOURCES,
205: "ContainerJNDIManager.ErrorBuildingMailSession",
206: name, err);
207: }
208: }
209:
210: // If unknown type, try to instantiate with the string constructor
211: else if (value != null) {
212: try {
213: Class objClass = Class.forName(className.trim(),
214: true, loader);
215: Constructor objConstr = objClass
216: .getConstructor(new Class[] { String.class });
217: return objConstr
218: .newInstance(new Object[] { value });
219: } catch (Throwable err) {
220: Logger.log(Logger.ERROR, JNDI_RESOURCES,
221: "ContainerJNDIManager.ErrorBuildingObject",
222: new String[] { name, className }, err);
223: }
224: }
225:
226: return null;
227:
228: } finally {
229: Thread.currentThread().setContextClassLoader(cl);
230: }
231: }
232:
233: /**
234: * Rips the parameters relevant to a particular resource from the command args
235: */
236: private Properties extractRelevantArgs(Map input, String name) {
237: Properties relevantArgs = new Properties();
238: for (Iterator i = input.keySet().iterator(); i.hasNext();) {
239: String key = (String) i.next();
240: if (key.startsWith("jndi.param." + name + "."))
241: relevantArgs.put(key.substring(12 + name.length()),
242: input.get(key));
243: }
244: return relevantArgs;
245: }
246:
247: }
|