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.3 $
022: */package org.apache.harmony.jndi.provider;
023:
024: import java.util.Hashtable;
025:
026: import javax.naming.Binding;
027: import javax.naming.CannotProceedException;
028: import javax.naming.CompositeName;
029: import javax.naming.Context;
030: import javax.naming.InvalidNameException;
031: import javax.naming.Name;
032: import javax.naming.NameClassPair;
033: import javax.naming.NameParser;
034: import javax.naming.NamingEnumeration;
035: import javax.naming.NamingException;
036: import javax.naming.OperationNotSupportedException;
037: import javax.naming.spi.NamingManager;
038: import javax.naming.spi.ResolveResult;
039:
040: import org.apache.harmony.jndi.internal.nls.Messages;
041:
042: /**
043: * Base class for URL naming context implementations.
044: *
045: * In many cases, subclasses should only override
046: * {@link #getRootURLContext(String, Hashtable)} method and provide a public
047: * constructor calling
048: * {@link GenericURLContext#GenericURLContext(Hashtable) super(environment)}.
049: */
050: public abstract class GenericURLContext implements Context {
051:
052: /**
053: * Local environment.
054: */
055: protected Hashtable<Object, Object> environment;
056:
057: /**
058: * Creates instance of this context with empty environment.
059: */
060: protected GenericURLContext() {
061: this (null);
062: }
063:
064: /**
065: * Creates instance of this context with specified environment.
066: *
067: * @param environment
068: * Environment to copy.
069: */
070: @SuppressWarnings("unchecked")
071: protected GenericURLContext(Hashtable<?, ?> environment) {
072: super ();
073: if (environment == null) {
074: this .environment = new Hashtable<Object, Object>();
075: } else {
076: this .environment = (Hashtable<Object, Object>) environment
077: .clone();
078: }
079: }
080:
081: /**
082: * {@inheritDoc}
083: */
084: public Object lookup(Name name) throws NamingException {
085: if (!(name instanceof CompositeName)) {
086: // jndi.26=URL context can't accept non-composite name: {0}
087: throw new InvalidNameException(Messages.getString(
088: "jndi.26", name)); //$NON-NLS-1$
089: }
090:
091: if (name.size() == 1) {
092: return lookup(name.get(0));
093: }
094: Context context = getContinuationContext(name);
095: try {
096: return context.lookup(name.getSuffix(1));
097: } finally {
098: context.close();
099: }
100: }
101:
102: /**
103: * {@inheritDoc}
104: */
105: public Object lookup(String name) throws NamingException {
106: ResolveResult result = getRootURLContext(name, environment);
107: Context context = (Context) result.getResolvedObj();
108:
109: try {
110: return context.lookup(result.getRemainingName());
111: } finally {
112: context.close();
113: }
114: }
115:
116: /**
117: * {@inheritDoc}
118: */
119: public Object lookupLink(Name name) throws NamingException {
120: if (!(name instanceof CompositeName)) {
121: // jndi.26=URL context can't accept non-composite name: {0}
122: throw new InvalidNameException(Messages.getString(
123: "jndi.26", name)); //$NON-NLS-1$
124: }
125:
126: if (name.size() == 1) {
127: return lookupLink(name.get(0));
128: }
129: Context context = getContinuationContext(name);
130: try {
131: return context.lookupLink(name.getSuffix(1));
132: } finally {
133: context.close();
134: }
135: }
136:
137: /**
138: * {@inheritDoc}
139: */
140: public Object lookupLink(String name) throws NamingException {
141: ResolveResult result = getRootURLContext(name, environment);
142: Context context = (Context) result.getResolvedObj();
143:
144: try {
145: return context.lookupLink(result.getRemainingName());
146: } finally {
147: context.close();
148: }
149: }
150:
151: /**
152: * {@inheritDoc}
153: */
154: public void bind(Name name, Object obj) throws NamingException {
155: if (!(name instanceof CompositeName)) {
156: // jndi.26=URL context can't accept non-composite name: {0}
157: throw new InvalidNameException(Messages.getString(
158: "jndi.26", name)); //$NON-NLS-1$
159: }
160:
161: if (name.size() == 1) {
162: bind(name.get(0), obj);
163: } else {
164: Context context = getContinuationContext(name);
165:
166: try {
167: context.bind(name.getSuffix(1), obj);
168: } finally {
169: context.close();
170: }
171: }
172: }
173:
174: /**
175: * {@inheritDoc}
176: */
177: public void bind(String name, Object obj) throws NamingException {
178: ResolveResult result = getRootURLContext(name, environment);
179: Context context = (Context) result.getResolvedObj();
180:
181: try {
182: context.bind(result.getRemainingName(), obj);
183: } finally {
184: context.close();
185: }
186: }
187:
188: /**
189: * {@inheritDoc}
190: */
191: public void rebind(Name name, Object obj) throws NamingException {
192: if (!(name instanceof CompositeName)) {
193: // jndi.26=URL context can't accept non-composite name: {0}
194: throw new InvalidNameException(Messages.getString(
195: "jndi.26", name)); //$NON-NLS-1$
196: }
197:
198: if (name.size() == 1) {
199: rebind(name.get(0), obj);
200: } else {
201: Context context = getContinuationContext(name);
202:
203: try {
204: context.rebind(name.getSuffix(1), obj);
205: } finally {
206: context.close();
207: }
208: }
209: }
210:
211: /**
212: * {@inheritDoc}
213: */
214: public void rebind(String name, Object obj) throws NamingException {
215: ResolveResult result = getRootURLContext(name, environment);
216: Context context = (Context) result.getResolvedObj();
217:
218: try {
219: context.rebind(result.getRemainingName(), obj);
220: } finally {
221: context.close();
222: }
223: }
224:
225: /**
226: * {@inheritDoc}
227: */
228: public void unbind(Name name) throws NamingException {
229: if (!(name instanceof CompositeName)) {
230: // jndi.26=URL context can't accept non-composite name: {0}
231: throw new InvalidNameException(Messages.getString(
232: "jndi.26", name)); //$NON-NLS-1$
233: }
234:
235: if (name.size() == 1) {
236: unbind(name.get(0));
237: } else {
238: Context context = getContinuationContext(name);
239:
240: try {
241: context.unbind(name.getSuffix(1));
242: } finally {
243: context.close();
244: }
245: }
246: }
247:
248: /**
249: * {@inheritDoc}
250: */
251: public void unbind(String name) throws NamingException {
252: ResolveResult result = getRootURLContext(name, environment);
253: Context context = (Context) result.getResolvedObj();
254:
255: try {
256: context.unbind(result.getRemainingName());
257: } finally {
258: context.close();
259: }
260: }
261:
262: /**
263: * {@inheritDoc}
264: */
265: public Context createSubcontext(Name name) throws NamingException {
266: if (!(name instanceof CompositeName)) {
267: // jndi.26=URL context can't accept non-composite name: {0}
268: throw new InvalidNameException(Messages.getString(
269: "jndi.26", name)); //$NON-NLS-1$
270: }
271:
272: if (name.size() == 1) {
273: return createSubcontext(name.get(0));
274: }
275: Context context = getContinuationContext(name);
276: try {
277: return context.createSubcontext(name.getSuffix(1));
278: } finally {
279: context.close();
280: }
281: }
282:
283: /**
284: * {@inheritDoc}
285: */
286: public Context createSubcontext(String name) throws NamingException {
287: ResolveResult result = getRootURLContext(name, environment);
288: Context context = (Context) result.getResolvedObj();
289:
290: try {
291: return context.createSubcontext(result.getRemainingName());
292: } finally {
293: context.close();
294: }
295: }
296:
297: /**
298: * {@inheritDoc}
299: */
300: public void destroySubcontext(Name name) throws NamingException {
301: if (!(name instanceof CompositeName)) {
302: // jndi.26=URL context can't accept non-composite name: {0}
303: throw new InvalidNameException(Messages.getString(
304: "jndi.26", name)); //$NON-NLS-1$
305: }
306:
307: if (name.size() == 1) {
308: destroySubcontext(name.get(0));
309: } else {
310: Context context = getContinuationContext(name);
311:
312: try {
313: context.destroySubcontext(name.getSuffix(1));
314: } finally {
315: context.close();
316: }
317: }
318: }
319:
320: /**
321: * {@inheritDoc}
322: */
323: public void destroySubcontext(String name) throws NamingException {
324: ResolveResult result = getRootURLContext(name, environment);
325: Context context = (Context) result.getResolvedObj();
326:
327: try {
328: context.destroySubcontext(result.getRemainingName());
329: } finally {
330: context.close();
331: }
332: }
333:
334: /**
335: * {@inheritDoc}
336: *
337: * This method uses {@link #urlEquals(String, String)} to compare URL
338: * prefixes of the names.
339: */
340: public void rename(Name oldName, Name newName)
341: throws NamingException {
342: if (!(oldName instanceof CompositeName)) {
343: // jndi.26=URL context can't accept non-composite name: {0}
344: throw new InvalidNameException(Messages.getString(
345: "jndi.26", oldName)); //$NON-NLS-1$
346: }
347:
348: if (!(newName instanceof CompositeName)) {
349: // jndi.26=URL context can't accept non-composite name: {0}
350: throw new InvalidNameException(Messages.getString(
351: "jndi.26", newName)); //$NON-NLS-1$
352: }
353:
354: if ((oldName.size() == 1) ^ (newName.size() != 1)) {
355: // jndi.27=Renaming of names of which one has only one component, +
356: // and another has more than one component is not supported: {0} ->
357: // {1}
358: throw new OperationNotSupportedException(Messages
359: .getString("jndi.27", oldName, newName)); //$NON-NLS-1$
360: }
361:
362: if (oldName.size() == 1) {
363: rename(oldName.get(0), newName.get(0));
364: } else {
365: if (!urlEquals(oldName.get(0), oldName.get(0))) {
366: // jndi.28=Renaming of names using different URLs as their first
367: // components is not supported: {0} -> {1}
368: throw new OperationNotSupportedException(Messages
369: .getString("jndi.28", oldName, newName)); //$NON-NLS-1$
370: }
371: Context context = getContinuationContext(oldName);
372:
373: try {
374: context.rename(oldName.getSuffix(1), newName
375: .getSuffix(1));
376: } finally {
377: context.close();
378: }
379: }
380: }
381:
382: /**
383: * {@inheritDoc}
384: *
385: * This method uses {@link #getURLPrefix(String)} and
386: * {@link #getURLSuffix(String, String)} methods to parse string names, and
387: * also uses {@link #urlEquals(String, String)} to compare URL prefixes of
388: * the names.
389: */
390: public void rename(String oldName, String newName)
391: throws NamingException {
392: String oldPrefix = getURLPrefix(oldName);
393: String newPrefix = getURLPrefix(newName);
394:
395: if (!urlEquals(oldPrefix, newPrefix)) {
396: // jndi.29=Renaming of names using different URL prefixes is not
397: // supported: {0} -> {1}
398: throw new OperationNotSupportedException(Messages
399: .getString("jndi.29", oldName, newName)); //$NON-NLS-1$
400: }
401: ResolveResult result = getRootURLContext(oldName, environment);
402: Context context = (Context) result.getResolvedObj();
403:
404: try {
405: context.rename(result.getRemainingName(), getURLSuffix(
406: newPrefix, newName));
407: } finally {
408: context.close();
409: }
410: }
411:
412: /**
413: * {@inheritDoc}
414: */
415: public NamingEnumeration<NameClassPair> list(Name name)
416: throws NamingException {
417: if (!(name instanceof CompositeName)) {
418: // jndi.26=URL context can't accept non-composite name: {0}
419: throw new InvalidNameException(Messages.getString(
420: "jndi.26", name)); //$NON-NLS-1$
421: }
422:
423: if (name.size() == 1) {
424: return list(name.get(0));
425: }
426: Context context = getContinuationContext(name);
427:
428: try {
429: return context.list(name.getSuffix(1));
430: } finally {
431: context.close();
432: }
433: }
434:
435: /**
436: * {@inheritDoc}
437: */
438: public NamingEnumeration<NameClassPair> list(String name)
439: throws NamingException {
440: ResolveResult result = getRootURLContext(name, environment);
441: Context context = (Context) result.getResolvedObj();
442:
443: try {
444: return context.list(result.getRemainingName());
445: } finally {
446: context.close();
447: }
448: }
449:
450: /**
451: * {@inheritDoc}
452: */
453: public NamingEnumeration<Binding> listBindings(Name name)
454: throws NamingException {
455: if (!(name instanceof CompositeName)) {
456: // jndi.26=URL context can't accept non-composite name: {0}
457: throw new InvalidNameException(Messages.getString(
458: "jndi.26", name)); //$NON-NLS-1$
459: }
460:
461: if (name.size() == 1) {
462: return listBindings(name.get(0));
463: }
464: Context context = getContinuationContext(name);
465:
466: try {
467: return context.listBindings(name.getSuffix(1));
468: } finally {
469: context.close();
470: }
471: }
472:
473: /**
474: * {@inheritDoc}
475: */
476: public NamingEnumeration<Binding> listBindings(String name)
477: throws NamingException {
478: ResolveResult result = getRootURLContext(name, environment);
479: Context context = (Context) result.getResolvedObj();
480:
481: try {
482: return context.listBindings(result.getRemainingName());
483: } finally {
484: context.close();
485: }
486: }
487:
488: /**
489: * {@inheritDoc}
490: */
491: public NameParser getNameParser(Name name) throws NamingException {
492: if (!(name instanceof CompositeName)) {
493: // jndi.26=URL context can't accept non-composite name: {0}
494: throw new InvalidNameException(Messages.getString(
495: "jndi.26", name)); //$NON-NLS-1$
496: }
497:
498: if (name.size() == 1) {
499: return getNameParser(name.get(0));
500: }
501: Context context = getContinuationContext(name);
502: try {
503: return context.getNameParser(name.getSuffix(1));
504: } finally {
505: context.close();
506: }
507: }
508:
509: /**
510: * {@inheritDoc}
511: */
512: public NameParser getNameParser(String name) throws NamingException {
513: ResolveResult result = getRootURLContext(name, environment);
514: Context context = (Context) result.getResolvedObj();
515:
516: try {
517: return context.getNameParser(result.getRemainingName());
518: } finally {
519: context.close();
520: }
521: }
522:
523: /**
524: * {@inheritDoc}
525: */
526: public Name composeName(Name name, Name prefix)
527: throws NamingException {
528: return ((Name) prefix.clone()).addAll(name);
529: }
530:
531: /**
532: * {@inheritDoc}
533: */
534: public String composeName(String name, String prefix) {
535: return ((prefix.length() < 1) ? name
536: : (name.length() < 1) ? prefix : (prefix + '/' + name));
537: }
538:
539: /**
540: * {@inheritDoc}
541: */
542: public String getNameInNamespace() {
543: return ""; //$NON-NLS-1$
544: }
545:
546: /**
547: * {@inheritDoc}
548: */
549: public Hashtable<?, ?> getEnvironment() {
550: return (Hashtable<?, ?>) environment.clone();
551: }
552:
553: /**
554: * {@inheritDoc}
555: */
556: public Object addToEnvironment(String propName, Object propVal) {
557: return environment.put(propName, propVal);
558: }
559:
560: /**
561: * {@inheritDoc}
562: */
563: public Object removeFromEnvironment(String propName) {
564: return environment.remove(propName);
565: }
566:
567: /**
568: * {@inheritDoc}
569: */
570: public void close() {
571: environment = null;
572: }
573:
574: /**
575: * Lookups the first component (considered a URL) of the specified name
576: * using {@link #lookup(String)}, wraps it into
577: * {@link CannotProceedException}, passes it to
578: * {@link NamingManager#getContinuationContext(CannotProceedException)}
579: * method and returns the result.
580: *
581: * This method is used by {@link #lookup(Name)} and other public methods
582: * taking {@link Name} as a parameter.
583: *
584: * This method uses {@link #createCannotProceedException(Name)} method.
585: *
586: * @param name
587: * Name to parse.
588: *
589: * @return Continuation context.
590: *
591: * @throws NamingException
592: * If some naming error occurs.
593: */
594: protected Context getContinuationContext(Name name)
595: throws NamingException {
596: return NamingManager
597: .getContinuationContext(createCannotProceedException(name));
598: }
599:
600: /**
601: * Lookups the first component (considered a URL) of the specified name
602: * using {@link #lookup(String)} and wraps it into
603: * {@link CannotProceedException}.
604: *
605: * @param name
606: * Name to parse.
607: *
608: * @return Created {@link CannotProceedException}.
609: *
610: * @throws NamingException
611: * If some naming error occurs.
612: */
613: protected final CannotProceedException createCannotProceedException(
614: Name name) throws NamingException {
615: CannotProceedException cpe = new CannotProceedException();
616: cpe.setResolvedObj(lookup(name.get(0)));
617: cpe.setEnvironment(environment);
618: return cpe;
619: }
620:
621: /**
622: * Determines the proper context from the specified URL and returns the
623: * {@link ResolveResult} object with that context as resolved object and the
624: * rest of the URL as remaining name.
625: *
626: * This method is used by {@link #lookup(String)} and other public methods
627: * taking {@link String} name as a parameter.
628: *
629: * This method must be overridden by particular URL context implementations.
630: *
631: * When overriding make sure that {@link #getURLPrefix(String)},
632: * {@link #getURLSuffix(String, String)} and
633: * {@link #getRootURLContext(String, Hashtable)} methods are in sync in how
634: * they parse URLs.
635: *
636: * @param url
637: * URL.
638: *
639: * @param environment
640: * Environment.
641: *
642: * @return {@link ResolveResult} object with resolved context as resolved
643: * object the rest of the URL as remaining name.
644: *
645: * @throws NamingException
646: * If some naming error occurs.
647: */
648: protected abstract ResolveResult getRootURLContext(String url,
649: Hashtable<?, ?> environment) throws NamingException;
650:
651: /**
652: * Compares two URLs for equality.
653: *
654: * Implemented here as <code>url1.equals(url2)</code>. Subclasses may
655: * provide different implementation.
656: *
657: * This method is only used by {@link #rename(Name, Name)} and
658: * {@link #rename(String, String)} methods.
659: *
660: * @param url1
661: * First URL to compare.
662: *
663: * @param url2
664: * Second URL to compare.
665: *
666: * @return <code>true</code> if specified URLs are equal,
667: * <code>false</code> otherwise.
668: */
669: protected boolean urlEquals(String url1, String url2) {
670: return url1.equals(url2);
671: }
672:
673: /**
674: * Returns URL prefix, containing scheme name, hostname and port.
675: *
676: * This method is only used by {@link #rename(String, String)} method and
677: * may be overridden by subclasses.
678: *
679: * When overriding make sure that {@link #getURLPrefix(String)},
680: * {@link #getURLSuffix(String, String)} and
681: * {@link #getRootURLContext(String, Hashtable)} methods are in sync in how
682: * they parse URLs.
683: *
684: * @param url
685: * URL to parse.
686: *
687: * @return URL prefix.
688: *
689: * @throws NamingException
690: * If some naming error occurs.
691: */
692: protected String getURLPrefix(String url) throws NamingException {
693: int index = url.indexOf(':');
694: if (index < 0) {
695: // jndi.2A=Invalid URL: {0}
696: throw new OperationNotSupportedException(Messages
697: .getString("jndi.2A", url)); //$NON-NLS-1$
698: }
699: index++;
700:
701: if (url.startsWith("//", index)) { //$NON-NLS-1$
702: int slashPos = url.indexOf('/', index + 2);
703: index = ((slashPos >= 0) ? slashPos : url.length());
704: }
705: return url.substring(0, index);
706: }
707:
708: /**
709: * Returns URL suffix, containing everything but the
710: * {@linkplain #getURLPrefix(String) prefix} and separating slash, as a
711: * single-component {@link CompositeName}.
712: *
713: * This method is only used by {@link #rename(String, String)} method and
714: * may be overridden by subclasses.
715: *
716: * This method uses {@link #decodeURLString(String)} to decode the suffix
717: * string.
718: *
719: * When overriding make sure that {@link #getURLPrefix(String)},
720: * {@link #getURLSuffix(String, String)} and
721: * {@link #getRootURLContext(String, Hashtable)} methods are in sync in how
722: * they parse URLs.
723: *
724: * @param prefix
725: * URL prefix, returned by {@link #getURLPrefix(String)}
726: * previously called on the same URL.
727: *
728: * @param url
729: * URL to parse.
730: *
731: * @return URL suffix as a single-component {@link CompositeName}.
732: *
733: * @throws NamingException
734: * If some naming error occurs.
735: */
736: protected Name getURLSuffix(String prefix, String url)
737: throws NamingException {
738: int length = prefix.length();
739:
740: if (length >= (url.length() - 1)) {
741: // If prefix is only 1 character shorter than URL,
742: // that character is slash and can be ignored.
743: return new CompositeName();
744: }
745:
746: String suffix = url
747: .substring((url.charAt(length) == '/') ? (length + 1)
748: : length);
749:
750: try {
751: return new CompositeName().add(decodeURLString(suffix));
752: } catch (IllegalArgumentException e) {
753: throw (InvalidNameException) new InvalidNameException()
754: .initCause(e);
755: }
756: }
757:
758: /**
759: * Decodes URL string by transforming URL-encoded characters into their
760: * Unicode character representations.
761: *
762: * This method is used by {@link #getURLSuffix(String, String)}.
763: *
764: * @param str
765: * URL or part of URL string.
766: *
767: * @return Decoded string.
768: *
769: * @throws IllegalArgumentException
770: * If URL format is incorrect.
771: */
772: protected static final String decodeURLString(String str)
773: throws IllegalArgumentException {
774: int length = str.length();
775: byte bytes[] = new byte[length];
776: int index = 0;
777:
778: for (int i = 0; i < length;) {
779: char c = str.charAt(i++);
780:
781: if (c == '%') {
782: int next = i + 2;
783:
784: if (next > length) {
785: // jndi.2B=Invalid URL format: {0}
786: new IllegalArgumentException(Messages.getString(
787: "jndi.2B", str)); //$NON-NLS-1$
788: }
789:
790: try {
791: bytes[index++] = (byte) Integer.parseInt(str
792: .substring(i, next), 16);
793: } catch (NumberFormatException e) {
794: throw (IllegalArgumentException)
795: // jndi.2B=Invalid URL format: {0}
796: new IllegalArgumentException(Messages.getString(
797: "jndi.2B", str)).initCause(e); //$NON-NLS-1$
798: }
799:
800: i = next;
801: } else {
802: bytes[index++] = (byte) c;
803: }
804: }
805: return new String(bytes, 0, index);
806: }
807:
808: }
|