blob: 870658404c43292bf52db7502cf1d24aa488d3e6 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2003 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.jndi.cosnaming;
27
28import javax.naming.*;
29import java.util.Properties;
30import java.util.Vector;
31import java.util.Enumeration;
32
33import org.omg.CosNaming.NameComponent;
34
35/**
36 * Parsing routines for NameParser as well as COS Naming stringified names.
37 * This is used by CNCtx to create a NameComponent[] object and vice versa.
38 * It follows Section 4.5 of Interoperable Naming Service (INS) 98-10-11.
39 * In summary, the stringified form is a left-to-right, forward-slash
40 * separated name. id and kinds are separated by '.'. backslash is the
41 * escape character.
42 *
43 * @author Rosanna Lee
44 */
45
46final public class CNNameParser implements NameParser {
47
48 private static final Properties mySyntax = new Properties();
49 private static final char kindSeparator = '.';
50 private static final char compSeparator = '/';
51 private static final char escapeChar = '\\';
52 static {
53 mySyntax.put("jndi.syntax.direction", "left_to_right");
54 mySyntax.put("jndi.syntax.separator", ""+compSeparator);
55 mySyntax.put("jndi.syntax.escape", ""+escapeChar);
56 };
57
58 /**
59 * Constructs a new name parser for parsing names in INS syntax.
60 */
61 public CNNameParser() {
62 }
63
64 /**
65 * Returns a CompoundName given a string in INS syntax.
66 * @param name The non-null string representation of the name.
67 * @return a non-null CompoundName
68 */
69 public Name parse(String name) throws NamingException {
70 Vector comps = insStringToStringifiedComps(name);
71 return new CNCompoundName(comps.elements());
72 }
73
74 /**
75 * Creates a NameComponent[] from a Name structure.
76 * Used by CNCtx to convert the input Name arg into a NameComponent[].
77 * @param a CompoundName or a CompositeName;
78 * each component must be the stringified form of a NameComponent.
79 */
80 static NameComponent[] nameToCosName(Name name)
81 throws InvalidNameException {
82 int len = name.size();
83 if (len == 0) {
84 return new NameComponent[0];
85 }
86
87 NameComponent[] answer = new NameComponent[len];
88 for (int i = 0; i < len; i++) {
89 answer[i] = parseComponent(name.get(i));
90 }
91 return answer;
92 }
93
94 /**
95 * Returns the INS stringified form of a NameComponent[].
96 * Used by CNCtx.getNameInNamespace(), CNCompoundName.toString().
97 */
98 static String cosNameToInsString(NameComponent[] cname) {
99 StringBuffer str = new StringBuffer();
100 for ( int i = 0; i < cname.length; i++) {
101 if ( i > 0) {
102 str.append(compSeparator);
103 }
104 str.append(stringifyComponent(cname[i]));
105 }
106 return str.toString();
107 }
108
109 /**
110 * Creates a CompositeName from a NameComponent[].
111 * Used by ExceptionMapper and CNBindingEnumeration to convert
112 * a NameComponent[] into a composite name.
113 */
114 static Name cosNameToName(NameComponent[] cname) {
115 Name nm = new CompositeName();
116 for ( int i = 0; cname != null && i < cname.length; i++) {
117 try {
118 nm.add(stringifyComponent(cname[i]));
119 } catch (InvalidNameException e) {
120 // ignore
121 }
122 }
123 return nm;
124 }
125
126 /**
127 * Converts an INS-syntax string name into a Vector in which
128 * each element of the vector contains a stringified form of
129 * a NameComponent.
130 */
131 private static Vector insStringToStringifiedComps(String str)
132 throws InvalidNameException {
133
134 int len = str.length();
135 Vector components = new Vector(10);
136 char[] id = new char[len];
137 char[] kind = new char[len];
138 int idCount, kindCount;
139 boolean idMode;
140 for (int i = 0; i < len; ) {
141 idCount = kindCount = 0; // reset for new component
142 idMode = true; // always start off parsing id
143 while (i < len) {
144 if (str.charAt(i) == compSeparator) {
145 break;
146
147 } else if (str.charAt(i) == escapeChar) {
148 if (i + 1 >= len) {
149 throw new InvalidNameException(str +
150 ": unescaped \\ at end of component");
151 } else if (isMeta(str.charAt(i+1))) {
152 ++i; // skip escape and let meta through
153 if (idMode) {
154 id[idCount++] = str.charAt(i++);
155 } else {
156 kind[kindCount++] = str.charAt(i++);
157 }
158 } else {
159 throw new InvalidNameException(str +
160 ": invalid character being escaped");
161 }
162
163 } else if (idMode && str.charAt(i) == kindSeparator) {
164 // just look for the first kindSeparator
165 ++i; // skip kind separator
166 idMode = false;
167
168 } else {
169 if (idMode) {
170 id[idCount++] = str.charAt(i++);
171 } else {
172 kind[kindCount++] = str.charAt(i++);
173 }
174 }
175 }
176 components.addElement(stringifyComponent(
177 new NameComponent(new String(id, 0, idCount),
178 new String(kind, 0, kindCount))));
179
180 if (i < len) {
181 ++i; // skip separator
182 }
183 }
184
185 return components;
186 }
187
188 /**
189 * Return a NameComponent given its stringified form.
190 */
191 private static NameComponent parseComponent(String compStr)
192 throws InvalidNameException {
193 NameComponent comp = new NameComponent();
194 int kindSep = -1;
195 int len = compStr.length();
196
197 int j = 0;
198 char[] newStr = new char[len];
199 boolean escaped = false;
200
201 // Find the kind separator
202 for (int i = 0; i < len && kindSep < 0; i++) {
203 if (escaped) {
204 newStr[j++] = compStr.charAt(i);
205 escaped = false;
206 } else if (compStr.charAt(i) == escapeChar) {
207 if (i + 1 >= len) {
208 throw new InvalidNameException(compStr +
209 ": unescaped \\ at end of component");
210 } else if (isMeta(compStr.charAt(i+1))) {
211 escaped = true;
212 } else {
213 throw new InvalidNameException(compStr +
214 ": invalid character being escaped");
215 }
216 } else if (compStr.charAt(i) == kindSeparator) {
217 kindSep = i;
218 } else {
219 newStr[j++] = compStr.charAt(i);
220 }
221 }
222
223 // Set id
224 comp.id = new String(newStr, 0, j);
225
226 // Set kind
227 if (kindSep < 0) {
228 comp.kind = ""; // no kind separator
229 } else {
230 // unescape kind
231 j = 0;
232 escaped = false;
233 for (int i = kindSep+1; i < len; i++) {
234 if (escaped) {
235 newStr[j++] = compStr.charAt(i);
236 escaped = false;
237 } else if (compStr.charAt(i) == escapeChar) {
238 if (i + 1 >= len) {
239 throw new InvalidNameException(compStr +
240 ": unescaped \\ at end of component");
241 } else if (isMeta(compStr.charAt(i+1))) {
242 escaped = true;
243 } else {
244 throw new InvalidNameException(compStr +
245 ": invalid character being escaped");
246 }
247 } else {
248 newStr[j++] = compStr.charAt(i);
249 }
250 }
251 comp.kind = new String(newStr, 0, j);
252 }
253 return comp;
254 }
255
256 private static String stringifyComponent(NameComponent comp) {
257 StringBuffer one = new StringBuffer(escape(comp.id));
258 if (comp.kind != null && !comp.kind.equals("")) {
259 one.append(kindSeparator + escape(comp.kind));
260 }
261 if (one.length() == 0) {
262 return ""+kindSeparator; // if neither id nor kind specified
263 } else {
264 return one.toString();
265 }
266 }
267
268 /**
269 * Returns a string with '.', '\', '/' escaped. Used when
270 * stringifying the name into its INS stringified form.
271 */
272 private static String escape(String str) {
273 if (str.indexOf(kindSeparator) < 0 &&
274 str.indexOf(compSeparator) < 0 &&
275 str.indexOf(escapeChar) < 0) {
276 return str; // no meta characters to escape
277 } else {
278 int len = str.length();
279 int j = 0;
280 char[] newStr = new char[len+len];
281 for (int i = 0; i < len; i++) {
282 if (isMeta(str.charAt(i))) {
283 newStr[j++] = escapeChar; // escape meta character
284 }
285 newStr[j++] = str.charAt(i);
286 }
287 return new String(newStr, 0, j);
288 }
289 }
290
291 /**
292 * In INS, there are three meta characters: '.', '/' and '\'.
293 */
294 private static boolean isMeta(char ch) {
295 switch (ch) {
296 case kindSeparator:
297 case compSeparator:
298 case escapeChar:
299 return true;
300 }
301 return false;
302 }
303
304 /**
305 * An implementation of CompoundName that bypasses the parsing
306 * and stringifying code of the default CompoundName.
307 */
308 static final class CNCompoundName extends CompoundName {
309 CNCompoundName(Enumeration enum_) {
310 super(enum_, CNNameParser.mySyntax);
311 }
312
313 public Object clone() {
314 return new CNCompoundName(getAll());
315 }
316
317 public Name getPrefix(int posn) {
318 Enumeration comps = super.getPrefix(posn).getAll();
319 return new CNCompoundName(comps);
320 }
321
322 public Name getSuffix(int posn) {
323 Enumeration comps = super.getSuffix(posn).getAll();
324 return new CNCompoundName(comps);
325 }
326
327 public String toString() {
328 try {
329 // Convert Name to NameComponent[] then stringify
330 return cosNameToInsString(nameToCosName(this));
331 } catch (InvalidNameException e) {
332 return super.toString();
333 }
334 }
335
336 private static final long serialVersionUID = -6599252802678482317L;
337 }
338
339// for testing only
340/*
341 private static void print(String input) {
342 try {
343 System.out.println("\n >>>>>> input: " + input);
344
345 System.out.println("--Compound Name: ");
346 NameParser parser = new CNNameParser();
347 Name name = parser.parse(input);
348 for (int i = 0; i < name.size(); i++) {
349 System.out.println("\t" + i + ": " + name.get(i));
350 NameComponent cp = parseComponent(name.get(i));
351 System.out.println("\t\t" + "id: " + cp.id + ";kind: " + cp.kind);
352 }
353 System.out.println("\t" + name.toString());
354
355 System.out.println("--Composite Name: ");
356 Name composite = new CompositeName(input);
357 for (int i = 0; i < composite.size(); i++) {
358 System.out.println("\t" + i+": " + composite.get(i));
359 }
360 System.out.println("\t" + composite.toString());
361
362 System.out.println("--Composite To NameComponent");
363 NameComponent[] names = nameToCosName(composite);
364 for (int i = 0; i < composite.size(); i++) {
365 System.out.println("\t" + i+": id: " + names[i].id + "; kind: " + names[i].kind);
366 }
367 System.out.println("\t" + cosNameToInsString(names));
368 } catch (NamingException e) {
369 System.out.println(e);
370 }
371 }
372
373 private static void checkName(Name name, String[] comps) throws Exception {
374 if (name.size() != comps.length) {
375 throw new Exception(
376 "test failed; incorrect component count in " + name + "; " +
377 "expecting " + comps.length + " got " + name.size());
378 }
379 for (int i = 0; i < name.size(); i++) {
380 if (!comps[i].equals(name.get(i))) {
381 throw new Exception (
382 "test failed; invalid component in " + name + "; " +
383 "expecting '" + comps[i] + "' got '" + name.get(i) + "'");
384 }
385 }
386 }
387
388 private static void checkCompound(NameParser parser,
389 String input, String[] comps) throws Exception {
390 checkName(parser.parse(input), comps);
391 }
392
393 private static void checkComposite(String input, String[] comps)
394 throws Exception {
395 checkName(new CompositeName(input), comps);
396 }
397
398 private static String[] compounds = {
399 "a/b/c",
400 "a.b/c.d",
401 "a",
402 ".",
403 "a.",
404 "c.d",
405 ".e",
406 "a/x\\/y\\/z/b",
407 "a\\.b.c\\.d/e.f",
408 "a/b\\\\/c",
409 "x\\\\.y",
410 "x\\.y",
411 "x.\\\\y",
412 "x.y\\\\",
413 "\\\\x.y",
414 "a.b\\.c/d"
415 };
416 private static String[][] compoundComps = {
417 {"a", "b", "c"},
418 {"a.b", "c.d"},
419 {"a"},
420 {"."},
421 {"a"},
422 {"c.d"},
423 {".e"},
424 {"a", "x\\/y\\/z", "b"},
425 {"a\\.b.c\\.d", "e.f"},
426 {"a", "b\\\\", "c"},
427 {"x\\\\.y"},
428 {"x\\.y"},
429 {"x.\\\\y"},
430 {"x.y\\\\"},
431 {"\\\\x.y"},
432 {"a.b\\.c", "d"},
433 };
434
435 private static String[] composites = {
436 "a/b/c",
437 "a.b/c.d",
438 "a",
439 ".",
440 "a.",
441 "c.d",
442 ".e",
443 "a/x\\\\\\/y\\\\\\/z/b",
444 "a\\\\.b.c\\\\.d/e.f",
445 "a/b\\\\\\\\/c",
446 "x\\\\\\.y",
447 "x\\\\.y",
448 "x.\\\\\\\\y",
449 "x.y\\\\\\\\",
450 "\\\\\\\\x.y"
451 };
452
453 private static String[][] compositeComps = {
454 {"a", "b", "c"},
455 {"a.b", "c.d"},
456 {"a"},
457 {"."},
458 {"a."}, // unlike compound, kind sep is not consumed
459 {"c.d"},
460 {".e"},
461 {"a", "x\\/y\\/z", "b"},
462 {"a\\.b.c\\.d", "e.f"},
463 {"a", "b\\\\", "c"},
464 {"x\\\\.y"},
465 {"x\\.y"},
466 {"x.\\\\y"},
467 {"x.y\\\\"},
468 {"\\\\x.y"}
469 };
470
471 public static void main(String[] args) throws Exception {
472 if (args.length > 0) {
473 for (int i = 0; i < args.length; i++) {
474 print(args[0]);
475 }
476 } else {
477 print("x\\\\.y");
478 print("x\\.y");
479 print("x.\\\\y");
480 print("x.y\\\\");
481 print("\\\\x.y");
482 }
483
484 NameParser parser = new com.sun.jndi.cosnaming.CNNameParser();
485 for (int i = 0; i < compounds.length; i++) {
486 checkCompound(parser, compounds[i], compoundComps[i]);
487 }
488 for (int i = 0; i < composites.length; i++) {
489 checkComposite(composites[i], compositeComps[i]);
490 }
491
492 System.out.println("hardwire");
493 NameComponent[] foo = new NameComponent[1];
494 foo[0] = new NameComponent("foo\\", "bar");
495
496 System.out.println(cosNameToInsString(foo));
497 System.out.println(cosNameToName(foo));
498 }
499*/
500}