OSDN Git Service

Normalise whitespace in GNU Classpath.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / CORBA / IOR.java
1 /* IOR.java --
2    Copyright (C) 2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package gnu.CORBA;
40
41 import gnu.CORBA.CDR.BufferredCdrInput;
42 import gnu.CORBA.CDR.BufferedCdrOutput;
43 import gnu.CORBA.CDR.AbstractCdrInput;
44 import gnu.CORBA.CDR.AbstractCdrOutput;
45 import gnu.CORBA.GIOP.CharSets_OSF;
46 import gnu.CORBA.GIOP.CodeSetServiceContext;
47
48 import gnu.java.lang.CPStringBuilder;
49
50 import org.omg.CORBA.BAD_PARAM;
51 import org.omg.CORBA.CompletionStatus;
52 import org.omg.CORBA.MARSHAL;
53 import org.omg.CORBA.ULongSeqHelper;
54 import org.omg.IOP.TAG_INTERNET_IOP;
55 import org.omg.IOP.TAG_MULTIPLE_COMPONENTS;
56 import org.omg.IOP.TaggedComponent;
57 import org.omg.IOP.TaggedComponentHelper;
58 import org.omg.IOP.TaggedProfile;
59 import org.omg.IOP.TaggedProfileHelper;
60
61 import java.io.ByteArrayOutputStream;
62 import java.io.IOException;
63 import java.util.ArrayList;
64 import java.util.Arrays;
65 import java.util.zip.Adler32;
66
67 /**
68  * The implementaton of the Interoperable Object Reference (IOR). IOR can be
69  * compared with the Internet address for a web page, it provides means to
70  * locate the CORBA service on the web. IOR contains the host address, port
71  * number, the object identifier (key) inside the server, the communication
72  * protocol version, supported charsets and so on.
73  *
74  * Ths class provides method for encoding and decoding the IOR information
75  * from/to the stringified references, usually returned by
76  * {@link org.omg.CORBA.ORB#String object_to_string()}.
77  *
78  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
79  *
80  * @see org.mog.CORBA.Object.object_to_string(Object forObject)
81  * @see string_to_object(String IOR)
82  */
83 public class IOR
84 {
85   /**
86    * The code sets tagged component, normally part of the Internet profile. This
87    * compone consists of the two componenets itself.
88    */
89   public static class CodeSets_profile
90   {
91     public CodeSets_profile()
92     {
93       int[] supported = CharSets_OSF.getSupportedCharSets();
94
95       narrow.native_set = CharSets_OSF.NATIVE_CHARACTER;
96       narrow.conversion = supported;
97
98       wide.native_set = CharSets_OSF.NATIVE_WIDE_CHARACTER;
99       wide.conversion = supported;
100     }
101
102     /**
103      * The code set component.
104      */
105     public static class CodeSet_component
106     {
107       /**
108        * The conversion code sets.
109        */
110       public int[] conversion;
111
112       /**
113        * The native code set.
114        */
115       public int native_set;
116
117       /**
118        * Read from the CDR stream.
119        */
120       public void read(org.omg.CORBA.portable.InputStream in)
121       {
122         native_set = in.read_ulong();
123         conversion = ULongSeqHelper.read(in);
124       }
125
126       /**
127        * Get a string representation.
128        */
129       public String toString()
130       {
131         CPStringBuilder b = new CPStringBuilder();
132         b.append("native " + name(native_set));
133         if (conversion != null && conversion.length > 0)
134           {
135             b.append(" conversion ");
136             for (int i = 0; i < conversion.length; i++)
137               {
138                 b.append(name(conversion[i]));
139                 b.append(' ');
140               }
141           }
142         b.append(' ');
143         return b.toString();
144       }
145
146       /**
147        * Get a better formatted multiline string representation.
148        */
149       public String toStringFormatted()
150       {
151         CPStringBuilder b = new CPStringBuilder();
152         b.append("\n  Native set " + name(native_set));
153         if (conversion != null && conversion.length > 0)
154           {
155             b.append("\n  Other supported sets:\n    ");
156             for (int i = 0; i < conversion.length; i++)
157               {
158                 b.append(name(conversion[i]));
159                 b.append(' ');
160               }
161           }
162         b.append("\n");
163         return b.toString();
164       }
165
166
167       /**
168        * Write into CDR stream.
169        */
170       public void write(org.omg.CORBA.portable.OutputStream out)
171       {
172         out.write_long(native_set);
173         ULongSeqHelper.write(out, conversion);
174       }
175
176       private String name(int set)
177       {
178         return "0x" + Integer.toHexString(set) + " ("
179                + CharSets_OSF.getName(set) + ") ";
180       }
181     }
182
183     /**
184      * The agreed tag for the Codesets profile.
185      */
186     public static final int TAG_CODE_SETS = 1;
187
188     /**
189      * Information about narrow character encoding (TCS-C).
190      */
191     public CodeSet_component narrow = new CodeSet_component();
192
193     /**
194      * About wide character encoding (TCS-W).
195      */
196     public CodeSet_component wide = new CodeSet_component();
197
198     /**
199      * The negotiated coding result for this IOR. Saves time, requred for
200      * negotiation computations.
201      */
202     public CodeSetServiceContext negotiated;
203
204     /**
205      * Read the code set profile information from the given input stream.
206      *
207      * @param profile a stream to read from.
208      */
209     public void read(AbstractCdrInput profile)
210     {
211       BufferredCdrInput encapsulation = profile.read_encapsulation();
212       narrow.read(encapsulation);
213       wide.read(encapsulation);
214     }
215
216     /**
217      * Returns a string representation.
218      */
219     public String toString()
220     {
221       return "Narrow char: " + narrow + ", Wide char: " + wide;
222     }
223
224     /**
225      * Write the code set profile information into the given input stream.
226      *
227      * @param profile a stream to write into.
228      */
229     public void write(AbstractCdrOutput profile)
230     {
231       AbstractCdrOutput encapsulation = profile.createEncapsulation();
232       narrow.write(encapsulation);
233       wide.write(encapsulation);
234       try
235         {
236           encapsulation.close();
237         }
238       catch (IOException ex)
239         {
240           throw new InternalError();
241         }
242     }
243   }
244
245   /**
246    * The internet profile.
247    */
248   public class Internet_profile
249   {
250     /**
251      * The agreed tag for the Internet profile.
252      */
253     public static final int TAG_INTERNET_IOP = 0;
254
255     /**
256      * The host.
257      */
258     public String host;
259
260     /**
261      * The IIOP version (initialised to 1.2 by default).
262      */
263     public Version version = new Version(1, 2);
264
265     /**
266      * The port.
267      */
268     public int port;
269
270     /**
271      * The code sets component in the internet profile of this IOR. This is not
272      * a separate profile.
273      */
274     public CodeSets_profile CodeSets = new CodeSets_profile();
275
276     /**
277      * Reserved for all components of this profile, this array holds the
278      * components other than code set components.
279      */
280     ArrayList components = new ArrayList();
281
282     /**
283      * Return the human readable representation.
284      */
285     public String toString()
286     {
287       CPStringBuilder b = new CPStringBuilder();
288       b.append(host);
289       b.append(":");
290       b.append(port);
291       b.append(" (v");
292       b.append(version);
293       b.append(")");
294       if (components.size() > 0)
295         b.append(" " + components.size() + " extra components.");
296       return b.toString();
297     }
298
299     /**
300      * Write the internet profile (except the heading tag.
301      */
302     public void write(AbstractCdrOutput out)
303     {
304       try
305         {
306           // Need to write the Internet profile into the separate
307           // stream as we must know the size in advance.
308           AbstractCdrOutput b = out.createEncapsulation();
309
310           version.write(b);
311           b.write_string(host);
312
313           b.write_ushort((short) (port & 0xFFFF));
314
315           // Write the object key.
316           b.write_long(key.length);
317           b.write(key);
318
319           // Number of the tagged components.
320           b.write_long(1 + components.size());
321
322           b.write_long(CodeSets_profile.TAG_CODE_SETS);
323           CodeSets.write(b);
324
325           TaggedComponent t;
326
327           for (int i = 0; i < components.size(); i++)
328             {
329               t = (TaggedComponent) components.get(i);
330               TaggedComponentHelper.write(b, t);
331             }
332
333           b.close();
334         }
335       catch (Exception e)
336         {
337           MARSHAL m = new MARSHAL("Unable to write Internet profile.");
338           m.minor = Minor.IOR;
339           m.initCause(e);
340           throw m;
341         }
342     }
343   }
344
345   /**
346    * The standard minor code, indicating that the string to object converstio
347    * has failed due non specific reasons.
348    */
349   public static final int FAILED = 10;
350
351   /**
352    * The internet profile of this IOR.
353    */
354   public Internet_profile Internet = new Internet_profile();
355
356   /**
357    * The object repository Id.
358    */
359   public String Id;
360
361   /**
362    * The object key.
363    */
364   public byte[] key;
365
366   /**
367    * All tagged profiles of this IOR, except the separately defined Internet
368    * profile.
369    */
370   ArrayList profiles = new ArrayList();
371
372   /**
373    * True if the profile was encoded using the Big Endian or the encoding is not
374    * known.
375    *
376    * false if it was encoded using the Little Endian.
377    */
378   public boolean Big_Endian = true;
379
380   /**
381    * Create an empty instance, initialising the code sets to default values.
382    */
383   public IOR()
384   {
385   }
386
387   /**
388    * Parse the provided stringifed reference.
389    *
390    * @param stringified_reference in the form of IOR:nnnnnn.....
391    *
392    * @return the parsed IOR
393    *
394    * @throws BAD_PARAM, minor code 10, if the IOR cannot be parsed.
395    *
396    * TODO corballoc and other alternative formats.
397    */
398   public static IOR parse(String stringified_reference)
399     throws BAD_PARAM
400   {
401     try
402       {
403         if (!stringified_reference.startsWith("IOR:"))
404           throw new BAD_PARAM("The string refernce must start with IOR:",
405                               FAILED, CompletionStatus.COMPLETED_NO);
406
407         IOR r = new IOR();
408
409         ByteArrayOutputStream buf = new ByteArrayOutputStream();
410         String x = stringified_reference;
411         x = x.substring(x.indexOf(":") + 1);
412
413         char cx;
414
415         for (int i = 0; i < x.length(); i = i + 2)
416           {
417             cx = (char) Integer.parseInt(x.substring(i, i + 2), 16);
418             buf.write(cx);
419           }
420
421         BufferredCdrInput cdr = new BufferredCdrInput(buf.toByteArray());
422
423         r._read(cdr);
424         return r;
425       }
426     catch (Exception ex)
427       {
428         ex.printStackTrace();
429         throw new BAD_PARAM(ex + " while parsing " + stringified_reference,
430                             FAILED, CompletionStatus.COMPLETED_NO);
431       }
432   }
433
434   /**
435    * Read the IOR from the provided input stream.
436    *
437    * @param c a stream to read from.
438    * @throws IOException if the stream throws it.
439    */
440   public void _read(AbstractCdrInput c)
441     throws IOException, BAD_PARAM
442   {
443     int endian;
444
445     endian = c.read_long();
446     if (endian != 0)
447       {
448         Big_Endian = false;
449         c.setBigEndian(false);
450       }
451     _read_no_endian(c);
452   }
453
454   /**
455    * Read the IOR from the provided input stream, not reading the endian data at
456    * the beginning of the stream. The IOR is thansferred in this form in
457    * {@link write_Object(org.omg.CORBA.Object)}.
458    *
459    * If the stream contains a null value, the Id and Internet fields become
460    * equal to null. Otherwise Id contains some string (possibly empty).
461    *
462    * Id is checked for null in AbstractCdrInput that then returns null instead of
463    * object.
464    *
465    * @param c a stream to read from.
466    * @throws IOException if the stream throws it.
467    */
468   public void _read_no_endian(AbstractCdrInput c)
469     throws IOException, BAD_PARAM
470   {
471     Id = c.read_string();
472
473     int n_profiles = c.read_long();
474
475     if (n_profiles == 0)
476       {
477         Id = null;
478         Internet = null;
479         return;
480       }
481
482     for (int i = 0; i < n_profiles; i++)
483       {
484         int tag = c.read_long();
485         BufferredCdrInput profile = c.read_encapsulation();
486
487         if (tag == Internet_profile.TAG_INTERNET_IOP)
488           {
489             Internet = new Internet_profile();
490             Internet.version = Version.read_version(profile);
491             Internet.host = profile.read_string();
492             Internet.port = profile.gnu_read_ushort();
493
494             key = profile.read_sequence();
495
496             // Read tagged components.
497             int n_components = 0;
498
499             try
500               {
501                 if (Internet.version.since_inclusive(1, 1))
502                   n_components = profile.read_long();
503
504                 for (int t = 0; t < n_components; t++)
505                   {
506                     int ctag = profile.read_long();
507
508                     if (ctag == CodeSets_profile.TAG_CODE_SETS)
509                       {
510                         Internet.CodeSets.read(profile);
511                       }
512                     else
513                       {
514                         // Construct a generic component for codesets
515                         // profile.
516                         TaggedComponent pc = new TaggedComponent();
517                         pc.tag = ctag;
518                         pc.component_data = profile.read_sequence();
519                         Internet.components.add(pc);
520                       }
521                   }
522               }
523             catch (Unexpected ex)
524               {
525                 ex.printStackTrace();
526               }
527           }
528         else
529           {
530             // Construct a generic profile.
531             TaggedProfile p = new TaggedProfile();
532             p.tag = tag;
533             p.profile_data = profile.buffer.getBuffer();
534
535             profiles.add(p);
536           }
537       }
538   }
539
540   /**
541    * Write this IOR record to the provided CDR stream. This procedure writes the
542    * zero (Big Endian) marker first.
543    */
544   public void _write(AbstractCdrOutput out)
545   {
546     // Always use Big Endian.
547     out.write(0);
548     _write_no_endian(out);
549   }
550
551   /**
552    * Write a null value to the CDR output stream.
553    *
554    * The null value is written as defined in OMG specification (zero length
555    * string, followed by an empty set of profiles).
556    */
557   public static void write_null(AbstractCdrOutput out)
558   {
559     // Empty Id string.
560     out.write_string("");
561
562     // Empty set of profiles.
563     out.write_long(0);
564   }
565
566   /**
567    * Write this IOR record to the provided CDR stream. The procedure writed data
568    * in Big Endian, but does NOT add any endian marker to the beginning.
569    */
570   public void _write_no_endian(AbstractCdrOutput out)
571   {
572     // Write repository id.
573     out.write_string(Id);
574
575     out.write_long(1 + profiles.size());
576
577     // Write the Internet profile.
578     out.write_long(Internet_profile.TAG_INTERNET_IOP);
579     Internet.write(out);
580
581     // Write other profiles.
582     TaggedProfile tp;
583
584     for (int i = 0; i < profiles.size(); i++)
585       {
586         tp = (TaggedProfile) profiles.get(i);
587         TaggedProfileHelper.write(out, tp);
588       }
589   }
590
591   /**
592    * Returns a human readable string representation of this IOR object.
593    */
594   public String toString()
595   {
596     CPStringBuilder b = new CPStringBuilder();
597     b.append(Id);
598     b.append(" at ");
599     b.append(Internet);
600
601     if (!Big_Endian)
602       b.append(" (Little endian) ");
603
604     b.append(" Key ");
605
606     for (int i = 0; i < key.length; i++)
607       {
608         b.append(Integer.toHexString(key[i] & 0xFF));
609       }
610
611     b.append(" ");
612     b.append(Internet.CodeSets);
613
614     return b.toString();
615   }
616
617   /**
618    * Returns a multiline formatted human readable string representation of
619    * this IOR object.
620    */
621   public String toStringFormatted()
622   {
623     CPStringBuilder b = new CPStringBuilder();
624     b.append("\nObject Id:\n  ");
625     b.append(Id);
626     b.append("\nObject is accessible at:\n  ");
627     b.append(Internet);
628
629     if (Big_Endian)
630       b.append("\n  Big endian encoding");
631     else
632       b.append("\n  Little endian encoding.");
633
634     b.append("\nObject Key\n  ");
635
636     for (int i = 0; i < key.length; i++)
637       {
638         b.append(Integer.toHexString(key[i] & 0xFF));
639       }
640
641     b.append("\nSupported code sets:");
642     b.append("\n Wide:");
643     b.append(Internet.CodeSets.wide.toStringFormatted());
644     b.append(" Narrow:");
645     b.append(Internet.CodeSets.wide.toStringFormatted());
646
647     return b.toString();
648   }
649
650   /**
651    * Returs a stringified reference.
652    *
653    * @return a newly constructed stringified reference.
654    */
655   public String toStringifiedReference()
656   {
657     BufferedCdrOutput out = new BufferedCdrOutput();
658
659     _write(out);
660
661     CPStringBuilder b = new CPStringBuilder("IOR:");
662
663     byte[] binary = out.buffer.toByteArray();
664     String s;
665
666     for (int i = 0; i < binary.length; i++)
667       {
668         s = Integer.toHexString(binary[i] & 0xFF);
669         if (s.length() == 1)
670           b.append('0');
671         b.append(s);
672       }
673
674     return b.toString();
675   }
676
677   /**
678    * Adds a service-specific component to the IOR profile. The specified
679    * component will be included in all profiles, present in the IOR.
680    *
681    * @param tagged_component a tagged component being added.
682    */
683   public void add_ior_component(TaggedComponent tagged_component)
684   {
685     // Add to the Internet profile.
686     Internet.components.add(tagged_component);
687
688     // Add to others.
689     for (int i = 0; i < profiles.size(); i++)
690       {
691         TaggedProfile profile = (TaggedProfile) profiles.get(i);
692         addComponentTo(profile, tagged_component);
693       }
694   }
695
696   /**
697    * Adds a service-specific component to the IOR profile.
698    *
699    * @param tagged_component a tagged component being added.
700    *
701    * @param profile_id the IOR profile to that the component must be added. The
702    * 0 value ({@link org.omg.IOP.TAG_INTERNET_IOP#value}) adds to the Internet
703    * profile where host and port are stored by default.
704    */
705   public void add_ior_component_to_profile(TaggedComponent tagged_component,
706                                            int profile_id)
707   {
708     if (profile_id == TAG_INTERNET_IOP.value)
709       // Add to the Internet profile
710       Internet.components.add(tagged_component);
711     else
712       {
713         // Add to others.
714         for (int i = 0; i < profiles.size(); i++)
715           {
716             TaggedProfile profile = (TaggedProfile) profiles.get(i);
717             if (profile.tag == profile_id)
718               addComponentTo(profile, tagged_component);
719           }
720       }
721   }
722
723   /**
724    * Add given component to the given profile that is NOT an Internet profile.
725    *
726    * @param profile the profile, where the component should be added.
727    * @param component the component to add.
728    */
729   private static void addComponentTo(TaggedProfile profile,
730                                      TaggedComponent component)
731   {
732     if (profile.tag == TAG_MULTIPLE_COMPONENTS.value)
733       {
734         TaggedComponent[] present;
735         if (profile.profile_data.length > 0)
736           {
737             BufferredCdrInput in = new BufferredCdrInput(profile.profile_data);
738
739             present = new TaggedComponent[in.read_long()];
740
741             for (int i = 0; i < present.length; i++)
742               {
743                 present[i] = TaggedComponentHelper.read(in);
744               }
745           }
746         else
747           present = new TaggedComponent[0];
748
749         BufferedCdrOutput out = new BufferedCdrOutput(profile.profile_data.length
750                                             + component.component_data.length
751                                             + 8);
752
753         // Write new amount of components.
754         out.write_long(present.length + 1);
755
756         // Write other components.
757         for (int i = 0; i < present.length; i++)
758           TaggedComponentHelper.write(out, present[i]);
759
760         // Write the passed component.
761         TaggedComponentHelper.write(out, component);
762
763         try
764           {
765             out.close();
766           }
767         catch (IOException e)
768           {
769             throw new Unexpected(e);
770           }
771         profile.profile_data = out.buffer.toByteArray();
772       }
773     else
774       // The future supported tagged profiles should be added here.
775       throw new BAD_PARAM("Unsupported profile type " + profile.tag);
776   }
777
778   /**
779    * Checks for equality.
780    */
781   public boolean equals(Object x)
782   {
783     if (x instanceof IOR)
784       {
785         boolean keys;
786         boolean hosts = true;
787
788         IOR other = (IOR) x;
789
790         if (Internet==null || other.Internet==null)
791           return Internet == other.Internet;
792
793         if (key != null && other.key != null)
794           keys = Arrays.equals(key, other.key);
795         else
796           keys = key == other.key;
797
798         if (Internet != null && Internet.host != null)
799           if (other.Internet != null && other.Internet.host != null)
800             hosts = other.Internet.host.equals(Internet.host);
801
802         return keys & hosts && Internet.port==other.Internet.port;
803       }
804     else
805       return false;
806   }
807
808   /**
809    * Get the hashcode of this IOR.
810    */
811   public int hashCode()
812   {
813     Adler32 adler = new Adler32();
814     if (key != null)
815       adler.update(key);
816     if (Internet != null)
817       {
818         if (Internet.host != null)
819           adler.update(Internet.host.getBytes());
820         adler.update(Internet.port);
821       }
822     return (int) adler.getValue();
823   }
824 }