diff options
Diffstat (limited to 'sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl')
17 files changed, 2943 insertions, 0 deletions
diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/AttributeMode.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/AttributeMode.java new file mode 100644 index 0000000000..437debd2e4 --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/AttributeMode.java @@ -0,0 +1,62 @@ +/* + * 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.ObjectStreamException; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.portable.IDLEntity; + +/** + * Mode of an IDL attribute + */ +public final class AttributeMode implements IDLEntity { + private static final long serialVersionUID = 4193442157999151834L; + + private int value; + + public static final int _ATTR_NORMAL = 0; + + public static final AttributeMode ATTR_NORMAL = new AttributeMode(_ATTR_NORMAL); + + public static final int _ATTR_READONLY = 1; + + public static final AttributeMode ATTR_READONLY = new AttributeMode(_ATTR_READONLY); + + public int value() { + return value; + } + + public static AttributeMode from_int(int i) { + switch (i) { + case _ATTR_NORMAL: + return ATTR_NORMAL; + case _ATTR_READONLY: + return ATTR_READONLY; + } + throw new BAD_PARAM(); + } + + private AttributeMode(int i) { + value = i; + } + + Object readResolve() throws ObjectStreamException { + return from_int(value()); + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/AttributeType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/AttributeType.java new file mode 100644 index 0000000000..0aa94b087e --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/AttributeType.java @@ -0,0 +1,136 @@ +/* + * 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.lang.reflect.Method; +import java.rmi.Remote; + +/** + * IDL Attribute + */ +public class AttributeType extends IDLType { + + /** + * Attribute mode. + */ + private AttributeMode mode; + + /** + * Read Method. + */ + private Method readMethod = null; + /** + * Write Method. This is null for read-only attributes. + */ + private Method writeMethod = null; + /** + * Read method type. + */ + private OperationType readOperationType = null; + /** + * Write method type. This is null for read-only attributes. + */ + private OperationType writeOperationType = null; + + /** + * Create an attribute type. + */ + private AttributeType(String javaName, AttributeMode mode, Method readMethod, Method writeMethod) { + super(IDLUtil.javaToIDLName(javaName), javaName); + this.mode = mode; + // this.cls = readMethod.getReturnType(); + this.readMethod = readMethod; + this.writeMethod = writeMethod; + // Only do operation type if the attribute is in a remote interface. + if (readMethod.getDeclaringClass().isInterface() && Remote.class.isAssignableFrom(readMethod + .getDeclaringClass())) { + readOperationType = new OperationType(readMethod); + if (writeMethod != null) + writeOperationType = new OperationType(writeMethod); + setIDLName(getIDLName()); // Fixup operation names + } + } + + /** + * Create an attribute type for a read-only attribute. + */ + AttributeType(String javaName, Method accessor) { + this(javaName, AttributeMode.ATTR_READONLY, accessor, null); + } + + /** + * Create an attribute type for a read-write attribute. + */ + AttributeType(String javaName, Method accessor, Method mutator) { + this(javaName, AttributeMode.ATTR_NORMAL, accessor, mutator); + } + + /** + * Return the attribute mode. + */ + public AttributeMode getMode() { + return mode; + } + + /** + * Return the accessor method + */ + public Method getReadMethod() { + return readMethod; + } + + /** + * Return the mutator method + */ + public Method getWriteMethod() { + return writeMethod; + } + + /** + * Return the accessor operation type + */ + public OperationType getReadOperationType() { + return readOperationType; + } + + /** + * Return the mutator operation type + */ + public OperationType getWriteOperationType() { + return writeOperationType; + } + + /** + * Set the unqualified IDL name. This also sets the names of the associated + * operations. + */ + void setIDLName(String idlName) { + super.setIDLName(idlName); + // If the first char is an uppercase letter and the second char is not + // an uppercase letter, then convert the first char to lowercase. + char ch0 = idlName.charAt(0); + if (Character.isUpperCase(ch0) && (idlName.length() <= 1 || (!Character.isUpperCase(idlName.charAt(1))))) { + idlName = Character.toLowerCase(ch0) + idlName.substring(1); + } + if (readOperationType != null) + readOperationType.setIDLName("_get_" + idlName); + if (writeOperationType != null) + writeOperationType.setIDLName("_set_" + idlName); + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ClassType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ClassType.java new file mode 100644 index 0000000000..b6e2dba87e --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ClassType.java @@ -0,0 +1,61 @@ +/* + * 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; + +/** + * IDL types. + */ +public class ClassType extends IDLType { + + /** + * java class. + */ + protected Class javaClass; + + private static String getJavaName(Class cls) { + if (cls == null) + throw new IllegalArgumentException("Class cannot be null."); + String s = cls.getName(); + int index = s.lastIndexOf('.'); + if (index == -1) + return s; + else + return s.substring(index + 1); + } + + public ClassType(Class cls, String idlName, String javaName) { + super(idlName, javaName); + this.javaClass = cls; + } + + public ClassType(Class cls, String javaName) { + this(cls, IDLUtil.javaToIDLName(javaName), javaName); + } + + public ClassType(Class cls) { + this(cls, getJavaName(cls)); + } + + /** + * Return java class. + */ + public Class getJavaClass() { + return javaClass; + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ConstantType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ConstantType.java new file mode 100644 index 0000000000..5a6cc78317 --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ConstantType.java @@ -0,0 +1,68 @@ +/* + * 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 org.omg.CORBA.Any; + +/** + * IDL Constant + */ +public class ConstantType extends IDLType { + + /** + * Java type of constant. + */ + private Class type; + /** + * The value of the constant. + */ + private Object value; + + ConstantType(String javaName, Class type, Object value) { + super(javaName); + if (type == void.class || (!type.isPrimitive()) && type != java.lang.String.class) + throw new IllegalArgumentException("Illegal type for constant: " + type.getName()); + this.type = type; + this.value = value; + } + + /** + * Return my Java type. + */ + public Class getType() { + return type; + } + + /** + * Return my value. + */ + public Object getValue() { + return value; + } + + /** + * Insert the constant value into the argument Any. + */ + public void insertValue(Any any) { + if (type == String.class) + any.insert_wstring((String)value); // 1.3.5.10 Map to wstring + else + IDLUtil.insertAnyPrimitive(any, value); + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ContainerType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ContainerType.java new file mode 100644 index 0000000000..18216db742 --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ContainerType.java @@ -0,0 +1,791 @@ +/* + * 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.Externalizable; +import java.io.ObjectStreamClass; +import java.io.Serializable; +import java.lang.ref.SoftReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; + +/** + * Common base class of ValueType and InterfaceType. + */ +public abstract class ContainerType extends ClassType { + + /** Flags a method as overloaded. */ + protected final byte M_OVERLOADED = 1; + /** Flags a method as the accessor of a read-write property. */ + protected final byte M_READ = 2; + /** Flags a method as the mutator of a read-write property. */ + protected final byte M_WRITE = 4; + /** Flags a method as the accessor of a read-only property. */ + protected final byte M_READONLY = 8; + /** Flags a method as being inherited. */ + protected final byte M_INHERITED = 16; + /** + * Flags a method as being the writeObject() method used for serialization. + */ + protected final byte M_WRITEOBJECT = 32; + /** Flags a field as being a constant (public final static). */ + protected final byte F_CONSTANT = 1; + /** + * Flags a field as being the special <code> public final static + * java.io.ObjectStreamField[] serialPersistentFields</code> + * field. + */ + protected final byte F_SPFFIELD = 2; + + /** + * Array of all java methods. + */ + protected Method[] methods; + /** + * Array with flags for all java methods. + */ + protected byte[] m_flags; + /** + * Index of the mutator for read-write attributes. Only entries + * <code>i</code> where <code>(m_flags[i]&M_READ) != 0</code> are used. + * These entries contain the index of the mutator method corresponding to + * the accessor method. + */ + protected int[] setters; + /** + * Array of all java fields. + */ + protected Field[] fields; + /** + * Array with flags for all java fields. + */ + protected byte[] f_flags; + /** + * The class hash code, as specified in "The Common Object Request Broker: + * Architecture and Specification" (01-02-33), section 10.6.2. + */ + protected long classHashCode = 0; + /** + * The repository ID. This is in the RMI hashed format, like + * "RMI:java.util.Hashtable:C03324C0EA357270:13BB0F25214AE4B8". + */ + protected String repositoryId; + /** + * The prefix and postfix of members repository ID. These are used to + * calculate member repository IDs and are like "RMI:java.util.Hashtable." + * and ":C03324C0EA357270:13BB0F25214AE4B8". + */ + protected String memberPrefix, memberPostfix; + /** + * Array of type of the interfaces implemented/extended here. + */ + protected InterfaceType[] interfaces; + /** + * Array of type of the abstract base valuetypes implemented/extended here. + */ + protected ValueType[] abstractBaseValuetypes; + /** + * Array of attributes. + */ + protected AttributeType[] attributes; + /** + * Array of Constants. + */ + protected ConstantType[] constants; + /** + * Array of operations. + */ + protected OperationType[] operations; + + /** + * A cache for the fully qualified IDL name of the IDL module we belong to. + */ + private String idlModuleName = null; + + protected ContainerType(Class cls) { + super(cls); + if (cls == java.lang.Object.class || cls == java.io.Serializable.class || cls == java.io.Externalizable.class) + throw new IllegalArgumentException("Cannot parse special class: " + cls.getName()); + this.javaClass = cls; + } + + protected void parse() { + parseInterfaces(); + parseMethods(); + parseFields(); + calculateClassHashCode(); + calculateRepositoryId(); + parseAttributes(); + parseConstants(); + parseOperations(); + fixupOverloadedOperationNames(); + } + + /** + * Return the interfaces. + */ + public InterfaceType[] getInterfaces() { + return (InterfaceType[])interfaces.clone(); + } + + /** + * Return the abstract base valuetypes. + */ + public ValueType[] getAbstractBaseValuetypes() { + return (ValueType[])abstractBaseValuetypes.clone(); + } + + /** + * Return the attributes. + */ + public AttributeType[] getAttributes() { + return (AttributeType[])attributes.clone(); + } + + /** + * Return the constants. + */ + public ConstantType[] getConstants() { + return (ConstantType[])constants.clone(); + } + + /** + * Return the operations. + */ + public OperationType[] getOperations() { + return (OperationType[])operations.clone(); + } + + /** + * Return the repository ID. + */ + public String getRepositoryId() { + return repositoryId; + } + + /** + * Return a repository ID for a member. + * + * @param memberName The Java name of the member. + */ + public String getMemberRepositoryId(String memberName) { + return memberPrefix + escapeIRName(memberName) + memberPostfix; + } + + /** + * Return the fully qualified IDL module name that this type should be + * placed in. + */ + public String getIDLModuleName() { + if (idlModuleName == null) { + String pkgName = javaClass.getPackage().getName(); + StringBuffer b = new StringBuffer(); + while (!"".equals(pkgName)) { + int idx = pkgName.indexOf('.'); + String n = (idx == -1) ? pkgName : pkgName.substring(0, idx); + b.append("::").append(IDLUtil.javaToIDLName(n)); + pkgName = (idx == -1) ? "" : pkgName.substring(idx + 1); + } + idlModuleName = b.toString(); + } + return idlModuleName; + } + + // Protected ----------------------------------------------------- + /** + * Convert an integer to a 16-digit hex string. + */ + protected String toHexString(int i) { + String s = Integer.toHexString(i).toUpperCase(); + if (s.length() < 8) + return "00000000".substring(0, 8 - s.length()) + s; + else + return s; + } + + /** + * Convert a long to a 16-digit hex string. + */ + protected String toHexString(long l) { + String s = Long.toHexString(l).toUpperCase(); + if (s.length() < 16) + return "0000000000000000".substring(0, 16 - s.length()) + s; + else + return s; + } + + /** + * Check if a method is an accessor. + */ + protected boolean isReadMethod(Method m) { + Class returnType = m.getReturnType(); + if (!m.getName().startsWith("get")) + if (!m.getName().startsWith("is") || !(returnType == boolean.class)) + return false; + if (returnType == void.class) + return false; + if (m.getParameterTypes().length != 0) + return false; + return hasNonAppExceptions(m); + } + + /** + * Check if a method is a mutator. + */ + protected boolean isWriteMethod(Method m) { + if (!m.getName().startsWith("set")) + return false; + if (m.getReturnType() != void.class) + return false; + if (m.getParameterTypes().length != 1) + return false; + return hasNonAppExceptions(m); + } + + private static boolean isCheckedException(Class type) { + /* + * Is a checked exception + */ + if (!Throwable.class.isAssignableFrom(type)) + return false; + + if (Error.class.isAssignableFrom(type)) + return false; + + if (RuntimeException.class.isAssignableFrom(type)) + return false; + return true; + } + + /** + * Check if a method throws anything checked other than + * java.rmi.RemoteException and its subclasses. + */ + protected boolean hasNonAppExceptions(Method m) { + Class[] ex = m.getExceptionTypes(); + for (int i = 0; i < ex.length; ++i) { + if (!isCheckedException(ex[i])) + continue; + if (!RemoteException.class.isAssignableFrom(ex[i])) + return false; + } + return true; + } + + /** + * Analyse the fields of the class. This will fill in the + * <code>fields</code> and <code>f_flags</code> arrays. + */ + protected void parseFields() { + fields = javaClass.getDeclaredFields(); + f_flags = new byte[fields.length]; + for (int i = 0; i < fields.length; ++i) { + int mods = fields[i].getModifiers(); + if (Modifier.isFinal(mods) && Modifier.isStatic(mods) && Modifier.isPublic(mods)) + f_flags[i] |= F_CONSTANT; + } + } + + /** + * Analyse the interfaces of the class. This will fill in the + * <code>interfaces</code> array. + */ + protected void parseInterfaces() { + Class[] intfs = javaClass.getInterfaces(); + ArrayList a = new ArrayList(); + ArrayList b = new ArrayList(); + for (int i = 0; i < intfs.length; ++i) { + // Ignore java.rmi.Remote + if (intfs[i] == java.rmi.Remote.class) + continue; + // Ignore java.io.Serializable + if (intfs[i] == java.io.Serializable.class) + continue; + // Ignore java.io.Externalizable + if (intfs[i] == java.io.Externalizable.class) + continue; + if (!Java2IDLUtil.isAbstractValueType(intfs[i])) { + a.add(InterfaceType.getInterfaceType(intfs[i])); + } else { + b.add(ValueType.getValueType(intfs[i])); + } + } + interfaces = new InterfaceType[a.size()]; + interfaces = (InterfaceType[])a.toArray(interfaces); + abstractBaseValuetypes = new ValueType[b.size()]; + abstractBaseValuetypes = (ValueType[])b.toArray(abstractBaseValuetypes); + } + + /** + * Analyse the methods of the class. This will fill in the + * <code>methods</code> and <code>m_flags</code> arrays. + */ + protected void parseMethods() { + // The dynamic stub and skeleton strategy generation mechanism + // requires the inclusion of inherited methods in the type of + // remote interfaces. To speed things up, inherited methods are + // not considered in the type of a class or non-remote interface. + if (javaClass.isInterface() && java.rmi.Remote.class.isAssignableFrom(javaClass)) + methods = javaClass.getMethods(); + else + methods = javaClass.getDeclaredMethods(); + m_flags = new byte[methods.length]; + setters = new int[methods.length]; + // Find read-write properties + for (int i = 0; i < methods.length; ++i) + setters[i] = -1; // no mutator here + for (int i = 0; i < methods.length; ++i) { + if (isReadMethod(methods[i]) && (m_flags[i] & M_READ) == 0) { + String attrName = attributeReadName(methods[i].getName()); + Class iReturn = methods[i].getReturnType(); + for (int j = i + 1; j < methods.length; ++j) { + if (isWriteMethod(methods[j]) && (m_flags[j] & M_WRITE) == 0 + && attrName.equals(attributeWriteName(methods[j].getName()))) { + Class[] jParams = methods[j].getParameterTypes(); + if (jParams.length == 1 && jParams[0] == iReturn) { + m_flags[i] |= M_READ; + m_flags[j] |= M_WRITE; + setters[i] = j; + break; + } + } + } + } else if (isWriteMethod(methods[i]) && (m_flags[i] & M_WRITE) == 0) { + String attrName = attributeWriteName(methods[i].getName()); + Class[] iParams = methods[i].getParameterTypes(); + for (int j = i + 1; j < methods.length; ++j) { + if (isReadMethod(methods[j]) && (m_flags[j] & M_READ) == 0 + && attrName.equals(attributeReadName(methods[j].getName()))) { + Class jReturn = methods[j].getReturnType(); + if (iParams.length == 1 && iParams[0] == jReturn) { + m_flags[i] |= M_WRITE; + m_flags[j] |= M_READ; + setters[j] = i; + break; + } + } + } + } + } + // Find read-only properties + for (int i = 0; i < methods.length; ++i) + if ((m_flags[i] & (M_READ | M_WRITE)) == 0 && isReadMethod(methods[i])) + m_flags[i] |= M_READONLY; + // Check for overloaded and inherited methods + for (int i = 0; i < methods.length; ++i) { + if ((m_flags[i] & (M_READ | M_WRITE | M_READONLY)) == 0) { + String iName = methods[i].getName(); + for (int j = i + 1; j < methods.length; ++j) { + if (iName.equals(methods[j].getName())) { + m_flags[i] |= M_OVERLOADED; + m_flags[j] |= M_OVERLOADED; + } + } + } + if (methods[i].getDeclaringClass() != javaClass) + m_flags[i] |= M_INHERITED; + } + } + + /** + * Convert an attribute read method name in Java format to an attribute name + * in Java format. + */ + protected String attributeReadName(String name) { + if (name.startsWith("get")) + name = name.substring(3); + else if (name.startsWith("is")) + name = name.substring(2); + else + throw new IllegalArgumentException("Not an accessor: " + name); + return name; + } + + /** + * Convert an attribute write method name in Java format to an attribute + * name in Java format. + */ + protected String attributeWriteName(String name) { + if (name.startsWith("set")) + name = name.substring(3); + else + throw new IllegalArgumentException("Not an accessor: " + name); + return name; + } + + /** + * Analyse constants. This will fill in the <code>constants</code> array. + */ + protected void parseConstants() { + ArrayList a = new ArrayList(); + for (int i = 0; i < fields.length; ++i) { + if ((f_flags[i] & F_CONSTANT) == 0) + continue; + Class type = fields[i].getType(); + // Only map primitives and java.lang.String + if (!type.isPrimitive() && type != java.lang.String.class) { + // It is an RMI/IIOP violation for interfaces. + if (javaClass.isInterface()) + throw new IDLViolationException("Field \"" + fields[i].getName() + + "\" of interface \"" + + javaClass.getName() + + "\" is a constant, but not of one " + + "of the primitive types, or String.", "1.2.3"); + continue; + } + String name = fields[i].getName(); + Object value; + try { + value = fields[i].get(null); + } catch (Exception ex) { + throw new RuntimeException(ex.toString()); + } + a.add(new ConstantType(name, type, value)); + } + constants = new ConstantType[a.size()]; + constants = (ConstantType[])a.toArray(constants); + } + + /** + * Analyse attributes. This will fill in the <code>attributes</code> + * array. + */ + protected void parseAttributes() { + ArrayList a = new ArrayList(); + for (int i = 0; i < methods.length; ++i) { + // if ((m_flags[i]&M_INHERITED) != 0) + // continue; + if ((m_flags[i] & (M_READ | M_READONLY)) != 0) { + // Read method of an attribute. + String name = attributeReadName(methods[i].getName()); + if ((m_flags[i] & M_READONLY) != 0) + a.add(new AttributeType(name, methods[i])); + else + a.add(new AttributeType(name, methods[i], methods[setters[i]])); + } + } + + attributes = new AttributeType[a.size()]; + attributes = (AttributeType[])a.toArray(attributes); + } + + /** + * Analyse operations. This will fill in the <code>operations</code> + * array. This implementation just creates an empty array; override in + * subclasses for a real type. + */ + protected void parseOperations() { + operations = new OperationType[0]; + } + + /** + * Fixup overloaded operation names. As specified in section 1.3.2.6. + */ + protected void fixupOverloadedOperationNames() { + for (int i = 0; i < methods.length; ++i) { + if ((m_flags[i] & M_OVERLOADED) == 0) + continue; + // Find the operation + OperationType oa = null; + for (int opIdx = 0; oa == null && opIdx < operations.length; ++opIdx) + if (operations[opIdx].getMethod().equals(methods[i])) + oa = operations[opIdx]; + if (oa == null) + continue; // This method is not mapped. + // Calculate new IDL name + ParameterType[] parms = oa.getParameters(); + StringBuffer b = new StringBuffer(oa.getIDLName()); + if (parms.length == 0) + b.append("__"); + for (int j = 0; j < parms.length; ++j) { + String s = parms[j].getTypeIDLName(); + if (s.startsWith("::")) + s = s.substring(2); + b.append('_'); + while (!"".equals(s)) { + int idx = s.indexOf("::"); + b.append('_'); + if (idx == -1) { + b.append(s); + s = ""; + } else { + b.append(s.substring(0, idx)); + s = s.substring(idx + 2); + } + } + } + // Set new IDL name + oa.setIDLName(b.toString()); + } + } + + /** + * Fixup names differing only in case. As specified in section 1.3.2.7. + */ + protected void fixupCaseNames() { + ArrayList entries = getContainedEntries(); + boolean[] clash = new boolean[entries.size()]; + String[] upperNames = new String[entries.size()]; + for (int i = 0; i < entries.size(); ++i) { + IDLType aa = (IDLType)entries.get(i); + clash[i] = false; + upperNames[i] = aa.getIDLName().toUpperCase(); + for (int j = 0; j < i; ++j) { + if (upperNames[i].equals(upperNames[j])) { + clash[i] = true; + clash[j] = true; + } + } + } + for (int i = 0; i < entries.size(); ++i) { + if (!clash[i]) + continue; + IDLType aa = (IDLType)entries.get(i); + boolean noUpper = true; + String name = aa.getIDLName(); + StringBuffer b = new StringBuffer(name); + b.append('_'); + for (int j = 0; j < name.length(); ++j) { + if (!Character.isUpperCase(name.charAt(j))) + continue; + if (noUpper) + noUpper = false; + else + b.append('_'); + b.append(j); + } + aa.setIDLName(b.toString()); + } + } + + /** + * Return a list of all the entries contained here. + * + * @param entries The list of entries contained here. Entries in this list + * must be subclasses of <code>AbstractType</code>. + */ + abstract protected ArrayList getContainedEntries(); + + /** + * Return the class hash code, as specified in "The Common Object Request + * Broker: Architecture and Specification" (01-02-33), section 10.6.2. + */ + protected void calculateClassHashCode() { + // The simple cases + if (javaClass.isInterface()) + classHashCode = 0; + else if (!Serializable.class.isAssignableFrom(javaClass)) + classHashCode = 0; + else if (Externalizable.class.isAssignableFrom(javaClass)) + classHashCode = 1; + else + // Go ask Util class for the hash code + classHashCode = IDLUtil.getClassHashCode(javaClass); + } + + /** + * Escape non-ISO characters for an IR name. + */ + protected String escapeIRName(String name) { + StringBuffer b = new StringBuffer(); + 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)); + } + return b.toString(); + } + + /** + * Return the IR global ID of the given class or interface. This is + * described in section 1.3.5.7. The returned string is in the RMI hashed + * format, like "RMI:java.util.Hashtable:C03324C0EA357270:13BB0F25214AE4B8". + */ + protected void calculateRepositoryId() { + if (javaClass.isArray() || javaClass.isPrimitive()) + throw new IllegalArgumentException("Not a class or interface."); + if (javaClass.isInterface() && org.omg.CORBA.Object.class.isAssignableFrom(javaClass) + && org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(javaClass)) { + StringBuffer b = new StringBuffer("IDL:"); + b.append(javaClass.getPackage().getName().replace('.', '/')); + b.append('/'); + String base = javaClass.getName(); + base = base.substring(base.lastIndexOf('.') + 1); + b.append(base).append(":1.0"); + repositoryId = b.toString(); + } else { + StringBuffer b = new StringBuffer("RMI:"); + b.append(escapeIRName(javaClass.getName())); + memberPrefix = b.toString() + "."; + String hashStr = toHexString(classHashCode); + b.append(':').append(hashStr); + ObjectStreamClass osClass = ObjectStreamClass.lookup(javaClass); + if (osClass != null) { + long serialVersionUID = osClass.getSerialVersionUID(); + String SVUID = toHexString(serialVersionUID); + if (classHashCode != serialVersionUID) + b.append(':').append(SVUID); + memberPostfix = ":" + hashStr + ":" + SVUID; + } else + memberPostfix = ":" + hashStr; + repositoryId = b.toString(); + } + } + + /** + * A simple aggregate of work-in-progress, and the thread doing the work. + */ + private static class Task { + ContainerType type; + Thread thread; + + Task(ContainerType type, Thread thread) { + this.type = type; + this.thread = thread; + } + } + + /** + * Instances of this class cache the most complex types. The types cached + * are: + * <ul> + * <li><code>InterfaceType</code> for interfaces.</li> + * <li><code>ValueType</code> for value types.</li> + * <li><code>ExceptionType</code> for exceptions.</li> + * </ul> + * Besides caching work already done, this caches work in progress, as we + * need to know about this to handle cyclic graphs of parses. When a thread + * re-enters the <code>getType()</code> metohd, an unfinished type will be + * returned if the same thread is already working on this type. + */ + protected static class WorkCache { + /** + * The type constructor of our type class. This constructor takes a + * single argument of type <code>Class</code>. + */ + private Constructor constructor; + + /** + * This maps the classes of completely done parses to soft references of + * their type. + */ + private Map workDone; + + /** + * This maps the classes of parses in progress to their type. + */ + private Map workInProgress; + + /** + * Create a new work cache manager. + * + * @param containerType The class of the type type we cache here. + */ + WorkCache(Class containerType) { + // Find the constructor and initializer. + try { + constructor = containerType.getDeclaredConstructor(new Class[] {Class.class}); + } catch (NoSuchMethodException ex) { + throw new IllegalArgumentException("Bad Class: " + ex.toString()); + } + workDone = new WeakHashMap(); + workInProgress = new HashMap(); + } + + /** + * Returns an type. If the calling thread is currently doing an type of + * this class, an unfinished type is returned. + */ + ContainerType getType(Class cls) { + ContainerType ret; + synchronized (this) { + ret = lookupDone(cls); + if (ret != null) + return ret; + // is it work-in-progress? + Task inProgress = (Task)workInProgress.get(cls); + if (inProgress != null) { + if (inProgress.thread == Thread.currentThread()) + return inProgress.type; // return unfinished + // Do not wait for the other thread: We may deadlock + // Double work is better than deadlock... + } + ret = createTask(cls); + } + // Do the work + parse(cls, ret); + // We did it + synchronized (this) { + workInProgress.remove(cls); + workDone.put(cls, new SoftReference(ret)); + notifyAll(); + } + return ret; + } + + /** + * Lookup an type in the fully done map. + */ + private ContainerType lookupDone(Class cls) { + SoftReference ref = (SoftReference)workDone.get(cls); + if (ref == null) + return null; + ContainerType ret = (ContainerType)ref.get(); + if (ret == null) + workDone.remove(cls); // clear map entry if soft ref. was + // cleared. + return ret; + } + + /** + * Create new work-in-progress. + */ + private ContainerType createTask(Class cls) { + try { + ContainerType type = (ContainerType)constructor.newInstance(new Object[] {cls}); + workInProgress.put(cls, new Task(type, Thread.currentThread())); + return type; + } catch (Exception ex) { + // Ignore it + return null; + } + } + + private void parse(Class cls, ContainerType ret) { + try { + ret.parse(); + } finally { + synchronized (this) { + workInProgress.remove(cls); + } + } + } + + } + +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ExceptionType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ExceptionType.java new file mode 100644 index 0000000000..d3b47802cb --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ExceptionType.java @@ -0,0 +1,73 @@ +/* + * 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.util.StringTokenizer; + +/** + * IDL Exception + */ +public class ExceptionType extends ValueType { + + private static WorkCache cache = new WorkCache(ExceptionType.class); + + private String repositoryId; + + public static ExceptionType getExceptionType(Class cls) { + return (ExceptionType)cache.getType(cls); + } + + protected ExceptionType(Class cls) { + super(cls); + } + + protected void parse() { + super.parse(); + if (!Exception.class.isAssignableFrom(javaClass) || RuntimeException.class.isAssignableFrom(javaClass)) + throw new IDLViolationException("Exception type " + javaClass.getName() + " must be a checked exception.", + "1.2.6"); + // calculate exceptionRepositoryId + StringBuffer b = new StringBuffer("IDL:"); + String base = javaClass.getName(); + if (base.endsWith("Exception")) + base = base.substring(0, base.length() - 9); + StringTokenizer tokenizer = new StringTokenizer(base, "."); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if (tokenizer.hasMoreTokens()) { + // Defect 281395 + b.append(IDLUtil.javaToIDLName(token)); + b.append('/'); + } else { + b.append(IDLUtil.javaToIDLName(token + "Ex")); + } + } + b.append(":1.0"); + repositoryId = b.toString(); + } + + /** + * Return the repository ID for the mapping of this analysis to an + * exception. + */ + public String getExceptionRepositoryId() { + return repositoryId; + } + +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLType.java new file mode 100644 index 0000000000..eae70245ca --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLType.java @@ -0,0 +1,65 @@ +/* + * 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; + +/** + * Abstract base class for all IDL types. + */ +abstract class IDLType { + + /** + * Unqualified IDL name. + */ + protected String idlName; + /** + * Unqualified java name. + */ + protected String javaName; + + IDLType(String idlName, String javaName) { + this.idlName = idlName; + this.javaName = javaName; + } + + IDLType(String javaName) { + this(IDLUtil.javaToIDLName(javaName), javaName); + } + + /** + * Return my unqualified IDL name. + */ + public String getIDLName() { + return idlName; + } + + /** + * Return unqualified java name. + */ + public String getJavaName() { + return javaName; + } + + /** + * Set unqualified IDL name. + */ + void setIDLName(String idlName) { + this.idlName = idlName; + } + +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java b/sca-java-1.x/tags/0.91-incubating/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/tags/0.91-incubating/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); + } + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLViolationException.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLViolationException.java new file mode 100644 index 0000000000..712a284b09 --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLViolationException.java @@ -0,0 +1,50 @@ +/* + * 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 org.osoa.sca.ServiceRuntimeException; + +/** + * Exception denoting an RMI/IIOP Java-To-IDL mapping spec violation. + */ +public class IDLViolationException extends ServiceRuntimeException { + + private static final long serialVersionUID = 3334304081465286631L; + + /** + * The section violated. + */ + private String section; + + public IDLViolationException(String msg) { + super(msg); + } + + public IDLViolationException(String msg, String section) { + this(msg); + this.section = section; + } + + /** + * Return the section violated. + */ + public String getSection() { + return section; + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/InterfaceType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/InterfaceType.java new file mode 100644 index 0000000000..6943eb7a6f --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/InterfaceType.java @@ -0,0 +1,158 @@ +/* + * 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.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * IDL Interface Routines here are conforming to the "Java(TM) Language to IDL + * Mapping Specification", version 1.1 (01-06-07). + */ +public class InterfaceType extends ContainerType { + + private boolean abstractInterface; + private String[] typeIDs; + + /** + * Map of IDL operation names to operation parses. + */ + private Map operationTypeMap; + + private static WorkCache cache = new WorkCache(InterfaceType.class); + + public static InterfaceType getInterfaceType(Class cls) { + return (InterfaceType)cache.getType(cls); + } + + protected InterfaceType(Class cls) { + super(cls); + } + + protected void parse() { + super.parse(); + if (!javaClass.isInterface()) + throw new IllegalArgumentException("Class [" + javaClass.getName() + "] is not an interface."); + abstractInterface = Java2IDLUtil.isAbstractInterface(javaClass); + calculateOperationTypeMap(); + calculateAllTypeIds(); + fixupCaseNames(); + } + + public boolean isAbstractInterface() { + return abstractInterface; + } + + private boolean isRemoteInterface() { + return (!abstractInterface); + } + + public String[] getTypeIDs() { + return (String[])typeIDs.clone(); + } + + /** + * Return a list of all the entries contained here. + * + * @param entries The list of entries contained here. Entries in this list + * are subclasses of <code>AbstractType</code>. + */ + protected ArrayList getContainedEntries() { + ArrayList ret = new ArrayList(constants.length + attributes.length + operations.length); + for (int i = 0; i < constants.length; ++i) + ret.add(constants[i]); + for (int i = 0; i < attributes.length; ++i) + ret.add(attributes[i]); + for (int i = 0; i < operations.length; ++i) + ret.add(operations[i]); + return ret; + } + + /** + * Analyse operations. This will fill in the <code>operations</code> + * array. + */ + protected void parseOperations() { + int operationCount = 0; + for (int i = 0; i < methods.length; ++i) + if ((m_flags[i] & (M_READ | M_WRITE | M_READONLY)) == 0) + ++operationCount; + operations = new OperationType[operationCount]; + operationCount = 0; + for (int i = 0; i < methods.length; ++i) { + if ((m_flags[i] & (M_READ | M_WRITE | M_READONLY)) == 0) { + operations[operationCount] = new OperationType(methods[i]); + ++operationCount; + } + } + } + + /** + * Calculate the map that maps IDL operation names to operation parses. + * Besides mapped operations, this map also contains the attribute accessor + * and mutator operations. + */ + protected void calculateOperationTypeMap() { + operationTypeMap = new HashMap(); + OperationType oa; + // Map the operations + for (int i = 0; i < operations.length; ++i) { + oa = operations[i]; + operationTypeMap.put(oa.getIDLName(), oa); + } + // Map the attributes + for (int i = 0; i < attributes.length; ++i) { + AttributeType attr = attributes[i]; + oa = attr.getReadOperationType(); + // Not having an accessor analysis means that + // the attribute is not in a remote interface + if (oa != null) { + operationTypeMap.put(oa.getIDLName(), oa); + oa = attr.getWriteOperationType(); + if (oa != null) + operationTypeMap.put(oa.getIDLName(), oa); + } + } + } + + /** + * Calculate the array containing all type ids of this interface, in the + * format that org.omg.CORBA.portable.Servant._all_interfaces() is expected + * to return. + */ + protected void calculateAllTypeIds() { + if (!isRemoteInterface()) { + typeIDs = new String[0]; + } else { + ArrayList a = new ArrayList(); + InterfaceType[] intfs = getInterfaces(); + for (int i = 0; i < intfs.length; ++i) { + String[] ss = intfs[i].getTypeIDs(); + for (int j = 0; j < ss.length; ++j) + if (!a.contains(ss[j])) + a.add(ss[j]); + } + typeIDs = new String[a.size() + 1]; + typeIDs[0] = getRepositoryId(); + for (int i = 1; i <= a.size(); ++i) + typeIDs[i] = (String)a.get(a.size() - i); + } + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/Java2IDL.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/Java2IDL.java new file mode 100644 index 0000000000..79cbce55b8 --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/Java2IDL.java @@ -0,0 +1,51 @@ +/* + * 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.util.HashMap; +import java.util.Map; + +/** + * Utility class responsible for Java To IDL Mapping + */ +public class Java2IDL { + + public static Map getIDLMapping(Class type) { + InterfaceType interfaceType = InterfaceType.getInterfaceType(type); + Map names = new HashMap(); + AttributeType[] attrs = interfaceType.getAttributes(); + for (int i = 0; i < attrs.length; i++) { + OperationType op = attrs[i].getReadOperationType(); + if (op != null) { + names.put(op.getMethod(), op); + } + op = attrs[i].getWriteOperationType(); + if (op != null) { + names.put(op.getMethod(), op); + } + } + OperationType[] ops = interfaceType.getOperations(); + for (int i = 0; i < ops.length; i++) { + names.put(ops[i].getMethod(), ops[i]); + } + // Generate the method _ids(), declared as abstract in ObjectImpl + interfaceType.getTypeIDs(); + return names; + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/Java2IDLUtil.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/Java2IDLUtil.java new file mode 100644 index 0000000000..b50ec4a04b --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/Java2IDLUtil.java @@ -0,0 +1,403 @@ +/* + * 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.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.rmi.Remote; +import java.rmi.RemoteException; + +/** + * Java to IDL Language Mapping Specificiation v1.3 (formal/03-09-04) IDL + * Utilities + */ +public class Java2IDLUtil { + + /* + * checks if the method includes java.rmi.RemoteException or its subclass in + * its throws clause. + */ + private static boolean throwsRemoteException(Method method) { + Class[] exTypes = method.getExceptionTypes(); + for (int i = 0; i < exTypes.length; ++i) { + if (RemoteException.class.isAssignableFrom(exTypes[i])) + return true; + } + return false; + } + + /* + * checks if the given class is declared as static (inner classes only) + */ + private static boolean isStatic(Class c) { + return (Modifier.isStatic(c.getModifiers())); + } + + /** + * 1.2.1 Overview of Conforming RMI/IDL Types A conforming RMI/IDL type is a + * Java type whose values may be transmitted across an RMI/IDL remote + * interface at run-time. A Java data type is a conforming RMI/IDL type if + * it is: one of the Java primitive types (see Section 1.2.2, "Primitive + * Types," on page 1-2). a conforming remote interface (as defined in + * Section 1.2.3, "RMI/IDL Remote Interfaces," on page 1-3). a conforming + * value type (as defined in Section 1.2.4, "RMI/IDL Value Types," on page + * 1-4). an array of conforming RMI/IDL types (see Section 1.2.5, "RMI/IDL + * Arrays," on page 1-5). a conforming exception type (see Section 1.2.6, + * "RMI/IDL Exception Types," on page 1-5). a conforming CORBA object + * reference type (see Section 1.2.7, "CORBA Object Reference Types," on + * page 1-6). a conforming IDL entity type (see Section 1.2.8, "IDL Entity + * Types," on page 1-6). + * + * @param type + * @return + */ + public static boolean isIDLType(Class type) { + /* + * Primitive types. Spec 28.2.2 + */ + if (isPrimitiveType(type)) + return true; + + /* + * Conforming array. Spec 28.2.5 + */ + if (isIDLArray(type)) + return true; + + /* + * Conforming CORBA reference type. Spec 28.2.7 + */ + if (isCORBAObjectType(type)) + return true; + + /* + * Conforming IDL Entity type. Spec 28.2.8 + */ + if (isEntityType(type)) + return true; + + /* + * Conforming remote interface. Spec 28.2.3 + */ + if (isRemoteInterface(type)) + return true; + + /* + * Conforming exception. Spec 28.2.6 + */ + if (isExceptionType(type)) + return true; + + /* + * Conforming value type. Spec 28.2.4 + */ + if (isValueType(type)) + return true; + + return false; + } + + /** + * Section 1.2.3 RMI/IDL Remote Interfaces + * + * @param type + * @return + */ + public static boolean isRemoteInterface(Class type) { + + /* + * The interface is or inherits from java.rmi.Remote either directly or + * indirectly. + */ + if (!Remote.class.isAssignableFrom(type)) + return false; + + /* + * All methods in the interface are defined to throw + * java.rmi.RemoteException or a superclass of java.rmi.RemoteException. + * Throughout this section, references to methods in the interface + * include methods in any inherited interfaces + */ + Method[] methods = type.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (!throwsRemoteException(methods[i])) { + return false; + } + + /* + * All checked exception classes used in method declarations (other + * than java.rmi.RemoteException and its subclasses) are conforming + * RMI/IDL exception types (see Section 1.2.6, "RMI/IDL Exception + * Types," on page 1-5).1 + */ + Class[] exTypes = methods[i].getExceptionTypes(); + for (int j = 0; j < exTypes.length; j++) { + if (!isExceptionType(exTypes[j])) + return false; + } + } + + // TODO: Check method overloading from inherited interfaces + /* + * Method names may be overloaded. However, when an interface directly + * inherits from several base interfaces, it is forbidden for there to + * be method name conflicts between the inherited interfaces. This + * outlaws the case where an interface A defines a method "foo," an + * interface B also defines a method "foo," and an interface C tries to + * inherit from both A and B. + */ + + /* + * Constant definitions in the form of interface variables are + * permitted. The constant value must be a compile-time constant of one + * of the RMI/IDL primitive types or String. + */ + Field[] fields = type.getFields(); + for (int k = 0; k < fields.length; k++) { + Class fieldType = fields[k].getType(); + if (fieldType.isPrimitive() || fieldType == String.class) + continue; + return false; + } + return true; + } + + /** + * Section 1.3.11 + * + * @param type The java class + * @return true if it is an IDL abstract interface + */ + public static boolean isAbstractInterface(Class type) { + /* + * It must be a Java interface. + */ + if (!type.isInterface()) + return false; + + /* + * It must not be the interface of a CORBA object. + */ + if (org.omg.CORBA.Object.class.isAssignableFrom(type)) + return false; + + /* + * It must not extend java.rmi.Remote directly or indirectly. + */ + if (Remote.class.isAssignableFrom(type)) + return false; + + Method[] methods = type.getMethods(); + + for (int i = 0; i < methods.length; i++) { + /* + * All methods MUST throw java.rmi.RemoteException or a subclass. + */ + if (!throwsRemoteException(methods[i])) { + return false; + } + } + return true; + } + + /** + * 1.2.6 RMI/IDL Exception Types An RMI/IDL exception type is a checked + * exception class (as defined by the Java Language Specification). Since + * checked exception classes extend java.lang.Throwable, which implements + * java.io.Serializable, it is unnecessary for an RMI/IDL exception class to + * directly implement java.io.Serializable. + */ + public static boolean isExceptionType(Class type) { + + /* + * Is a checked exception + */ + if (!Throwable.class.isAssignableFrom(type)) + return false; + + if (Error.class.isAssignableFrom(type)) + return false; + + if (RuntimeException.class.isAssignableFrom(type)) + return false; + + /* + * meets the requirements for RMI/IDL value types defined in Section + * 1.2.4, "RMI/IDL Value Types," on page 1-4. + */ + if (!isValueType(type)) + return false; + + return true; + } + + /** + * 1.2.4 RMI/IDL Value Types An RMI/IDL value type represents a class whose + * values can be moved between systems. So rather than transmitting a + * reference between systems, the actual state of the object is transmitted + * between systems. This requires that the receiving system have an + * analogous class that can be used to hold the received value. Value types + * may be passed as arguments or results of remote methods, or as fields + * within other objects that are passed remotely. + */ + public static boolean isValueType(Class type) { + /* + * The class must implement the java.io.Serializable interface, either + * directly or indirectly, and must be serializable at run-time. It may + * serialize references to other RMI/IDL types, including value types + * and remote interfaces. + */ + if (!Serializable.class.isAssignableFrom(type)) + return false; + + /* + * A value type must not either directly or indirectly implement the + * java.rmi.Remote interface. (If this were allowed, then there would be + * potential confusion between value types and remote interface + * references.) + */ + if (Remote.class.isAssignableFrom(type)) + return false; + + /* + * It cannot be a CORBA object. + */ + if (org.omg.CORBA.Object.class.isAssignableFrom(type)) + return false; + + /* + * If the class is a non-static inner class, then its containing class + * must also be a conforming RMI/IDL value type. + */ + if ((type.getDeclaringClass() != null) && (!isStatic(type))) + if (!isValueType(type.getDeclaringClass())) + return false; + + return true; + } + + public static boolean isAbstractValueType(Class type) { + if (!type.isInterface()) + return false; + + if (org.omg.CORBA.Object.class.isAssignableFrom(type)) + return false; + + boolean cannotBeRemote = false; + boolean cannotBeAbstractInterface = false; + + if (java.rmi.Remote.class.isAssignableFrom(type)) { + cannotBeAbstractInterface = true; + } else { + cannotBeRemote = true; + } + + Method[] methods = type.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (!throwsRemoteException(methods[i])) { + cannotBeAbstractInterface = true; + cannotBeRemote = true; + break; + } + + Class[] exTypes = methods[i].getExceptionTypes(); + for (int j = 0; j < exTypes.length; j++) { + if (!isExceptionType(exTypes[j])) { + cannotBeRemote = true; + break; + } + } + } + + if (!cannotBeRemote) { + Field[] fields = type.getFields(); + for (int k = 0; k < fields.length; k++) { + if (fields[k].getType().isPrimitive()) + continue; + if (fields[k].getType().equals(java.lang.String.class)) + continue; + cannotBeRemote = true; + break; + } + } + return cannotBeRemote && cannotBeAbstractInterface; + } + + /** + * 1.2.2 Primitive Types All the standard Java primitive types are supported + * as part of RMI/IDL. These are: void, boolean, byte, char, short, int, + * long, float, double + * + * @param type + * @return + */ + public static boolean isPrimitiveType(Class type) { + return (type != null && type.isPrimitive()); + } + + /** + * 1.2.7 CORBA Object Reference Types A conforming CORBA object reference + * type is either + * <ul> + * <li>the Java interface org.omg.CORBA.Object, or + * <li>a Java interface that extends org.omg.CORBA.Object directly or + * indirectly and conforms to the rules specified in the Java Language + * Mapping (i.e., could have been generated by applying the mapping to an + * OMG IDL definition). + * </ul> + */ + public static boolean isCORBAObjectType(Class type) { + if (type == org.omg.CORBA.Object.class) + return true; + if (type.isInterface() && org.omg.CORBA.Object.class.isAssignableFrom(type)) + return true; + return false; + } + + /** + * 1.2.8 IDL Entity Types A Java class is a conforming IDL entity type if it + * extends org.omg.CORBA.portable.IDLEntity and conforms to the rules + * specified in the Java Language Mapping (i.e., could have been generated + * by applying the mapping to an OMG IDL definition) and is not an OMG IDL + * user exception. + */ + public static boolean isEntityType(Class type) { + if (!org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(type)) + return false; + if (isExceptionType(type)) + return false; + return true; + } + + /** + * 1.2.5 RMI/IDL Arrays Arrays of any conforming RMI/IDL type are also + * conforming RMI/IDL types. So int[] and String[][][] are conforming + * RMI/IDL types. Similarly if Wombat is a conforming RMI/IDL interface + * type, then Wombat[] is a conforming RMI/IDL type. + */ + public static boolean isIDLArray(Class type) { + if (!type.isArray()) + return false; + Class componentType = type.getComponentType(); + return isIDLType(componentType); + } + +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/OperationType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/OperationType.java new file mode 100644 index 0000000000..f10a66d72d --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/OperationType.java @@ -0,0 +1,106 @@ +/* + * 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.lang.reflect.Method; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.ArrayList; + +/** + * IDL Operation. + */ +public class OperationType extends IDLType { + + /** + * The Method that this OperationType is mapping. + */ + private Method method; + /** + * The mapped exceptions of this operation. + */ + private ExceptionType[] mappedExceptions; + /** + * The parameters of this operation. + */ + private ParameterType[] parameters; + + OperationType(Method method) { + super(method.getName()); + this.method = method; + // Check if valid return type, IF it is a remote interface. + Class retCls = method.getReturnType(); + if (retCls.isInterface() && Remote.class.isAssignableFrom(retCls)) + IDLUtil.isValidRMIIIOP(retCls); + // Analyze exceptions + Class[] ex = method.getExceptionTypes(); + boolean gotRemoteException = false; + ArrayList a = new ArrayList(); + for (int i = 0; i < ex.length; ++i) { + if (ex[i].isAssignableFrom(java.rmi.RemoteException.class)) + gotRemoteException = true; + if (Exception.class.isAssignableFrom(ex[i]) && !RuntimeException.class.isAssignableFrom(ex[i]) + && !RemoteException.class.isAssignableFrom(ex[i])) + a.add(ExceptionType.getExceptionType(ex[i])); // map this + } + if (!gotRemoteException && Remote.class.isAssignableFrom(method.getDeclaringClass())) + throw new IDLViolationException( + "All interface methods must throw java.rmi.RemoteException, " + "or a superclass of java.rmi.RemoteException, but method " + + getJavaName() + + " of interface " + + method.getDeclaringClass().getName() + + " does not.", "1.2.3"); + mappedExceptions = new ExceptionType[a.size()]; + mappedExceptions = (ExceptionType[])a.toArray(mappedExceptions); + // Analyze parameters + Class[] params = method.getParameterTypes(); + parameters = new ParameterType[params.length]; + for (int i = 0; i < params.length; ++i) { + parameters[i] = new ParameterType("param" + (i + 1), params[i]); + } + } + + /** + * Return my Java return type. + */ + public Class getReturnType() { + return method.getReturnType(); + } + + /** + * Return my mapped Method. + */ + public Method getMethod() { + return method; + } + + /** + * Return my mapped exceptions. + */ + public ExceptionType[] getMappedExceptions() { + return (ExceptionType[])mappedExceptions.clone(); + } + + /** + * Return my parameters. + */ + public ParameterType[] getParameters() { + return (ParameterType[])parameters.clone(); + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ParameterType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ParameterType.java new file mode 100644 index 0000000000..09d48ad169 --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ParameterType.java @@ -0,0 +1,63 @@ +/* + * 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 org.omg.CORBA.ParameterMode; + +/** + * IDL Parameter + */ +public class ParameterType extends IDLType { + + /** + * Java type of parameter. + */ + private Class javaClass; + /** + * IDL type name of parameter type. + */ + private String typeIDLName; + + ParameterType(String javaName, Class cls) { + super(javaName); + this.javaClass = cls; + this.typeIDLName = IDLUtil.getTypeIDLName(cls); + } + + /** + * Return the attribute mode. + */ + public ParameterMode getMode() { + return ParameterMode.PARAM_IN; + } + + /** + * Return the Java type. + */ + public Class getJavaClass() { + return javaClass; + } + + /** + * Return the IDL type name of the parameter type. + */ + public String getTypeIDLName() { + return typeIDLName; + } +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/PrimitiveType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/PrimitiveType.java new file mode 100644 index 0000000000..c48188112e --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/PrimitiveType.java @@ -0,0 +1,66 @@ +/* + * 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.util.HashMap; +import java.util.Map; + +/** + * Type class for primitive types. + */ +public class PrimitiveType extends ClassType { + + public final static PrimitiveType voidType = new PrimitiveType(void.class, "void", "void"); + public final static PrimitiveType booleanType = new PrimitiveType(boolean.class, "boolean", "boolean"); + public final static PrimitiveType charType = new PrimitiveType(char.class, "wchar", "char"); + public final static PrimitiveType byteType = new PrimitiveType(byte.class, "octet", "byte"); + public final static PrimitiveType shortType = new PrimitiveType(short.class, "short", "short"); + public final static PrimitiveType intType = new PrimitiveType(int.class, "long", "int"); + public final static PrimitiveType longType = new PrimitiveType(long.class, "long_long", "long"); + public final static PrimitiveType floatType = new PrimitiveType(float.class, "float", "float"); + public final static PrimitiveType doubleType = new PrimitiveType(double.class, "double", "double"); + + private final static Map types = new HashMap(); + static { + types.put(void.class, voidType); + types.put(boolean.class, booleanType); + types.put(byte.class, byteType); + types.put(char.class, charType); + types.put(short.class, shortType); + types.put(int.class, intType); + types.put(long.class, longType); + types.put(float.class, floatType); + types.put(double.class, doubleType); + } + + private PrimitiveType(Class cls, String idlName, String javaName) { + super(cls, idlName, javaName); + } + + /** + * Get a singleton instance representing one of the peimitive types. + */ + public final static PrimitiveType getPrimitiveType(Class cls) { + PrimitiveType type = (PrimitiveType)types.get(cls); + if (type == null) + throw new IllegalArgumentException(cls + " is not a primitive type"); + return type; + } + +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ValueMemberType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ValueMemberType.java new file mode 100644 index 0000000000..3e152301a7 --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ValueMemberType.java @@ -0,0 +1,55 @@ +/* + * 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; + +/** + * Value member type. + */ +public class ValueMemberType extends IDLType { + + /** + * Java type. + */ + private Class javaClass; + /** + * Flags that this member is public. + */ + private boolean isPublic; + + ValueMemberType(String javaName, Class cls, boolean isPublic) { + super(javaName); + this.javaClass = cls; + this.isPublic = isPublic; + } + + /** + * Return my Java type. + */ + public Class getJavaClass() { + return javaClass; + } + + /** + * Returns true iff this member has private visibility. + */ + public boolean isPublic() { + return isPublic; + } + +} diff --git a/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ValueType.java b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ValueType.java new file mode 100644 index 0000000000..3d2c8935cf --- /dev/null +++ b/sca-java-1.x/tags/0.91-incubating/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ValueType.java @@ -0,0 +1,271 @@ +/* + * 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.Externalizable; +import java.io.ObjectStreamField; +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.util.ArrayList; +import java.util.Comparator; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.osoa.sca.ServiceRuntimeException; + +/** + * Value Type. + */ +public class ValueType extends ContainerType { + + private static WorkCache cache = new WorkCache(ValueType.class); + + /** + * Type of our superclass, of null if our superclass is java.lang.Object. + */ + ValueType superType; + /** + * Flags that this is an abstract value. + */ + private boolean abstractValue = false; + /** + * Flags that this implements <code>java.io.Externalizable</code>. + */ + private boolean externalizable = false; + /** + * Flags that this has a <code>writeObject()</code> method. + */ + private boolean hasWriteObjectMethod = false; + /** + * The <code>serialPersistentFields of the value, or <code>null</code> + * if the value does not have this field. + */ + private ObjectStreamField[] serialPersistentFields; + /** + * The value members of this value class. + */ + private ValueMemberType[] members; + + public static ValueType getValueType(Class cls) { + return (ValueType)cache.getType(cls); + } + + protected ValueType(Class cls) { + super(cls); + } + + protected void parse() { + super.parse(); + if (javaClass == String.class) + throw new IllegalArgumentException("Cannot parse java.lang.String here: It is a " + "special case."); // 1.3.5.11 + if (javaClass == Class.class) + throw new IllegalArgumentException("Cannot parse java.lang.Class here: It is a " + "special case."); // 1.3.5.10 + if (Remote.class.isAssignableFrom(javaClass)) + throw new IDLViolationException("Value type " + javaClass.getName() + " cannot implement java.rmi.Remote.", + "1.2.4"); + if (javaClass.getName().indexOf('$') != -1) + throw new ServiceRuntimeException(javaClass.getName() + " is not supported (proxy or inner classes)."); + externalizable = Externalizable.class.isAssignableFrom(javaClass); + if (!externalizable) { + // Look for serialPersistentFields field. + Field spf = null; + try { + spf = javaClass.getField("serialPersistentFields"); + } catch (NoSuchFieldException ex) { + // ignore + } + if (spf != null) { // Right modifiers? + int mods = spf.getModifiers(); + if (!Modifier.isFinal(mods) || !Modifier.isStatic(mods) || !Modifier.isPrivate(mods)) + spf = null; // wrong modifiers + } + if (spf != null) { // Right type? + Class type = spf.getType(); + if (type.isArray()) { + type = type.getComponentType(); + if (type != ObjectStreamField.class) + spf = null; // Array of wrong type + } else + spf = null; // Wrong type: Not an array + } + if (spf != null) { + // We have the serialPersistentFields field + // Get this constant + try { + serialPersistentFields = (ObjectStreamField[])spf.get(null); + } catch (IllegalAccessException ex) { + throw new RuntimeException("Unexpected IllegalException: " + ex.toString()); + } + // Mark this in the fields array + for (int i = 0; i < fields.length; ++i) { + if (fields[i] == spf) { + f_flags[i] |= F_SPFFIELD; + break; + } + } + } + // Look for a writeObject Method + Method wo = null; + try { + wo = javaClass.getMethod("writeObject", new Class[] {java.io.OutputStream[].class}); + } catch (NoSuchMethodException ex) { + // ignore + } + if (wo != null) { // Right return type? + if (wo.getReturnType() != Void.TYPE) + wo = null; // Wrong return type + } + if (wo != null) { // Right modifiers? + int mods = spf.getModifiers(); + if (!Modifier.isPrivate(mods)) + wo = null; // wrong modifiers + } + if (wo != null) { // Right arguments? + Class[] paramTypes = wo.getParameterTypes(); + if (paramTypes.length != 1) + wo = null; // Bad number of parameters + else if (paramTypes[0] != java.io.OutputStream.class) + wo = null; // Bad parameter type + } + if (wo != null) { + // We have the writeObject() method. + hasWriteObjectMethod = true; + // Mark this in the methods array + for (int i = 0; i < methods.length; ++i) { + if (methods[i] == wo) { + m_flags[i] |= M_WRITEOBJECT; + break; + } + } + } + } + // Map all fields not flagged constant or serialPersistentField. + SortedSet m = new TreeSet(new ValueMemberComparator()); + for (int i = 0; i < fields.length; ++i) { + if (f_flags[i] != 0) + continue; // flagged + int mods = fields[i].getModifiers(); + if (Modifier.isStatic(mods) || Modifier.isTransient(mods)) + continue; // don't map this + ValueMemberType vma = + new ValueMemberType(fields[i].getName(), fields[i].getType(), Modifier.isPublic(mods)); + m.add(vma); + } + members = new ValueMemberType[m.size()]; + members = (ValueMemberType[])m.toArray(members); + // Get superclass analysis + Class superClass = javaClass.getSuperclass(); + if (superClass == java.lang.Object.class) + superClass = null; + if (superClass == null) + superType = null; + else { + superType = getValueType(superClass); + } + if (!Serializable.class.isAssignableFrom(javaClass)) + abstractValue = true; + fixupCaseNames(); + } + + /** + * Returns the superclass analysis, or null if this inherits from + * java.lang.Object. + */ + public ValueType getSuperType() { + return superType; + } + + /** + * Returns true if this value is abstract. + */ + public boolean isAbstractValue() { + return abstractValue; + } + + /** + * Returns true if this value is custom. + */ + public boolean isCustom() { + return externalizable || hasWriteObjectMethod; + } + + /** + * Returns true if this value implements java.io.Externalizable. + */ + public boolean isExternalizable() { + return externalizable; + } + + /** + * Return the value members of this value class. + */ + public ValueMemberType[] getMembers() { + return (ValueMemberType[])members.clone(); + } + + /** + * Analyse attributes. This will fill in the <code>attributes</code> + * array. Here we override the implementation in ContainerType and create an + * empty array, because for valuetypes we don't want to parse IDL attributes + * or operations (as in "rmic -idl -noValueMethods"). + */ + protected void parseAttributes() { + attributes = new AttributeType[0]; + } + + /** + * Return a list of all the entries contained here. + * + * @param entries The list of entries contained here. Entries in this list + * are subclasses of <code>AbstractType</code>. + */ + protected ArrayList getContainedEntries() { + ArrayList ret = new ArrayList(constants.length + attributes.length + members.length); + for (int i = 0; i < constants.length; ++i) + ret.add(constants[i]); + for (int i = 0; i < attributes.length; ++i) + ret.add(attributes[i]); + for (int i = 0; i < members.length; ++i) + ret.add(members[i]); + return ret; + } + + /** + * A <code>Comparator</code> for the field ordering specified at the end + * of section 1.3.5.6. + */ + private static class ValueMemberComparator implements Comparator { + public int compare(Object o1, Object o2) { + if (o1 == o2) + return 0; + ValueMemberType m1 = (ValueMemberType)o1; + ValueMemberType m2 = (ValueMemberType)o2; + boolean p1 = m1.getJavaClass().isPrimitive(); + boolean p2 = m2.getJavaClass().isPrimitive(); + if (p1 && !p2) + return -1; + if (!p1 && p2) + return 1; + return m1.getJavaName().compareTo(m2.getJavaName()); + } + } +} |