1 /* NameTransformer.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.NamingService;
40 
41 import org.omg.CORBA.IntHolder;
42 import org.omg.CosNaming.NameComponent;
43 import org.omg.CosNaming.NamingContextPackage.InvalidName;
44 
45 import java.util.ArrayList;
46 import java.util.StringTokenizer;
47 
48 /**
49  * This class converts between string and array representations of the
50  * multi component object names.
51  *
52  * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
53  */
54 public class NameTransformer
55 {
56   /**
57    * A string, indicating the escape character.
58    */
59   public static final String ESCAPE = "\\";
60 
61   /**
62    * Convert the string name representation into the array name
63    * representation. See {@link #toString(NameComponent)} for the
64    * description of this format.
65    *
66    * @param name the string form of the name.
67    *
68    * @return the array form of the name.
69    *
70    * @throws InvalidName if the name cannot be parsed.
71    */
toName(String a_name)72   public NameComponent[] toName(String a_name)
73                          throws InvalidName
74   {
75     ArrayList components = new ArrayList();
76     StringTokenizer st = new StringTokenizer(a_name, "./\\", true);
77 
78     String id;
79     String kind;
80     String next;
81 
82     // Create the buffer array, reserving the last element for null.
83     String[] n = new String[ st.countTokens() + 1 ];
84 
85     int pp = 0;
86     while (st.hasMoreTokens())
87       n [ pp++ ] = st.nextToken();
88 
89     IntHolder p = new IntHolder();
90 
91     NameComponent node = readNode(p, n);
92 
93     while (node != null)
94       {
95         components.add(node);
96         node = readNode(p, n);
97       }
98 
99     NameComponent[] name = new NameComponent[ components.size() ];
100     for (int i = 0; i < name.length; i++)
101       {
102         name [ i ] = (NameComponent) components.get(i);
103       }
104 
105     NameValidator.check(name);
106 
107     return name;
108   }
109 
110   /**
111    * Converts the name into its string representation, as defined in
112    * the specification CORBA naming service.
113    *
114    * A string representation for the name consists of the name components,
115    * separated by a slash '/' character (for example, 'a/b/c'). If the
116    * {@link NameComponent#kind} field is  not empty, it is given after
117    * period ('.'), for example 'a.b/c.d/.' .
118    * The period alone represents node where part where both
119    * {@link NameComponent#kind} and {@link NameComponent#id} are empty strings.
120    *
121    * If slash or dot are part of the name, they are escaped by backslash ('\').
122    * If the backslash itself is part of the name, it is doubled.
123    *
124    * @param a_name a name to convert.
125    * @return a string representation.
126    */
toString(NameComponent[] a_name)127   public String toString(NameComponent[] a_name)
128                   throws InvalidName
129   {
130     NameValidator.check(a_name);
131 
132     StringBuffer b = new StringBuffer();
133 
134     NameComponent n;
135 
136     for (int ni = 0; ni < a_name.length; ni++)
137       {
138         n = a_name [ ni ];
139         appEscaping(b, n.id);
140         if (n.kind.length() > 0)
141           {
142             b.append('.');
143             appEscaping(b, n.kind);
144           }
145 
146         if (ni < a_name.length - 1)
147           b.append('/');
148       }
149     return b.toString();
150   }
151 
152   /**
153    * Append the contents of the string to this
154    * string buffer, inserting the escape sequences, where required.
155    *
156    * @param b a buffer to append the contents to.
157    * @param s a string to append.
158    */
appEscaping(StringBuffer b, String s)159   private void appEscaping(StringBuffer b, String s)
160   {
161     char c;
162     for (int i = 0; i < s.length(); i++)
163       {
164         c = s.charAt(i);
165         switch (c)
166           {
167             case '.' :
168             case '/' :
169             case '\\' :
170               b.append('\\');
171               b.append(c);
172               break;
173 
174             default :
175               b.append(c);
176               break;
177           }
178       }
179   }
180 
181   /**
182    * Assert the end of the current name component.
183    */
assertEndOfNode(IntHolder p, String[] t)184   private void assertEndOfNode(IntHolder p, String[] t)
185                         throws InvalidName
186   {
187     if (t [ p.value ] != null)
188       if (!t [ p.value ].equals("/"))
189         throw new InvalidName("End of node expected at token " + p.value);
190   }
191 
192   /**
193    * Read the named component node. After reading the current positon
194    * advances to the beginning of the next node in an array.
195    *
196    * @param p the current position being wrapped inside the passed
197    * IntHolder.
198    *
199    * @param t the text buffer.
200    *
201    * @return the created node.
202    */
readNode(IntHolder p, String[] t)203   private NameComponent readNode(IntHolder p, String[] t)
204                           throws InvalidName
205   {
206     // End of stream has been reached.
207     if (t [ p.value ] == null)
208       return null;
209 
210     NameComponent n = new NameComponent();
211 
212     if (t [ p.value ].equals("."))
213       {
214         // The 'id' is missing, but the 'kind' may follow.
215         n.id = "";
216         p.value++;
217         n.kind = readPart(p, t);
218         assertEndOfNode(p, t);
219         if (t [ p.value ] != null)
220           p.value++;
221       }
222     else if (t [ p.value ].equals("/"))
223       {
224         // This is not allowed here and may happen only
225         // on two subsequent slashes.
226         throw new InvalidName("Unexpected '/' token " + p.value);
227       }
228     else
229       {
230         n.id = readPart(p, t);
231 
232         // If some chars follow the id.
233         if (t [ p.value ] != null)
234           {
235             // Dot means that the kind part follows
236             if (t [ p.value ].equals("."))
237               {
238                 p.value++;
239                 n.kind = readPart(p, t);
240                 assertEndOfNode(p, t);
241                 if (t [ p.value ] != null)
242                   p.value++;
243               }
244 
245             // The next name component follows - advance to
246             // the beginning of the next name component.
247             else if (t [ p.value ].equals("/"))
248               {
249                 n.kind = "";
250                 p.value++;
251               }
252             else
253               throw new InvalidName("Unexpected '" + t [ p.value ] +
254                                        "' at token " + p.value
255                                       );
256           }
257         else
258 
259           // Id, and then end of sequence.
260           n.kind = "";
261       }
262 
263     return n;
264   }
265 
266   /**
267    * Read the name part (id or kind).
268    *
269    * @param p the current position. After reading, advances
270    * to the beginning of the next name fragment.
271    *
272    * @param t the string buffer.
273    *
274    * @return the name part with resolved escape sequences.
275    */
readPart(IntHolder p, String[] t)276   private String readPart(IntHolder p, String[] t)
277   {
278     StringBuffer part = new StringBuffer();
279 
280     while (t [ p.value ] != null && !t [ p.value ].equals(".") &&
281            !t [ p.value ].equals("/")
282           )
283       {
284         if (t [ p.value ].equals(ESCAPE))
285           {
286             p.value++;
287             part.append(t [ p.value ]);
288           }
289         else
290           part.append(t [ p.value ]);
291 
292         p.value++;
293       }
294 
295     return part.toString();
296   }
297 
main(String[] args)298   public static void main(String[] args)
299   {
300     NameComponent a = new NameComponent("a", "ak");
301     NameComponent b = new NameComponent("b/z", "b.k");
302     NameComponent c = new NameComponent("c", "");
303 
304     NameTransformer sn = new NameTransformer();
305 
306     try
307       {
308         String s = sn.toString(new NameComponent[] { a, b, c });
309         System.out.println(s);
310 
311         //NameComponent[] k = toName("a.k/b.k2/c/d/.");
312         //NameComponent[] k = toName("a.bc/.b/c.x");
313 
314         NameComponent[] k = sn.toName(s);
315         System.out.println("ToString");
316 
317         for (int i = 0; i < k.length; i++)
318           {
319             System.out.println(k [ i ].id + ":" + k [ i ].kind);
320           }
321       }
322     catch (InvalidName ex)
323       {
324         ex.printStackTrace();
325       }
326   }
327 
328 }
329