| 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; |
| } |
| } |
| } |