/*
* Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.wildfly.iiop.openjdk.naming.jndi;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import javax.naming.CompositeName;
import javax.naming.CompoundName;
import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.NameParser;
import javax.naming.NamingException;
import org.omg.CosNaming.NameComponent;
import org.wildfly.iiop.openjdk.logging.IIOPLogger;
/**
* Parsing routines for NameParser as well as COS Naming stringified names.
* This is used by CNCtx to create a NameComponent[] object and vice versa.
* It follows Section 4.5 of Interoperable Naming Service (INS) 98-10-11.
* In summary, the stringified form is a left-to-right, forward-slash
* separated name. id and kinds are separated by '.'. backslash is the
* escape character.
*
* @author Rosanna Lee
*/
public final class CNNameParser implements NameParser {
private static final Properties mySyntax = new Properties();
private static final char kindSeparator = '.';
private static final char compSeparator = '/';
private static final char escapeChar = '\\';
static {
mySyntax.put("jndi.syntax.direction", "left_to_right");
mySyntax.put("jndi.syntax.separator", "" + compSeparator);
mySyntax.put("jndi.syntax.escape", "" + escapeChar);
}
;
/**
* Constructs a new name parser for parsing names in INS syntax.
*/
public CNNameParser() {
}
/**
* Returns a CompoundName given a string in INS syntax.
*
* @param name The non-null string representation of the name.
* @return a non-null CompoundName
*/
public Name parse(String name) throws NamingException {
Vector comps = insStringToStringifiedComps(name);
return new CNCompoundName(comps.elements());
}
/**
* Creates a NameComponent[] from a Name structure.
* Used by CNCtx to convert the input Name arg into a NameComponent[].
*
* @param name a CompoundName or a CompositeName;
* each component must be the stringified form of a NameComponent.
*/
static NameComponent[] nameToCosName(Name name)
throws InvalidNameException {
int len = name.size();
if (len == 0) {
return new NameComponent[0];
}
NameComponent[] answer = new NameComponent[len];
for (int i = 0; i < len; i++) {
answer[i] = parseComponent(name.get(i));
}
return answer;
}
/**
* Returns the INS stringified form of a NameComponent[].
* Used by CNCtx.getNameInNamespace(), CNCompoundName.toString().
*/
static String cosNameToInsString(NameComponent[] cname) {
StringBuffer str = new StringBuffer();
for (int i = 0; i < cname.length; i++) {
if (i > 0) {
str.append(compSeparator);
}
str.append(stringifyComponent(cname[i]));
}
return str.toString();
}
/**
* Creates a CompositeName from a NameComponent[].
* Used by ExceptionMapper and CNBindingEnumeration to convert
* a NameComponent[] into a composite name.
*/
static Name cosNameToName(NameComponent[] cname) {
Name nm = new CompositeName();
for (int i = 0; cname != null && i < cname.length; i++) {
try {
nm.add(stringifyComponent(cname[i]));
} catch (InvalidNameException e) {
// ignore
}
}
return nm;
}
/**
* Converts an INS-syntax string name into a Vector in which
* each element of the vector contains a stringified form of
* a NameComponent.
*/
private static Vector insStringToStringifiedComps(String str)
throws InvalidNameException {
int len = str.length();
Vector components = new Vector(10);
char[] id = new char[len];
char[] kind = new char[len];
int idCount, kindCount;
boolean idMode;
for (int i = 0; i < len; ) {
idCount = kindCount = 0; // reset for new component
idMode = true; // always start off parsing id
while (i < len) {
if (str.charAt(i) == compSeparator) {
break;
} else if (str.charAt(i) == escapeChar) {
if (i + 1 >= len) {
throw IIOPLogger.ROOT_LOGGER.unescapedCharacter(str);
} else if (isMeta(str.charAt(i + 1))) {
++i; // skip escape and let meta through
if (idMode) {
id[idCount++] = str.charAt(i++);
} else {
kind[kindCount++] = str.charAt(i++);
}
} else {
throw IIOPLogger.ROOT_LOGGER.invalidEscapedCharacter(str);
}
} else if (idMode && str.charAt(i) == kindSeparator) {
// just look for the first kindSeparator
++i; // skip kind separator
idMode = false;
} else {
if (idMode) {
id[idCount++] = str.charAt(i++);
} else {
kind[kindCount++] = str.charAt(i++);
}
}
}
components.addElement(stringifyComponent(
new NameComponent(new String(id, 0, idCount),
new String(kind, 0, kindCount))));
if (i < len) {
++i; // skip separator
}
}
return components;
}
/**
* Return a NameComponent given its stringified form.
*/
private static NameComponent parseComponent(String compStr)
throws InvalidNameException {
NameComponent comp = new NameComponent();
int kindSep = -1;
int len = compStr.length();
int j = 0;
char[] newStr = new char[len];
boolean escaped = false;
// Find the kind separator
for (int i = 0; i < len && kindSep < 0; i++) {
if (escaped) {
newStr[j++] = compStr.charAt(i);
escaped = false;
} else if (compStr.charAt(i) == escapeChar) {
if (i + 1 >= len) {
throw IIOPLogger.ROOT_LOGGER.unescapedCharacter(compStr);
} else if (isMeta(compStr.charAt(i + 1))) {
escaped = true;
} else {
throw IIOPLogger.ROOT_LOGGER.invalidEscapedCharacter(compStr);
}
} else if (compStr.charAt(i) == kindSeparator) {
kindSep = i;
} else {
newStr[j++] = compStr.charAt(i);
}
}
// Set id
comp.id = new String(newStr, 0, j);
// Set kind
if (kindSep < 0) {
comp.kind = ""; // no kind separator
} else {
// unescape kind
j = 0;
escaped = false;
for (int i = kindSep + 1; i < len; i++) {
if (escaped) {
newStr[j++] = compStr.charAt(i);
escaped = false;
} else if (compStr.charAt(i) == escapeChar) {
if (i + 1 >= len) {
throw IIOPLogger.ROOT_LOGGER.unescapedCharacter(compStr);
} else if (isMeta(compStr.charAt(i + 1))) {
escaped = true;
} else {
throw IIOPLogger.ROOT_LOGGER.invalidEscapedCharacter(compStr);
}
} else {
newStr[j++] = compStr.charAt(i);
}
}
comp.kind = new String(newStr, 0, j);
}
return comp;
}
private static String stringifyComponent(NameComponent comp) {
StringBuffer one = new StringBuffer(escape(comp.id));
if (comp.kind != null && !comp.kind.equals("")) {
one.append(kindSeparator + escape(comp.kind));
}
if (one.length() == 0) {
return "" + kindSeparator; // if neither id nor kind specified
} else {
return one.toString();
}
}
/**
* Returns a string with '.', '\', '/' escaped. Used when
* stringifying the name into its INS stringified form.
*/
private static String escape(String str) {
if (str.indexOf(kindSeparator) < 0 &&
str.indexOf(compSeparator) < 0 &&
str.indexOf(escapeChar) < 0) {
return str; // no meta characters to escape
} else {
int len = str.length();
int j = 0;
char[] newStr = new char[len + len];
for (int i = 0; i < len; i++) {
if (isMeta(str.charAt(i))) {
newStr[j++] = escapeChar; // escape meta character
}
newStr[j++] = str.charAt(i);
}
return new String(newStr, 0, j);
}
}
/**
* In INS, there are three meta characters: '.', '/' and '\'.
*/
private static boolean isMeta(char ch) {
switch (ch) {
case kindSeparator:
case compSeparator:
case escapeChar:
return true;
}
return false;
}
/**
* An implementation of CompoundName that bypasses the parsing
* and stringifying code of the default CompoundName.
*/
static final class CNCompoundName extends CompoundName {
CNCompoundName(Enumeration enum_) {
super(enum_, CNNameParser.mySyntax);
}
public Object clone() {
return new CNCompoundName(getAll());
}
public Name getPrefix(int posn) {
Enumeration comps = super.getPrefix(posn).getAll();
return new CNCompoundName(comps);
}
public Name getSuffix(int posn) {
Enumeration comps = super.getSuffix(posn).getAll();
return new CNCompoundName(comps);
}
public String toString() {
try {
// Convert Name to NameComponent[] then stringify
return cosNameToInsString(nameToCosName(this));
} catch (InvalidNameException e) {
return super.toString();
}
}
private static final long serialVersionUID = -6599252802678482317L;
}
}