001: package org.jacorb.orb;
002:
003: /*
004: * JacORB - a free Java ORB
005: *
006: * Copyright (C) 1997-2004 Gerald Brose.
007: *
008: * This library is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Library General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * This library is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * Library General Public License for more details.
017: *
018: * You should have received a copy of the GNU Library General Public
019: * License along with this library; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: */
022:
023: import java.io.ByteArrayOutputStream;
024: import java.io.IOException;
025: import java.net.URL;
026: import java.util.*;
027:
028: import org.jacorb.orb.util.CorbaLoc;
029:
030: import org.apache.avalon.framework.logger.Logger;
031:
032: import org.jacorb.util.ObjectUtil;
033: import org.omg.CONV_FRAME.CodeSetComponentInfo;
034: import org.omg.CONV_FRAME.CodeSetComponentInfoHelper;
035: import org.omg.CORBA.BAD_PARAM;
036: import org.omg.CORBA.CompletionStatus;
037: import org.omg.CORBA.MARSHAL;
038: import org.omg.CosNaming.*;
039: import org.omg.GIOP.*;
040: import org.omg.IOP.*;
041: import org.omg.ETF.*;
042:
043: /**
044: * Class to convert IOR strings into IOR structures
045: *
046: * @author Gerald Brose
047: * @version $Id: ParsedIOR.java,v 1.80 2006/08/03 16:40:12 alphonse.bendt Exp $
048: */
049:
050: public class ParsedIOR {
051: //for byte -> hexchar
052: private static final char[] lookup = new char[] { '0', '1', '2',
053: '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
054: 'F' };
055:
056: private Profile effectiveProfile = null;
057: private final List profiles = new ArrayList();
058:
059: /** top-level tagged components, i.e. NOT part of IOP components. Other
060: * tagged components may be part of the profile bodies
061: */
062: private TaggedComponentList components = new TaggedComponentList();
063: private ProfileSelector profileSelector;
064:
065: protected boolean endianness = false;
066: private String ior_str = null;
067: private IOR ior = null;
068:
069: private final ORB orb;
070:
071: private CodeSetComponentInfo cs_info = null;
072: private Integer orbTypeId = null;
073: private final Logger logger;
074:
075: /* static part */
076:
077: /**
078: * factory method
079: */
080:
081: public static IOR createObjectIOR(org.omg.ETF.Profile profile) {
082: String repId = "IDL:omg.org/CORBA/Object:1.0";
083: TaggedComponentList components = new TaggedComponentList();
084:
085: final CDROutputStream out = new CDROutputStream();
086: try {
087: out.beginEncapsulatedArray();
088: out.write_long(ORBConstants.JACORB_ORB_ID);
089: components.addComponent(new TaggedComponent(
090: TAG_ORB_TYPE.value, out.getBufferCopy()));
091: } finally {
092: out.close();
093: }
094:
095: List taggedProfileList = new ArrayList();
096: TaggedProfileHolder tp = new TaggedProfileHolder();
097: TaggedComponentSeqHolder tcs = new TaggedComponentSeqHolder();
098: tcs.value = components.asArray();
099:
100: profile.marshal(tp, tcs);
101: taggedProfileList.add(tp.value);
102:
103: // copy the profiles into the IOR
104:
105: TaggedProfile[] tps = new TaggedProfile[taggedProfileList
106: .size()];
107: taggedProfileList.toArray(tps);
108:
109: return new IOR(repId, tps);
110: }
111:
112: /**
113: * This method replaces the unfiyTargetAddress method.
114: * <P>
115: * It will extract an object key from any given GIOP::TargetAddress
116: * assuming an appropriate ETF::Factories implementation is availble
117: * for the profile in use.
118: */
119: public static byte[] extractObjectKey(TargetAddress addr, ORB orb) {
120: TaggedProfile tp = null;
121: switch (addr.discriminator()) {
122: case KeyAddr.value: {
123: return addr.object_key();
124: }
125: case ProfileAddr.value: {
126: tp = new TaggedProfile(addr.profile().tag,
127: addr.profile().profile_data);
128: break;
129: }
130: case ReferenceAddr.value: {
131: IORAddressingInfo info = addr.ior();
132: tp = new TaggedProfile(
133: info.ior.profiles[info.selected_profile_index].tag,
134: info.ior.profiles[info.selected_profile_index].profile_data);
135: break;
136: }
137: default: {
138: throw new BAD_PARAM(
139: "Invalid value for TargetAddress discriminator");
140: }
141: }
142:
143: TaggedProfileHolder profile = new TaggedProfileHolder(tp);
144: org.omg.ETF.Factories profileFactory = orb
145: .getTransportManager().getFactories(tp.tag);
146: if (profileFactory != null) {
147: return profileFactory.demarshal_profile(profile,
148: new TaggedComponentSeqHolder()).get_object_key();
149: }
150: return null;
151: }
152:
153: /**
154: * Returns the value of the TAG_JAVA_CODEBASE component from this IOR,
155: * or null if no such component exists. The component is first searched
156: * in the effective profile, if that is an IIOPProfile, and failing that,
157: * in the MULTIPLE_COMPONENTS list.
158: */
159: public String getCodebaseComponent() {
160: return getStringComponent(TAG_JAVA_CODEBASE.value);
161: }
162:
163: private ParsedIOR(org.jacorb.orb.ORB orb) {
164: super ();
165:
166: this .orb = orb;
167: this .logger = this .orb.getConfiguration().getNamedLogger(
168: "jacorb.orb.parsedior");
169: }
170:
171: /**
172: * Creates a new <code>ParsedIOR</code> instance.
173: * @param orb an <code>org.jacorb.orb.ORB</code> value
174: * @param object_reference a <code>String</code> value
175: */
176: public ParsedIOR(org.jacorb.orb.ORB orb, String object_reference)
177: throws IllegalArgumentException {
178: this (orb);
179: parse(object_reference);
180: }
181:
182: /**
183: * Creates a new <code>ParsedIOR</code> instance.
184: * @param orb an <code>org.jacorb.orb.ORB</code> value
185: * @param ior an <code>IOR</code> value
186: */
187: public ParsedIOR(org.jacorb.orb.ORB orb, IOR ior) {
188: this (orb);
189: decode(ior);
190: }
191:
192: /**
193: * <code>equals</code> contract is that they have the same IOR string and the
194: * same effective profile. i.e. if one profile is SSL enabled then this will
195: * return false.
196: *
197: * @param other an <code>Object</code> value
198: * @return a <code>boolean</code> value
199: */
200: public boolean equals(Object other) {
201: if (other == null) {
202: return false;
203: }
204:
205: return ((other instanceof ParsedIOR)
206: && ((ParsedIOR) other).getIORString().equals(
207: getIORString()) && effectiveProfile != null && effectiveProfile
208: .is_match(((ParsedIOR) other).effectiveProfile));
209: }
210:
211: public int hashCode() {
212: return getIORString().hashCode();
213: }
214:
215: /**
216: * When multiple internet IOP tags are present, they will probably
217: * have different versions, we will use the highest version
218: * between 0 and 1.
219: */
220: public void decode(IOR _ior) {
221: for (int i = 0; i < _ior.profiles.length; i++) {
222: int tag = _ior.profiles[i].tag;
223:
224: switch (tag) {
225: case TAG_MULTIPLE_COMPONENTS.value: {
226: components = new TaggedComponentList(
227: _ior.profiles[i].profile_data);
228: break;
229: }
230: default: {
231: org.omg.ETF.Factories factories = orb
232: .getTransportManager().getFactories(tag);
233: if (factories != null) {
234: TaggedProfileHolder tp = new TaggedProfileHolder(
235: _ior.profiles[i]);
236: profiles.add(factories.demarshal_profile(tp,
237: new TaggedComponentSeqHolder()));
238: } else {
239: if (logger.isDebugEnabled()) {
240: logger
241: .debug("No transport available for profile tag "
242: + tag);
243: }
244: }
245: break;
246: }
247: }
248: }
249:
250: ior = _ior;
251:
252: setEffectiveProfile();
253: }
254:
255: public CodeSetComponentInfo getCodeSetComponentInfo() {
256: return cs_info;
257: }
258:
259: public Integer getORBTypeId() {
260: return orbTypeId;
261: }
262:
263: public IOR getIOR() {
264: return ior;
265: }
266:
267: public String getIORString() {
268: if (ior_str == null) {
269: try {
270: CDROutputStream out = new CDROutputStream(orb);
271: out.beginEncapsulatedArray();
272:
273: IORHelper.write(out, ior);
274:
275: byte bytes[] = out.getBufferCopy();
276:
277: StringBuffer sb = new StringBuffer("IOR:");
278:
279: for (int j = 0; j < bytes.length; j++) {
280: sb.append(lookup[(bytes[j] >> 4) & 0xF]);
281: sb.append(lookup[(bytes[j]) & 0xF]);
282: }
283:
284: ior_str = sb.toString();
285: } catch (Exception e) {
286: if (logger.isErrorEnabled()) {
287: logger.error("Error in building IIOP-IOR", e);
288: }
289: throw new org.omg.CORBA.UNKNOWN(
290: "Error in building IIOP-IOR");
291: }
292: }
293:
294: return ior_str;
295: }
296:
297: public byte[] get_object_key() {
298: return effectiveProfile.get_object_key();
299: }
300:
301: public List getProfiles() {
302: return profiles;
303: }
304:
305: public Profile getEffectiveProfile() {
306: return effectiveProfile;
307: }
308:
309: private void setEffectiveProfile() {
310: effectiveProfile = getProfileSelector().selectProfile(profiles,
311: orb.getClientConnectionManager());
312: ior_str = getIORString();
313:
314: if (effectiveProfile != null) {
315: cs_info = (CodeSetComponentInfo) getComponent(
316: TAG_CODE_SETS.value,
317: CodeSetComponentInfoHelper.class);
318: orbTypeId = getLongComponent(TAG_ORB_TYPE.value);
319: }
320: }
321:
322: public String getTypeId() {
323: return ior.type_id;
324: }
325:
326: public String getIDString() {
327: StringBuffer buff = new StringBuffer(getTypeId());
328: buff.append(":");
329: byte[] key = get_object_key();
330:
331: for (int j = 0; j < key.length; j++) {
332: buff.append(lookup[(key[j] >> 4) & 0xF]);
333: buff.append(lookup[(key[j]) & 0xF]);
334: }
335:
336: return (buff.toString());
337: }
338:
339: public TaggedComponentList getMultipleComponents() {
340: return components;
341: }
342:
343: public boolean isNull() {
344: return "".equals(ior.type_id) && ior.profiles.length == 0;
345: }
346:
347: /**
348: * <code>parse</code> decodes the object_reference passed to ParsedIOR.
349: *
350: * @param object_reference a <code>String</code> value.
351: * @exception IllegalArgumentException if object_reference is null or the
352: * designated resource cannot be found.
353: */
354: protected void parse(String object_reference)
355: throws IllegalArgumentException {
356: if (object_reference == null) {
357: throw new IllegalArgumentException("Null object reference");
358: }
359:
360: if (object_reference.startsWith("IOR:")) {
361: parse_stringified_ior(object_reference);
362: } else if (object_reference.startsWith("corbaloc:")) {
363: parse_corbaloc(object_reference);
364: } else if (object_reference.startsWith("corbaname:")) {
365: parse_corbaname(object_reference);
366: } else if (object_reference.startsWith("resource:")) {
367: parse_resource(object_reference.substring(9));
368: } else if (object_reference.startsWith("jndi:")) {
369: parse_jndi(object_reference.substring(5));
370: } else {
371: if (logger.isDebugEnabled()) {
372: logger.debug("Trying to resolve URL/IOR from: "
373: + object_reference);
374: }
375:
376: String content = null;
377: try {
378: content = ObjectUtil.readURL(object_reference);
379: } catch (java.io.IOException ioe) {
380: if (logger.isDebugEnabled()) {
381: logger.debug("Error reading IOR/URL: ", ioe);
382: }
383: // ignore;
384: }
385: if (content == null) {
386: throw new IllegalArgumentException(
387: "Invalid or unreadable URL/IOR: "
388: + object_reference);
389: }
390: parse(content);
391: }
392: ior_str = getIORString();
393: }
394:
395: // parser helper methods
396:
397: private void parse_stringified_ior(String object_reference) {
398: int length = object_reference.length();
399: int cnt = (length - 4) / 2;
400:
401: if ((length % 2) != 0) {
402: throw new BAD_PARAM(
403: "Odd number of characters within object reference");
404: }
405:
406: ByteArrayOutputStream bos = new ByteArrayOutputStream();
407:
408: for (int j = 0; j < cnt; j++) {
409: char c1 = object_reference.charAt(j * 2 + 4);
410: char c2 = object_reference.charAt(j * 2 + 5);
411: int i1 = (c1 >= 'a') ? (10 + c1 - 'a')
412: : ((c1 >= 'A') ? (10 + c1 - 'A') : (c1 - '0'));
413: int i2 = (c2 >= 'a') ? (10 + c2 - 'a')
414: : ((c2 >= 'A') ? (10 + c2 - 'A') : (c2 - '0'));
415: bos.write((i1 * 16 + i2));
416: }
417:
418: final CDRInputStream in_;
419:
420: if (orb == null) {
421: in_ = new CDRInputStream(org.omg.CORBA.ORB.init(), bos
422: .toByteArray());
423: } else {
424: in_ = new CDRInputStream(orb, bos.toByteArray());
425: }
426:
427: endianness = in_.read_boolean();
428: if (endianness) {
429: in_.setLittleEndian(true);
430: }
431:
432: try {
433: IOR _ior = IORHelper.read(in_);
434:
435: decode(_ior);
436: } catch (MARSHAL e) {
437: if (logger.isDebugEnabled()) {
438: logger.debug("Invalid IOR", e);
439: }
440: throw new BAD_PARAM("Invalid IOR " + e, 10,
441: CompletionStatus.COMPLETED_NO);
442: }
443: }
444:
445: private void parse_corbaloc(String object_reference) {
446: CorbaLoc corbaLoc = new CorbaLoc(orb, object_reference);
447: IOR ior = null;
448: if (corbaLoc.rir()) {
449: try {
450: org.omg.CORBA.Object obj = orb
451: .resolve_initial_references(corbaLoc
452: .getKeyString());
453:
454: if (obj == null) {
455: throw new IllegalArgumentException(
456: "Unable to resolve reference for "
457: + corbaLoc.getKeyString());
458: }
459:
460: ior = ((Delegate) ((org.omg.CORBA.portable.ObjectImpl) obj)
461: ._get_delegate()).getIOR();
462: } catch (Exception e) {
463: if (logger.isErrorEnabled()) {
464: logger.error(e.getMessage());
465: }
466: throw new IllegalArgumentException(
467: "Invalid corbaloc: URL");
468: }
469: } else {
470: Profile profile = corbaLoc.profileList[0];
471: if (profile == null) {
472: return; // could not decode any address in list
473: }
474:
475: profile.set_object_key(corbaLoc.getKey());
476: ior = createObjectIOR(profile);
477: }
478:
479: decode(ior);
480: }
481:
482: private void parse_corbaname(String object_reference) {
483: String corbaloc = "corbaloc:";
484: String name = "";
485: int colon = object_reference.indexOf(':');
486: int pound = object_reference.indexOf('#');
487:
488: if (pound == -1) {
489: corbaloc += object_reference.substring(colon + 1);
490: } else {
491: corbaloc += object_reference.substring(colon + 1, pound);
492: name = object_reference.substring(pound + 1);
493: }
494:
495: /* empty key string in corbaname becomes NameService */
496: if (corbaloc.indexOf('/') == -1) {
497: corbaloc += "/NameService";
498: }
499:
500: logger.debug(corbaloc);
501:
502: try {
503: NamingContextExt n = NamingContextExtHelper.narrow(orb
504: .string_to_object(corbaloc));
505: IOR ior = null;
506: // If the name hasn't been set - which is possible if we're just
507: // resolving the root context down try to use name.
508: if (name.length() > 0) {
509: org.omg.CORBA.Object target = n.resolve_str(name);
510: ior = ((Delegate) ((org.omg.CORBA.portable.ObjectImpl) target)
511: ._get_delegate()).getIOR();
512: } else {
513: ior = ((Delegate) ((org.omg.CORBA.portable.ObjectImpl) n)
514: ._get_delegate()).getIOR();
515: }
516: decode(ior);
517: } catch (Exception e) {
518: logger.error("Invalid object reference", e);
519:
520: throw new IllegalArgumentException(
521: "Invalid object reference: " + object_reference);
522: }
523: }
524:
525: private void parse_resource(String resourceName) {
526: if (logger.isDebugEnabled()) {
527: logger.debug("Trying to resolve URL/IOR from resource: "
528: + resourceName);
529: }
530:
531: URL url = ObjectUtil.getResource(resourceName);
532:
533: if (url == null) {
534: throw new IllegalArgumentException(
535: "Failed to get resource: " + resourceName);
536: }
537:
538: try {
539: String content = ObjectUtil.readURL(url.toString());
540: parse(content);
541: } catch (IOException e) {
542: throw new IllegalArgumentException(
543: "Failed to read resource: " + resourceName);
544: }
545: }
546:
547: private void parse_jndi(String jndiName) {
548: if (logger.isDebugEnabled()) {
549: logger.debug("Trying to resolve JNDI/IOR from name: "
550: + jndiName);
551: }
552:
553: java.lang.Object obj = null;
554: try {
555: // javax.naming.Context initialContext =
556: // new javax.naming.InitialContext ();
557: // obj = initialContext.lookup (jndiName);
558:
559: // Replaced lines above with reflected equivalent so will compile
560: // under JDK < 1.3 which do not include javax.naming classes. For
561: // jndi based name resolution to work obviously javax.naming
562: // classes must be in CLASSPATH.
563: //
564: Class[] types = new Class[1];
565: java.lang.Object[] params = new java.lang.Object[1];
566:
567: Class cls = ObjectUtil
568: .classForName("javax.naming.InitialContext");
569: java.lang.Object initialContext = cls.newInstance();
570:
571: types[0] = String.class;
572: params[0] = jndiName;
573:
574: java.lang.reflect.Method method = cls.getMethod("lookup",
575: types);
576: obj = method.invoke(initialContext, params);
577: } catch (Exception ex) {
578: throw new IllegalArgumentException(
579: "Failed to lookup JNDI/IOR: " + ex);
580: }
581:
582: if (obj == null) {
583: throw new IllegalArgumentException("Null JNDI/IOR: "
584: + jndiName);
585: }
586: parse(obj.toString());
587: }
588:
589: /**
590: * Returns the component with the given tag, searching the effective
591: * profile's components first (this is only possible with org.jacorb.orb.etf.ProfileBase implementations),
592: * and then the MULTIPLE_COMPONENTS profile, if one exists. If no
593: * component with the given tag exists, this method returns null.
594: */
595: private Object getComponent(int tag, Class helper) {
596: Object result = null;
597: if (effectiveProfile instanceof org.jacorb.orb.etf.ProfileBase) {
598: // TODO Should there be a component access mechanism for all
599: // ETF profiles? Clarify with OMG.
600: result = ((org.jacorb.orb.etf.ProfileBase) effectiveProfile)
601: .getComponent(tag, helper);
602: }
603:
604: if (result != null) {
605: return result;
606: }
607: return components.getComponent(tag, helper);
608: }
609:
610: private static class LongHelper {
611: public static Integer read(org.omg.CORBA.portable.InputStream in) {
612: return new Integer(in.read_long());
613: }
614: }
615:
616: /**
617: * Works like getComponent(), but for component values of CORBA type long.
618: */
619: private Integer getLongComponent(int tag) {
620: return (Integer) getComponent(tag, LongHelper.class);
621: }
622:
623: private static class StringHelper {
624: public static String read(org.omg.CORBA.portable.InputStream in) {
625: return in.read_string();
626: }
627: }
628:
629: /**
630: * Works like getComponent(), but for component values of type string.
631: */
632: private String getStringComponent(int tag) {
633: return (String) getComponent(tag, StringHelper.class);
634: }
635:
636: /**
637: * <code>isParsableProtocol</code> returns true if ParsedIOR can handle the
638: * protocol within the string.
639: *
640: * @param check a <code>String</code> a string containing a protocol.
641: * @return a <code>boolean</code> denoting whether ParsedIOR can handle this
642: * protocol
643: */
644: public static boolean isParsableProtocol(String check) {
645: if (check.startsWith("IOR:") || check.startsWith("corbaloc:")
646: || check.startsWith("corbaname:")
647: || check.startsWith("resource:")
648: || check.startsWith("jndi:")
649: || check.startsWith("file:")
650: || check.startsWith("http:")) {
651: return true;
652: }
653: return false;
654: }
655:
656: public void setProfileSelector(ProfileSelector sel) {
657: profileSelector = sel;
658: setEffectiveProfile();
659: }
660:
661: private ProfileSelector getProfileSelector() {
662: if (profileSelector == null) {
663: return orb.getTransportManager().getProfileSelector();
664: }
665: return profileSelector;
666: }
667: }
|