blob: 3fd7d4a65980785d30f60371578fb77418eef53e [file] [log] [blame]
package org.apache.yoko.util.cmsf;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.rmi.CORBA.Util;
public enum RepIds {
;
public interface Query {
public Query suffix(String suffix);
public Query codebase(String codebase);
public Class<?> toClass();
public String toClassName();
}
private static final class QueryImpl implements Query {
public final String repid;
public final String suffix;
public final String codebase;
private QueryImpl(String repid) {
this(Objects.requireNonNull(repid), "", null);
}
private QueryImpl(String repid, String suffix, String codebase) {
this.repid = repid;
this.suffix = suffix;
this.codebase = codebase;
}
@Override
public QueryImpl suffix(String suffix) {
return new QueryImpl(repid, Objects.requireNonNull(suffix), codebase);
}
@Override
public QueryImpl codebase(String codebase) {
return new QueryImpl(repid, suffix, codebase);
}
@Override
public Class<?> toClass() {
return RepIds.toClass(this);
}
@Override
public String toClassName() {
return RepIds.toClassName(this);
}
}
private static final Logger LOGGER = Logger.getLogger(RepIds.class.getName());
public static Query query(String repid) {
return new QueryImpl(repid);
}
private static Class<?> toClass(final QueryImpl query) {
final String repid = query.repid;
final String suffix = query.suffix;
final String codebase = query.codebase;
if (LOGGER.isLoggable(Level.FINE))
LOGGER.fine(String.format("Searching for class from repid \"%s\" using suffix \"%s\"", repid, suffix));
Class<?> result = null;
//Special case IDL:omg.org/CORBA/WStringValue:1.0
if ("IDL:omg.org/CORBA/WStringValue:1.0".equals(repid) && "".equals(suffix)) return String.class;
final String className = toClassName(query);
if (LOGGER.isLoggable(Level.FINE))
LOGGER.fine(String.format("Class name from repid \"%s\" using suffix \"%s\" is \"%s\"", repid, suffix, className));
if (className != null) {
try {
// get the appropriate class for the loading.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
result = Util.loadClass(className, codebase, loader);
} catch (ClassNotFoundException ex) {
if (LOGGER.isLoggable(Level.FINE))
LOGGER.fine(String.format("Class \"%s\" not found", className));
// ignore
}
}
return result;
}
private static final Pattern dotPattern = Pattern.compile(Pattern.quote("."));
private static final Pattern slashPattern = Pattern.compile(Pattern.quote("/"));
private static String toClassName(QueryImpl query) {
final String repid = query.repid;
final String suffix = query.suffix;
//Special case IDL:omg.org/CORBA/WStringValue:1.0
if ("IDL:omg.org/CORBA/WStringValue:1.0".equals(repid) && "".equals(suffix)) return String.class.getName();
String result = null;
if (repid.startsWith("IDL:")) {
result = idlToClassName(repid);
} else if (repid.startsWith("RMI:")) {
result = rmiToClassName(repid);
}
if (result != null) {
result += suffix;
result = removeUnicodeEscapes(result);
}
return result;
}
private static String rmiToClassName(final String repid) {
String result;
final int end = repid.indexOf (':', 4);
result = end < 0 ? repid.substring (4) : repid.substring (4, end);
return result;
}
private static String idlToClassName(final String repid) {
try {
final StringBuilder sb = new StringBuilder(repid.length());
final int end = repid.lastIndexOf(':');
String s = end < 0 ? repid.substring(4) : repid.substring(4, end);
//
// reverse order of dot-separated name components up
// till the first slash.
//
final int firstSlash = s.indexOf('/');
if (firstSlash > 0) {
String prefix = s.substring(0, firstSlash);
String[] elems = dotPattern.split(prefix);
Collections.reverse(Arrays.asList(elems)); //reverses the order in the underlying array - i.e. 'elems'
for (String elem: elems) {
sb.append(fixName(elem)).append('.');
}
s = s.substring(firstSlash + 1);
}
//
// Append slash-separated name components ...
//
for (String elem: slashPattern.split(s)) {
sb.append(fixName(elem)).append('.');
}
sb.deleteCharAt(sb.length() - 1); // eliminate final '.'
return sb.toString();
} catch (IndexOutOfBoundsException ex) {
// id has bad format
return null;
}
}
private static String removeUnicodeEscapes(String in) {
// if no escape sequences are in the string, this is easy
int escape = in.indexOf("\\U");
if (escape < 0) {
return in;
}
StringBuilder out = new StringBuilder(in.length());
int start = 0;
while (escape >= 0) {
out.append(in.substring(start, escape));
// step over the escape sequence
escape += 2;
int value = 0;
for (int i=0; i<4; i++) {
char ch = in.charAt(escape++);
switch (ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
value = (value << 4) + ch - '0';
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
value = (value << 4) + 10 + ch - 'a';
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
value = (value << 4) + 10 + ch - 'A';
break;
default:
// not sure what to do here. Just treat it as a 0 nibble
value = (value << 4);
}
}
// now append this as a char value
out.append((char)value);
// now step and find the next one
start = escape;
escape = in.indexOf("\\U", escape);
}
// don't forget the trailing segment
if (start < in.length()) {
out.append(in.substring(start));
}
return out.toString();
}
private static final Set<String> keywords = createStringSet(
"abstract", "assert", "boolean", "break", "byte", "case",
"catch", "char", "class", "clone", "const", "continue",
"default", "do", "double", "else", "equals", "extends",
"false", "final", "finalize", "finally", "float", "for",
"getClass", "goto", "hashCode", "if", "implements", "import",
"instanceof", "int", "interface", "long", "native", "new",
"notify", "notifyAll", "null", "package", "private",
"protected", "public", "return", "short", "static", "super",
"switch", "synchronized", "this", "throw", "throws",
"toString", "transient", "true", "try", "void", "volatile",
"wait", "while");
private static Set<String> createStringSet(String...strings) {
return Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(strings)));
}
private static final List<String> reservedSuffixes = createStringList(
"Helper", "Holder", "Operations", "POA",
"POATie", "Package", "ValueFactory");
private static List<String> createStringList(String...strings) {
return Collections.unmodifiableList(Arrays.asList(strings));
}
private static String fixName(String name) {
assert(name.indexOf('.') == -1); // Not for absolute names
int nameLen = name.length();
if (nameLen == 0)
return name;
if (keywords.contains(name)) return "_" + name;
//
// Prepend an underscore for each of the reserved suffixes
//
String result = name;
String curr = name;
OUTER_LOOP: while (true) {
for (String reservedSuffix: reservedSuffixes) {
if (curr.endsWith(reservedSuffix)) {
result = "_" + result;
int currLength = curr.length();
int resLength = reservedSuffix.length();
if (currLength == resLength)
return result;
curr = curr.substring(0, currLength - resLength);
continue OUTER_LOOP;
}
}
return result;
}
}
}