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: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Vasily Zakharov
021: * @version $Revision: 1.1.2.4 $
022: */package org.apache.harmony.jndi.provider.rmi.registry;
023:
024: import java.rmi.AccessException;
025: import java.rmi.AlreadyBoundException;
026: import java.rmi.ConnectException;
027: import java.rmi.ConnectIOException;
028: import java.rmi.MarshalException;
029: import java.rmi.NoSuchObjectException;
030: import java.rmi.NotBoundException;
031: import java.rmi.RMISecurityManager;
032: import java.rmi.Remote;
033: import java.rmi.RemoteException;
034: import java.rmi.ServerException;
035: import java.rmi.StubNotFoundException;
036: import java.rmi.UnknownHostException;
037: import java.rmi.UnmarshalException;
038: import java.rmi.activation.ActivateFailedException;
039: import java.rmi.registry.LocateRegistry;
040: import java.rmi.registry.Registry;
041: import java.rmi.server.ExportException;
042: import java.rmi.server.RMIClientSocketFactory;
043: import java.util.Hashtable;
044:
045: import javax.naming.Binding;
046: import javax.naming.CommunicationException;
047: import javax.naming.CompositeName;
048: import javax.naming.ConfigurationException;
049: import javax.naming.Context;
050: import javax.naming.InvalidNameException;
051: import javax.naming.Name;
052: import javax.naming.NameAlreadyBoundException;
053: import javax.naming.NameClassPair;
054: import javax.naming.NameNotFoundException;
055: import javax.naming.NameParser;
056: import javax.naming.NamingEnumeration;
057: import javax.naming.NamingException;
058: import javax.naming.NoPermissionException;
059: import javax.naming.NotContextException;
060: import javax.naming.OperationNotSupportedException;
061: import javax.naming.Reference;
062: import javax.naming.Referenceable;
063: import javax.naming.ServiceUnavailableException;
064: import javax.naming.StringRefAddr;
065: import javax.naming.spi.NamingManager;
066:
067: import org.apache.harmony.jndi.internal.nls.Messages;
068:
069: /**
070: * RMI Registry context implementation.
071: */
072: public class RegistryContext implements Context, Referenceable {
073:
074: /**
075: * System property used to state whether the RMI security manager should be
076: * installed.
077: */
078: public static final String SECURITY_MANAGER = "java.naming.rmi.security.manager"; //$NON-NLS-1$
079:
080: /**
081: * System property used to supply the name of the
082: * {@link RMIClientSocketFactory} to use.
083: */
084: public static final String CLIENT_SOCKET_FACTORY = "org.apache.harmony.jndi.provider.rmi.registry.clientSocketFactory"; //$NON-NLS-1$
085:
086: /**
087: * Prefix for RMI URLs.
088: */
089: public static final String RMI_URL_PREFIX = "rmi:"; //$NON-NLS-1$
090:
091: /**
092: * Address type for RMI context references.
093: */
094: public static final String ADDRESS_TYPE = "URL"; //$NON-NLS-1$
095:
096: /**
097: * Name parser.
098: */
099: protected static final NameParser nameParser = new AtomicNameParser();
100:
101: /**
102: * Registry host, stored to produce copies of this context.
103: */
104: protected String host;
105:
106: /**
107: * Registry port, stored to produce copies of this context.
108: */
109: protected int port;
110:
111: /**
112: * RMI client socket factory, stored to produce copies of this context.
113: */
114: protected RMIClientSocketFactory csf;
115:
116: /**
117: * Local environment.
118: */
119: protected Hashtable<Object, Object> environment;
120:
121: /**
122: * RMI Registry.
123: */
124: protected Registry registry;
125:
126: /**
127: * Reference for this context, initialized by
128: * {@link RegistryContextFactory#getObjectInstance(Object, Name, Context, Hashtable)}.
129: */
130: protected Reference reference;
131:
132: /**
133: * Creates RMI registry context bound to RMI Registry operating on the
134: * specified host and port.
135: *
136: * @param host
137: * Host. If <code>null</code>, localhost is assumed.
138: *
139: * @param port
140: * Port. If <code>0</code>, default registry port (<code>1099</code>)
141: * is assumed.
142: *
143: * @param environment
144: * Context environment, may be <code>null</code> which denotes
145: * empty environment.
146: *
147: * @throws NamingException
148: * If some naming error occurs.
149: */
150: @SuppressWarnings("unchecked")
151: public RegistryContext(String host, int port,
152: Hashtable<?, ?> environment) throws NamingException {
153: this .host = host;
154: this .port = port;
155:
156: this .environment = ((environment != null) ? (Hashtable<Object, Object>) environment
157: .clone()
158: : new Hashtable<Object, Object>());
159:
160: if (this .environment.get(SECURITY_MANAGER) != null) {
161: installSecurityManager();
162: }
163:
164: String clientSocketFactoryName = (String) this .environment
165: .get(CLIENT_SOCKET_FACTORY);
166:
167: if (clientSocketFactoryName == null) {
168: csf = null;
169: } else {
170: try {
171: csf = (RMIClientSocketFactory) Class.forName(
172: clientSocketFactoryName, true,
173: Thread.currentThread().getContextClassLoader())
174: .newInstance();
175: } catch (ClassNotFoundException e) {
176: // jndi.79=RMI Client Socket Factory cannot be instantiated
177: throw (ConfigurationException) new ConfigurationException(
178: Messages.getString("jndi.79")) //$NON-NLS-1$
179: .initCause(e);
180: } catch (InstantiationException e) {
181: // jndi.79=RMI Client Socket Factory cannot be instantiated
182: throw (ConfigurationException) new ConfigurationException(
183: Messages.getString("jndi.79")) //$NON-NLS-1$
184: .initCause(e);
185: } catch (IllegalAccessException e) {
186: // jndi.79=RMI Client Socket Factory cannot be instantiated
187: throw (NoPermissionException) new NoPermissionException(
188: Messages.getString("jndi.79")) //$NON-NLS-1$
189: .initCause(e);
190: }
191: }
192: registry = getRegistry(host, port, csf);
193: reference = null;
194: }
195:
196: /**
197: * Creates RMI registry context by copying the specified context.
198: *
199: * @param context
200: * Context to copy.
201: */
202: @SuppressWarnings("unchecked")
203: protected RegistryContext(RegistryContext context) {
204: host = context.host;
205: port = context.port;
206: csf = context.csf;
207: environment = (Hashtable<Object, Object>) context.environment
208: .clone();
209: registry = context.registry;
210: reference = context.reference;
211: }
212:
213: /**
214: * {@inheritDoc}
215: */
216: public Object lookup(Name name) throws NamingException {
217: if (name.isEmpty()) {
218: return cloneContext();
219: }
220: String stringName = getMyComponents(name);
221:
222: try {
223: return getObjectInstance(stringName, registry
224: .lookup(stringName));
225: } catch (NotBoundException e) {
226: // jndi.7A=Name is not bound: {0}
227: throw (NameNotFoundException) new NameNotFoundException(
228: Messages.getString("jndi.7A", stringName)).initCause(e); //$NON-NLS-1$
229: } catch (RemoteException e) {
230: throw (NamingException) newNamingException(e)
231: .fillInStackTrace();
232: }
233: }
234:
235: /**
236: * {@inheritDoc}
237: */
238: public Object lookup(String name) throws NamingException {
239: return lookup(new CompositeName(name));
240: }
241:
242: /**
243: * {@inheritDoc}
244: */
245: public Object lookupLink(Name name) throws NamingException {
246: return lookup(name);
247: }
248:
249: /**
250: * {@inheritDoc}
251: */
252: public Object lookupLink(String name) throws NamingException {
253: return lookupLink(new CompositeName(name));
254: }
255:
256: /**
257: * {@inheritDoc}
258: */
259: public void bind(Name name, Object obj) throws NamingException {
260: if (name.isEmpty()) {
261: // jndi.7B=Cannot bind empty name
262: throw new InvalidNameException(Messages
263: .getString("jndi.7B")); //$NON-NLS-1$
264: }
265: String stringName = getMyComponents(name);
266:
267: try {
268: registry.bind(stringName, getStateToBind(stringName, obj));
269: } catch (AlreadyBoundException e) {
270: // jndi.7C=Name is already bound: {0}
271: throw (NameAlreadyBoundException) new NameAlreadyBoundException(
272: Messages.getString("jndi.7C", stringName)).initCause(e); //$NON-NLS-1$
273: } catch (RemoteException e) {
274: throw (NamingException) newNamingException(e)
275: .fillInStackTrace();
276: }
277: }
278:
279: /**
280: * {@inheritDoc}
281: */
282: public void bind(String name, Object obj) throws NamingException {
283: bind(new CompositeName(name), obj);
284: }
285:
286: /**
287: * {@inheritDoc}
288: */
289: public void rebind(Name name, Object obj) throws NamingException {
290: if (name.isEmpty()) {
291: // jndi.7D=Cannot rebind empty name
292: throw new InvalidNameException(Messages
293: .getString("jndi.7D")); //$NON-NLS-1$
294: }
295: String stringName = getMyComponents(name);
296:
297: try {
298: registry
299: .rebind(stringName, getStateToBind(stringName, obj));
300: } catch (RemoteException e) {
301: throw (NamingException) newNamingException(e)
302: .fillInStackTrace();
303: }
304: }
305:
306: /**
307: * {@inheritDoc}
308: */
309: public void rebind(String name, Object obj) throws NamingException {
310: rebind(new CompositeName(name), obj);
311: }
312:
313: /**
314: * {@inheritDoc}
315: */
316: public void unbind(Name name) throws NamingException {
317: if (name.isEmpty()) {
318: // jndi.7E=Cannot unbind empty name
319: throw new InvalidNameException(Messages
320: .getString("jndi.7E")); //$NON-NLS-1$
321: }
322: String stringName = getMyComponents(name);
323:
324: try {
325: registry.unbind(stringName);
326: } catch (NotBoundException e) {
327: // Returning ok if target name is not found, by the specification.
328: } catch (RemoteException e) {
329: throw (NamingException) newNamingException(e)
330: .fillInStackTrace();
331: }
332: }
333:
334: /**
335: * {@inheritDoc}
336: */
337: public void unbind(String name) throws NamingException {
338: unbind(new CompositeName(name));
339: }
340:
341: /**
342: * {@inheritDoc}
343: */
344: public Context createSubcontext(Name name)
345: throws OperationNotSupportedException {
346: // jndi.7F=RMI Registry is a flat context and doesn't support
347: // subcontexts
348: throw new OperationNotSupportedException(Messages
349: .getString("jndi.7F")); //$NON-NLS-1$
350: }
351:
352: /**
353: * {@inheritDoc}
354: */
355: public Context createSubcontext(String name) throws NamingException {
356: return createSubcontext(new CompositeName(name));
357: }
358:
359: /**
360: * {@inheritDoc}
361: */
362: public void destroySubcontext(Name name)
363: throws OperationNotSupportedException {
364: // jndi.7F=RMI Registry is a flat context and doesn't support
365: // subcontexts
366: throw new OperationNotSupportedException(Messages
367: .getString("jndi.7F")); //$NON-NLS-1$
368: }
369:
370: /**
371: * {@inheritDoc}
372: */
373: public void destroySubcontext(String name) throws NamingException {
374: destroySubcontext(new CompositeName(name));
375: }
376:
377: /**
378: * {@inheritDoc}
379: */
380: public void rename(Name oldName, Name newName)
381: throws NamingException {
382: bind(newName, lookup(oldName));
383: unbind(oldName);
384: }
385:
386: /**
387: * {@inheritDoc}
388: */
389: public void rename(String oldName, String newName)
390: throws NamingException {
391: rename(new CompositeName(oldName), new CompositeName(newName));
392: }
393:
394: /**
395: * {@inheritDoc}
396: */
397: public NamingEnumeration<NameClassPair> list(Name name)
398: throws NamingException {
399: if (name.isEmpty()) {
400: try {
401: return new NameClassPairEnumeration(registry.list());
402: } catch (RemoteException e) {
403: throw (NamingException) newNamingException(e)
404: .fillInStackTrace();
405: }
406: }
407: Object obj = lookup(name);
408:
409: if (obj instanceof Context) {
410: try {
411: return ((Context) obj).list(""); //$NON-NLS-1$
412: } finally {
413: ((Context) obj).close();
414: }
415: }
416: // jndi.80=Name specifies an object that is not a context: {0}
417: throw new NotContextException(Messages.getString(
418: "jndi.80", name)); //$NON-NLS-1$
419: }
420:
421: /**
422: * {@inheritDoc}
423: */
424: public NamingEnumeration<NameClassPair> list(String name)
425: throws NamingException {
426: return list(new CompositeName(name));
427: }
428:
429: /**
430: * {@inheritDoc}
431: */
432: public NamingEnumeration<Binding> listBindings(Name name)
433: throws NamingException {
434: if (name.isEmpty()) {
435: try {
436: return new BindingEnumeration(registry.list(), this );
437: } catch (RemoteException e) {
438: throw (NamingException) newNamingException(e)
439: .fillInStackTrace();
440: }
441: }
442: Object obj = lookup(name);
443:
444: if (obj instanceof Context) {
445: try {
446: return ((Context) obj).listBindings(""); //$NON-NLS-1$
447: } finally {
448: ((Context) obj).close();
449: }
450: }
451: // jndi.80=Name specifies an object that is not a context: {0}
452: throw new NotContextException(Messages.getString(
453: "jndi.80", name)); //$NON-NLS-1$
454: }
455:
456: /**
457: * {@inheritDoc}
458: */
459: public NamingEnumeration<Binding> listBindings(String name)
460: throws NamingException {
461: return listBindings(new CompositeName(name));
462: }
463:
464: /**
465: * {@inheritDoc}
466: */
467: public NameParser getNameParser(Name name) {
468: return nameParser;
469: }
470:
471: /**
472: * {@inheritDoc}
473: */
474: public NameParser getNameParser(String name) throws NamingException {
475: return getNameParser(new CompositeName(name));
476: }
477:
478: /**
479: * {@inheritDoc}
480: */
481: public Name composeName(Name name, Name prefix)
482: throws NamingException {
483: return ((Name) prefix.clone()).addAll(name);
484: }
485:
486: /**
487: * {@inheritDoc}
488: */
489: public String composeName(String name, String prefix)
490: throws NamingException {
491: return composeName(new CompositeName(name),
492: new CompositeName(prefix)).toString();
493: }
494:
495: /**
496: * {@inheritDoc}
497: */
498: public String getNameInNamespace() {
499: return ""; //$NON-NLS-1$
500: }
501:
502: /**
503: * {@inheritDoc}
504: */
505: public Hashtable<?, ?> getEnvironment() {
506: return (Hashtable<?, ?>) environment.clone();
507: }
508:
509: /**
510: * {@inheritDoc}
511: */
512: public Object addToEnvironment(String propName, Object propVal)
513: throws NoPermissionException {
514: if (propName.equals(SECURITY_MANAGER)) {
515: installSecurityManager();
516: }
517: return environment.put(propName, propVal);
518: }
519:
520: /**
521: * {@inheritDoc}
522: */
523: public Object removeFromEnvironment(String propName) {
524: return environment.remove(propName);
525: }
526:
527: /**
528: * {@inheritDoc}
529: */
530: public void close() {
531: environment = null;
532: registry = null;
533: }
534:
535: /**
536: * {@inheritDoc}
537: */
538: public Reference getReference() throws NamingException {
539: if (reference == null) {
540: if ((host == null) || (host.equals("localhost"))) { //$NON-NLS-1$
541: // jndi.81=Cannot create reference for RMI registry that is
542: // being accessed using localhost
543: throw new ConfigurationException(Messages
544: .getString("jndi.81")); //$NON-NLS-1$
545: }
546: reference = new Reference(RegistryContext.class.getName(),
547: new StringRefAddr(ADDRESS_TYPE, RMI_URL_PREFIX
548: + "//" //$NON-NLS-1$
549: + host + ((port > 0) ? (":" + port) : "")), //$NON-NLS-1$ //$NON-NLS-2$
550: RegistryContextFactory.class.getName(), null);
551: }
552: return (Reference) reference.clone();
553: }
554:
555: /**
556: * Initializes reference for this context instance. Called by
557: * {@link RegistryContextFactory#getObjectInstance(Object, Name, Context, Hashtable)}.
558: *
559: * @param reference
560: * Reference for this context instance.
561: */
562: protected void setReference(Reference reference) {
563: this .reference = reference;
564: }
565:
566: /**
567: * Returns a clone of this context.
568: *
569: * @return Clone of this context.
570: */
571: protected RegistryContext cloneContext() {
572: return new RegistryContext(this );
573: }
574:
575: /**
576: * Verifies that the specified name is valid for this context and returns
577: * string representation of that name for this provider.
578: *
579: * Returns returns first component of a {@link CompositeName} or a string
580: * representation of a name otherwise.
581: *
582: * @param name
583: * Name to verify.
584: *
585: * @return {@link CompositeName#get(int) CompositeName#get(0)} if
586: * <code>name</code> is a {@link CompositeName},
587: * {@link Object#toString() name.toString()} otherwise.
588: */
589: protected String getMyComponents(Name name) {
590: if (name instanceof CompositeName) {
591: return name.get(0);
592: }
593: return name.toString();
594: }
595:
596: /**
597: * Prepares object for binding. It calls
598: * {@link NamingManager#getStateToBind(Object, Name, Context, Hashtable)}
599: * and makes the resulting object {@link Remote} by wrapping it into
600: * {@link RemoteReferenceWrapper}.
601: *
602: * @param name
603: * Object name.
604: *
605: * @param obj
606: * Object to prepare for binding.
607: *
608: * @return Object ready for binding.
609: *
610: * @throws NamingException
611: * If some naming error occurs.
612: *
613: * @throws RemoteException
614: * If remote exception occurs.
615: */
616: protected Remote getStateToBind(String name, Object obj)
617: throws NamingException, RemoteException {
618: obj = NamingManager.getStateToBind(obj, new CompositeName()
619: .add(name), this , environment);
620:
621: if (obj instanceof Remote) {
622: return (Remote) obj;
623: }
624:
625: if (obj instanceof Reference) {
626: return new RemoteReferenceWrapper((Reference) obj);
627: }
628:
629: if (obj instanceof Referenceable) {
630: return new RemoteReferenceWrapper(((Referenceable) obj)
631: .getReference());
632: }
633: // jndi.82=Cannot bind to RMI Registry object that is neither Remote nor
634: // Reference nor Referenceable
635: throw new IllegalArgumentException(Messages
636: .getString("jndi.82")); //$NON-NLS-1$
637: }
638:
639: /**
640: * Processes object returned from {@linkplain Registry RMI registry}. It
641: * unwraps {@link RemoteReference} if necessary and calls
642: * {@link NamingManager#getObjectInstance(Object, Name, Context, Hashtable)}.
643: *
644: * @param name
645: * Object name.
646: *
647: * @param remote
648: * Returned object.
649: *
650: * @return Processed object.
651: *
652: * @throws NamingException
653: * If some naming error occurs.
654: *
655: * @throws RemoteException
656: * If remote exception occurs.
657: */
658: protected Object getObjectInstance(String name, Remote remote)
659: throws NamingException, RemoteException {
660: Object obj;
661:
662: obj = ((remote instanceof RemoteReference) ? ((RemoteReference) remote)
663: .getReference()
664: : (Object) remote);
665:
666: try {
667: return NamingManager.getObjectInstance(obj,
668: new CompositeName().add(name), this , environment);
669: } catch (NamingException e) {
670: throw e;
671: } catch (RemoteException e) {
672: throw e;
673: } catch (Exception e) {
674: // jndi.83=NamingManager.getObjectInstance() failed
675: throw (NamingException) new NamingException(Messages
676: .getString("jndi.83")).initCause(e); //$NON-NLS-1$
677: }
678: }
679:
680: /**
681: * Prepares a new {@link NamingException} wrapping the specified
682: * {@link RemoteException} source exception. Source exception becomes a
683: * {@linkplain NamingException#getCause() cause} of the generated exception.
684: *
685: * The particular subclass of {@link NamingException} returned depends on
686: * the particular subclass of source {@link RemoteException}.
687: *
688: * If source exception is not of a specific class or is not a
689: * {@link RemoteException} or is <code>null</code>, then plain
690: * {@link NamingException} is returned.
691: *
692: * Note: {@link Throwable#fillInStackTrace()} should be called before
693: * throwing the generated exception, to provide the proper (not including
694: * this method) stack trace for the exception.
695: *
696: * Example of use:
697: *
698: * <code>try {
699: * ...
700: * } catch (RemoteException e) {
701: * throw (NamingException) newNamingException(e).fillInStackTrace();
702: * }</code>
703: *
704: * @param e
705: * Source {@link RemoteException}.
706: *
707: * @return Generated {@link NamingException} exception.
708: */
709: @SuppressWarnings("deprecation")
710: protected NamingException newNamingException(Throwable e) {
711: NamingException ret = (e instanceof AccessException) ? new NoPermissionException()
712: : (e instanceof ConnectException) ? new ServiceUnavailableException()
713: : (e instanceof ConnectIOException)
714: || (e instanceof ExportException)
715: || (e instanceof MarshalException)
716: || (e instanceof UnmarshalException) ? new CommunicationException()
717: : (e instanceof ActivateFailedException)
718: || (e instanceof NoSuchObjectException)
719: || (e instanceof java.rmi.server.SkeletonMismatchException)
720: || (e instanceof java.rmi.server.SkeletonNotFoundException)
721: || (e instanceof StubNotFoundException)
722: || (e instanceof UnknownHostException) ? new ConfigurationException()
723: : (e instanceof ServerException) ? newNamingException(e
724: .getCause())
725: : new NamingException();
726:
727: if (ret.getCause() == null) {
728: ret.initCause(e);
729: }
730: return ret;
731: }
732:
733: /**
734: * Installs {@link RMISecurityManager} if it is not already installed.
735: *
736: * @throws NoPermissionException
737: * If security manager other than {@link RMISecurityManager} is
738: * installed and prohibits installing a new security manager.
739: */
740: protected void installSecurityManager()
741: throws NoPermissionException {
742: if (!(System.getSecurityManager() instanceof RMISecurityManager)) {
743: try {
744: System.setSecurityManager(new RMISecurityManager());
745: } catch (SecurityException e) {
746: // jndi.84=Cannot install RMISecurityManager
747: throw (NoPermissionException) new NoPermissionException(
748: Messages.getString("jndi.84")).initCause(e); //$NON-NLS-1$
749: }
750: }
751: }
752:
753: /**
754: * Creates reference to the {@linkplain Registry RMI registry} located on
755: * the specified host and port.
756: *
757: * @param host
758: * Host. If <code>null</code>, localhost is assumed. May not
759: * be <code>null</code> if <code>csf</code> is not
760: * <code>null</code>.
761: *
762: * @param port
763: * Port. If <code>0</code>, default registry port (<code>1099</code>)
764: * is assumed. May not be <code>0</code> if <code>csf</code>
765: * is not <code>null</code>.
766: *
767: * @param csf
768: * RMIClientSocketFactory that is used to create socket
769: * connections to the registry. If <code>null</code>, default
770: * socket factory is used. See
771: * {@link LocateRegistry#getRegistry(String, int, RMIClientSocketFactory)}.
772: *
773: * @return Registry reference.
774: *
775: * @throws NamingException
776: * If getting registry failed.
777: */
778: protected Registry getRegistry(String host, int port,
779: RMIClientSocketFactory csf) throws NamingException {
780: try {
781: return ((csf != null) ? LocateRegistry.getRegistry(host,
782: port, csf)
783: : ((host != null) ? ((port != 0) ? LocateRegistry
784: .getRegistry(host, port) : LocateRegistry
785: .getRegistry(host))
786: : ((port != 0) ? LocateRegistry
787: .getRegistry(port) : LocateRegistry
788: .getRegistry())));
789: } catch (RemoteException e) {
790: throw (NamingException) new NamingException().initCause(e);
791: }
792: }
793:
794: }
|