001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.core.ivm.naming;
017:
018: import java.io.File;
019: import java.io.FileInputStream;
020: import java.io.FileNotFoundException;
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.NotSerializableException;
024: import java.io.ObjectStreamException;
025: import java.io.Serializable;
026: import java.net.URL;
027: import java.util.Enumeration;
028: import java.util.HashMap;
029: import java.util.HashSet;
030: import java.util.Hashtable;
031: import java.util.Map;
032: import java.util.Properties;
033: import java.util.Set;
034: import java.util.StringTokenizer;
035: import java.util.Vector;
036: import javax.naming.Binding;
037: import javax.naming.CompositeName;
038: import javax.naming.Context;
039: import javax.naming.LinkRef;
040: import javax.naming.Name;
041: import javax.naming.NameClassPair;
042: import javax.naming.NameNotFoundException;
043: import javax.naming.NameParser;
044: import javax.naming.NamingEnumeration;
045: import javax.naming.NamingException;
046: import javax.naming.OperationNotSupportedException;
047: import javax.naming.spi.ObjectFactory;
048:
049: import org.apache.openejb.ClassLoaderUtil;
050: import org.apache.openejb.core.ivm.IntraVmCopyMonitor;
051: import org.apache.xbean.naming.context.ContextUtil;
052:
053: /*
054: * This class wrappers a specific NameNode which is the data model for the JNDI
055: * name space. This class provides javax.naming.Context specific functionality
056: * to the NameNode so that it can be used by beans the JNDI ENC.
057: */
058:
059: /**
060: * @org.apache.xbean.XBean element="ivmContext"
061: */
062: public class IvmContext implements Context, Serializable {
063:
064: private static final long serialVersionUID = -626353930051783641L;
065: Hashtable<String, Object> myEnv;
066: boolean readOnly = false;
067: Map<String, Object> fastCache = new HashMap<String, Object>();
068: public NameNode mynode;
069:
070: public static IvmContext createRootContext() {
071: return new IvmContext(new NameNode(null, new ParsedName("/"),
072: null, null));
073: }
074:
075: public IvmContext() {
076: this (new NameNode(null, new ParsedName("root"), null, null));
077: }
078:
079: public IvmContext(String nodeName) {
080: this (new NameNode(null, new ParsedName(nodeName), null, null));
081: }
082:
083: public IvmContext(NameNode node) {
084: mynode = node;
085: }
086:
087: public IvmContext(Hashtable<String, Object> environment)
088: throws NamingException {
089: this ();
090: if (environment == null)
091: throw new NamingException("Invalid Argument");
092: else
093: myEnv = (Hashtable<String, Object>) environment.clone();
094:
095: }
096:
097: public Object lookup(String compositName) throws NamingException {
098: if (compositName.equals("")) {
099: return this ;
100: }
101:
102: String compoundName;
103: int indx = compositName.indexOf(":");
104: if (indx > -1) {
105: /*
106: The ':' character will be in the path if its an absolute path name starting with the schema
107: 'java:'. We strip the schema off the path before passing it to the node.resolve method.
108: */
109: compoundName = compositName.substring(indx + 1);
110: } else {
111: /*
112: the resolve method always starts with the comparison assuming that the first
113: component of the name is a context of a peer node or the same node, so we have
114: to prepend the current context name to the relative lookup path.
115: */
116: compoundName = mynode.getAtomicName() + '/' + compositName;
117: }
118:
119: /*
120: If the object has been resolved in the past from this context and the specified path (name)
121: it will be in the fastCache which is significantly faster then peruse the Node graph.
122: 80 ms compared to 300 ms for a full node path search.
123: */
124: Object obj = fastCache.get(compoundName);
125: if (obj == null) {
126:
127: try {
128: obj = mynode.resolve(new ParsedName(compoundName));
129: } catch (NameNotFoundException nnfe) {
130: obj = federate(compositName);
131: }
132:
133: fastCache.put(compoundName, obj);
134: }
135:
136: if (obj == null) {
137: throw new javax.naming.NameNotFoundException("Name \""
138: + compositName + "\" not found.");
139: }
140:
141: if (obj.getClass() == IvmContext.class)
142: ((IvmContext) obj).myEnv = myEnv;
143: else if (obj instanceof Reference) {
144: /**
145: * EJB references and resource references are wrapped in special
146: * org.apache.openejb.core.ivm.naming.Reference types that check to
147: * see if the current operation is allowed access to the entry (See EJB 1.1/2.0 Allowed Operations)
148: * If the operation is not allowed, a javax.naming.NameNotFoundException is thrown.
149: *
150: * A Reference type can also carry out dynamic resolution of references if necessary.
151: */
152: obj = ((Reference) obj).getObject();
153: } else if (obj instanceof LinkRef) {
154: obj = lookup(((LinkRef) obj).getLinkName());
155: }
156: return obj;
157: }
158:
159: protected Object federate(String compositName)
160: throws NamingException {
161: ObjectFactory factories[] = getFederatedFactories();
162: for (ObjectFactory factory : factories) {
163: try {
164: CompositeName name = new CompositeName(compositName);
165: Object obj = factory.getObjectInstance(null, name,
166: null, null);
167:
168: if (obj instanceof Context)
169: return ((Context) obj).lookup(compositName);
170: else if (obj != null)
171: return obj;
172: } catch (Exception doNothing) {
173: }
174: }
175:
176: throw new javax.naming.NameNotFoundException("Name \""
177: + compositName + "\" not found.");
178: }
179:
180: static ObjectFactory[] federatedFactories = null;
181:
182: public static ObjectFactory[] getFederatedFactories()
183: throws NamingException {
184: if (federatedFactories == null) {
185: Set<ObjectFactory> factories = new HashSet<ObjectFactory>();
186: String urlPackagePrefixes = getUrlPackagePrefixes();
187: if (urlPackagePrefixes == null) {
188: return new ObjectFactory[0];
189: }
190: for (StringTokenizer tokenizer = new StringTokenizer(
191: urlPackagePrefixes, ":"); tokenizer.hasMoreTokens();) {
192: String urlPackagePrefix = tokenizer.nextToken();
193: String className = urlPackagePrefix
194: + ".java.javaURLContextFactory";
195: if (className
196: .equals("org.apache.openejb.core.ivm.naming.java.javaURLContextFactory"))
197: continue;
198: try {
199: ClassLoader cl = ClassLoaderUtil
200: .getContextClassLoader();
201: Class factoryClass = Class.forName(className, true,
202: cl);
203: ObjectFactory factoryInstance = (ObjectFactory) factoryClass
204: .newInstance();
205: factories.add(factoryInstance);
206: } catch (ClassNotFoundException cnfe) {
207:
208: } catch (Throwable e) {
209: NamingException ne = new NamingException(
210: "Federation failed: Cannot instantiate "
211: + className);
212: ne.setRootCause(e);
213: throw ne;
214: }
215: }
216: Object[] temp = factories.toArray();
217: federatedFactories = new ObjectFactory[temp.length];
218: System.arraycopy(temp, 0, federatedFactories, 0,
219: federatedFactories.length);
220: }
221: return federatedFactories;
222: }
223:
224: private static String getUrlPackagePrefixes() {
225: // 1. System.getProperty
226: String urlPackagePrefixes = System
227: .getProperty(Context.URL_PKG_PREFIXES);
228:
229: // 2. Thread.currentThread().getContextClassLoader().getResources("jndi.properties")
230: if (urlPackagePrefixes == null) {
231: ClassLoader classLoader = Thread.currentThread()
232: .getContextClassLoader();
233: if (classLoader == null)
234: classLoader = ClassLoader.getSystemClassLoader();
235:
236: try {
237: Enumeration<URL> resources = classLoader
238: .getResources("jndi.properties");
239: while (urlPackagePrefixes == null
240: && resources.hasMoreElements()) {
241: URL resource = resources.nextElement();
242: InputStream in = resource.openStream();
243: urlPackagePrefixes = getUrlPackagePrefixes(in);
244: }
245: } catch (IOException ignored) {
246: }
247: }
248:
249: // 3. ${java.home}/lib/jndi.properties
250: if (urlPackagePrefixes == null) {
251: String javahome = System.getProperty("java.home");
252: if (javahome != null) {
253: try {
254: File propertiesFile = new File(new File(javahome,
255: "lib"), "jndi.properties");
256: InputStream in = new FileInputStream(propertiesFile);
257: urlPackagePrefixes = getUrlPackagePrefixes(in);
258: } catch (FileNotFoundException ignored) {
259: }
260: }
261:
262: }
263: return urlPackagePrefixes;
264: }
265:
266: private static String getUrlPackagePrefixes(InputStream in) {
267: try {
268: Properties properties = new Properties();
269: properties.load(in);
270: String urlPackagePrefixes = properties
271: .getProperty(Context.URL_PKG_PREFIXES);
272: return urlPackagePrefixes;
273: } catch (IOException e) {
274: return null;
275: }
276: }
277:
278: public Object lookup(Name compositName) throws NamingException {
279: return lookup(compositName.toString());
280: }
281:
282: public void bind(String name, Object obj) throws NamingException {
283: checkReadOnly();
284: int indx = name.indexOf(":");
285: if (indx > -1) {
286: /*
287: The ':' character will be in the path if its an absolute path name starting with the schema
288: 'java:'. We strip the schema off the path before passing it to the node.resolve method.
289: */
290: name = name.substring(indx + 1);
291: }
292: if (fastCache.containsKey(name))
293: throw new javax.naming.NameAlreadyBoundException();
294: else {
295: ParsedName parsedName = new ParsedName(name);
296: mynode.bind(parsedName, obj);
297: }
298: }
299:
300: public void bind(Name name, Object obj) throws NamingException {
301: bind(name.toString(), obj);
302: }
303:
304: public void rebind(String name, Object obj) throws NamingException {
305: throw new javax.naming.OperationNotSupportedException();
306: }
307:
308: public void rebind(Name name, Object obj) throws NamingException {
309: rebind(name.toString(), obj);
310: }
311:
312: public void unbind(String name) throws NamingException {
313: checkReadOnly();
314: int indx = name.indexOf(":");
315: if (indx > -1) {
316: /*
317: The ':' character will be in the path if its an absolute path name starting with the schema
318: 'java:'. We strip the schema off the path before passing it to the node.resolve method.
319: */
320: name = name.substring(indx + 1);
321: }
322: fastCache.clear();
323: mynode.clearCache();
324:
325: mynode.unbind(new ParsedName(name));
326: }
327:
328: public void unbind(Name name) throws NamingException {
329: unbind(name.toString());
330: }
331:
332: public void prune(String name) throws NamingException {
333: IvmContext ctx = (IvmContext) lookup(name);
334: ctx.prune();
335: }
336:
337: public void prune() throws NamingException {
338: mynode.prune();
339: }
340:
341: public void rename(String oldname, String newname)
342: throws NamingException {
343: throw new javax.naming.OperationNotSupportedException();
344: }
345:
346: public void rename(Name oldname, Name newname)
347: throws NamingException {
348: rename(oldname.toString(), newname.toString());
349: }
350:
351: public NamingEnumeration<NameClassPair> list(String name)
352: throws NamingException {
353: Object obj = lookup(name);
354: if (obj.getClass() == IvmContext.class)
355: return new MyListEnumeration(((IvmContext) obj).mynode);
356: else {
357: return null;
358: }
359: }
360:
361: public NamingEnumeration<NameClassPair> list(Name name)
362: throws NamingException {
363: return list(name.toString());
364: }
365:
366: public NamingEnumeration<Binding> listBindings(String name)
367: throws NamingException {
368: Object obj = lookup(name);
369: if (obj.getClass() == IvmContext.class)
370: return new MyBindingEnumeration(((IvmContext) obj).mynode);
371: else {
372: return null;
373: }
374: }
375:
376: public NamingEnumeration<Binding> listBindings(Name name)
377: throws NamingException {
378: return listBindings(name.toString());
379: }
380:
381: public void destroySubcontext(String name) throws NamingException {
382: throw new javax.naming.OperationNotSupportedException();
383: }
384:
385: public void destroySubcontext(Name name) throws NamingException {
386: destroySubcontext(name.toString());
387: }
388:
389: public Context createSubcontext(String name) throws NamingException {
390: checkReadOnly();
391: int indx = name.indexOf(":");
392: if (indx > -1) {
393: /*
394: The ':' character will be in the path if its an absolute path name starting with the schema
395: 'java:'. We strip the schema off the path before passing it to the node.resolve method.
396: */
397: name = name.substring(indx + 1);
398: }
399: if (fastCache.containsKey(name))
400: throw new javax.naming.NameAlreadyBoundException();
401: else
402: return mynode.createSubcontext(new ParsedName(name));
403: }
404:
405: public Context createSubcontext(Name name) throws NamingException {
406: return createSubcontext(name.toString());
407: }
408:
409: public Object lookupLink(String name) throws NamingException {
410: return lookup(name);
411: }
412:
413: public Object lookupLink(Name name) throws NamingException {
414: return lookupLink(name.toString());
415: }
416:
417: public NameParser getNameParser(String name) throws NamingException {
418: return ContextUtil.NAME_PARSER;
419: }
420:
421: public NameParser getNameParser(Name name) throws NamingException {
422: return getNameParser(name.toString());
423: }
424:
425: public String composeName(String name, String prefix)
426: throws NamingException {
427: Name result = composeName(new CompositeName(name),
428: new CompositeName(prefix));
429: return result.toString();
430: }
431:
432: public Name composeName(Name name, Name prefix)
433: throws NamingException {
434: Name result = (Name) (prefix.clone());
435: result.addAll(name);
436: return result;
437: }
438:
439: public Object addToEnvironment(String propName, Object propVal)
440: throws NamingException {
441: if (myEnv == null) {
442: myEnv = new Hashtable<String, Object>(5);
443: }
444: return myEnv.put(propName, propVal);
445: }
446:
447: public Object removeFromEnvironment(String propName)
448: throws NamingException {
449: if (myEnv == null)
450: return null;
451: return myEnv.remove(propName);
452: }
453:
454: public Hashtable getEnvironment() throws NamingException {
455: if (myEnv == null) {
456:
457: return new Hashtable(3);
458: } else {
459: return (Hashtable) myEnv.clone();
460: }
461: }
462:
463: public String getNameInNamespace() throws NamingException {
464: return "";
465: }
466:
467: public void close() throws NamingException {
468: }
469:
470: protected void checkReadOnly()
471: throws OperationNotSupportedException {
472: if (readOnly)
473: throw new OperationNotSupportedException();
474: }
475:
476: protected class MyBindingEnumeration extends MyNamingEnumeration {
477:
478: public MyBindingEnumeration(NameNode parentNode) {
479: super (parentNode);
480: }
481:
482: protected void buildEnumeration(Vector vect) {
483: for (int i = 0; i < vect.size(); i++) {
484: NameNode node = (NameNode) vect.elementAt(i);
485: String className = node.getBinding().getClass()
486: .getName();
487: vect.setElementAt(new Binding(node.getAtomicName(),
488: className, node.getBinding()), i);
489: }
490: myEnum = vect.elements();
491: }
492:
493: }
494:
495: protected class MyListEnumeration extends MyNamingEnumeration {
496:
497: public MyListEnumeration(NameNode parentNode) {
498: super (parentNode);
499: }
500:
501: protected void buildEnumeration(Vector vect) {
502: for (int i = 0; i < vect.size(); i++) {
503: NameNode node = (NameNode) vect.elementAt(i);
504: String className = node.getBinding().getClass()
505: .getName();
506: vect.setElementAt(new NameClassPair(node
507: .getAtomicName(), className), i);
508: }
509: myEnum = vect.elements();
510: }
511:
512: }
513:
514: protected abstract class MyNamingEnumeration implements
515: NamingEnumeration {
516:
517: Enumeration myEnum;
518:
519: public MyNamingEnumeration(NameNode parentNode) {
520: Vector vect = new Vector();
521:
522: NameNode node = parentNode.getSubTree();
523:
524: if (node == null) {
525: node = parentNode;
526: } else {
527: vect.addElement(node);
528: }
529:
530: gatherNodes(node, vect);
531:
532: buildEnumeration(vect);
533: }
534:
535: abstract protected void buildEnumeration(Vector<NameNode> vect);
536:
537: protected void gatherNodes(NameNode node, Vector vect) {
538: if (node.getLessTree() != null) {
539: vect.addElement(node.getLessTree());
540: gatherNodes(node.getLessTree(), vect);
541: }
542: if (node.getGrtrTree() != null) {
543: vect.addElement(node.getGrtrTree());
544: gatherNodes(node.getGrtrTree(), vect);
545: }
546: }
547:
548: public void close() {
549: myEnum = null;
550: }
551:
552: public boolean hasMore() {
553: return hasMoreElements();
554: }
555:
556: public Object next() {
557: return nextElement();
558: }
559:
560: public boolean hasMoreElements() {
561: return myEnum.hasMoreElements();
562: }
563:
564: public Object nextElement() {
565: return myEnum.nextElement();
566: }
567: }
568:
569: protected Object writeReplace() throws ObjectStreamException {
570: if (IntraVmCopyMonitor.isStatefulPassivationOperation()) {
571: return new JndiEncArtifact(this );
572: } else if (IntraVmCopyMonitor.isCrossClassLoaderOperation()) {
573: return new JndiEncArtifact(this );
574: }
575:
576: throw new NotSerializableException(
577: "IntraVM java.naming.Context objects can not be passed as arguments");
578: }
579:
580: /* for testing only*/
581: public static void main(String str[]) throws Exception {
582: String str1 = "root/comp/env/rate/work/doc/lot/pop";
583: String str2 = "root/comp/env/rate/work/doc/lot/price";
584: String str3 = "root/comp/env/rate/work/doc/lot";
585: String str4 = "root/comp/env/rate/work/doc/lot/break/story";
586:
587: IvmContext context = new IvmContext();
588: context.bind(str1, new Integer(1));
589: context.bind(str2, new Integer(2));
590: context.bind(str4, new Integer(3));
591: /*
592: Object obj = context.lookup(str1);
593: obj = context.lookup(str2);
594: obj = context.lookup(str1);
595: obj = context.lookup(str3);
596: obj = obj;
597:
598: NamingEnumeration ne = context.list(str3);
599: while(ne.hasMore()){
600: NameClassPair ncp = (NameClassPair)ne.nextElement();
601: System.out.println(ncp.getName()+" "+ncp.getClassName());
602: }
603: */
604:
605: Context subcntx = (Context) context.lookup(str3);
606: org.apache.openejb.core.ivm.IntraVmCopyMonitor x = null;
607: java.io.FileOutputStream fos = new java.io.FileOutputStream(
608: "x.ser");
609: java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(
610: fos);
611: org.apache.openejb.core.ivm.IntraVmCopyMonitor
612: .prePassivationOperation();
613: oos.writeObject(subcntx);
614: org.apache.openejb.core.ivm.IntraVmCopyMonitor
615: .postPassivationOperation();
616: oos.flush();
617: oos.close();
618: java.io.FileInputStream fis = new java.io.FileInputStream(
619: "x.ser");
620: java.io.ObjectInputStream ois = new java.io.ObjectInputStream(
621: fis);
622: Object newObj = ois.readObject();
623: ois.close();
624: }
625:
626: //
627: // Helper methods for debugging
628: //
629:
630: }
|