1 /* NameParser.java --
2    Copyright (C) 2005, 2006 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.NamingService;
40 
41 import gnu.CORBA.Minor;
42 import gnu.CORBA.OrbFunctional;
43 import gnu.CORBA.IOR;
44 import gnu.CORBA.Unexpected;
45 import gnu.CORBA.Version;
46 
47 import gnu.java.lang.CPStringBuilder;
48 
49 import org.omg.CORBA.BAD_PARAM;
50 import org.omg.CORBA.DATA_CONVERSION;
51 import org.omg.CORBA.ORB;
52 import org.omg.CORBA.Object;
53 import org.omg.CORBA.ORBPackage.InvalidName;
54 import org.omg.CORBA.portable.Delegate;
55 import org.omg.CORBA.portable.ObjectImpl;
56 import org.omg.CosNaming.NamingContext;
57 import org.omg.CosNaming._NamingContextStub;
58 
59 import java.io.File;
60 import java.io.FileReader;
61 import java.io.IOException;
62 import java.io.InputStreamReader;
63 import java.io.UnsupportedEncodingException;
64 import java.net.MalformedURLException;
65 import java.net.URL;
66 import java.net.URLDecoder;
67 import java.util.StringTokenizer;
68 
69 /**
70  * Parses the alternative IOR representations into our IOR structure.
71  *
72  * TODO This parser currently supports only one address per target string. A
73  * string with the multiple addresses will be accepted, but only the last
74  * address will be taken into consideration. The fault tolerance is not yet
75  * implemented.
76  *
77  * The key string is filtered using {@link java.net.URLDecoder} that replaces
78  * the agreed escape sequences by the corresponding non alphanumeric characters.
79  *
80  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
81  */
82 public class NameParser
83   extends NameTransformer
84 {
85   /**
86    * The corbaloc prefix.
87    */
88   public static final String pxCORBALOC = "corbaloc";
89 
90   /**
91    * The corbaname prefix.
92    */
93   public static final String pxCORBANAME = "corbaname";
94 
95   /**
96    * The IOR prefix.
97    */
98   public static final String pxIOR = "ior";
99 
100   /**
101    * The file:// prefix.
102    */
103   public static final String pxFILE = "file://";
104 
105   /**
106    * The ftp:// prefix.
107    */
108   public static final String pxFTP = "ftp://";
109 
110   /**
111    * The http:// prefix.
112    */
113   public static final String pxHTTP = "http://";
114 
115   /**
116    * Marks iiop protocol.
117    */
118   public static final String IIOP = "iiop";
119 
120   /**
121    * Marks rir protocol.
122    */
123   public static final String RIR = "rir";
124 
125   /**
126    * The default port value, as specified in OMG documentation.
127    */
128   public static final int DEFAULT_PORT = 2809;
129 
130   /**
131    * The default name.
132    */
133   public static final String DEFAULT_NAME = "NameService";
134 
135   /**
136    * The string to name converter, initialized on demand.
137    */
138   static NameTransformer converter;
139 
140   /**
141    * The current position.
142    */
143   int p;
144 
145   /**
146    * The address being parsed, splitted into tokens.
147    */
148   String[] t;
149 
150   /**
151    * Parse CORBALOC.
152    *
153    * The expected format is: <br>
154    * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key <br>
155    * 2. corbaloc:rir:[/key] <br>
156    * 3. corbaname:[iiop][version.subversion@]:host[:port]/key <br>
157    * 4. corbaname:rir:[/key] <br>
158    * 5. file://[file name]<br>
159    * 6. http://[url]<br>
160    * 7. ftp://[url]<br>
161    *
162    * Protocol defaults to IOP, the object key defaults to the NameService.
163    *
164    * @param corbaloc the string to parse.
165    * @param orb the ORB, needed to create IORs and resolve rir references.
166    *
167    * @return the resolved object.
168    */
corbaloc(String corbaloc, OrbFunctional orb)169   public synchronized org.omg.CORBA.Object corbaloc(String corbaloc,
170     OrbFunctional orb)
171     throws BAD_PARAM
172   {
173     return corbaloc(corbaloc, orb, 0);
174   }
175 
176   /**
177    * Parse controlling against the infinite recursion loop.
178    */
corbaloc(String corbaloc, OrbFunctional orb, int recursion)179   private org.omg.CORBA.Object corbaloc(String corbaloc,
180     OrbFunctional orb, int recursion)
181   {
182     // The used CORBA specification does not state how many times we should to
183     //redirect, but the infinite loop may be used to knock out the system.
184     // by malicious attempt.
185     if (recursion > 10)
186       throw new DATA_CONVERSION("More than 10 redirections");
187 
188     if (corbaloc.startsWith(pxFILE))
189       return corbaloc(readFile(corbaloc.substring(pxFILE.length())), orb, recursion+1);
190     else if (corbaloc.startsWith(pxHTTP))
191       return corbaloc(readUrl(corbaloc), orb, recursion+1);
192     else if (corbaloc.startsWith(pxFTP))
193       return corbaloc(readUrl(corbaloc), orb, recursion+1);
194 
195     boolean corbaname;
196 
197     // The version numbers with default values.
198     int major = 1;
199     int minor = 0;
200 
201     // The host address.
202     String host;
203 
204     // The port.
205     int port = DEFAULT_PORT;
206 
207     // The object key as string.
208     String key;
209 
210     StringTokenizer st = new StringTokenizer(corbaloc, ":@/.,#", true);
211 
212     t = new String[st.countTokens()];
213 
214     for (int i = 0; i < t.length; i++)
215       {
216         t[i] = st.nextToken();
217       }
218 
219     p = 0;
220 
221     if (t[p].startsWith(pxCORBANAME))
222       corbaname = true;
223     else if (t[p].equalsIgnoreCase(pxCORBALOC))
224       corbaname = false;
225     else if (t[p].equalsIgnoreCase(pxIOR))
226       {
227         IOR ior = IOR.parse(corbaloc);
228         return orb.ior_to_object(ior);
229       }
230     else
231       throw new DATA_CONVERSION("Unsupported protocol: '" + t[p] + "'");
232 
233     p++;
234 
235     if (!t[p++].equals(":"))
236       throw new BAD_PARAM("Syntax (':' expected after name prefix)");
237 
238     // Check for rir:
239     if (t[p].equals(RIR))
240       {
241         p++;
242         if (!t[p++].equals(":"))
243           throw new BAD_PARAM("':' expected after 'rir'");
244 
245         key = readKey("/");
246 
247         Object object;
248         try
249           {
250             object = orb.resolve_initial_references(key);
251             return corbaname ? resolve(object) : object;
252           }
253         catch (InvalidName e)
254           {
255             throw new BAD_PARAM("Unknown initial reference '" + key + "'");
256           }
257       }
258     else
259     // Check for iiop.
260     if (t[p].equals(IIOP) || t[p].equals(":"))
261       {
262         IOR ior = new IOR();
263 
264         Addresses: do
265           { // Read addresses.
266             if (t[p].equals(":"))
267               {
268                 p++;
269               }
270             else
271               {
272                 p++;
273                 if (!t[p++].equals(":"))
274                   throw new BAD_PARAM("':' expected after 'iiop'");
275                 // Check if version is present.
276                 if (t[p + 1].equals("."))
277                   if (t[p + 3].equals("@"))
278                     {
279                       // Version info present.
280                       try
281                         {
282                           major = Integer.parseInt(t[p++]);
283                         }
284                       catch (NumberFormatException e)
285                         {
286                           throw new BAD_PARAM("Major version number '"
287                             + t[p - 1] + "'");
288                         }
289                       p++; // '.' at this point.
290                       try
291                         {
292                           minor = Integer.parseInt(t[p++]);
293                         }
294                       catch (NumberFormatException e)
295                         {
296                           throw new BAD_PARAM("Major version number '"
297                             + t[p - 1] + "'");
298                         }
299                       p++; // '@' at this point.
300                     }
301               }
302 
303             ior.Internet.version = new Version(major, minor);
304 
305             // Then host data goes till '/' or ':'.
306             CPStringBuilder bhost = new CPStringBuilder(corbaloc.length());
307             while (!t[p].equals(":") && !t[p].equals("/") && !t[p].equals(","))
308               bhost.append(t[p++]);
309 
310             host = bhost.toString();
311 
312             ior.Internet.host = host;
313 
314             if (t[p].equals(":"))
315               {
316                 // Port specified.
317                 p++;
318                 try
319                   {
320                     port = Integer.parseInt(t[p++]);
321                   }
322                 catch (NumberFormatException e)
323                   {
324                     throw new BAD_PARAM("Invalid port '" + t[p - 1] + "'");
325                   }
326               }
327 
328             ior.Internet.port = port;
329 
330             // Id is not listed.
331             ior.Id = "";
332 
333             if (t[p].equals(","))
334               p++;
335             else
336               break Addresses;
337           }
338         while (true);
339 
340         key = readKey("/");
341         ior.key = key.getBytes();
342 
343         org.omg.CORBA.Object object = orb.ior_to_object(ior);
344         return corbaname ? resolve(object) : object;
345       }
346 
347     else
348       throw new DATA_CONVERSION("Unsupported protocol '" + t[p] + "'");
349   }
350 
351   /**
352    * Read IOR from the file in the local file system.
353    */
readFile(String file)354   String readFile(String file)
355   {
356     File f = new File(file);
357     if (!f.exists())
358       {
359         DATA_CONVERSION err = new DATA_CONVERSION(f.getAbsolutePath()
360           + " does not exist.");
361         err.minor = Minor.Missing_IOR;
362       }
363     try
364       {
365         char[] c = new char[(int) f.length()];
366         FileReader fr = new FileReader(f);
367         fr.read(c);
368         fr.close();
369         return new String(c).trim();
370       }
371     catch (IOException ex)
372       {
373         DATA_CONVERSION d = new DATA_CONVERSION();
374         d.initCause(ex);
375         d.minor = Minor.Missing_IOR;
376         throw (d);
377       }
378   }
379 
380   /**
381    * Read IOR from the remote URL.
382    */
readUrl(String url)383   String readUrl(String url)
384   {
385     URL u;
386     try
387       {
388         u = new URL(url);
389       }
390     catch (MalformedURLException mex)
391       {
392         throw new BAD_PARAM("Malformed URL: '" + url + "'");
393       }
394 
395     try
396       {
397         InputStreamReader r = new InputStreamReader(u.openStream());
398 
399         CPStringBuilder b = new CPStringBuilder();
400         int c;
401 
402         while ((c = r.read()) > 0)
403           b.append((char) c);
404 
405         return b.toString().trim();
406       }
407     catch (Exception exc)
408       {
409         DATA_CONVERSION d = new DATA_CONVERSION("Reading " + url + " failed.");
410         d.minor = Minor.Missing_IOR;
411         throw d;
412       }
413   }
414 
resolve(org.omg.CORBA.Object object)415   private org.omg.CORBA.Object resolve(org.omg.CORBA.Object object)
416   {
417     NamingContext ns;
418     String key = "?";
419     try
420       {
421         if (object instanceof NamingContext)
422           ns = (NamingContext) object;
423         else
424           {
425             Delegate delegate = ((ObjectImpl) object)._get_delegate();
426             ns = new _NamingContextStub();
427             ((_NamingContextStub) ns)._set_delegate(delegate);
428           }
429       }
430     catch (Exception ex)
431       {
432         BAD_PARAM bad = new BAD_PARAM("The CORBANAME target " + object
433           + " is not a NamingContext");
434         bad.minor = 10;
435         bad.initCause(ex);
436         throw bad;
437       }
438 
439     if (converter == null)
440       converter = new NameTransformer();
441 
442     try
443       {
444         key = readKey("#");
445         object = ns.resolve(converter.toName(key));
446         return object;
447       }
448     catch (Exception ex)
449       {
450         BAD_PARAM bad = new BAD_PARAM("Wrong CORBANAME '" + key + "'");
451         bad.minor = 10;
452         bad.initCause(ex);
453         throw bad;
454       }
455   }
456 
readKey(String delimiter)457   private String readKey(String delimiter)
458     throws BAD_PARAM
459   {
460     if (p < t.length)
461       if (!t[p].equals(delimiter))
462         {
463           if (t[p].equals("#"))
464             return DEFAULT_NAME;
465           else
466             throw new BAD_PARAM("'" + delimiter + "String' expected '" + t[p]
467               + "' found");
468         }
469 
470     CPStringBuilder bKey = new CPStringBuilder();
471     p++;
472 
473     while (p < t.length && !t[p].equals("#"))
474       bKey.append(t[p++]);
475 
476     if (bKey.length() == 0)
477       return DEFAULT_NAME;
478 
479     try
480       {
481         return URLDecoder.decode(bKey.toString(), "UTF-8");
482       }
483     catch (UnsupportedEncodingException e)
484       {
485         throw new Unexpected("URLDecoder does not support UTF-8", e);
486       }
487   }
488 
489   static NameParser n = new NameParser();
490 
corbalocT(String ior, OrbFunctional orb)491   static void corbalocT(String ior, OrbFunctional orb)
492   {
493     System.out.println(ior);
494     System.out.println(n.corbaloc(ior, orb));
495     System.out.println();
496   }
497 
main(String[] args)498   public static void main(String[] args)
499   {
500     try
501       {
502         OrbFunctional orb = (OrbFunctional) ORB.init(args, null);
503         corbalocT("corbaloc:iiop:1.3@155axyz.com/Prod/aTradingService", orb);
504         corbalocT("corbaloc:iiop:2.7@255bxyz.com/Prod/bTradingService", orb);
505         corbalocT("corbaloc:iiop:355cxyz.com/Prod/cTradingService", orb);
506         corbalocT("corbaloc:iiop:2.7@255bxyz.com/Prod/bTradingService", orb);
507         corbalocT("corbaloc:iiop:355cxyz.com:7777/Prod/cTradingService", orb);
508 
509         corbalocT("corbaloc::556xyz.com:80/Dev/NameService", orb);
510         corbalocT("corbaloc:iiop:1.2@host1:3076/0", orb);
511 
512         corbalocT("corbaloc:rir:/NameService", orb);
513         corbalocT("corbaloc:rir:/", orb);
514         corbalocT("corbaloc:rir:", orb);
515 
516         corbalocT("corbaloc:rir:/NameService", orb);
517         corbalocT("corbaloc:rir:/", orb);
518         corbalocT("corbaloc:rir:", orb);
519 
520         corbalocT("corbaloc::555xyz.com,:556xyz.com:80/Dev/NameService", orb);
521       }
522     catch (BAD_PARAM e)
523       {
524         e.printStackTrace(System.out);
525       }
526   }
527 }
528