summaryrefslogtreecommitdiffstats
path: root/sca-java-1.x/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-1.x/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java')
-rw-r--r--sca-java-1.x/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java464
1 files changed, 464 insertions, 0 deletions
diff --git a/sca-java-1.x/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java b/sca-java-1.x/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java
new file mode 100644
index 0000000000..fe8698122c
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java
@@ -0,0 +1,464 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tuscany.sca.binding.ejb.java2idl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.rmi.Remote;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.WeakHashMap;
+
+import org.omg.CORBA.Any;
+
+/**
+ * This is a RMI/IIOP metadata conversion utility class.
+ */
+public class IDLUtil {
+
+ /**
+ * Return the IDL type name for the given class. Here we use the mapping for
+ * parameter types and return values.
+ */
+ public static String getTypeIDLName(Class cls) {
+ if (cls.isPrimitive())
+ return PrimitiveType.getPrimitiveType(cls).getIDLName();
+ if (cls.isArray()) {
+ int dimension = 0;
+ Class type = cls;
+ while (type.isArray()) {
+ dimension++;
+ type = type.getComponentType();
+ }
+ String baseName = getTypeIDLName(type);
+ int index = baseName.lastIndexOf("::");
+ String prefix = "";
+ String suffix = baseName;
+ if (index != -1) {
+ prefix = baseName.substring(0, index);
+ suffix = baseName.substring(index + 2);
+ }
+ String name = "::org::omg::boxedRMI" + prefix + "::seq" + dimension + "_" + suffix;
+ return name;
+ }
+
+ // special classes
+ if (cls == java.lang.String.class)
+ return "::CORBA::WStringValue";
+ if (cls == java.lang.Object.class)
+ return "::java::lang::_Object";
+ if (cls == java.lang.Class.class)
+ return "::javax::rmi::CORBA::ClassDesc";
+ if (cls == java.io.Serializable.class)
+ return "::java::io::Serializable";
+ if (cls == java.io.Externalizable.class)
+ return "::java::io::Externalizable";
+ if (cls == java.rmi.Remote.class)
+ return "::java::rmi::Remote";
+ if (cls == org.omg.CORBA.Object.class)
+ return "::CORBA::Object";
+ // remote interface?
+ if (cls.isInterface() && java.rmi.Remote.class.isAssignableFrom(cls)) {
+ InterfaceType ia = InterfaceType.getInterfaceType(cls);
+ return ia.getIDLModuleName() + "::" + ia.getIDLName();
+ }
+ // IDL interface?
+ if (cls.isInterface() && org.omg.CORBA.Object.class.isAssignableFrom(cls)
+ && org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(cls)) {
+ InterfaceType ia = InterfaceType.getInterfaceType(cls);
+ return ia.getIDLModuleName() + "::" + ia.getIDLName();
+ }
+ // exception?
+ if (Throwable.class.isAssignableFrom(cls)) {
+ if (Exception.class.isAssignableFrom(cls) && !RuntimeException.class.isAssignableFrom(cls)) {
+ ExceptionType ea = ExceptionType.getExceptionType(cls);
+ return ea.getIDLModuleName() + "::" + ea.getIDLName();
+ }
+ }
+ // got to be value
+ ValueType va = ValueType.getValueType(cls);
+ return va.getIDLModuleName() + "::" + va.getIDLName();
+ }
+
+ /**
+ * Check if this class is valid for RMI/IIOP mapping. This method will
+ * either throw an exception or return true.
+ */
+ public static boolean isValidRMIIIOP(Class cls) {
+ if (cls.isPrimitive())
+ return true;
+ if (cls.isArray())
+ return isValidRMIIIOP(cls.getComponentType());
+ // special interfaces
+ if (cls == Serializable.class || cls == Externalizable.class)
+ return true;
+ // interface?
+ if (cls.isInterface() && Remote.class.isAssignableFrom(cls)) {
+ InterfaceType.getInterfaceType(cls);
+ return true;
+ }
+ // exception?
+ if (Throwable.class.isAssignableFrom(cls)) {
+ if (Exception.class.isAssignableFrom(cls) && (!RuntimeException.class.isAssignableFrom(cls))) {
+ ExceptionType.getExceptionType(cls);
+ }
+ return true;
+ }
+ // special values
+ if (cls == Object.class || cls == String.class || cls == Class.class)
+ return true;
+ // got to be value
+ ValueType.getValueType(cls);
+ return true;
+ }
+
+ /**
+ * Insert a java primitive into an Any. The primitive is assumed to be
+ * wrapped in one of the primitive wrapper classes.
+ */
+ public static void insertAnyPrimitive(Any any, Object primitive) {
+ Class type = primitive.getClass();
+ if (type == Boolean.class)
+ any.insert_boolean(((Boolean)primitive).booleanValue());
+ else if (type == Character.class)
+ any.insert_wchar(((Character)primitive).charValue());
+ else if (type == Byte.class)
+ any.insert_octet(((Byte)primitive).byteValue());
+ else if (type == Short.class)
+ any.insert_short(((Short)primitive).shortValue());
+ else if (type == Integer.class)
+ any.insert_long(((Integer)primitive).intValue());
+ else if (type == Long.class)
+ any.insert_longlong(((Long)primitive).longValue());
+ else if (type == Float.class)
+ any.insert_float(((Float)primitive).floatValue());
+ else if (type == Double.class)
+ any.insert_double(((Double)primitive).doubleValue());
+ else
+ throw new IllegalArgumentException(type.getName() + "is not a primitive type");
+ }
+
+ /**
+ * Map Java name to IDL name, as per sections 1.3.2.3, 1.3.2.4 and 1.3.2.2.
+ * This only works for a single name component, without a qualifying dot.
+ */
+ public static String javaToIDLName(String name) {
+ if (name == null || "".equals(name))
+ throw new IllegalArgumentException("Illegal name: " + name);
+ if (name.indexOf('.') != -1)
+ throw new IllegalArgumentException("Qualified name is not supported: " + name);
+ StringBuffer res = new StringBuffer(name.length());
+ if (name.charAt(0) == '_')
+ res.append('J'); // 1.3.2.3
+ for (int i = 0; i < name.length(); ++i) {
+ char c = name.charAt(i);
+ if (isLegalIDLIdentifierChar(c))
+ res.append(c);
+ else
+ // 1.3.2.4
+ res.append('U').append(toHexString((int)c));
+ }
+ String s = res.toString();
+ if (isReservedIDLKeyword(s))
+ return "_" + s;
+ else
+ return s;
+ }
+
+ /**
+ * Return the IR global ID of the given class or interface. This is
+ * described in section 1.3.5.7.
+ */
+ public static String getIRIdentifier(Class cls) {
+ if (cls.isPrimitive())
+ throw new IllegalArgumentException("Primitive type doesn't have IR IDs.");
+ String result = (String)classIRIdentifierCache.get(cls);
+ if (result != null)
+ return result;
+ String name = cls.getName();
+ StringBuffer b = new StringBuffer("RMI:");
+ for (int i = 0; i < name.length(); ++i) {
+ char c = name.charAt(i);
+ if (c < 256)
+ b.append(c);
+ else
+ b.append("\\U").append(toHexString((int)c));
+ }
+ long clsHash = getClassHashCode(cls);
+ b.append(':').append(toHexString(clsHash));
+ ObjectStreamClass osClass = ObjectStreamClass.lookup(cls);
+ if (osClass != null) {
+ long serialVersionUID = osClass.getSerialVersionUID();
+ if (clsHash != serialVersionUID)
+ b.append(':').append(toHexString(serialVersionUID));
+ }
+ result = b.toString();
+ classIRIdentifierCache.put(cls, result);
+ return result;
+ }
+
+ /**
+ * A cache for calculated class hash codes.
+ */
+ private static Map classHashCodeCache = Collections.synchronizedMap(new WeakHashMap());
+ /**
+ * A cache for class IR identifiers.
+ */
+ private static Map classIRIdentifierCache = Collections.synchronizedMap(new WeakHashMap());
+ /**
+ * Reserved IDL keywords. Section 1.3.2.2 says that Java identifiers with
+ * these names should have prepended an underscore.
+ */
+
+ private static final Set reservedIDLKeywordSet = new HashSet();
+ static {
+ String[] reservedIDLKeywords = new String[] {"abstract", "any", "attribute", "boolean", "case", "char",
+ "const", "context", "custom", "default", "double", "exception",
+ "enum", "factory", "FALSE", "fixed", "float", "in", "inout",
+ "interface", "local", "long", "module", "native", "Object",
+ "octet", "oneway", "out", "private", "public", "raises",
+ "readonly", "sequence", "short", "string", "struct", "supports",
+ "switch", "TRUE", "truncatable", "typedef", "unsigned", "union",
+ "ValueBase", "valuetype", "void", "wchar", "wstring"};
+ for (int i = 0; i < reservedIDLKeywords.length; i++)
+ reservedIDLKeywordSet.add(reservedIDLKeywords[i]);
+ }
+
+ /**
+ * Convert an integer to a 16-digit hex string.
+ */
+ private static String toHexString(int i) {
+ String s = Integer.toHexString(i).toUpperCase();
+ if (s.length() < 8)
+ return "00000000".substring(8 - s.length()) + s;
+ else
+ return s;
+ }
+
+ /**
+ * Convert a long to a 16-digit hex string.
+ */
+ private static String toHexString(long l) {
+ String s = Long.toHexString(l).toUpperCase();
+ if (s.length() < 16)
+ return "0000000000000000".substring(16 - s.length()) + s;
+ else
+ return s;
+ }
+
+ /**
+ * Determine if the argument is a reserved IDL keyword.
+ */
+ private static boolean isReservedIDLKeyword(String s) {
+ return reservedIDLKeywordSet.contains(s);
+ /*
+ * // TODO: faster lookup for (int i = 0; i <
+ * reservedIDLKeywords.length; ++i) if
+ * (reservedIDLKeywords[i].equals(s)) return true; return false;
+ */
+ }
+
+ /**
+ * Determine if a <code>char</code> is a legal IDL identifier character.
+ */
+ private static boolean isLegalIDLIdentifierChar(char c) {
+ if (c >= 0x61 && c <= 0x7a)
+ return true; // lower case letter
+ if (c >= 0x30 && c <= 0x39)
+ return true; // digit
+ if (c >= 0x41 && c <= 0x5a)
+ return true; // upper case letter
+ if (c == '_')
+ return true; // underscore
+ return false;
+ }
+
+ /**
+ * Return the class hash code, as specified in "The Common Object Request
+ * Broker: Architecture and Specification" (01-02-33), section 10.6.2.
+ */
+ static long getClassHashCode(Class cls) {
+ // The simple cases
+ if (cls.isInterface())
+ return 0;
+ if (!Serializable.class.isAssignableFrom(cls))
+ return 0;
+ if (Externalizable.class.isAssignableFrom(cls))
+ return 1;
+ // Try cache
+ Long l = (Long)classHashCodeCache.get(cls);
+ if (l != null)
+ return l.longValue();
+ // Has to calculate the hash.
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
+ DataOutputStream dos = new DataOutputStream(baos);
+ // Step 1
+ Class superClass = cls.getSuperclass();
+ if (superClass != null && superClass != Object.class) {
+ try {
+ dos.writeLong(getClassHashCode(superClass));
+ } catch (IOException ex) {
+ throw new RuntimeException("Unexpected IOException: " + ex);
+ }
+ }
+ // Step 2
+ boolean hasWriteObject = false;
+ try {
+ Method m;
+ int mods;
+ m = cls.getDeclaredMethod("writeObject", new Class[] {ObjectOutputStream.class});
+ mods = m.getModifiers();
+ if (!Modifier.isPrivate(mods) && !Modifier.isStatic(mods))
+ hasWriteObject = true;
+ } catch (NoSuchMethodException ex) {
+ // ignore
+ }
+ try {
+ dos.writeInt(hasWriteObject ? 2 : 1);
+ } catch (IOException ex) {
+ throw new RuntimeException("Unexpected IOException: " + ex);
+ }
+ // Step 3
+ Field[] fields = cls.getDeclaredFields();
+ SortedSet set = new TreeSet(new FieldComparator());
+ for (int i = 0; i < fields.length; ++i) {
+ int mods = fields[i].getModifiers();
+ if (!Modifier.isStatic(mods) && !Modifier.isTransient(mods))
+ set.add(fields[i]);
+ }
+ Iterator iter = set.iterator();
+ try {
+ while (iter.hasNext()) {
+ Field f = (Field)iter.next();
+ dos.writeUTF(f.getName());
+ dos.writeUTF(getSignature(f.getType()));
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException("Unexpected IOException: " + ex);
+ }
+ // Convert to byte[]
+ try {
+ dos.flush();
+ } catch (IOException ex) {
+ throw new RuntimeException("Unexpected IOException: " + ex);
+ }
+ byte[] bytes = baos.toByteArray();
+ // Calculate SHA digest
+ MessageDigest digest;
+ try {
+ digest = MessageDigest.getInstance("SHA");
+ } catch (NoSuchAlgorithmException ex) {
+ throw new RuntimeException("No SHA MEssageDigest: " + ex);
+ }
+ digest.update(bytes);
+ byte[] sha = digest.digest();
+ // Calculate hash as per section 10.6.2
+ long hash = 0;
+ for (int i = 0; i < Math.min(8, sha.length); i++) {
+ hash += (long)(sha[i] & 255) << (i * 8);
+ }
+ // Save in cache
+ classHashCodeCache.put(cls, new Long(hash));
+ return hash;
+ }
+
+ /**
+ * Calculate the signature of a class, according to the Java VM
+ * specification, section 4.3.2.
+ */
+ private static String getSignature(Class cls) {
+ if (cls.isArray())
+ return "[" + cls.getComponentType();
+ if (cls.isPrimitive()) {
+ if (cls == Byte.TYPE)
+ return "B";
+ if (cls == Character.TYPE)
+ return "C";
+ if (cls == Double.TYPE)
+ return "D";
+ if (cls == Float.TYPE)
+ return "F";
+ if (cls == Integer.TYPE)
+ return "I";
+ if (cls == Long.TYPE)
+ return "J";
+ if (cls == Short.TYPE)
+ return "S";
+ if (cls == Boolean.TYPE)
+ return "Z";
+ throw new RuntimeException("Unknown primitive class.");
+ }
+ return "L" + cls.getName().replace('.', '/') + ";";
+ }
+
+ /**
+ * Handle mappings for primitive types, as per section 1.3.3.
+ */
+ static String primitiveTypeIDLName(Class type) {
+ if (type == Void.TYPE)
+ return "void";
+ if (type == Boolean.TYPE)
+ return "boolean";
+ if (type == Character.TYPE)
+ return "wchar";
+ if (type == Byte.TYPE)
+ return "octet";
+ if (type == Short.TYPE)
+ return "short";
+ if (type == Integer.TYPE)
+ return "long";
+ if (type == Long.TYPE)
+ return "long long";
+ if (type == Float.TYPE)
+ return "float";
+ if (type == Double.TYPE)
+ return "double";
+ throw new IllegalArgumentException(type + "is not a primitive type.");
+ }
+
+ /**
+ * A <code>Comparator</code> for <code>Field</code>s, ordering the
+ * fields according to the lexicographic ordering of their Java names.
+ */
+ private static class FieldComparator implements Comparator {
+ public int compare(Object o1, Object o2) {
+ if (o1 == o2)
+ return 0;
+ String n1 = ((Field)o1).getName();
+ String n2 = ((Field)o2).getName();
+ return n1.compareTo(n2);
+ }
+ }
+}