diff options
Diffstat (limited to '')
29 files changed, 4958 insertions, 0 deletions
diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/EJBBinding.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/EJBBinding.java new file mode 100644 index 0000000000..c4b72ed274 --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/EJBBinding.java @@ -0,0 +1,102 @@ +/* + * 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; + + + +/** + * An implementation of EJBBinding. + */ +public class EJBBinding { + + /** + * corba location For exmaple, + * "corbaname:iiop:localhost:2809/NameServiceServerRoot#ejb/MyEJBHome" + */ + private String uri; + + /** + * homeInterface. remote or local + */ + private String homeInterface; + + /** + * The ejb-link-name attribute allows a SCA client to bind to an EJB that is + * packaged in the same JEE EAR file as the SCA client. This is functionally + * equivalent to using the <ejb-link/> subelement of the <ejb-ref/> element + * in s EJB deployment descriptor. Used only for Service binding + */ + private String ejbLinkName; + + /** + * Gets the homeInterface. + * + * @return home interface of the service binding + */ + public String getHomeInterface() { + return homeInterface; + } + + /** + * Set homeInterface + * + * @param homeInterface + */ + public void setHomeInterface(String homeInterface) { + this.homeInterface = homeInterface; + } + + /** + * get ejb-link-name + * + * @return ejb-link-name + */ + public String getEjbLinkName() { + return ejbLinkName; + } + + /** + * Set ejb-link-name + * + * @param ejb-link-name + */ + public void setEjbLinkName(String ejbLinkName) { + this.ejbLinkName = ejbLinkName; + } + + // TODO: uri needs to be part of runtime extension helper + + /** + * Sets binding URI. + * + * @param value the binding uri + */ + public void setUri(String value) { + this.uri = value; + } + + /** + * gets binding URI. + * + * @return value the binding uri + */ + public String getUri() { + return uri; + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/EJBBindingActivator.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/EJBBindingActivator.java new file mode 100644 index 0000000000..5538186dc4 --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/EJBBindingActivator.java @@ -0,0 +1,53 @@ +/* + * 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; + +import org.apache.tuscany.sca.assembly.Binding; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.runtime.RuntimeComponent; +import org.apache.tuscany.sca.runtime.RuntimeComponentReference; +import org.apache.tuscany.sca.runtime.RuntimeComponentService; +import org.apache.tuscany.sca.spi.BindingActivator; +import org.apache.tuscany.sca.spi.ComponentLifecycle; +import org.apache.tuscany.sca.spi.InvokerFactory; +import org.osoa.sca.ServiceRuntimeException; + +public class EJBBindingActivator implements BindingActivator<EJBBinding> { + + public InvokerFactory createInvokerFactory(RuntimeComponent rc, RuntimeComponentReference rcr, final Binding b, final EJBBinding binding) { + // TODO: assumes a Java interface, need to support tuscany generic Interface + final Class si = ((JavaInterface)rcr.getInterfaceContract().getInterface()).getJavaClass(); + return new InvokerFactory() { + public Invoker createInvoker(Operation operation) { + return new EJBTargetInvoker((EJBBinding)binding, si, operation); + } + }; + } + + public ComponentLifecycle createService(RuntimeComponent rc, RuntimeComponentService rcs, Binding b, EJBBinding binding) { + throw new ServiceRuntimeException("services not yet implemented for binding.ejb"); + } + + public Class<EJBBinding> getBindingClass() { + return EJBBinding.class; + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/EJBTargetInvoker.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/EJBTargetInvoker.java new file mode 100644 index 0000000000..0c384c2c7b --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/EJBTargetInvoker.java @@ -0,0 +1,79 @@ +/* + * 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; + +import org.apache.tuscany.sca.binding.ejb.util.EJBHandler; +import org.apache.tuscany.sca.binding.ejb.util.NamingEndpoint; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.invocation.Invoker; +import org.apache.tuscany.sca.invocation.Message; + +/** + * EJBTargetInvoker + */ +public class EJBTargetInvoker implements Invoker { + + private Operation operation; + private String location; + private Class serviceInterface; + + public EJBTargetInvoker(EJBBinding ejbBinding, Class serviceInterface, Operation operation) { + this.serviceInterface = serviceInterface; + this.location = ejbBinding.getUri(); + this.operation = operation; + } + + public Message invoke(Message msg) { + try { + Object resp = doInvoke(msg.getBody()); + msg.setBody(resp); + } catch (Throwable e) { + e.printStackTrace(); + msg.setBody(e); + } + return msg; + } + + /** + * Invoke a EJB operation + * + * @param payload + * @return + */ + public Object doInvoke(final Object payload) { + + // construct NamingendPoint + NamingEndpoint endpoint = getNamingEndpoint(); + + // lookup home and ejb stub + EJBHandler ejbHandler = new EJBHandler(endpoint, serviceInterface); + + String methodName = operation.getName(); + + // invoke business method on ejb + Object response = ejbHandler.invoke(methodName, (Object[])payload); + + return response; + } + + protected NamingEndpoint getNamingEndpoint() { + return new NamingEndpoint(location); + } + +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/AttributeMode.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/AttributeType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ClassType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ConstantType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ContainerType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ExceptionType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java new file mode 100644 index 0000000000..fe8698122c --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLUtil.java @@ -0,0 +1,464 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.binding.ejb.java2idl; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.rmi.Remote; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.WeakHashMap; + +import org.omg.CORBA.Any; + +/** + * This is a RMI/IIOP metadata conversion utility class. + */ +public class IDLUtil { + + /** + * Return the IDL type name for the given class. Here we use the mapping for + * parameter types and return values. + */ + public static String getTypeIDLName(Class cls) { + if (cls.isPrimitive()) + return PrimitiveType.getPrimitiveType(cls).getIDLName(); + if (cls.isArray()) { + int dimension = 0; + Class type = cls; + while (type.isArray()) { + dimension++; + type = type.getComponentType(); + } + String baseName = getTypeIDLName(type); + int index = baseName.lastIndexOf("::"); + String prefix = ""; + String suffix = baseName; + if (index != -1) { + prefix = baseName.substring(0, index); + suffix = baseName.substring(index + 2); + } + String name = "::org::omg::boxedRMI" + prefix + "::seq" + dimension + "_" + suffix; + return name; + } + + // special classes + if (cls == java.lang.String.class) + return "::CORBA::WStringValue"; + if (cls == java.lang.Object.class) + return "::java::lang::_Object"; + if (cls == java.lang.Class.class) + return "::javax::rmi::CORBA::ClassDesc"; + if (cls == java.io.Serializable.class) + return "::java::io::Serializable"; + if (cls == java.io.Externalizable.class) + return "::java::io::Externalizable"; + if (cls == java.rmi.Remote.class) + return "::java::rmi::Remote"; + if (cls == org.omg.CORBA.Object.class) + return "::CORBA::Object"; + // remote interface? + if (cls.isInterface() && java.rmi.Remote.class.isAssignableFrom(cls)) { + InterfaceType ia = InterfaceType.getInterfaceType(cls); + return ia.getIDLModuleName() + "::" + ia.getIDLName(); + } + // IDL interface? + if (cls.isInterface() && org.omg.CORBA.Object.class.isAssignableFrom(cls) + && org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(cls)) { + InterfaceType ia = InterfaceType.getInterfaceType(cls); + return ia.getIDLModuleName() + "::" + ia.getIDLName(); + } + // exception? + if (Throwable.class.isAssignableFrom(cls)) { + if (Exception.class.isAssignableFrom(cls) && !RuntimeException.class.isAssignableFrom(cls)) { + ExceptionType ea = ExceptionType.getExceptionType(cls); + return ea.getIDLModuleName() + "::" + ea.getIDLName(); + } + } + // got to be value + ValueType va = ValueType.getValueType(cls); + return va.getIDLModuleName() + "::" + va.getIDLName(); + } + + /** + * Check if this class is valid for RMI/IIOP mapping. This method will + * either throw an exception or return true. + */ + public static boolean isValidRMIIIOP(Class cls) { + if (cls.isPrimitive()) + return true; + if (cls.isArray()) + return isValidRMIIIOP(cls.getComponentType()); + // special interfaces + if (cls == Serializable.class || cls == Externalizable.class) + return true; + // interface? + if (cls.isInterface() && Remote.class.isAssignableFrom(cls)) { + InterfaceType.getInterfaceType(cls); + return true; + } + // exception? + if (Throwable.class.isAssignableFrom(cls)) { + if (Exception.class.isAssignableFrom(cls) && (!RuntimeException.class.isAssignableFrom(cls))) { + ExceptionType.getExceptionType(cls); + } + return true; + } + // special values + if (cls == Object.class || cls == String.class || cls == Class.class) + return true; + // got to be value + ValueType.getValueType(cls); + return true; + } + + /** + * Insert a java primitive into an Any. The primitive is assumed to be + * wrapped in one of the primitive wrapper classes. + */ + public static void insertAnyPrimitive(Any any, Object primitive) { + Class type = primitive.getClass(); + if (type == Boolean.class) + any.insert_boolean(((Boolean)primitive).booleanValue()); + else if (type == Character.class) + any.insert_wchar(((Character)primitive).charValue()); + else if (type == Byte.class) + any.insert_octet(((Byte)primitive).byteValue()); + else if (type == Short.class) + any.insert_short(((Short)primitive).shortValue()); + else if (type == Integer.class) + any.insert_long(((Integer)primitive).intValue()); + else if (type == Long.class) + any.insert_longlong(((Long)primitive).longValue()); + else if (type == Float.class) + any.insert_float(((Float)primitive).floatValue()); + else if (type == Double.class) + any.insert_double(((Double)primitive).doubleValue()); + else + throw new IllegalArgumentException(type.getName() + "is not a primitive type"); + } + + /** + * Map Java name to IDL name, as per sections 1.3.2.3, 1.3.2.4 and 1.3.2.2. + * This only works for a single name component, without a qualifying dot. + */ + public static String javaToIDLName(String name) { + if (name == null || "".equals(name)) + throw new IllegalArgumentException("Illegal name: " + name); + if (name.indexOf('.') != -1) + throw new IllegalArgumentException("Qualified name is not supported: " + name); + StringBuffer res = new StringBuffer(name.length()); + if (name.charAt(0) == '_') + res.append('J'); // 1.3.2.3 + for (int i = 0; i < name.length(); ++i) { + char c = name.charAt(i); + if (isLegalIDLIdentifierChar(c)) + res.append(c); + else + // 1.3.2.4 + res.append('U').append(toHexString((int)c)); + } + String s = res.toString(); + if (isReservedIDLKeyword(s)) + return "_" + s; + else + return s; + } + + /** + * Return the IR global ID of the given class or interface. This is + * described in section 1.3.5.7. + */ + public static String getIRIdentifier(Class cls) { + if (cls.isPrimitive()) + throw new IllegalArgumentException("Primitive type doesn't have IR IDs."); + String result = (String)classIRIdentifierCache.get(cls); + if (result != null) + return result; + String name = cls.getName(); + StringBuffer b = new StringBuffer("RMI:"); + for (int i = 0; i < name.length(); ++i) { + char c = name.charAt(i); + if (c < 256) + b.append(c); + else + b.append("\\U").append(toHexString((int)c)); + } + long clsHash = getClassHashCode(cls); + b.append(':').append(toHexString(clsHash)); + ObjectStreamClass osClass = ObjectStreamClass.lookup(cls); + if (osClass != null) { + long serialVersionUID = osClass.getSerialVersionUID(); + if (clsHash != serialVersionUID) + b.append(':').append(toHexString(serialVersionUID)); + } + result = b.toString(); + classIRIdentifierCache.put(cls, result); + return result; + } + + /** + * A cache for calculated class hash codes. + */ + private static Map classHashCodeCache = Collections.synchronizedMap(new WeakHashMap()); + /** + * A cache for class IR identifiers. + */ + private static Map classIRIdentifierCache = Collections.synchronizedMap(new WeakHashMap()); + /** + * Reserved IDL keywords. Section 1.3.2.2 says that Java identifiers with + * these names should have prepended an underscore. + */ + + private static final Set reservedIDLKeywordSet = new HashSet(); + static { + String[] reservedIDLKeywords = new String[] {"abstract", "any", "attribute", "boolean", "case", "char", + "const", "context", "custom", "default", "double", "exception", + "enum", "factory", "FALSE", "fixed", "float", "in", "inout", + "interface", "local", "long", "module", "native", "Object", + "octet", "oneway", "out", "private", "public", "raises", + "readonly", "sequence", "short", "string", "struct", "supports", + "switch", "TRUE", "truncatable", "typedef", "unsigned", "union", + "ValueBase", "valuetype", "void", "wchar", "wstring"}; + for (int i = 0; i < reservedIDLKeywords.length; i++) + reservedIDLKeywordSet.add(reservedIDLKeywords[i]); + } + + /** + * Convert an integer to a 16-digit hex string. + */ + private static String toHexString(int i) { + String s = Integer.toHexString(i).toUpperCase(); + if (s.length() < 8) + return "00000000".substring(8 - s.length()) + s; + else + return s; + } + + /** + * Convert a long to a 16-digit hex string. + */ + private static String toHexString(long l) { + String s = Long.toHexString(l).toUpperCase(); + if (s.length() < 16) + return "0000000000000000".substring(16 - s.length()) + s; + else + return s; + } + + /** + * Determine if the argument is a reserved IDL keyword. + */ + private static boolean isReservedIDLKeyword(String s) { + return reservedIDLKeywordSet.contains(s); + /* + * // TODO: faster lookup for (int i = 0; i < + * reservedIDLKeywords.length; ++i) if + * (reservedIDLKeywords[i].equals(s)) return true; return false; + */ + } + + /** + * Determine if a <code>char</code> is a legal IDL identifier character. + */ + private static boolean isLegalIDLIdentifierChar(char c) { + if (c >= 0x61 && c <= 0x7a) + return true; // lower case letter + if (c >= 0x30 && c <= 0x39) + return true; // digit + if (c >= 0x41 && c <= 0x5a) + return true; // upper case letter + if (c == '_') + return true; // underscore + return false; + } + + /** + * Return the class hash code, as specified in "The Common Object Request + * Broker: Architecture and Specification" (01-02-33), section 10.6.2. + */ + static long getClassHashCode(Class cls) { + // The simple cases + if (cls.isInterface()) + return 0; + if (!Serializable.class.isAssignableFrom(cls)) + return 0; + if (Externalizable.class.isAssignableFrom(cls)) + return 1; + // Try cache + Long l = (Long)classHashCodeCache.get(cls); + if (l != null) + return l.longValue(); + // Has to calculate the hash. + ByteArrayOutputStream baos = new ByteArrayOutputStream(256); + DataOutputStream dos = new DataOutputStream(baos); + // Step 1 + Class superClass = cls.getSuperclass(); + if (superClass != null && superClass != Object.class) { + try { + dos.writeLong(getClassHashCode(superClass)); + } catch (IOException ex) { + throw new RuntimeException("Unexpected IOException: " + ex); + } + } + // Step 2 + boolean hasWriteObject = false; + try { + Method m; + int mods; + m = cls.getDeclaredMethod("writeObject", new Class[] {ObjectOutputStream.class}); + mods = m.getModifiers(); + if (!Modifier.isPrivate(mods) && !Modifier.isStatic(mods)) + hasWriteObject = true; + } catch (NoSuchMethodException ex) { + // ignore + } + try { + dos.writeInt(hasWriteObject ? 2 : 1); + } catch (IOException ex) { + throw new RuntimeException("Unexpected IOException: " + ex); + } + // Step 3 + Field[] fields = cls.getDeclaredFields(); + SortedSet set = new TreeSet(new FieldComparator()); + for (int i = 0; i < fields.length; ++i) { + int mods = fields[i].getModifiers(); + if (!Modifier.isStatic(mods) && !Modifier.isTransient(mods)) + set.add(fields[i]); + } + Iterator iter = set.iterator(); + try { + while (iter.hasNext()) { + Field f = (Field)iter.next(); + dos.writeUTF(f.getName()); + dos.writeUTF(getSignature(f.getType())); + } + } catch (IOException ex) { + throw new RuntimeException("Unexpected IOException: " + ex); + } + // Convert to byte[] + try { + dos.flush(); + } catch (IOException ex) { + throw new RuntimeException("Unexpected IOException: " + ex); + } + byte[] bytes = baos.toByteArray(); + // Calculate SHA digest + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA"); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException("No SHA MEssageDigest: " + ex); + } + digest.update(bytes); + byte[] sha = digest.digest(); + // Calculate hash as per section 10.6.2 + long hash = 0; + for (int i = 0; i < Math.min(8, sha.length); i++) { + hash += (long)(sha[i] & 255) << (i * 8); + } + // Save in cache + classHashCodeCache.put(cls, new Long(hash)); + return hash; + } + + /** + * Calculate the signature of a class, according to the Java VM + * specification, section 4.3.2. + */ + private static String getSignature(Class cls) { + if (cls.isArray()) + return "[" + cls.getComponentType(); + if (cls.isPrimitive()) { + if (cls == Byte.TYPE) + return "B"; + if (cls == Character.TYPE) + return "C"; + if (cls == Double.TYPE) + return "D"; + if (cls == Float.TYPE) + return "F"; + if (cls == Integer.TYPE) + return "I"; + if (cls == Long.TYPE) + return "J"; + if (cls == Short.TYPE) + return "S"; + if (cls == Boolean.TYPE) + return "Z"; + throw new RuntimeException("Unknown primitive class."); + } + return "L" + cls.getName().replace('.', '/') + ";"; + } + + /** + * Handle mappings for primitive types, as per section 1.3.3. + */ + static String primitiveTypeIDLName(Class type) { + if (type == Void.TYPE) + return "void"; + if (type == Boolean.TYPE) + return "boolean"; + if (type == Character.TYPE) + return "wchar"; + if (type == Byte.TYPE) + return "octet"; + if (type == Short.TYPE) + return "short"; + if (type == Integer.TYPE) + return "long"; + if (type == Long.TYPE) + return "long long"; + if (type == Float.TYPE) + return "float"; + if (type == Double.TYPE) + return "double"; + throw new IllegalArgumentException(type + "is not a primitive type."); + } + + /** + * A <code>Comparator</code> for <code>Field</code>s, ordering the + * fields according to the lexicographic ordering of their Java names. + */ + private static class FieldComparator implements Comparator { + public int compare(Object o1, Object o2) { + if (o1 == o2) + return 0; + String n1 = ((Field)o1).getName(); + String n2 = ((Field)o2).getName(); + return n1.compareTo(n2); + } + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/IDLViolationException.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/InterfaceType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/Java2IDL.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/Java2IDLUtil.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/OperationType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ParameterType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/PrimitiveType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ValueMemberType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/java2idl/ValueType.java b/branches/sca-java-0.91/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/branches/sca-java-0.91/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()); + } + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBHandler.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBHandler.java new file mode 100644 index 0000000000..8d0d309aef --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBHandler.java @@ -0,0 +1,420 @@ +/* + * 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.util; + +import java.io.Externalizable; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.rmi.RemoteException; +import java.rmi.UnexpectedException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Map; + +import javax.ejb.EJBObject; +import javax.rmi.CORBA.Util; + +import org.apache.tuscany.sca.binding.ejb.java2idl.ExceptionType; +import org.apache.tuscany.sca.binding.ejb.java2idl.Java2IDLUtil; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.portable.ApplicationException; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.RemarshalException; +import org.omg.CORBA.portable.ServantObject; +import org.omg.CORBA_2_3.portable.InputStream; +import org.omg.CORBA_2_3.portable.OutputStream; +import org.osoa.sca.ServiceRuntimeException; + +/** + * EJBMessageHandler + */ +public class EJBHandler { + private Object ejbStub; + + private InterfaceInfo interfaceInfo; + private Class ejbInterface; + + public EJBHandler(NamingEndpoint namingEndpoint, Class ejbInterface) { + this(namingEndpoint, InterfaceInfo.getInstance(ejbInterface)); + this.ejbInterface = ejbInterface; + } + + // locates the stub + public EJBHandler(NamingEndpoint namingEndpoint, InterfaceInfo ejbInterface) { + try { + this.ejbStub = EJBStubHelper.lookup(namingEndpoint); + this.interfaceInfo = ejbInterface; + } catch (Exception e) { + Throwable b = e.getCause(); + b.printStackTrace(); + throw new ServiceRuntimeException(e); + } + } + + private final static Map<String, Class> primitiveClasses = new HashMap<String, Class>(); + static { + primitiveClasses.put("boolean", boolean.class); + primitiveClasses.put("byte", byte.class); + primitiveClasses.put("char", char.class); + primitiveClasses.put("short", short.class); + primitiveClasses.put("int", int.class); + primitiveClasses.put("long", long.class); + primitiveClasses.put("float", float.class); + primitiveClasses.put("double", double.class); + primitiveClasses.put("void", void.class); + } + + private static Class loadClass(final String name) { + Class type = (Class)primitiveClasses.get(name); + if (type != null) + return type; + return (Class)AccessController.doPrivileged(new PrivilegedAction<Class>() { + public Class run() { + try { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + return Class.forName(name, true, classLoader); + } catch (ClassNotFoundException e) { + return null; + } + } + }); + } + + // invokes EJB method + public Object invoke(String methodName, Object[] args) { + Object response = null; + try { + if (ejbStub instanceof ObjectImpl) { + ObjectImpl objectImpl = (ObjectImpl)ejbStub; + // TODO: If the Java 2 security is turned on, then + // the ORB will try to create proxy + // from the interfaces defined on the stub + if (System.getSecurityManager() == null && objectImpl._is_local()) { + /* + * CORBA.Stub is what the object from JNDI will be for a + * remote EJB in the same JVM as the client, but with no + * stub classes available on the client + */ + response = invokeLocalCORBACall(objectImpl, methodName, args); + } else { + /* + * _EJBObject_Stub is what the object from JNDI will be for + * a remote EJB with no stub classes available on the client + */ + response = invokeRemoteCORBACall(objectImpl, methodName, args); + } + } else { + /* + * A generated ejb stub or it must be an EJB in the same ear as + * the client or an AppServer with a single classloader, so + * reflection can be used directly on the JNDI + */ + JavaReflectionAdapter reflectionAdapter = + JavaReflectionAdapter.createJavaReflectionAdapter(ejbStub.getClass()); + try { + Method method = reflectionAdapter.getMethod(methodName); + response = method.invoke(ejbStub, args); + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + // FIXME need to throw really a business exception. + // ServiceBusinessException? + // Tuscany core doesn't have ServiceBusinessException + throw new ServiceRuntimeException(t); + } + } + + return response; + } catch (Exception e) { + // FIXME this be business exception? Tuscany core doesn't have + // ServiceBusinessException + throw new ServiceRuntimeException(e); + + } catch (Throwable e) { + throw new ServiceRuntimeException(e); + } + } + + /** + * Get the IDL operation name for a java method + * + * @param methodName java method name + * @return The IDL operation name + */ + private String getOperation(String methodName) { + if (interfaceInfo == null) + return methodName; + MethodInfo methodInfo = interfaceInfo.getMethod(methodName); + if (methodInfo != null) + return methodInfo.getIDLName(); + else + return null; + } + + /* + * Derive the EJB interface name from the Stub When loading a stub class + * corresponding to an interface or class <packagename>.<typename>, the + * class <packagename>._<typename>_Stub shall be used if it exists; + * otherwise, the class org.omg.stub.<packagename>._<typename>_Stub shall + * be used. + */ + private static String getInterface(String stubName) { + int index = stubName.lastIndexOf('.'); + String packageName = null; + String typeName = stubName; + if (index != -1) { + packageName = stubName.substring(0, index); + if (packageName.startsWith("org.omg.stub.")) { + packageName = packageName.substring("org.omg.stub.".length()); + } + typeName = stubName.substring(index + 1); + } + if (typeName.startsWith("_") && typeName.endsWith("_Stub")) { + typeName = typeName.substring(1, typeName.length() - "_Stub".length()); + } + if (packageName != null) + return packageName + "." + typeName; + else + return typeName; + } + + /** + * Invoke a method on the local CORBA object + * + * @param stub + * @param methodName + * @param args + * @return + * @throws RemoteException + * @throws ServiceBusinessException + */ + protected Object invokeLocalCORBACall(final ObjectImpl stub, String methodName, Object[] args) + throws RemoteException { + + final String operation = getOperation(methodName); + + Class type = loadClass(getInterface(stub.getClass().getName())); + if (type == null) + type = (ejbInterface != null) ? ejbInterface : EJBObject.class; + + ServantObject so = stub._servant_preinvoke(operation, type); + if (so == null) { + // The Servant is not local any more + return invokeRemoteCORBACall(stub, methodName, args); + } + Object[] newArgs = null; + ORB orb = stub._orb(); + try { + if (args != null) + newArgs = Util.copyObjects(args, orb); + JavaReflectionAdapter reflectionAdapter = + JavaReflectionAdapter.createJavaReflectionAdapter(so.servant.getClass()); + Method method = reflectionAdapter.getMethod(methodName); + Object obj = reflectionAdapter.invoke(method, so.servant, newArgs); + Object result = Util.copyObject(obj, orb); + return result; + + } catch (InvocationTargetException e) { + Throwable exCopy = (Throwable)Util.copyObject(e.getTargetException(), orb); + MethodInfo methodInfo = interfaceInfo.getMethod(methodName); + String[] exceptionTypes = methodInfo.getExceptionTypes(); + for (int i = 0; i < exceptionTypes.length; i++) { + Class exceptionType = loadClass(exceptionTypes[i]); + if (exceptionType.isAssignableFrom(exCopy.getClass())) + throw new ServiceRuntimeException(exCopy); // FIXME should + // be business + // exception? + } + throw Util.wrapException(exCopy); + } catch (Throwable e) { + // Other exceptions thrown from "invoke" + throw new ServiceRuntimeException(e); + } finally { + stub._servant_postinvoke(so); + } + } + + /** + * Invoke a method on a remote CORBA object + * + * @param stub The remote stub + * @param methodName The name of the method + * @param args Argument list + * @return + * @throws RemoteException + * @throws ServiceBusinessException + */ + protected Object invokeRemoteCORBACall(ObjectImpl stub, String methodName, Object[] args) throws RemoteException { + + try { + String operation = getOperation(methodName); + + MethodInfo methodInfo = interfaceInfo.getMethod(methodName); + if (methodInfo == null) { + throw new ServiceRuntimeException("Invalid Method " + methodName); + } + String[] types = methodInfo.getParameterTypes(); + if (args != null) { + if (types.length != args.length) + throw new ServiceRuntimeException( + "The argument list doesn't match the method signature of " + methodName); + } + + Class[] parameterTypes = new Class[types.length]; + for (int i = 0; i < types.length; i++) { + parameterTypes[i] = loadClass(types[i]); + } + Class returnType = loadClass(methodInfo.getReturnType()); + + InputStream in = null; + try { + OutputStream out = (OutputStream)stub._request(operation, true); + + for (int i = 0; i < types.length; i++) { + // Object arg = (args.length < i) ? null : args[i]; + writeValue(out, args[i], parameterTypes[i]); + } + if (returnType == void.class) { + // void return + stub._invoke(out); + return null; + } else { + // read the return value + in = (InputStream)stub._invoke(out); + Object response = readValue(in, returnType); + return response; + } + + } catch (ApplicationException ex) { + in = (InputStream)ex.getInputStream(); + String id = in.read_string(); + // Check if the id matches to any declared exceptions for the + // method + String[] exceptionTypes = methodInfo.getExceptionTypes(); + for (int i = 0; i < exceptionTypes.length; i++) { + Class exceptionType = loadClass(exceptionTypes[i]); + String exceptionId = ExceptionType.getExceptionType(exceptionType).getExceptionRepositoryId(); + if (id.equals(exceptionId)) { + Throwable t = (Throwable)in.read_value(exceptionType); + throw new ServiceRuntimeException(t); // FIXME should + // be + // ServcieBusinessException? + // no support by + // Tuscany core + // for + // ServcieBusinessException. + } + } + throw new UnexpectedException(id); + } catch (RemarshalException ex) { + return invokeRemoteCORBACall(stub, methodName, args); + } finally { + stub._releaseReply(in); + } + } catch (SystemException ex) { + throw Util.mapSystemException(ex); + } + } + + /** + * @param out + * @param value + * @param type + */ + protected void writeValue(OutputStream out, Object value, Class type) { + if (type == null) + out.write_value((Serializable)value); + else if (type == Object.class || type == Serializable.class || type == Externalizable.class) { + // Any + Util.writeAny(out, value); + } else if (type == Integer.TYPE) { + // java int maps to CORBA long + out.write_long(((Integer)value).intValue()); + } else if (type == Short.TYPE) { + out.write_short(((Short)value).shortValue()); + } else if (type == Boolean.TYPE) { + out.write_boolean(((Boolean)value).booleanValue()); + } else if (type == Byte.TYPE) { + out.write_octet(((Byte)value).byteValue()); + } else if (type == Long.TYPE) { + out.write_longlong(((Long)value).longValue()); + } else if (type == Double.TYPE) { + out.write_double(((Double)value).doubleValue()); + } else if (type == Float.TYPE) { + out.write_float(((Float)value).floatValue()); + } else if (type == Character.TYPE) { + out.write_wchar(((Character)value).charValue()); + } else if (type.isArray()) { + out.write_value((Serializable)value, type); + } else if (Java2IDLUtil.isRemoteInterface(type)) { + // Remote interface + Util.writeRemoteObject(out, value); + } else if (Java2IDLUtil.isAbstractInterface(type)) { + // Non-remote Interface + Util.writeAbstractObject(out, value); + } else { + out.write_value((Serializable)value, type); + } + } + + /** + * @param in + * @param type + * @return + */ + protected Object readValue(InputStream in, Class type) { + Object value = null; + if (type == null) + value = in.read_value(); + else if (type == Object.class || type == Serializable.class || type == Externalizable.class) { + value = Util.readAny(in); + } else if (type == Integer.TYPE) { + value = new Integer(in.read_long()); + } else if (type == Short.TYPE) { + value = new Short(in.read_short()); + } else if (type == Boolean.TYPE) { + value = new Boolean(in.read_boolean()); + } else if (type == Byte.TYPE) { + value = new Byte(in.read_octet()); + } else if (type == Long.TYPE) { + value = new Long(in.read_longlong()); + } else if (type == Float.TYPE) { + value = new Float(in.read_float()); + } else if (type == Double.TYPE) { + value = new Double(in.read_double()); + } else if (type == Character.TYPE) { + value = new Character(in.read_wchar()); + } else if (type.isArray()) { + // [] + value = in.read_value(type); + } else if (Java2IDLUtil.isRemoteInterface(type)) { + // java.rmi.Remote + value = in.read_Object(type); + } else if (Java2IDLUtil.isAbstractInterface(type)) { + // Non-remote Interface + value = in.read_abstract_interface(type); + } else { + // java.io.Serializable + value = in.read_value(type); + } + return value; + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java new file mode 100644 index 0000000000..1369b92715 --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java @@ -0,0 +1,511 @@ +/* + * 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.util; + +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.InvalidNameException; +import javax.naming.NamingException; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.ORBPackage.InvalidName; +import org.omg.CosNaming.NamingContextExt; +import org.omg.CosNaming.NamingContextExtHelper; + +/** + * CosNaming utility + */ +public class EJBLocator { + + /* + * Root Context Initial Reference Key ------------ + * ----------------------------------- Server Root NameServiceServerRoot + * Cell Persistent Root NameServiceCellPersistentRoot Cell Root + * NameServiceCellRoot, NameService Node Root NameServiceNodeRoot + */ + public static final String SERVER_ROOT = "NameServiceServerRoot"; + public static final String CELL_PERSISTENT_ROOT = "NameServiceCellPersistentRoot"; + public static final String CELL_ROOT = "NameServiceCellRoot"; + public static final String NODE_ROOT = "NameServiceNodeRoot"; + public static final String DEFAULT_ROOT = "NameService"; // Same as + // CELL_ROOT + + private static final Set ROOTS = new HashSet(Arrays.asList(new String[] {SERVER_ROOT, CELL_PERSISTENT_ROOT, + CELL_ROOT, DEFAULT_ROOT, NODE_ROOT})); + + public static final String DEFAULT_HOST = "127.0.0.1"; // Default host name + // or IP address for + // Websphere + public static final int DEFAULT_NAMING_PORT = 2809; // Default port + public static final String NAMING_SERVICE = "NameService"; // The name of + // the naming + // service + + // private static final String CHARS_TO_ESCAPE = "\\/."; + private static final String RFC2396 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;/:?@&=+$,-_.!~*'()"; + private static final String HEX = "0123456789ABCDEF"; + + private String hostName = DEFAULT_HOST; + private int port = DEFAULT_NAMING_PORT; + private String root = SERVER_ROOT; + + private ORB orb = null; + private ObjectLocator locator = null; + boolean managed = true; + + public EJBLocator(boolean managed) { + this.managed = managed; + if (!managed) { + String url = (String)AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty(Context.PROVIDER_URL); + } + }); + processCorbaURL(url); + } + } + + private void processCorbaURL(String url) { + if (url != null && (url.startsWith("corbaname:iiop:") || url.startsWith("corbaloc:iiop:"))) { + /** + * corbaname:iiop:<hostName>:<port>/<root>#name corbaloc:iiop:<hostname>:<port>/<root> + * For exmaple, + * "corbaname:iiop:localhost:2809/NameServiceServerRoot#ejb/MyEJBHome"; + * or "corbaloc:iiop:myhost:2809/NameServiceServerRoot" + */ + String[] parts = url.split("(:|/|#)"); + if (parts.length > 2 && parts[2].length() > 0) { + hostName = parts[2]; // The host name + int index = hostName.lastIndexOf('@'); // version@hostname + if (index != -1) + hostName = hostName.substring(index + 1); + } + if (parts.length > 3 && parts[3].length() > 0) + port = Integer.parseInt(parts[3]); // The port number + if (parts.length > 4 && parts[4].length() > 0) + root = parts[4]; // The root of naming + } + } + + public EJBLocator(String hostName, int port) { + this.hostName = (hostName == null) ? DEFAULT_HOST : hostName; + this.port = port > 0 ? port : DEFAULT_NAMING_PORT; + this.root = SERVER_ROOT; + } + + public EJBLocator(String hostName, int port, String root) { + this(hostName, port); + if (ROOTS.contains(root)) + this.root = root; + else + throw new IllegalArgumentException(root + " is not a legal root"); + } + + public EJBLocator(String corbaName, boolean managed) { + this.managed = managed; + if (corbaName.startsWith("corbaname:iiop:")) { + processCorbaURL(corbaName); + } else + throw new IllegalArgumentException(corbaName + " is not a legal corbaname"); + } + + /** + * The corbaloc and corbaname formats enable you to provide a URL to access + * CORBA objects. Use the corbaloc format for resolving to a particular + * CORBAservice without going through a naming service. Use the corbaname + * format to resolve a stringified name from a specific naming context. + */ + + /** + * Compose a corbaloc URI + * + * @param hostName + * @param port + * @param service + * @return + */ + private static String getCorbaloc(String hostName, int port, String service) { + if (service == null) + return "corbaloc:iiop:" + hostName + ":" + port; + else + return "corbaloc:iiop:" + hostName + ":" + port + "/" + service; + } + + private String getCorbaloc(String service) { + return getCorbaloc(hostName, port, service); + } + + /** + * corbaname Syntax The full corbaname BNF is: <corbaname> = + * "corbaname:"<corbaloc_obj>["#"<string_name>] + * <corbaloc_obj> = <obj_addr_list> ["/"<key_string>] + * <obj_addr_list> = as defined in a corbaloc URL <key_string> = + * as defined in a corbaloc URL <string_name>= stringified Name + * empty_string Where: + * <ul> + * <li>corbaloc_obj: portion of a corbaname URL that identifies the naming + * context. The syntax is identical to its use in a corbaloc URL. + * <li>obj_addr_list: as defined in a corbaloc URL + * <li>key_string: as defined in a corbaloc URL. + * <li>string_name: a stringified Name with URL escapes as defined below. + * </ul> + * + * @param hostName The host name or IP address of the naming server + * @param port The port number of the naming service + * @param root The root of the namespace + * @param name The JNDI name + */ + private static String getCorbaname(String hostName, int port, String root, String name) { + if (name == null) + return "corbaname:iiop:" + hostName + ":" + port + "/" + root; + else + return "corbaname:iiop:" + hostName + ":" + port + "/" + root + "#" + toCorbaname(name); + } + + String getCorbaname(String name) { + return getCorbaname(hostName, port, root, name); + } + + /** + * Connect to the ORB. + */ + + // FIXME. May need to change the IBM classes if this binding is contributed + // to Tuscany + public ORB connect() { + if (orb == null) { + Properties props = new Properties(); + /* This code is for IBM JVM + props.put("org.omg.CORBA.ORBClass", "com.ibm.CORBA.iiop.ORB"); + props.put("com.ibm.CORBA.ORBInitRef.NameService", getCorbaloc(NAMING_SERVICE)); + props.put("com.ibm.CORBA.ORBInitRef.NameServiceServerRoot", getCorbaloc("NameServiceServerRoot")); */ + orb = ORB.init((String[])null, props); + } + return orb; + } + + /** + * Replace substrings + * + * @param source The source string. + * @param match The string to search for within the source string. + * @param replace The replacement for any matching components. + * @return + */ + private static String replace(String source, String match, String replace) { + int index = source.indexOf(match, 0); + if (index >= 0) { + + // We have at least one match, so gotta do the + // work... + + StringBuffer result = new StringBuffer(source.length() + 16); + int matchLength = match.length(); + int startIndex = 0; + + while (index >= 0) { + result.append(source.substring(startIndex, index)); + result.append(replace); + startIndex = index + matchLength; + index = source.indexOf(match, startIndex); + } + + // Grab the last piece, if any... + if (startIndex < source.length()) { + result.append(source.substring(startIndex)); + } + + return result.toString(); + + } else { + // No matches, just return the source... + return source; + } + } + + /** + * Resovled the JNDI name from the initial CosNaming context + * + * @param jndiName + * @return resovled CORBA ojbect + * @throws NamingException + */ + private static org.omg.CORBA.Object resovleString(NamingContextExt initCtx, String jndiName) throws NamingException { + try { + String name = stringify(jndiName); + return initCtx.resolve_str(name); + } catch (Exception e) { + NamingException ne = new NamingException(e.getMessage()); + ne.setRootCause(e); + throw ne; + } + } + + private NamingContextExt getCosNamingContext(String namingRoot) throws NamingException { + /* + * Using an ORB reference to get an initial naming reference There are + * two basic ways to get an initial CosNaming context. Both ways involve + * an ORB method invocation. The first way is to invoke the + * resolve_initial_references method on the ORB with an initial + * reference key. For this call to work, the ORB must be initialized + * with an initial reference for that key. The other way is to invoke + * the string_to_object method on the ORB, passing in a CORBA object URL + * with the host and port of the bootstrap server. The following + * examples illustrate both approaches. + */ + + /* + * Invoking resolve_initial_references Once an ORB reference is + * obtained, invoke the resolve_initial_references method on the ORB to + * obtain a reference to the initial context. The following code example + * invokes resolve_initial_reference on an ORB reference + */ + try { + connect(); + org.omg.CORBA.Object rootCtx = orb.resolve_initial_references(namingRoot); + return NamingContextExtHelper.narrow(rootCtx); + } catch (InvalidName e) { + InvalidNameException ne = new InvalidNameException(e.getMessage()); + ne.setRootCause(e); + throw ne; + } + } + + /** + * Look up a CORBA object by its JNDI name + * + * @param jndiName + * @return + * @throws NamingException + */ + org.omg.CORBA.Object stringToObject(String jndiName) throws NamingException { + /* + * Using an existing ORB and invoking string_to_object with a CORBA + * object URL with multiple name server addresses to get an initial + * context CORBA object URLs can contain more than one bootstrap server + * address. Use this feature when attempting to obtain an initial + * context from a server cluster. You can specify the bootstrap server + * addresses for all servers in the cluster in the URL. The operation + * will succeed if at least one of the servers is running, eliminating a + * single point of failure. There is no guarantee of any particular + * order in which the address list will be processed. For example, the + * second bootstrap server address may be used to obtain the initial + * context even though the first bootstrap server in the list is + * available. An example of a corbaloc URL with multiple addresses + * follows. obj = + * orb.string_to_object("corbaloc::myhost1:9810,:myhost1:9811,:myhost2:9810/NameService"); + */ + String corbaName = null; + if (jndiName.startsWith("corbaloc:") || jndiName.startsWith("corbaname:")) { + // Keep the qualified URL + corbaName = jndiName; + } else { + // Create a corbaname URL + corbaName = getCorbaname(jndiName); + } + + connect(); + org.omg.CORBA.Object obj = orb.string_to_object(corbaName); + return obj; + } + + private boolean isJndiConfigured() { + if (managed) + return true; + Boolean provided = (Boolean)AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + String initCtxFactory = System.getProperty(Context.INITIAL_CONTEXT_FACTORY); + if (initCtxFactory == null) { + URL file = Thread.currentThread().getContextClassLoader().getResource("jndi.properties"); + if (file != null) + return Boolean.TRUE; + else + return Boolean.FALSE; + } else + return Boolean.TRUE; + } + }); + return provided.booleanValue(); + } + + /** + * The character escape rules for the stringified name portion of an + * corbaname are: US-ASCII alphanumeric characters are not escaped. + * Characters outside this range are escaped, except for the following: ; / : ? @ & = + $ , - _ . ! ~ * ' ( ) + * corbaname Escape Mechanism The percent '%' character is used as an + * escape. If a character that requires escaping is present in a name + * component it is encoded as two hexadecimal digits following a "%" + * character to represent the octet. (The first hexadecimal character + * represent the highorder nibble of the octet, the second hexadecimal + * character represents the low-order nibble.) If a '%' is not followed by + * two hex digits, the stringified name is syntactically invalid. + * @param s + * @return RFC2396-encoded stringified name + */ + static String encode2396(String s) { + if (s == null) + return null; + StringBuffer encoded = new StringBuffer(s); + for (int i = 0; i < encoded.length(); i++) { + char c = encoded.charAt(i); + if (RFC2396.indexOf(c) == -1) { + encoded.setCharAt(i, '%'); + char ac[] = Integer.toHexString(c).toCharArray(); + if (ac.length == 2) + encoded.insert(i + 1, ac); + else if (ac.length == 1) { + encoded.insert(i + 1, '0'); + encoded.insert(i + 2, ac[0]); + } else { + throw new IllegalArgumentException("Invalid character '" + c + "' in \"" + s + "\""); + } + i += 2; + } + } + return encoded.toString(); + } + + /** + * Decode an RFC2396-encoded string + * + * @param s + * @return Plain string + */ + static String decode2396(String s) { + if (s == null) + return null; + StringBuffer decoded = new StringBuffer(s); + for (int i = 0; i < decoded.length(); i++) { + char c = decoded.charAt(i); + if (c == '%') { + if (i + 2 >= decoded.length()) + throw new IllegalArgumentException("Incomplete key_string escape sequence"); + int j; + j = HEX.indexOf(decoded.charAt(i + 1)) * 16 + HEX.indexOf(decoded.charAt(i + 2)); + decoded.setCharAt(i, (char)j); + decoded.delete(i + 1, i + 3); + } else if (RFC2396.indexOf(c) == -1) + throw new IllegalArgumentException("Invalid key_string character '" + c + "'"); + } + return decoded.toString(); + } + + /** + * The backslash '\' character escapes the reserved meaning of '/', '.', and + * '\' in a stringified name. + * + * @param jndiName + * @return Escaped stringified name for CosNaming + */ + private static String stringify(String jndiName) { + // Esacpe . into \. since it's an INS naming delimeter + return replace(encode2396(jndiName), ".", "\\."); + } + + /** + * Escape the "." into "%5C%2E" + * + * @param jndiName + * @return corbaname treating "." as a literal + */ + private static String toCorbaname(String jndiName) { + // Esacpe . into %5C%2E (\.) since it's an INS naming delimeter + // For example, sca.sample.StockQuote ---> + // sca%5C%2Esample%5C%2EStockQuote/StockQuote + return replace(encode2396(jndiName), ".", "%5C%2E"); + } + + private ObjectLocator getObjectLocator() throws NamingException { + if (locator != null) + return locator; + /* + * For managed env, jndi is assumed to be configured by default For + * unmanaged environment, jndi could have configured through + * jndi.properties file + */ + if (isJndiConfigured()) { + locator = new JndiLocator(); + } else { // this is definitely JSE env without jndi configured. Use + // Corba. + locator = new CosNamingLocator(); + } + return locator; + } + + public Object locate(String jndiName) throws NamingException { + + Object result = getObjectLocator().locate(jndiName); + return result; + } + + private static interface ObjectLocator { + public Object locate(String name) throws NamingException; + } + + private class JndiLocator implements ObjectLocator { + private Context context; + + private JndiLocator() throws NamingException { + this.context = new InitialContext(); + } + + private JndiLocator(Context context) { + this.context = context; + } + + public Object locate(String name) throws NamingException { + try { + return context.lookup(name); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + } + + private class CosNamingLocator implements ObjectLocator { + private NamingContextExt context = null; + + private CosNamingLocator() { + } + + private CosNamingLocator(NamingContextExt context) { + this.context = context; + } + + public Object locate(String name) throws NamingException { + if (context != null) + return resovleString(context, name); + else + return stringToObject(name); + } + } + + public void setHostEnv(boolean managed) { + this.managed = managed; + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBObjectFactory.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBObjectFactory.java new file mode 100644 index 0000000000..1538c27716 --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBObjectFactory.java @@ -0,0 +1,188 @@ +/* + * 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.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.rmi.RemoteException; +import java.rmi.UnexpectedException; + +import javax.ejb.CreateException; +import javax.ejb.EJBLocalHome; +import javax.naming.NamingException; +import javax.rmi.CORBA.Util; + +import org.omg.CORBA.SystemException; +import org.omg.CORBA.portable.ApplicationException; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.RemarshalException; +import org.osoa.sca.ServiceRuntimeException; + +public class EJBObjectFactory { + + private EJBObjectFactory() { + } + + /** + * Get either a generated of dynamic EJB stub using the specified JNDI + * properties. + * <p> + * The returned stub will implement the specified stubInterface Interface. + * If the underlying EJB stub is not assignable from the specified + * stubInterface then a proxy is used to convert between the two. + * <p> + * The returned EJB stub may be either the pregenerated EJB stub or a + * dynamic stub. This allows a client to invoke an EJB without requiring any + * of the pregenerated EJB stub classes be avaiable in the classpath. + * <p> + */ + public static Object createStub(NamingEndpoint namingEndpoint) throws NamingException, RemoteException, + CreateException { + + EJBLocator locator = namingEndpoint.getLocator(); + Object homeObject = locator.locate(namingEndpoint.getJndiName()); + /* + * The type of the object returned from the lookup is as follows: If the + * generated stub exists on the classpath, it's an instance of that + * type, otherwise, "org.omg.stub.java.rmi._Remote_Stub" or + * "org.omg.stub.javax.ejb._EJBHome_Stub" + */ + Object stub = getEJBStub(homeObject); + // Cache dynamic stub only + return stub; + } + + /** + * @param homeObject + * @param ejbHomeClass + * @return + * @throws RemoteException + */ + protected static Object getEJBStub(Object homeObject) throws RemoteException, CreateException { + + Object stub = null; + if (homeObject instanceof EJBLocalHome) { + // Local EJB + stub = createEJBLocalObject(homeObject); + } else { + // Handle dynamic stub + if (homeObject instanceof ObjectImpl) { + ObjectImpl objectImpl = (ObjectImpl)homeObject; + stub = createEJBObject(objectImpl); + } /** + * Above checks will be satisfied if Bean is running on servers like Websphere. With this + * logic, client (SCA composite with EJB ref binding) doesn't need to include home class or + * client stubs. + * + * Below check is needed SCA composite with EJB ref binding is accessing openEJB implementation. + * For e.g if the bean is running on Geronimo. + */ + else if ((javax.rmi.PortableRemoteObject.narrow(homeObject, javax.ejb.EJBHome.class)) instanceof javax.ejb.EJBHome) { + stub = createEJBObjectFromHome(homeObject); + } else + throw new ServiceRuntimeException("Invalid stub type: " + homeObject.getClass()); + } + return stub; + } + + /** + * Create a pre-generated EJB stub + * + * @param homeObject + * @return + * @throws RemoteException + */ + protected static Object createEJBLocalObject(Object homeObject) throws RemoteException { + + Object stub = null; + try { + // Find the "create()" method + Method createMethod = homeObject.getClass().getMethod("create", null); + // Create an EJB object + stub = createMethod.invoke(homeObject, null); + } catch (NoSuchMethodException e) { + // "create()" method not found, it's still a dynamic stub + stub = null; + } catch (InvocationTargetException e) { + throw new RemoteException(e.getTargetException().toString()); + } catch (Exception e) { + throw new RemoteException(e.toString()); + } + return stub; + } + + /** + * Here homeObject is instance of EJBHome + * + * @param homeObject + * @return + * @throws RemoteException + */ + protected static Object createEJBObjectFromHome(Object homeObject) throws RemoteException { + + Object stub = null; + try { + // Find the "create()" method + Method createMethod = homeObject.getClass().getMethod("create", null); + // Create an EJB object + stub = createMethod.invoke(homeObject, null); + } catch (NoSuchMethodException e) { + // "create()" method not found, it's still a dynamic stub + stub = null; + } catch (InvocationTargetException e) { + throw new RemoteException(e.getTargetException().toString()); + } catch (Exception e) { + throw new RemoteException(e.toString()); + } + return stub; + } + + /** + * Create an EJBObject using RMI/IIOP APIs + * + * @param ejbHomeObject + * @return The EJBObject remote stub + * @throws CreateException + * @throws RemoteException + */ + protected static Object createEJBObject(ObjectImpl ejbHomeObject) throws CreateException, RemoteException { + + try { + org.omg.CORBA_2_3.portable.InputStream in = null; + try { + org.omg.CORBA.portable.OutputStream out = ejbHomeObject._request("create", true); + in = (org.omg.CORBA_2_3.portable.InputStream)ejbHomeObject._invoke(out); + return (Object)in.read_Object(Object.class); + } catch (ApplicationException ex) { + in = (org.omg.CORBA_2_3.portable.InputStream)ex.getInputStream(); + String id = in.read_string(); + if (id.equals("IDL:javax/ejb/CreateEx:1.0")) { + throw (CreateException)in.read_value(CreateException.class); + } + throw new UnexpectedException(id); + } catch (RemarshalException ex) { + return createEJBObject(ejbHomeObject); + } finally { + ejbHomeObject._releaseReply(in); + } + } catch (SystemException ex) { + throw Util.mapSystemException(ex); + } + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBStubHelper.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBStubHelper.java new file mode 100644 index 0000000000..ee05420cd7 --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBStubHelper.java @@ -0,0 +1,69 @@ +/* + * 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.util; + +import java.rmi.RemoteException; + +import javax.ejb.CreateException; +import javax.naming.NamingException; + +import org.osoa.sca.ServiceRuntimeException; +import org.osoa.sca.ServiceUnavailableException; + +public class EJBStubHelper { + + private static Object stub; + private static ServiceRuntimeException exception; + + private EJBStubHelper() { + } + + /** + * @param owner + * @param jndiName + * @return + */ + + public static Object lookup(NamingEndpoint endpoint) { + return getStub(endpoint); + } + + public static Object getStub(NamingEndpoint namingEndpoint) { + try { + stub = EJBObjectFactory.createStub(namingEndpoint); + } catch (NamingException e) { + exception = new ServiceUnavailableException(e); + e.printStackTrace(); + throw (ServiceUnavailableException)exception; + } catch (CreateException e) { + exception = new ServiceUnavailableException(e); + throw (ServiceUnavailableException)exception; + } catch (RemoteException e) { + exception = new ServiceRuntimeException(e); + throw (ServiceRuntimeException)exception; + } + + if (exception == null) { + return stub; // Normal result + } else { + throw exception; // Throw the exception + } + } + +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/InterfaceInfo.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/InterfaceInfo.java new file mode 100644 index 0000000000..19f4063a12 --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/InterfaceInfo.java @@ -0,0 +1,125 @@ +/* + * 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.util; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; + +import org.apache.tuscany.sca.binding.ejb.java2idl.Java2IDL; +import org.apache.tuscany.sca.binding.ejb.java2idl.OperationType; + +// import commonj.sdo.DataObject; + +/** + * The signature for a java interface + */ +public class InterfaceInfo implements Serializable { + + private static final Map interfaces = Collections.synchronizedMap(new WeakHashMap()); + + private static final long serialVersionUID = 2314533906465094860L; + private String name; + + private Map methods = new HashMap(); + + public synchronized final static InterfaceInfo getInstance(final Class iface) { + InterfaceInfo info = (InterfaceInfo)interfaces.get(iface); + if (info == null) { + info = new InterfaceInfo(iface); + interfaces.put(iface, info); + } + return info; + } + + public InterfaceInfo(final Class iface) { + super(); + if (iface == null) + throw new IllegalArgumentException("The interface cannot be null"); + this.name = iface.getName(); + // SECURITY + /* + * Permission: accessDeclaredMembers : Access denied + * (java.lang.RuntimePermission accessDeclaredMembers) + */ + Map idlNames = (Map)AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return Java2IDL.getIDLMapping(iface); + } + }); + Iterator i = idlNames.entrySet().iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + Method method = (Method)entry.getKey(); + OperationType operationType = (OperationType)entry.getValue(); + MethodInfo methodInfo = new MethodInfo(method); + methodInfo.setIDLName(operationType.getIDLName()); + methods.put(method.getName(), methodInfo); + } + } + + /* + * public InterfaceInfo(String portType, String wsdlOperationName) { + * super(); this.name = portType; // <DataObject> operation(<DataObject>) + * throws RemoteException MethodInfo method = new + * MethodInfo(wsdlOperationName, DataObject.class.getName(), new + * String[]{DataObject.class.getName()}, new + * String[]{RemoteException.class.getName()}); methods.put(method.getName(), + * method); } + */ + + /** + * @return + */ + public Map getMethods() { + return methods; + } + + /** + * @return + */ + public MethodInfo getMethod(String name) { + return (MethodInfo)methods.get(name); + } + + /** + * @return + */ + public String getName() { + return name; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("interface ").append(name).append("{ \n"); + Iterator i = methods.values().iterator(); + while (i.hasNext()) { + MethodInfo methodInfo = (MethodInfo)i.next(); + sb.append("\t").append(methodInfo).append("\n"); + } + sb.append("};\n"); + return sb.toString(); + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/JavaReflectionAdapter.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/JavaReflectionAdapter.java new file mode 100644 index 0000000000..db762aeb13 --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/JavaReflectionAdapter.java @@ -0,0 +1,155 @@ +/* + * 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.util; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; + +import org.osoa.sca.ServiceRuntimeException; + +/** + * An adapter for java classes, indexes the methods by name and provides an + * invoke method that takes a method name. + */ +public class JavaReflectionAdapter { + + private static Map adapters = Collections.synchronizedMap(new WeakHashMap()); + + private Class clazz; + private Map methodMap = new HashMap(); + + /** + * Create a java reflection adapter + * + * @param clazz + */ + public synchronized static JavaReflectionAdapter createJavaReflectionAdapter(Class clazz) { + JavaReflectionAdapter adapter = (JavaReflectionAdapter)adapters.get(clazz); + if (adapter == null) { + adapter = new JavaReflectionAdapter(clazz); + adapters.put(clazz, adapter); + } + return adapter; + } + + /** + * Constructor + * + * @param clazz + */ + private JavaReflectionAdapter(final Class clazz) { + this.clazz = clazz; + + // Index the methods on the implementation class + Method[] methods = (Method[])AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return clazz.getMethods(); + } + }); + for (int i = 0, n = methods.length; i < n; i++) { + methodMap.put(methods[i].getName(), methods[i]); + } + } + + /** + * Returns a map containing the methods on the class, keyed by name + * + * @return + */ + public Map getMethods() { + return methodMap; + } + + /** + * Return the specified method + * + * @param methodName + * @return + * @throws NoSuchMethodException + */ + public Method getMethod(String methodName) throws NoSuchMethodException { + + Method method = (Method)methodMap.get(methodName); + if (method == null) + throw new NoSuchMethodException(methodName); + return method; + } + + private final static Map DEFAULT_PRIMITIVE_VALUES = new HashMap(); + static { + DEFAULT_PRIMITIVE_VALUES.put(boolean.class, Boolean.FALSE); + DEFAULT_PRIMITIVE_VALUES.put(byte.class, new Byte((byte)0)); + DEFAULT_PRIMITIVE_VALUES.put(char.class, new Character((char)0)); + DEFAULT_PRIMITIVE_VALUES.put(short.class, new Short((short)0)); + DEFAULT_PRIMITIVE_VALUES.put(int.class, new Integer(0)); + DEFAULT_PRIMITIVE_VALUES.put(long.class, new Long(0)); + DEFAULT_PRIMITIVE_VALUES.put(float.class, new Float(0.0)); + DEFAULT_PRIMITIVE_VALUES.put(double.class, new Double(0.0)); + } + + /** + * Invoke a method using Java reflection. + * + * @param method + * @param object + * @param args + * @return + * @throws InvocationTargetException + * @throws IllegalAccessException + */ + public Object invoke(Method method, Object object, Object[] args) throws InvocationTargetException, + IllegalAccessException { + Class[] parameterTypes = method.getParameterTypes(); + for (int i = 0; i < parameterTypes.length; i++) { + Class parameterType = parameterTypes[i]; + if (args[i] == null && parameterType.isPrimitive()) { + args[i] = DEFAULT_PRIMITIVE_VALUES.get(parameterType); + } + } + return method.invoke(object, args); + } + + /** + * Set the java bean property + * + * @param bean + * @param propertyName + * @param value + * @return + */ + public boolean setProperty(Object bean, String propertyName, Object value) { + try { + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(propertyName, bean.getClass()); + Method writeMethod = propertyDescriptor.getWriteMethod(); + writeMethod.invoke(bean, new Object[] {value}); + return true; + } catch (InvocationTargetException e) { + throw new ServiceRuntimeException(e.getTargetException()); + } catch (Exception e) { + return false; + } + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/MethodInfo.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/MethodInfo.java new file mode 100644 index 0000000000..ac3ace2d6c --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/MethodInfo.java @@ -0,0 +1,176 @@ +/* + * 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.util; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * MetaData for a java method + */ +public class MethodInfo implements Serializable { + + /** Automatically generated javadoc for: serialVersionUID */ + private static final long serialVersionUID = -5557260979514687514L; + private String name; + private String returnType; + private String[] parameterTypes; + private String[] exceptionTypes; + + private String IDLName; + + /** + * Type Signature Java Type -------------- --------- Z boolean B byte C char + * S short I int J long F float D double L fully-qualified-class ; + * fully-qualified-class [ type type[] ( arg-types ) ret-type method type + */ + private final static Map signatures = new HashMap(); + static { + signatures.put("Z", boolean.class); + signatures.put("B", byte.class); + signatures.put("C", char.class); + signatures.put("S", short.class); + signatures.put("I", int.class); + signatures.put("J", long.class); + signatures.put("F", float.class); + signatures.put("D", double.class); + signatures.put("V", void.class); + } + + public MethodInfo(Method method) { + this.name = method.getName(); + // this.declaringClass = method.getDeclaringClass().getName(); + this.returnType = method.getReturnType().getName(); + Class[] types = method.getParameterTypes(); + this.parameterTypes = new String[types.length]; + for (int i = 0; i < types.length; i++) { + this.parameterTypes[i] = types[i].getName(); + } + types = method.getExceptionTypes(); + this.exceptionTypes = new String[types.length]; + for (int i = 0; i < types.length; i++) { + this.exceptionTypes[i] = types[i].getName(); + } + IDLName = this.name; + } + + protected MethodInfo(String name, String returnType, String[] parameterTypes, String[] exceptionTypes) { + this.name = name; + this.returnType = returnType; + this.parameterTypes = parameterTypes; + this.exceptionTypes = exceptionTypes; + this.IDLName = name; + } + + /** + * Parse the class name from the internal signature Sample signatures: int + * ---> I; int[] ---> [I Object ---> java/lang/Object Object[] ---> + * [Ljava/lang/Object; + * + * @param value + * @return + */ + private static String getName(String signature) { + String name = signature; + // Remove leading ARRAY ([) signatures + int index = name.lastIndexOf('['); + if (index != -1) + name = name.substring(index + 1); + + // Remove L<...>; + if (name.charAt(0) == 'L' && name.charAt(name.length() - 1) == ';') + name = name.substring(1, name.length() - 1); + + // Primitive types + Class primitiveClass = (Class)signatures.get(name); + if (primitiveClass != null) { + name = primitiveClass.getName(); + } + + for (int i = 0; i < index + 1; i++) { + name = name + "[]"; + } + return name; + } + + /** + * @return + */ + public String getName() { + return name; + } + + /** + * @return + */ + public String[] getParameterTypes() { + return parameterTypes; + } + + /** + * @return + */ + public String getReturnType() { + return returnType; + } + + /** + * @return + */ + public String[] getExceptionTypes() { + return exceptionTypes; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(getName(returnType)).append(" ").append(name).append("("); + for (int j = 0; j < parameterTypes.length; j++) { + sb.append(getName(parameterTypes[j])).append(" ").append("arg" + j); + if (j < (parameterTypes.length - 1)) + sb.append(", "); + } + sb.append(")"); + if (exceptionTypes.length > 0) { + sb.append(" throws "); + for (int k = 0; k < exceptionTypes.length; k++) { + sb.append(exceptionTypes[k]); + if (k < (exceptionTypes.length - 1)) + sb.append(", "); + } + } + sb.append(";"); + return sb.toString(); + } + + /** + * @return Returns the iDLName. + */ + public String getIDLName() { + return IDLName; + } + + /** + * @param name The iDLName to set. + */ + public void setIDLName(String name) { + IDLName = name; + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/NamingEndpoint.java b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/NamingEndpoint.java new file mode 100644 index 0000000000..5d4b91d0f9 --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/java/org/apache/tuscany/sca/binding/ejb/util/NamingEndpoint.java @@ -0,0 +1,118 @@ +/* + * 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.util; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +public class NamingEndpoint { + private String jndiName; + private EJBLocator locator; + private boolean managed = true; + + public NamingEndpoint(String hostName, int port, String jndiName) { + this.jndiName = jndiName; + this.locator = new EJBLocator(hostName, port); + } + + public NamingEndpoint(String name) { + + /** + * by default it's a managed environment means SCA composite with ref binding is running on + * an AppServer. If running on J2SE, pass -Dmanaged=false for the VM + */ + String managedEnv = (String)AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty("managed"); + } + }); + + if (managedEnv != null) + managed = new Boolean(managedEnv); + + if ((!managed) && name.startsWith("corbaname:iiop:")) { + /** + * if (name.startsWith("corbaname:iiop:")) { corbaname:iiop:<hostName>:<port>/<root>#name + * For exmaple, + * "corbaname:iiop:localhost:2809/NameServiceServerRoot#ejb/MyEJBHome"; + */ + + String[] parts = split(name, '#'); + if (parts.length != 2) + throw new IllegalArgumentException("Invalid corbaname: " + name); + + this.jndiName = parts[1]; // The logical jndi name + this.locator = new EJBLocator(parts[0], managed); + + } else { + this.jndiName = name; + this.locator = new EJBLocator(managed); + } + + } + + private static String[] split(String str, char ch) { + int index = str.lastIndexOf(ch); + if (index == -1) { + return new String[] {str, ""}; + } else { + return new String[] {str.substring(0, index), str.substring(index + 1)}; + } + } + + /** + * @return Returns the jndiName. + */ + public String getJndiName() { + return jndiName; + } + + public EJBLocator getLocator() { + return locator; + } + + public String getCorbaname() { + return locator.getCorbaname(jndiName); + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (obj instanceof NamingEndpoint) { + NamingEndpoint endpoint = (NamingEndpoint)obj; + return jndiName.equals(endpoint.jndiName); + } + return false; + } + + /** + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return jndiName.hashCode(); + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + return jndiName; + } +} diff --git a/branches/sca-java-0.91/modules/binding-ejb/src/main/resources/META-INF/services/org.apache.tuscany.sca.spi.BindingActivator b/branches/sca-java-0.91/modules/binding-ejb/src/main/resources/META-INF/services/org.apache.tuscany.sca.spi.BindingActivator new file mode 100644 index 0000000000..1e69e1a07c --- /dev/null +++ b/branches/sca-java-0.91/modules/binding-ejb/src/main/resources/META-INF/services/org.apache.tuscany.sca.spi.BindingActivator @@ -0,0 +1,19 @@ +# 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.
+# Implementation class for the ExtensionActivator
+org.apache.tuscany.sca.binding.ejb.EJBBindingActivator
+
|