summaryrefslogtreecommitdiffstats
path: root/branches/sca-equinox/modules/binding-ejb-runtime/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'branches/sca-equinox/modules/binding-ejb-runtime/src/main')
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/ClassLoadingUtil.java365
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/DynamicStubClassLoader.java150
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/Java2IDLUtil.java811
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/ObjectInputStreamExt.java61
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/StubMethodInterceptor.java154
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/UtilInitializer.java69
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingInvoker.java92
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingProviderFactory.java56
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingReferenceBindingProvider.java86
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBHandler.java338
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java483
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBObjectFactory.java209
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBStubHelper.java69
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/InterfaceInfo.java117
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/JavaReflectionAdapter.java157
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/MethodInfo.java189
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/NamingEndpoint.java124
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory19
-rw-r--r--branches/sca-equinox/modules/binding-ejb-runtime/src/main/resources/binding-ejb-validation-messages.properties23
19 files changed, 3572 insertions, 0 deletions
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/ClassLoadingUtil.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/ClassLoadingUtil.java
new file mode 100644
index 0000000000..c65868c23b
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/ClassLoadingUtil.java
@@ -0,0 +1,365 @@
+/*
+ * 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.corba;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Utility class for loading classes by a variety of name variations.
+ * <p/>
+ * Supported names types are:
+ * <p/>
+ * 1) Fully qualified class name (e.g., "java.lang.String", "org.apache.geronimo.kernel.ClassLoading"
+ * 2) Method signature encoding ("Ljava.lang.String;", "J", "I", etc.)
+ * 3) Primitive type names ("int", "boolean", etc.)
+ * 4) Method array signature strings ("[I", "[Ljava.lang.String")
+ * 5) Arrays using Java code format ("int[]", "java.lang.String[][]")
+ * <p/>
+ * The classes are loaded using the provided class loader. For the basic types, the primitive
+ * reflection types are returned.
+ *
+ * @version $Rev$ $Date$
+ */
+public class ClassLoadingUtil {
+
+ /**
+ * Table for mapping primitive class names/signatures to the implementing
+ * class object
+ */
+ private static final HashMap PRIMITIVE_CLASS_MAP = new HashMap();
+
+ /**
+ * Table for mapping primitive classes back to their name signature type, which
+ * allows a reverse mapping to be performed from a class object into a resolvable
+ * signature.
+ */
+ private static final HashMap CLASS_TO_SIGNATURE_MAP = new HashMap();
+
+
+ /**
+ * Setup the primitives map. We make any entry for each primitive class using both the
+ * human readable name and the method signature shorthand type.
+ */
+ static {
+ PRIMITIVE_CLASS_MAP.put("boolean", boolean.class);
+ PRIMITIVE_CLASS_MAP.put("Z", boolean.class);
+ PRIMITIVE_CLASS_MAP.put("byte", byte.class);
+ PRIMITIVE_CLASS_MAP.put("B", byte.class);
+ PRIMITIVE_CLASS_MAP.put("char", char.class);
+ PRIMITIVE_CLASS_MAP.put("C", char.class);
+ PRIMITIVE_CLASS_MAP.put("short", short.class);
+ PRIMITIVE_CLASS_MAP.put("S", short.class);
+ PRIMITIVE_CLASS_MAP.put("int", int.class);
+ PRIMITIVE_CLASS_MAP.put("I", int.class);
+ PRIMITIVE_CLASS_MAP.put("long", long.class);
+ PRIMITIVE_CLASS_MAP.put("J", long.class);
+ PRIMITIVE_CLASS_MAP.put("float", float.class);
+ PRIMITIVE_CLASS_MAP.put("F", float.class);
+ PRIMITIVE_CLASS_MAP.put("double", double.class);
+ PRIMITIVE_CLASS_MAP.put("D", double.class);
+ PRIMITIVE_CLASS_MAP.put("void", void.class);
+ PRIMITIVE_CLASS_MAP.put("V", void.class);
+
+ // Now build a reverse mapping table. The table above has a many-to-one mapping for
+ // class names. To do the reverse, we need to pick just one. As long as the
+ // returned name supports "round tripping" of the requests, this will work fine.
+
+ CLASS_TO_SIGNATURE_MAP.put(boolean.class, "Z");
+ CLASS_TO_SIGNATURE_MAP.put(byte.class, "B");
+ CLASS_TO_SIGNATURE_MAP.put(char.class, "C");
+ CLASS_TO_SIGNATURE_MAP.put(short.class, "S");
+ CLASS_TO_SIGNATURE_MAP.put(int.class, "I");
+ CLASS_TO_SIGNATURE_MAP.put(long.class, "J");
+ CLASS_TO_SIGNATURE_MAP.put(float.class, "F");
+ CLASS_TO_SIGNATURE_MAP.put(double.class, "D");
+ CLASS_TO_SIGNATURE_MAP.put(void.class, "V");
+ }
+
+
+ /**
+ * Load a class that matches the requested name, using the provided class loader context.
+ * <p/>
+ * The class name may be a standard class name, the name of a primitive type Java
+ * reflection class (e.g., "boolean" or "int"), or a type in method type signature
+ * encoding. Array classes in either encoding form are also processed.
+ *
+ * @param className The name of the required class.
+ * @param classLoader The class loader used to resolve the class object.
+ * @return The Class object resolved from "className".
+ * @throws ClassNotFoundException When unable to resolve the class object.
+ * @throws IllegalArgumentException If either argument is null.
+ */
+ public static Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException {
+
+ // the tests require IllegalArgumentExceptions for null values on either of these.
+ if (className == null) {
+ throw new IllegalArgumentException("className is null");
+ }
+
+ if (classLoader == null) {
+ throw new IllegalArgumentException("classLoader is null");
+ }
+ // The easiest case is a proper class name. We just have the class loader resolve this.
+ // If the class loader throws a ClassNotFoundException, then we need to check each of the
+ // special name encodings we support.
+ try {
+ return classLoader.loadClass(className);
+ } catch (ClassNotFoundException ignore) {
+ // if not found, continue on to the other name forms.
+ }
+
+
+ // The second easiest version to resolve is a direct map to a primitive type name
+ // or method signature. Check our name-to-class map for one of those.
+ Class resolvedClass = (Class) PRIMITIVE_CLASS_MAP.get(className);
+ if (resolvedClass != null) {
+ return resolvedClass;
+ }
+
+ // Class names in method signature have the format "Lfully.resolved.name;",
+ // so if it ends in a semicolon and begins with an "L", this must be in
+ // this format. Have the class loader try to load this. There are no other
+ // options if this fails, so just allow the class loader to throw the
+ // ClassNotFoundException.
+ if (className.endsWith(";") && className.startsWith("L")) {
+ // pick out the name portion
+ String typeName = className.substring(1, className.length() - 1);
+ // and delegate the loading to the class loader.
+ return classLoader.loadClass(typeName);
+ }
+
+ // All we have left now are the array types. Method signature array types
+ // have a series of leading "[" characters to specify the number of dimensions.
+ // The other array type we handle uses trailing "[]" for the dimensions, just
+ // like the Java language syntax.
+
+ // first check for the signature form ([[[[type).
+ if (className.charAt(0) == '[') {
+ // we have at least one array marker, now count how many leading '['s we have
+ // to get the dimension count.
+ int count = 0;
+ int nameLen = className.length();
+
+ while (count < nameLen && className.charAt(count) == '[') {
+ count++;
+ }
+
+ // pull of the name subtype, which is everything after the last '['
+ String arrayTypeName = className.substring(count, className.length());
+ // resolve the type using a recursive call, which will load any of the primitive signature
+ // types as well as class names.
+ Class arrayType = loadClass(arrayTypeName, classLoader);
+
+ // Resolving array types require a little more work. The array classes are
+ // created dynamically when the first instance of a given dimension and type is
+ // created. We need to create one using reflection to do this.
+ return getArrayClass(arrayType, count);
+ }
+
+
+ // ok, last chance. Now check for an array specification in Java language
+ // syntax. This will be a type name followed by pairs of "[]" to indicate
+ // the number of dimensions.
+ if (className.endsWith("[]")) {
+ // get the base component class name and the arrayDimensions
+ int count = 0;
+ int position = className.length();
+
+ while (position > 1 && className.substring(position - 2, position).equals("[]")) {
+ // count this dimension
+ count++;
+ // and step back the probe position.
+ position -= 2;
+ }
+
+ // position now points at the location of the last successful test. This makes it
+ // easy to pick off the class name.
+
+ String typeName = className.substring(0, position);
+
+ // load the base type, again, doing this recursively
+ Class arrayType = loadClass(typeName, classLoader);
+ // and turn this into the class object
+ return getArrayClass(arrayType, count);
+ }
+
+ throw new ClassNotFoundException("Could not load class " + className + " from unknown classloader; " + classLoader);
+ }
+
+
+ /**
+ * Map a class object back to a class name. The returned class object
+ * must be "round trippable", which means
+ * <p/>
+ * type == ClassLoading.loadClass(ClassLoading.getClassName(type), classLoader)
+ * <p/>
+ * must be true. To ensure this, the class name is always returned in
+ * method signature format.
+ *
+ * @param type The class object we convert into name form.
+ * @return A string representation of the class name, in method signature
+ * format.
+ */
+ public static String getClassName(Class type) {
+ StringBuffer name = new StringBuffer();
+
+ // we test these in reverse order from the resolution steps,
+ // first handling arrays, then primitive types, and finally
+ // "normal" class objects.
+
+ // First handle arrays. If a class is an array, the type is
+ // element stored at that level. So, for a 2-dimensional array
+ // of ints, the top-level type will be "[I". We need to loop
+ // down the hierarchy until we hit a non-array type.
+ while (type.isArray()) {
+ // add another array indicator at the front of the name,
+ // and continue with the next type.
+ name.append('[');
+ type = type.getComponentType();
+ }
+
+ // we're down to the base type. If this is a primitive, then
+ // we poke in the single-character type specifier.
+ if (type.isPrimitive()) {
+ name.append((String) CLASS_TO_SIGNATURE_MAP.get(type));
+ }
+ // a "normal" class. This gets expressing using the "Lmy.class.name;" syntax.
+ else {
+ name.append('L');
+ name.append(type.getName());
+ name.append(';');
+ }
+ return name.toString();
+ }
+
+ private static Class getArrayClass(Class type, int dimension) {
+ // Array.newInstance() requires an array of the requested number of dimensions
+ // that gives the size for each dimension. We just request 0 in each of the
+ // dimensions, which is not unlike a black hole singularity.
+ int[] dimensions = new int[dimension];
+ // create an instance and return the associated class object.
+ return Array.newInstance(type, dimensions).getClass();
+ }
+
+ public static Set getAllTypes(Class type) {
+ Set allTypes = new LinkedHashSet();
+ allTypes.add(type);
+ allTypes.addAll(getAllSuperClasses(type));
+ allTypes.addAll(getAllInterfaces(type));
+ return allTypes;
+ }
+
+ private static Set getAllSuperClasses(Class clazz) {
+ Set allSuperClasses = new LinkedHashSet();
+ for (Class superClass = clazz.getSuperclass(); superClass != null; superClass = superClass.getSuperclass()) {
+ allSuperClasses.add(superClass);
+ }
+ return allSuperClasses;
+ }
+
+ private static Set getAllInterfaces(Class clazz) {
+ Set allInterfaces = new LinkedHashSet();
+ LinkedList stack = new LinkedList();
+ stack.addAll(Arrays.asList(clazz.getInterfaces()));
+ while (!stack.isEmpty()) {
+ Class intf = (Class) stack.removeFirst();
+ if (!allInterfaces.contains(intf)) {
+ allInterfaces.add(intf);
+ stack.addAll(Arrays.asList(intf.getInterfaces()));
+ }
+ }
+ return allInterfaces;
+ }
+
+ public static Set reduceInterfaces(Set source) {
+ Class[] classes = (Class[]) source.toArray(new Class[source.size()]);
+ classes = reduceInterfaces(classes);
+ return new LinkedHashSet(Arrays.asList(classes));
+ }
+
+ /**
+ * If there are multiple interfaces, and some of them extend each other,
+ * eliminate the superclass in favor of the subclasses that extend them.
+ *
+ * If one of the entries is a class (not an interface), make sure it's
+ * the first one in the array. If more than one of the entries is a
+ * class, throws an IllegalArgumentException
+ *
+ * @param source the original list of interfaces
+ * @return the equal or smaller list of interfaces
+ */
+ public static Class[] reduceInterfaces(Class[] source) {
+ // use a copy of the source array
+ source = (Class[]) source.clone();
+
+ for (int leftIndex = 0; leftIndex < source.length-1; leftIndex++) {
+ Class left = source[leftIndex];
+ if(left == null) {
+ continue;
+ }
+
+ for (int rightIndex = leftIndex +1; rightIndex < source.length; rightIndex++) {
+ Class right = source[rightIndex];
+ if(right == null) {
+ continue;
+ }
+
+ if(left == right || right.isAssignableFrom(left)) {
+ // right is the same as class or a sub class of left
+ source[rightIndex] = null;
+ } else if(left.isAssignableFrom(right)) {
+ // left is the same as class or a sub class of right
+ source[leftIndex] = null;
+
+ // the left has been eliminated; move on to the next left
+ break;
+ }
+ }
+ }
+
+ Class clazz = null;
+ for (int i = 0; i < source.length; i++) {
+ if (source[i] != null && !source[i].isInterface()) {
+ if (clazz != null) {
+ throw new IllegalArgumentException("Source contains two classes which are not subclasses of each other: " + clazz.getName() + ", " + source[i].getName());
+ }
+ clazz = source[i];
+ source[i] = null;
+ }
+ }
+
+ List list = new ArrayList(source.length);
+ if (clazz != null) list.add(clazz);
+ for (int i = 0; i < source.length; i++) {
+ if(source[i] != null) {
+ list.add(source[i]);
+ }
+ }
+ return (Class[]) list.toArray(new Class[list.size()]);
+ }
+}
+
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/DynamicStubClassLoader.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/DynamicStubClassLoader.java
new file mode 100644
index 0000000000..82554a1c8f
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/DynamicStubClassLoader.java
@@ -0,0 +1,150 @@
+/*
+ * 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.corba;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import javax.rmi.CORBA.Stub;
+
+import net.sf.cglib.core.NamingPolicy;
+import net.sf.cglib.core.Predicate;
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.CallbackFilter;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.FixedValue;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.NoOp;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class DynamicStubClassLoader extends ClassLoader {
+ private static final String PACKAGE_PREFIX = "org.omg.stub.";
+
+ @Override
+ public synchronized Class loadClass(final String name) throws ClassNotFoundException {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+ // check if the stub already exists first
+ try {
+ return classLoader.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ }
+
+ // if this is not a class from the org.omg.stub name space don't attempt to generate
+ if (!name.startsWith(PACKAGE_PREFIX)) {
+ throw new ClassNotFoundException("Could not load class: " + name);
+ }
+
+ // load the interfaces class we are attempting to create a stub for
+ Class iface = loadStubInterfaceClass(name, classLoader);
+
+ // create the stub builder
+ try {
+ Enhancer enhancer = new Enhancer();
+ enhancer.setSuperclass(Stub.class);
+ enhancer.setInterfaces(new Class[] {iface});
+ enhancer.setCallbackFilter(FILTER);
+ enhancer.setCallbackTypes(new Class[] {NoOp.class, MethodInterceptor.class, FixedValue.class});
+ enhancer.setUseFactory(false);
+ enhancer.setClassLoader(classLoader);
+ enhancer.setNamingPolicy(new NamingPolicy() {
+ public String getClassName(String s, String s1, Object o, Predicate predicate) {
+ return name;
+ }
+ });
+
+ // generate the class
+ Class result = enhancer.createClass();
+ assert result != null;
+
+ StubMethodInterceptor interceptor = new StubMethodInterceptor(iface);
+ Ids ids = new Ids(iface);
+ Enhancer.registerStaticCallbacks(result, new Callback[] {NoOp.INSTANCE, interceptor, ids});
+
+ return result;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Error e) {
+ throw e;
+ }
+ }
+
+ private Class loadStubInterfaceClass(String name, ClassLoader classLoader) throws ClassNotFoundException {
+ try {
+ int begin = name.lastIndexOf('.') + 1;
+ String iPackage = name.substring(13, begin);
+ String iName = iPackage + name.substring(begin + 1, name.length() - 5);
+
+ return classLoader.loadClass(iName);
+ } catch (ClassNotFoundException e) {
+ // don't log exceptions from CosNaming because it attempts to load every
+ // class bound into the name server
+
+ //FIXME this variable is never read, can we remove the
+ // whole block of code??
+ //boolean shouldLog = true;
+ StackTraceElement[] stackTrace = e.getStackTrace();
+ for (int i = 0; i < stackTrace.length; i++) {
+ StackTraceElement stackTraceElement = stackTrace[i];
+ if (stackTraceElement.getClassName().equals("org.omg.CosNaming.NamingContextExtPOA") && stackTraceElement
+ .getMethodName().equals("_invoke")) {
+ //shouldLog = false;
+ break;
+ }
+ }
+
+ throw new ClassNotFoundException("Unable to generate stub", e);
+ }
+ }
+
+ private static final CallbackFilter FILTER = new CallbackFilter() {
+ public int accept(Method method) {
+ // we don't intercept non-public methods like finalize
+ if (!Modifier.isPublic(method.getModifiers())) {
+ return 0;
+ }
+
+ if (method.getReturnType().equals(String[].class) && method.getParameterTypes().length == 0
+ && method.getName().equals("_ids")) {
+ return 2;
+ }
+
+ if (Modifier.isAbstract(method.getModifiers())) {
+ return 1;
+ }
+
+ return 0;
+ }
+ };
+
+ private static final class Ids implements FixedValue {
+ private final String[] typeIds;
+
+ public Ids(Class type) {
+ typeIds = Java2IDLUtil.createCorbaIds(type);
+ }
+
+ public Object loadObject() throws Exception {
+ return typeIds;
+ }
+ }
+
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/Java2IDLUtil.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/Java2IDLUtil.java
new file mode 100644
index 0000000000..de8090c45b
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/Java2IDLUtil.java
@@ -0,0 +1,811 @@
+/*
+ * 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.corba;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.UnexpectedException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.ejb.spi.HandleDelegate;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.rmi.PortableRemoteObject;
+
+import org.omg.CORBA.ORB;
+import org.omg.CORBA.UserException;
+import org.omg.CORBA.portable.IDLEntity;
+import org.omg.CORBA.portable.ResponseHandler;
+import org.omg.CORBA.portable.UnknownException;
+import org.omg.CORBA_2_3.portable.InputStream;
+import org.omg.CORBA_2_3.portable.OutputStream;
+import org.omg.IOP.Codec;
+import org.omg.IOP.CodecFactory;
+import org.omg.IOP.ENCODING_CDR_ENCAPS;
+import org.omg.IOP.Encoding;
+
+/**
+ * Various utility functions.
+ * <p/>
+ * Note: #getORB() and #getCodec() rely on UtilInitializer to initialize the ORB and codec.
+ *
+ * @version $Rev$ $Date$
+ * @see UtilInitializer
+ */
+public final class Java2IDLUtil {
+ private static ORB orb;
+ private static Codec codec;
+ private static HandleDelegate handleDelegate;
+
+ public static ORB getORB() {
+ assert orb != null;
+ return orb;
+ }
+
+
+
+ public static void setORB(ORB orb) throws UserException {
+ if (Java2IDLUtil.orb == null) {
+ Java2IDLUtil.orb = orb;
+ CodecFactory factory = (CodecFactory) Java2IDLUtil.orb.resolve_initial_references("CodecFactory");
+ codec = factory.create_codec(new Encoding(ENCODING_CDR_ENCAPS.value, (byte) 1, (byte) 2));
+ }
+ }
+
+ public static Codec getCodec() {
+ assert codec != null;
+ return codec;
+ }
+
+ public static HandleDelegate getHandleDelegate() throws NamingException {
+ if (handleDelegate == null) {
+ InitialContext ic = new InitialContext();
+ handleDelegate = (HandleDelegate) ic.lookup("java:comp/HandleDelegate");
+ }
+ return handleDelegate;
+ }
+
+ private static final Pattern SCOPED_NAME_EXTRACTION_PATTERN = Pattern.compile("(\\\\\\\\)|(\\\\@)|(@)|(\\z)");
+
+ /**
+ * See csiv2 Specification 16.2.5 par. 63-64. We extract the username if any and un-escape any
+ * escaped \ and @ characters.
+ *
+ * @param scopedNameBytes
+ * @return
+ * @throws UnsupportedEncodingException
+ */
+ public static String extractUserNameFromScopedName(byte[] scopedNameBytes) throws UnsupportedEncodingException {
+ String scopedUserName = new String(scopedNameBytes, "UTF8");
+ return extractUserNameFromScopedName(scopedUserName);
+ }
+
+ public static String extractUserNameFromScopedName(String scopedUserName) {
+ Matcher m = SCOPED_NAME_EXTRACTION_PATTERN.matcher(scopedUserName);
+ StringBuffer buf = new StringBuffer();
+ while (m.find()) {
+ m.appendReplacement(buf, "");
+ if (m.group(1) != null) {
+ buf.append('\\');
+ } else if (m.group(2) != null) {
+ buf.append("@");
+ } else if (m.group(3) != null) {
+ break;
+ }
+ }
+ return buf.toString();
+ }
+
+ private static final Pattern SCOPED_NAME_ESCAPE_PATTERN = Pattern.compile("(\\\\)|(@)");
+
+ public static String buildScopedUserName(String user, String domain) {
+ StringBuffer buf = new StringBuffer();
+ if (user != null) {
+ escape(user, buf);
+ }
+ if (domain != null) {
+ buf.append('@');
+ escape(domain, buf);
+ }
+ return buf.toString();
+ }
+
+ private static void escape(String s, StringBuffer buf) {
+ Matcher m = SCOPED_NAME_ESCAPE_PATTERN.matcher(s);
+ while (m.find()) {
+ m.appendReplacement(buf, "");
+ if (m.group(1) != null) {
+ buf.append("\\\\");
+ } else if (m.group(2) != null) {
+ buf.append("\\@");
+ }
+ }
+ m.appendTail(buf);
+ }
+
+
+ public static String byteToString(byte[] data) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < data.length; i++) {
+ buffer.append(HEXCHAR[(data[i] >>> 4) & 0x0F]);
+ buffer.append(HEXCHAR[(data[i]) & 0x0F]);
+ }
+ return buffer.toString();
+
+ }
+
+ private static final char[] HEXCHAR = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ public static void writeObject(Class type, Object object, OutputStream out) {
+ if (type == Void.TYPE) {
+ // do nothing for a void
+ } else if (type == Boolean.TYPE) {
+ out.write_boolean(((Boolean) object).booleanValue());
+ } else if (type == Byte.TYPE) {
+ out.write_octet(((Byte) object).byteValue());
+ } else if (type == Character.TYPE) {
+ out.write_wchar(((Character) object).charValue());
+ } else if (type == Double.TYPE) {
+ out.write_double(((Double) object).doubleValue());
+ } else if (type == Float.TYPE) {
+ out.write_float(((Float) object).floatValue());
+ } else if (type == Integer.TYPE) {
+ out.write_long(((Integer) object).intValue());
+ } else if (type == Long.TYPE) {
+ out.write_longlong(((Long) object).longValue());
+ } else if (type == Short.TYPE) {
+ out.write_short(((Short) object).shortValue());
+ } else {
+ // object types must be written in the context of the CORBA application server
+ // which properly write replaces our objects for CORBA
+ // ApplicationServer oldApplicationServer = ServerFederation.getApplicationServer();
+ try {
+ // ServerFederation.setApplicationServer(corbaApplicationServer);
+
+ // todo check if
+ // copy the result to force replacement
+ // CORBA does not call writeReplace on remote proxies
+ //
+ // HOWEVER, if this is an array, then we don't want to do the replacement
+ // because we can end up with a replacement element that's not compatible with the
+ // original array type, which results in an ArrayStoreException. Fortunately,
+ // the Yoko RMI support appears to be able to sort this out for us correctly.
+ if (object instanceof Serializable && !object.getClass().isArray()) {
+ try {
+ object = copyObj(Thread.currentThread().getContextClassLoader(), object);
+ } catch (Exception e) {
+ throw new UnknownException(e);
+ }
+ }
+
+ if (type == Object.class || type == Serializable.class) {
+ javax.rmi.CORBA.Util.writeAny(out, object);
+ } else if (org.omg.CORBA.Object.class.isAssignableFrom(type)) {
+ out.write_Object((org.omg.CORBA.Object) object);
+ } else if (Remote.class.isAssignableFrom(type)) {
+ javax.rmi.CORBA.Util.writeRemoteObject(out, object);
+ } else if (type.isInterface() && Serializable.class.isAssignableFrom(type)) {
+ javax.rmi.CORBA.Util.writeAbstractObject(out, object);
+ } else {
+ out.write_value((Serializable) object, type);
+ }
+ } finally {
+ // ServerFederation.setApplicationServer(oldApplicationServer);
+ }
+ }
+ }
+
+ private static Object copyObj(ClassLoader classLoader, Object object) throws IOException, ClassNotFoundException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(object);
+ oos.flush();
+ oos.close();
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ ObjectInputStreamExt ois = new ObjectInputStreamExt(bais, classLoader);
+ return ois.readObject();
+ }
+
+ public static Object readObject(Class type, InputStream in) {
+ if (type == Void.TYPE) {
+ return null;
+ } else if (type == Boolean.TYPE) {
+ return new Boolean(in.read_boolean());
+ } else if (type == Byte.TYPE) {
+ return new Byte(in.read_octet());
+ } else if (type == Character.TYPE) {
+ return new Character(in.read_wchar());
+ } else if (type == Double.TYPE) {
+ return new Double(in.read_double());
+ } else if (type == Float.TYPE) {
+ return new Float(in.read_float());
+ } else if (type == Integer.TYPE) {
+ return new Integer(in.read_long());
+ } else if (type == Long.TYPE) {
+ return new Long(in.read_longlong());
+ } else if (type == Short.TYPE) {
+ return new Short(in.read_short());
+ } else if (type == Object.class || type == Serializable.class) {
+ return javax.rmi.CORBA.Util.readAny(in);
+ } else if (org.omg.CORBA.Object.class.isAssignableFrom(type)) {
+ return in.read_Object(type);
+ } else if (Remote.class.isAssignableFrom(type)) {
+ return PortableRemoteObject.narrow(in.read_Object(), type);
+ } else if (type.isInterface() && Serializable.class.isAssignableFrom(type)) {
+ return in.read_abstract_interface();
+ } else {
+ return in.read_value(type);
+ }
+ }
+
+ public static void throwException(Method method, InputStream in) throws Throwable {
+ // read the exception id
+ final String id = in.read_string();
+
+ // get the class name from the id
+ if (!id.startsWith("IDL:")) {
+ return;
+ }
+
+ Class[] exceptionTypes = method.getExceptionTypes();
+ for (int i = 0; i < exceptionTypes.length; i++) {
+ Class exceptionType = exceptionTypes[i];
+
+ String exceptionId = getExceptionId(exceptionType);
+ if (id.equals(exceptionId)) {
+ throw (Throwable) in.read_value(exceptionType);
+ }
+ }
+ throw new UnexpectedException(id);
+ }
+
+ public static OutputStream writeUserException(Method method, ResponseHandler reply, Exception exception) throws Exception {
+ if (exception instanceof RuntimeException || exception instanceof RemoteException) {
+ throw exception;
+ }
+
+ Class[] exceptionTypes = method.getExceptionTypes();
+ for (int i = 0; i < exceptionTypes.length; i++) {
+ Class exceptionType = exceptionTypes[i];
+ if (!exceptionType.isInstance(exception)) {
+ continue;
+ }
+
+ OutputStream out = (OutputStream) reply.createExceptionReply();
+ String exceptionId = getExceptionId(exceptionType);
+ out.write_string(exceptionId);
+ out.write_value(exception);
+ return out;
+ }
+ throw exception;
+ }
+
+ public static String getExceptionId(Class exceptionType) {
+ String exceptionName = exceptionType.getName().replace('.', '/');
+ if (exceptionName.endsWith("Exception")) {
+ exceptionName = exceptionName.substring(0, exceptionName.length() - "Exception".length());
+ }
+ exceptionName += "Ex";
+ String exceptionId = "IDL:" + exceptionName + ":1.0";
+ return exceptionId;
+ }
+
+ public static String[] createCorbaIds(Class type) {
+ List ids = new LinkedList();
+ for (Iterator iterator = getAllInterfaces(type).iterator(); iterator.hasNext();) {
+ Class superInterface = (Class) iterator.next();
+ if (Remote.class.isAssignableFrom(superInterface) && superInterface != Remote.class) {
+ ids.add("RMI:" + superInterface.getName() + ":0000000000000000");
+ }
+ }
+ return (String[]) ids.toArray(new String[ids.size()]);
+ }
+
+ private static Set getAllInterfaces(Class intfClass) {
+ Set allInterfaces = new LinkedHashSet();
+
+ LinkedList stack = new LinkedList();
+ stack.addFirst(intfClass);
+
+ while (!stack.isEmpty()) {
+ Class intf = (Class) stack.removeFirst();
+ allInterfaces.add(intf);
+ stack.addAll(0, Arrays.asList(intf.getInterfaces()));
+ }
+
+ return allInterfaces;
+ }
+
+ public static Map mapMethodToOperation(Class intfClass) {
+ return iiopMap(intfClass, false);
+ }
+
+ public static Map mapOperationToMethod(Class intfClass) {
+ return iiopMap(intfClass, true);
+ }
+
+ private static Map iiopMap(Class intfClass, boolean operationToMethod) {
+ Method[] methods = getAllMethods(intfClass);
+
+ // find every valid getter
+ HashMap getterByMethod = new HashMap(methods.length);
+ HashMap getterByName = new HashMap(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ String methodName = method.getName();
+
+ // no arguments allowed
+ if (method.getParameterTypes().length != 0) {
+ continue;
+ }
+
+ // must start with get or is
+ String verb;
+ if (methodName.startsWith("get") && methodName.length() > 3 && method.getReturnType() != void.class) {
+ verb = "get";
+ } else if (methodName.startsWith("is") && methodName.length() > 2 && method.getReturnType() == boolean.class) {
+ verb = "is";
+ } else {
+ continue;
+ }
+
+ // must only throw Remote or Runtime Exceptions
+ boolean exceptionsValid = true;
+ Class[] exceptionTypes = method.getExceptionTypes();
+ for (int j = 0; j < exceptionTypes.length; j++) {
+ Class exceptionType = exceptionTypes[j];
+ if (!RemoteException.class.isAssignableFrom(exceptionType) &&
+ !RuntimeException.class.isAssignableFrom(exceptionType) &&
+ !Error.class.isAssignableFrom(exceptionType)) {
+ exceptionsValid = false;
+ break;
+ }
+ }
+ if (!exceptionsValid) {
+ continue;
+ }
+
+ String propertyName;
+ if (methodName.length() > verb.length() + 1 && Character.isUpperCase(methodName.charAt(verb.length() + 1))) {
+ propertyName = methodName.substring(verb.length());
+ } else {
+ propertyName = Character.toLowerCase(methodName.charAt(verb.length())) + methodName.substring(verb.length() + 1);
+ }
+ getterByMethod.put(method, propertyName);
+ getterByName.put(propertyName, method);
+ }
+
+ HashMap setterByMethod = new HashMap(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ String methodName = method.getName();
+
+ // must have exactally one arg
+ if (method.getParameterTypes().length != 1) {
+ continue;
+ }
+
+ // must return non void
+ if (method.getReturnType() != void.class) {
+ continue;
+ }
+
+ // must start with set
+ if (!methodName.startsWith("set") || methodName.length() <= 3) {
+ continue;
+ }
+
+ // must only throw Remote or Runtime Exceptions
+ boolean exceptionsValid = true;
+ Class[] exceptionTypes = method.getExceptionTypes();
+ for (int j = 0; j < exceptionTypes.length; j++) {
+ Class exceptionType = exceptionTypes[j];
+ if (!RemoteException.class.isAssignableFrom(exceptionType) &&
+ !RuntimeException.class.isAssignableFrom(exceptionType) &&
+ !Error.class.isAssignableFrom(exceptionType)) {
+ exceptionsValid = false;
+ break;
+ }
+ }
+ if (!exceptionsValid) {
+ continue;
+ }
+
+ String propertyName;
+ if (methodName.length() > 4 && Character.isUpperCase(methodName.charAt(4))) {
+ propertyName = methodName.substring(3);
+ } else {
+ propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
+ }
+
+ // must have a matching getter
+ Method getter = (Method) getterByName.get(propertyName);
+ if (getter == null) {
+ continue;
+ }
+
+ // setter property must match getter return value
+ if (!method.getParameterTypes()[0].equals(getter.getReturnType())) {
+ continue;
+ }
+ setterByMethod.put(method, propertyName);
+ }
+
+ // index the methods by name... used to determine which methods are overloaded
+ HashMap overloadedMethods = new HashMap(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ if (getterByMethod.containsKey(method) || setterByMethod.containsKey(method)) {
+ continue;
+ }
+ String methodName = method.getName();
+ List methodList = (List) overloadedMethods.get(methodName);
+ if (methodList == null) {
+ methodList = new LinkedList();
+ overloadedMethods.put(methodName, methodList);
+ }
+ methodList.add(method);
+ }
+
+ // index the methods by lower case name... used to determine which methods differ only by case
+ HashMap caseCollisionMethods = new HashMap(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+ if (getterByMethod.containsKey(method) || setterByMethod.containsKey(method)) {
+ continue;
+ }
+ String lowerCaseMethodName = method.getName().toLowerCase();
+ Set methodSet = (Set) caseCollisionMethods.get(lowerCaseMethodName);
+ if (methodSet == null) {
+ methodSet = new HashSet();
+ caseCollisionMethods.put(lowerCaseMethodName, methodSet);
+ }
+ methodSet.add(method.getName());
+ }
+
+ String className = getClassName(intfClass);
+ Map iiopMap = new HashMap(methods.length);
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ String iiopName = (String) getterByMethod.get(method);
+ if (iiopName != null) {
+ // if we have a leading underscore prepend with J
+ if (iiopName.charAt(0) == '_') {
+ iiopName = "J_get_" + iiopName.substring(1);
+ } else {
+ iiopName = "_get_" + iiopName;
+ }
+ } else {
+ iiopName = (String) setterByMethod.get(method);
+ if (iiopName != null) {
+ // if we have a leading underscore prepend with J
+ if (iiopName.charAt(0) == '_') {
+ iiopName = "J_set_" + iiopName.substring(1);
+ } else {
+ iiopName = "_set_" + iiopName;
+ }
+ } else {
+ iiopName = method.getName();
+
+ // if we have a leading underscore prepend with J
+ if (iiopName.charAt(0) == '_') {
+ iiopName = "J" + iiopName;
+ }
+ }
+ }
+
+ // if this name only differs by case add the case index to the end
+ Set caseCollisions = (Set) caseCollisionMethods.get(method.getName().toLowerCase());
+ if (caseCollisions != null && caseCollisions.size() > 1) {
+ iiopName += upperCaseIndexString(iiopName);
+ }
+
+ // if this is an overloaded method append the parameter string
+ List overloads = (List) overloadedMethods.get(method.getName());
+ if (overloads != null && overloads.size() > 1) {
+ iiopName += buildOverloadParameterString(method.getParameterTypes());
+ }
+
+ // if we have a leading underscore prepend with J
+ iiopName = replace(iiopName, '$', "U0024");
+
+ // if we have matched a keyword prepend with an underscore
+ if (keywords.contains(iiopName.toLowerCase())) {
+ iiopName = "_" + iiopName;
+ }
+
+ // if the name is the same as the class name, append an underscore
+ if (iiopName.equalsIgnoreCase(className)) {
+ iiopName += "_";
+ }
+
+ if (operationToMethod) {
+ iiopMap.put(iiopName, method);
+ } else {
+ iiopMap.put(method, iiopName);
+ }
+ }
+
+ return iiopMap;
+ }
+
+ private static Method[] getAllMethods(Class intfClass) {
+ LinkedList methods = new LinkedList();
+ for (Iterator iterator = getAllInterfaces(intfClass).iterator(); iterator.hasNext();) {
+ Class intf = (Class) iterator.next();
+ methods.addAll(Arrays.asList(intf.getDeclaredMethods()));
+ }
+
+ return (Method[]) methods.toArray(new Method[methods.size()]);
+ }
+
+ /**
+ * Return the a string containing an underscore '_' index of each uppercase character in the IIOP name.
+ *
+ * This is used for distinction of names that only differ by case, since CORBA does not support case sensitive names.
+ */
+ private static String upperCaseIndexString(String iiopName) {
+ StringBuffer stringBuffer = new StringBuffer();
+ for (int i = 0; i < iiopName.length(); i++) {
+ char c = iiopName.charAt(i);
+ if (Character.isUpperCase(c)) {
+ stringBuffer.append('_').append(i);
+ }
+ }
+ return stringBuffer.toString();
+ }
+
+ /**
+ * Replaces any occurances of the specified "oldChar" with the new string.
+ *
+ * This is used to replace occurances if '$' in CORBA names since '$' is a special character
+ */
+ private static String replace(String source, char oldChar, String newString) {
+ StringBuffer stringBuffer = new StringBuffer(source.length());
+ for (int i = 0; i < source.length(); i++) {
+ char c = source.charAt(i);
+ if (c == oldChar) {
+ stringBuffer.append(newString);
+ } else {
+ stringBuffer.append(c);
+ }
+ }
+ return stringBuffer.toString();
+ }
+
+ /**
+ * Return the a string containing a double underscore '__' list of parameter types encoded using the Java to IDL rules.
+ *
+ * This is used for distinction of methods that only differ by parameter lists.
+ */
+ private static String buildOverloadParameterString(Class[] parameterTypes) {
+ String name = "";
+ if (parameterTypes.length ==0) {
+ name += "__";
+ } else {
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Class parameterType = parameterTypes[i];
+ name += buildOverloadParameterString(parameterType);
+ }
+ }
+ return name.replace('.', '_');
+ }
+
+ /**
+ * Returns a single parameter type encoded using the Java to IDL rules.
+ */
+ private static String buildOverloadParameterString(Class parameterType) {
+ String name = "_";
+
+ int arrayDimensions = 0;
+ while (parameterType.isArray()) {
+ arrayDimensions++;
+ parameterType = parameterType.getComponentType();
+ }
+
+ // arrays start with org_omg_boxedRMI_
+ if (arrayDimensions > 0) {
+ name += "_org_omg_boxedRMI";
+ }
+
+ // IDLEntity types must be prefixed with org_omg_boxedIDL_
+ if (IDLEntity.class.isAssignableFrom(parameterType)) {
+ name += "_org_omg_boxedIDL";
+ }
+
+ // add package... some types have special mappings in corba
+ String packageName = (String) specialTypePackages.get(parameterType.getName());
+ if (packageName == null) {
+ packageName = getPackageName(parameterType.getName());
+ }
+ if (packageName.length() > 0) {
+ name += "_" + packageName;
+ }
+
+ // arrays now contain a dimension indicator
+ if (arrayDimensions > 0) {
+ name += "_" + "seq" + arrayDimensions;
+ }
+
+ // add the class name
+ String className = (String) specialTypeNames.get(parameterType.getName());
+ if (className == null) {
+ className = buildClassName(parameterType);
+ }
+ name += "_" + className;
+
+ return name;
+ }
+
+ /**
+ * Returns a string containing an encoded class name.
+ */
+ private static String buildClassName(Class type) {
+ if (type.isArray()) {
+ throw new IllegalArgumentException("type is an array: " + type);
+ }
+
+ // get the classname
+ String typeName = type.getName();
+ int endIndex = typeName.lastIndexOf('.');
+ if (endIndex < 0) {
+ return typeName;
+ }
+ StringBuffer className = new StringBuffer(typeName.substring(endIndex + 1));
+
+ // for innerclasses replace the $ separator with two underscores
+ // we can't just blindly replace all $ characters since class names can contain the $ character
+ if (type.getDeclaringClass() != null) {
+ String declaringClassName = getClassName(type.getDeclaringClass());
+ assert className.toString().startsWith(declaringClassName + "$");
+ className.replace(declaringClassName.length(), declaringClassName.length() + 1, "__");
+ }
+
+ // if we have a leading underscore prepend with J
+ if (className.charAt(0) == '_') {
+ className.insert(0, "J");
+ }
+ return className.toString();
+ }
+
+ private static String getClassName(Class type) {
+ if (type.isArray()) {
+ throw new IllegalArgumentException("type is an array: " + type);
+ }
+
+ // get the classname
+ String typeName = type.getName();
+ int endIndex = typeName.lastIndexOf('.');
+ if (endIndex < 0) {
+ return typeName;
+ }
+ return typeName.substring(endIndex + 1);
+ }
+
+ private static String getPackageName(String interfaceName) {
+ int endIndex = interfaceName.lastIndexOf('.');
+ if (endIndex < 0) {
+ return "";
+ }
+ return interfaceName.substring(0, endIndex);
+ }
+
+ private static final Map specialTypeNames;
+ private static final Map specialTypePackages;
+ private static final Set keywords;
+
+ static {
+ specialTypeNames = new HashMap();
+ specialTypeNames.put("boolean", "boolean");
+ specialTypeNames.put("char", "wchar");
+ specialTypeNames.put("byte", "octet");
+ specialTypeNames.put("short", "short");
+ specialTypeNames.put("int", "long");
+ specialTypeNames.put("long", "long_long");
+ specialTypeNames.put("float", "float");
+ specialTypeNames.put("double", "double");
+ specialTypeNames.put("java.lang.Class", "ClassDesc");
+ specialTypeNames.put("java.lang.String", "WStringValue");
+ specialTypeNames.put("org.omg.CORBA.Object", "Object");
+
+ specialTypePackages = new HashMap();
+ specialTypePackages.put("boolean", "");
+ specialTypePackages.put("char", "");
+ specialTypePackages.put("byte", "");
+ specialTypePackages.put("short", "");
+ specialTypePackages.put("int", "");
+ specialTypePackages.put("long", "");
+ specialTypePackages.put("float", "");
+ specialTypePackages.put("double", "");
+ specialTypePackages.put("java.lang.Class", "javax.rmi.CORBA");
+ specialTypePackages.put("java.lang.String", "CORBA");
+ specialTypePackages.put("org.omg.CORBA.Object", "");
+
+ keywords = new HashSet();
+ keywords.add("abstract");
+ keywords.add("any");
+ keywords.add("attribute");
+ keywords.add("boolean");
+ keywords.add("case");
+ keywords.add("char");
+ keywords.add("const");
+ keywords.add("context");
+ keywords.add("custom");
+ keywords.add("default");
+ keywords.add("double");
+ keywords.add("enum");
+ keywords.add("exception");
+ keywords.add("factory");
+ keywords.add("false");
+ keywords.add("fixed");
+ keywords.add("float");
+ keywords.add("in");
+ keywords.add("inout");
+ keywords.add("interface");
+ keywords.add("long");
+ keywords.add("module");
+ keywords.add("native");
+ keywords.add("object");
+ keywords.add("octet");
+ keywords.add("oneway");
+ keywords.add("out");
+ keywords.add("private");
+ keywords.add("public");
+ keywords.add("raises");
+ keywords.add("readonly");
+ keywords.add("sequence");
+ keywords.add("short");
+ keywords.add("string");
+ keywords.add("struct");
+ keywords.add("supports");
+ keywords.add("switch");
+ keywords.add("true");
+ keywords.add("truncatable");
+ keywords.add("typedef");
+ keywords.add("union");
+ keywords.add("unsigned");
+ keywords.add("valuebase");
+ keywords.add("valuetype");
+ keywords.add("void");
+ keywords.add("wchar");
+ keywords.add("wstring");
+ }
+
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/ObjectInputStreamExt.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/ObjectInputStreamExt.java
new file mode 100644
index 0000000000..1be4a98a48
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/ObjectInputStreamExt.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.corba;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Proxy;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class ObjectInputStreamExt extends ObjectInputStream {
+
+ private ClassLoader classloader;
+
+ public ObjectInputStreamExt(InputStream in, ClassLoader loader) throws IOException {
+ super(in);
+ this.classloader = loader;
+ }
+
+ @Override
+ protected Class resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {
+ return ClassLoadingUtil.loadClass(classDesc.getName(), classloader);
+ }
+
+ @Override
+ protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException {
+ Class[] cinterfaces = new Class[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++)
+ cinterfaces[i] = classloader.loadClass(interfaces[i]);
+
+ try {
+ return Proxy.getProxyClass(classloader, cinterfaces);
+ } catch (IllegalArgumentException e) {
+ throw new ClassNotFoundException(null, e);
+ }
+ }
+
+ ClassLoader getClassloader() {
+ return classloader;
+ }
+
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/StubMethodInterceptor.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/StubMethodInterceptor.java
new file mode 100644
index 0000000000..3ff0ed552a
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/StubMethodInterceptor.java
@@ -0,0 +1,154 @@
+/*
+ * 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.corba;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.ejb.EJBObject;
+import javax.rmi.CORBA.Stub;
+import javax.rmi.CORBA.Util;
+
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
+
+import org.omg.CORBA.SystemException;
+import org.omg.CORBA.portable.ApplicationException;
+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;
+
+/**
+ * @version $Revision$ $Date$
+ */
+public class StubMethodInterceptor implements MethodInterceptor {
+ private static final Method ISIDENTICAL;
+
+ static {
+ try {
+ ISIDENTICAL = EJBObject.class.getMethod("isIdentical", new Class[]{EJBObject.class});
+ } catch (NoSuchMethodException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private final Class type;
+ private final Map operations;
+
+ public StubMethodInterceptor(Class type) {
+ this.type = type;
+ this.operations = Collections.unmodifiableMap(org.apache.tuscany.sca.binding.ejb.corba.Java2IDLUtil.mapMethodToOperation(type));
+ }
+
+ public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
+ Stub stub = (Stub) proxy;
+
+ // handle is identical in stub to avoid unnecessary round trip
+ if (method.equals(ISIDENTICAL)) {
+ org.omg.CORBA.Object otherObject = (org.omg.CORBA.Object) args[0];
+ return new Boolean(stub._is_equivalent(otherObject));
+ }
+
+ // get the operation name object
+ String operationName = (String) operations.get(method);
+ if (operationName == null) {
+ throw new IllegalStateException("Unknown method: " + method);
+ }
+
+ while (true) {
+ // if this is a stub to a remote object we invoke over the wire
+ if (!Util.isLocal(stub)) {
+
+ InputStream in = null;
+ try {
+ // create the request output stream
+ OutputStream out = (OutputStream) stub._request(operationName, true);
+
+ // write the arguments
+ Class[] parameterTypes = method.getParameterTypes();
+ for (int i = 0; i < parameterTypes.length; i++) {
+ Class parameterType = parameterTypes[i];
+ org.apache.tuscany.sca.binding.ejb.corba.Java2IDLUtil.writeObject(parameterType, args[i], out);
+ }
+
+ // send the invocation
+ in = (InputStream) stub._invoke(out);
+
+ // read the result
+ Object result = org.apache.tuscany.sca.binding.ejb.corba.Java2IDLUtil.readObject(method.getReturnType(), in);
+ return result;
+ } catch (RemarshalException exception) {
+ continue;
+ } catch (ApplicationException exception) {
+ org.apache.tuscany.sca.binding.ejb.corba.Java2IDLUtil.throwException(method, (InputStream) exception.getInputStream());
+ } catch (SystemException e) {
+ throw Util.mapSystemException(e);
+ } finally {
+ stub._releaseReply(in);
+ }
+ } else {
+ // get the servant
+ ServantObject servantObject = stub._servant_preinvoke(operationName, type);
+ if (servantObject == null) {
+ continue;
+ }
+
+ try {
+ // copy the arguments
+ Object[] argsCopy = Util.copyObjects(args, stub._orb());
+
+ // invoke the servant
+ Object result = null;
+ try {
+ result = method.invoke(servantObject.servant, argsCopy);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() != null) {
+ throw e.getCause();
+ }
+ throw e;
+ }
+
+ // copy the result
+ result = Util.copyObject(result, stub._orb());
+
+ return result;
+ } catch (Throwable throwable) {
+ // copy the exception
+ Throwable throwableCopy = (Throwable) Util.copyObject(throwable, stub._orb());
+
+ // if it is one of my exception rethrow it
+ Class[] exceptionTypes = method.getExceptionTypes();
+ for (int i = 0; i < exceptionTypes.length; i++) {
+ Class exceptionType = exceptionTypes[i];
+ if (exceptionType.isInstance(throwableCopy)) {
+ throw throwableCopy;
+ }
+ }
+
+ throw Util.wrapException(throwableCopy);
+ } finally {
+ stub._servant_postinvoke(servantObject);
+ }
+ }
+ }
+ }
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/UtilInitializer.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/UtilInitializer.java
new file mode 100644
index 0000000000..f9aa9ffa22
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/corba/UtilInitializer.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.corba;
+
+import org.omg.CORBA.LocalObject;
+import org.omg.PortableInterceptor.ORBInitInfo;
+import org.omg.PortableInterceptor.ORBInitializer;
+
+/**
+ * The sole purpose of this initializer is to register a non-singleton ORB
+ * with the class <code>Util</code>.
+ *
+ * @version $Revision$ $Date$
+ * @see Java2IDLUtil
+ */
+public class UtilInitializer extends LocalObject implements ORBInitializer {
+
+ private static final long serialVersionUID = 4901857563505370955L;
+
+ /**
+ * Called during ORB initialization. If it is expected that initial
+ * services registered by an interceptor will be used by other
+ * interceptors, then those initial services shall be registered at
+ * this point via calls to
+ * <code>ORBInitInfo.register_initial_reference</code>.
+ *
+ * @param info provides initialization attributes and operations by
+ * which Interceptors can be registered.
+ */
+ public void pre_init(ORBInitInfo info) {
+ }
+
+ /**
+ * Called during ORB initialization. If a service must resolve initial
+ * references as part of its initialization, it can assume that all
+ * initial references will be available at this point.
+ * <p/>
+ * Calling the <code>post_init</code> operations is not the final
+ * task of ORB initialization. The final task, following the
+ * <code>post_init</code> calls, is attaching the lists of registered
+ * interceptors to the ORB. Therefore, the ORB does not contain the
+ * interceptors during calls to <code>post_init</code>. If an
+ * ORB-mediated call is made from within <code>post_init</code>, no
+ * request interceptors will be invoked on that call.
+ * Likewise, if an operation is performed which causes an IOR to be
+ * created, no IOR interceptors will be invoked.
+ *
+ * @param info provides initialization attributes and
+ * operations by which Interceptors can be registered.
+ */
+ public void post_init(ORBInitInfo info) {
+ }
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingInvoker.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingInvoker.java
new file mode 100644
index 0000000000..9247c1d3db
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingInvoker.java
@@ -0,0 +1,92 @@
+/*
+ * 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.provider;
+
+import org.apache.tuscany.sca.binding.ejb.EJBBinding;
+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;
+import org.apache.tuscany.sca.invocation.DataExchangeSemantics;
+
+/**
+ * EJBTargetInvoker
+ *
+ * @version $Rev$ $Date$
+ */
+public class EJBBindingInvoker implements Invoker, DataExchangeSemantics {
+
+ private Operation operation;
+ private String location;
+ private Class serviceInterface;
+
+ public EJBBindingInvoker(EJBBinding ejbBinding, Class serviceInterface, Operation operation) {
+ this.serviceInterface = serviceInterface;
+ this.location = ejbBinding.getURI();
+ this.operation = operation;
+ }
+
+ public Message invoke(Message msg) {
+ ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(serviceInterface.getClassLoader());
+ Object resp = doInvoke(msg.getBody());
+ msg.setBody(resp);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ msg.setFaultBody(e);
+ } finally {
+ Thread.currentThread().setContextClassLoader(tccl);
+ }
+ 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);
+ }
+
+ public boolean allowsPassByReference() {
+ // EJB RMI/IIOP always pass by value
+ return true;
+ }
+
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingProviderFactory.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingProviderFactory.java
new file mode 100644
index 0000000000..a6ea583d0b
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingProviderFactory.java
@@ -0,0 +1,56 @@
+/*
+ * 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.provider;
+
+import org.apache.tuscany.sca.binding.ejb.EJBBinding;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.provider.BindingProviderFactory;
+import org.apache.tuscany.sca.provider.ReferenceBindingProvider;
+import org.apache.tuscany.sca.provider.ServiceBindingProvider;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
+import org.apache.tuscany.sca.runtime.RuntimeComponentService;
+
+/**
+ * A factory from creating the EJB binding provider.
+ *
+ * @version $Rev$ $Date$
+ */
+public class EJBBindingProviderFactory implements BindingProviderFactory<EJBBinding> {
+
+ public EJBBindingProviderFactory(ExtensionPointRegistry extensionPoints) {
+ }
+
+ public ReferenceBindingProvider createReferenceBindingProvider(RuntimeComponent component,
+ RuntimeComponentReference reference,
+ EJBBinding binding) {
+ return new EJBBindingReferenceBindingProvider(component, reference, binding);
+ }
+
+ public ServiceBindingProvider createServiceBindingProvider(RuntimeComponent component,
+ RuntimeComponentService service,
+ EJBBinding binding) {
+ return null;
+ //throw new EJBBindingException("Service Binding not supported for EJB Binding");
+ }
+
+ public Class<EJBBinding> getModelType() {
+ return EJBBinding.class;
+ }
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingReferenceBindingProvider.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingReferenceBindingProvider.java
new file mode 100644
index 0000000000..2a02bf0d08
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/provider/EJBBindingReferenceBindingProvider.java
@@ -0,0 +1,86 @@
+/*
+ * 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.provider;
+
+import org.apache.tuscany.sca.binding.ejb.EJBBinding;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+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.provider.ReferenceBindingProvider;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeComponentReference;
+
+/**
+ * Implementation of the ReferenceBindingProvider for the EJBBinding.
+ *
+ * @version $Rev$ $Date$
+ */
+public class EJBBindingReferenceBindingProvider implements ReferenceBindingProvider {
+ private EJBBinding ejbBinding;
+ private RuntimeComponentReference reference;
+
+ /**
+ * Constructor
+ *
+ * @param component
+ * @param reference
+ * @param binding
+ */
+ public EJBBindingReferenceBindingProvider(RuntimeComponent component,
+ RuntimeComponentReference reference,
+ EJBBinding binding) {
+ this.reference = reference;
+ this.ejbBinding = binding;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Invoker createInvoker(Operation operation) {
+ return new EJBBindingInvoker(ejbBinding, ((JavaInterface)reference.getInterfaceContract().getInterface())
+ .getJavaClass(), operation);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public InterfaceContract getBindingInterfaceContract() {
+ return reference.getInterfaceContract();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void start() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stop() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean supportsOneWayInvocation() {
+ return true;
+ }
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBHandler.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBHandler.java
new file mode 100644
index 0000000000..d41dbd0a0f
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBHandler.java
@@ -0,0 +1,338 @@
+/*
+ * 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.util.HashMap;
+import java.util.Map;
+
+import javax.ejb.EJBObject;
+import javax.rmi.CORBA.Util;
+
+import org.apache.tuscany.sca.binding.ejb.corba.ClassLoadingUtil;
+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
+ *
+ * @version $Rev$ $Date$
+ */
+public class EJBHandler {
+ private static final Map<String, Class> PRIMITIVE_TYPES = new HashMap<String, Class>();
+ static {
+ PRIMITIVE_TYPES.put("boolean", boolean.class);
+ PRIMITIVE_TYPES.put("byte", byte.class);
+ PRIMITIVE_TYPES.put("char", char.class);
+ PRIMITIVE_TYPES.put("short", short.class);
+ PRIMITIVE_TYPES.put("int", int.class);
+ PRIMITIVE_TYPES.put("long", long.class);
+ PRIMITIVE_TYPES.put("float", float.class);
+ PRIMITIVE_TYPES.put("double", double.class);
+ PRIMITIVE_TYPES.put("void", void.class);
+ }
+
+ 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
+ private EJBHandler(NamingEndpoint namingEndpoint, InterfaceInfo ejbInterface) {
+ try {
+ this.ejbStub = EJBStubHelper.lookup(namingEndpoint, ejbInterface);
+ this.interfaceInfo = ejbInterface;
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ private static Class loadClass(final String name) {
+ try {
+ return ClassLoadingUtil.loadClass(name, Thread.currentThread().getContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ // 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
+ */
+ private 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 =
+ methodInfo.getMethod() != null ? methodInfo.getMethod().getExceptionTypes()[i]
+ : 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
+ */
+ private 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);
+ }
+ Class[] parameterTypes = null;
+ Class returnType = null;
+ if (methodInfo.getMethod() != null) {
+ parameterTypes = methodInfo.getMethod().getParameterTypes();
+ returnType = methodInfo.getMethod().getReturnType();
+ } else {
+ 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);
+ }
+
+ parameterTypes = new Class[types.length];
+ for (int i = 0; i < types.length; i++) {
+ parameterTypes[i] = loadClass(types[i]);
+ }
+ returnType = loadClass(methodInfo.getReturnType());
+ }
+
+ InputStream in = null;
+ try {
+ OutputStream out = (OutputStream)stub._request(operation, true);
+
+ for (int i = 0; i < parameterTypes.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();
+ try {
+ org.apache.tuscany.sca.binding.ejb.corba.Java2IDLUtil.throwException(methodInfo.getMethod(), in);
+ return null;
+ } catch (Throwable e) {
+ throw new RemoteException(e.getMessage(), e);
+ }
+ } 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
+ */
+ private void writeValue(OutputStream out, Object value, Class type) {
+ org.apache.tuscany.sca.binding.ejb.corba.Java2IDLUtil.writeObject(type, value, out);
+ }
+
+ /**
+ * @param in
+ * @param type
+ * @return
+ */
+ private Object readValue(InputStream in, Class type) {
+ return org.apache.tuscany.sca.binding.ejb.corba.Java2IDLUtil.readObject(type, in);
+ }
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java
new file mode 100644
index 0000000000..0b97f42746
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBLocator.java
@@ -0,0 +1,483 @@
+/*
+ * 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.NamingException;
+
+import org.omg.CORBA.ORB;
+import org.omg.CosNaming.NamingContextExt;
+
+/**
+ * CosNaming utility
+ *
+ * @version $Rev$ $Date$
+ */
+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
+
+ 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 Set<String> ROOTS =
+ new HashSet<String>(Arrays.asList(new String[] {SERVER_ROOT, CELL_PERSISTENT_ROOT, CELL_ROOT, DEFAULT_ROOT,
+ NODE_ROOT}));
+
+ // 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;
+ private boolean managed = true;
+
+ EJBLocator(boolean managed) {
+ this.managed = managed;
+ if (!managed) {
+ String url = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return System.getProperty(Context.PROVIDER_URL);
+ }
+ });
+ processCorbaURL(url);
+ }
+ }
+
+ EJBLocator(String hostName, int port) {
+ this.hostName = (hostName == null) ? DEFAULT_HOST : hostName;
+ this.port = port > 0 ? port : DEFAULT_NAMING_PORT;
+ this.root = SERVER_ROOT;
+ }
+
+ 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");
+ }
+ }
+
+ 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");
+ }
+ }
+
+ 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 example,
+ * "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
+ }
+ }
+ }
+
+ /**
+ * 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.
+ */
+
+ /**
+ * corbaname Syntax The full corbaname BNF is: &lt;corbaname&gt; =
+ * "corbaname:"&lt;corbaloc_obj&gt;["#"&lt;string_name&gt;]
+ * &lt;corbaloc_obj&gt; = &lt;obj_addr_list&gt; ["/"&lt;key_string&gt;]
+ * &lt;obj_addr_list&gt; = as defined in a corbaloc URL &lt;key_string&gt; =
+ * as defined in a corbaloc URL &lt;string_name&gt;= 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 got to 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;
+ }
+ }
+
+ /**
+ * Resolved the JNDI name from the initial CosNaming context
+ *
+ * @param jndiName
+ * @return resolved CORBA object
+ * @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;
+ }
+ }
+
+ /**
+ * 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 = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ public Boolean 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; // NOPMD
+ }
+ }
+ 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) {
+ // Escape . into \. since it's an INS naming delimiter
+ return replace(encode2396(jndiName), ".", "\\.");
+ }
+
+ /**
+ * Escape the "." into "%5C%2E"
+ *
+ * @param jndiName
+ * @return corbaname treating "." as a literal
+ */
+ private static String toCorbaname(String jndiName) {
+ // Escape . into %5C%2E (\.) since it's an INS naming delimiter
+ // 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 {
+ Object locate(String name) throws NamingException;
+ }
+
+ private final class JndiLocator implements ObjectLocator {
+ private Context context;
+
+ private JndiLocator() throws NamingException {
+ /*
+ final Properties props = AccessController.doPrivileged(new PrivilegedAction<Properties>() {
+ public Properties run() {
+ return System.getProperties();
+ }
+ });
+ Properties properties = new Properties();
+ for (Map.Entry e : props.entrySet()) {
+ String name = (String)e.getKey();
+ if (name.startsWith("java.naming.")) {
+ properties.setProperty(name, (String)e.getValue());
+ }
+ }
+ // System.out.println(properties);
+ this.context = new InitialContext(properties);
+ */
+ this.context = new InitialContext();
+ }
+
+ public Object locate(String name) throws NamingException {
+ return context.lookup(name);
+ }
+ }
+
+ private final class CosNamingLocator implements ObjectLocator {
+ private NamingContextExt context;
+
+ private CosNamingLocator() {
+ }
+
+ 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-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBObjectFactory.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBObjectFactory.java
new file mode 100644
index 0000000000..d34cfe1b16
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBObjectFactory.java
@@ -0,0 +1,209 @@
+/*
+ * 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.omg.stub.java.rmi._Remote_Stub;
+import org.osoa.sca.ServiceRuntimeException;
+
+/**
+ * Factor class that is used to create EJB Proxies.
+ *
+ * @version $Rev$ $Date$
+ */
+final 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 available in the classpath.
+ * <p>
+ */
+ static Object createStub(NamingEndpoint namingEndpoint, InterfaceInfo ejbInterface) 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, ejbInterface);
+ // Cache dynamic stub only
+ return stub;
+ }
+
+ /**
+ * @param homeObject
+ * @param ejbHomeClass
+ * @return
+ * @throws RemoteException
+ */
+ private static Object getEJBStub(Object homeObject, InterfaceInfo ejbInterface) throws RemoteException,
+ CreateException {
+
+ Object stub = null;
+
+ // Get the business interface of the EJB
+ Class ejbInterfaceClass = null;
+ try {
+ ejbInterfaceClass = Thread.currentThread().getContextClassLoader().loadClass(ejbInterface.getName());
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+
+ if (ejbInterfaceClass != null && ejbInterfaceClass.isInstance(homeObject)) {
+ // EJB 3
+ stub = homeObject;
+ } else 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
+ */
+ static private 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
+ */
+ private 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
+ */
+ private 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);
+ // The Remote stub should be available in JDK
+ // TODO: [rfeng] Work around an issue in Apache Yoko which doesn't understand the org.omg.stub.*
+ return in.read_Object(_Remote_Stub.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-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBStubHelper.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/EJBStubHelper.java
new file mode 100644
index 0000000000..b699a02d1d
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/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;
+
+final class EJBStubHelper {
+
+ private static Object stub;
+ private static ServiceRuntimeException exception;
+
+ private EJBStubHelper() {
+ }
+
+ /**
+ * @param owner
+ * @param jndiName
+ * @return
+ */
+
+ static Object lookup(NamingEndpoint endpoint, InterfaceInfo ejbInterface) {
+ return getStub(endpoint, ejbInterface);
+ }
+
+ private static Object getStub(NamingEndpoint namingEndpoint, InterfaceInfo ejbInterface) {
+ try {
+ stub = EJBObjectFactory.createStub(namingEndpoint, ejbInterface);
+ } 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-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/InterfaceInfo.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/InterfaceInfo.java
new file mode 100644
index 0000000000..e60e526e01
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/InterfaceInfo.java
@@ -0,0 +1,117 @@
+/*
+ * 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.corba.Java2IDLUtil;
+
+/**
+ * The signature for a java interface
+ *
+ * @version $Rev$ $Date$
+ */
+class InterfaceInfo implements Serializable {
+
+ private static final Map<Class, InterfaceInfo> INTERFACES =
+ Collections.synchronizedMap(new WeakHashMap<Class, InterfaceInfo>());
+
+ private static final long serialVersionUID = 2314533906465094860L;
+ private String name;
+
+ private Map<String, MethodInfo> methods = new HashMap<String, MethodInfo>();
+
+ 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 = AccessController.doPrivileged(new PrivilegedAction<Map>() {
+ public Map run() {
+ return Java2IDLUtil.mapMethodToOperation(iface);
+ }
+ });
+ Iterator i = idlNames.entrySet().iterator();
+ while (i.hasNext()) {
+ Map.Entry entry = (Map.Entry)i.next();
+ Method method = (Method)entry.getKey();
+ MethodInfo methodInfo = new MethodInfo(method);
+ methodInfo.setIDLName((String) entry.getValue());
+ methods.put(method.getName(), methodInfo);
+ methods.put(methodInfo.getIDLName(), methodInfo);
+ }
+ }
+
+ static final synchronized InterfaceInfo getInstance(final Class iface) {
+ InterfaceInfo info = (InterfaceInfo)INTERFACES.get(iface);
+ if (info == null) {
+ info = new InterfaceInfo(iface);
+ INTERFACES.put(iface, info);
+ }
+ return info;
+ }
+
+ /**
+ * @return
+ */
+ Map<String, MethodInfo> getMethods() {
+ return methods;
+ }
+
+ /**
+ * @return
+ */
+ MethodInfo getMethod(String name) {
+ return (MethodInfo)methods.get(name);
+ }
+
+ /**
+ * @return
+ */
+ String getName() {
+ return name;
+ }
+
+ @Override
+ 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-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/JavaReflectionAdapter.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/JavaReflectionAdapter.java
new file mode 100644
index 0000000000..5e7d6761d9
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/JavaReflectionAdapter.java
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ *
+ * @version $Rev$ $Date$
+ */
+final class JavaReflectionAdapter {
+
+ private static Map<Class, JavaReflectionAdapter> adapters =
+ Collections.synchronizedMap(new WeakHashMap<Class, JavaReflectionAdapter>());
+
+ private static final Map<Class, Object> DEFAULT_VALUES = new HashMap<Class, Object>();
+ static {
+ DEFAULT_VALUES.put(boolean.class, Boolean.FALSE);
+ DEFAULT_VALUES.put(byte.class, new Byte((byte)0));
+ DEFAULT_VALUES.put(char.class, new Character((char)0));
+ DEFAULT_VALUES.put(short.class, new Short((short)0));
+ DEFAULT_VALUES.put(int.class, Integer.valueOf(0));
+ DEFAULT_VALUES.put(long.class, new Long(0));
+ DEFAULT_VALUES.put(float.class, new Float(0.0));
+ DEFAULT_VALUES.put(double.class, new Double(0.0));
+ }
+
+ private Map<String, Method> methodMap = new HashMap<String, Method>();
+
+ /**
+ * Constructor
+ *
+ * @param clazz
+ */
+ private JavaReflectionAdapter(final Class clazz) {
+ // Index the methods on the implementation class
+ // FIXME J2 Security - promote this to callers of this method
+ Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
+ public Method[] run() {
+ return clazz.getMethods();
+ }
+ });
+ for (int i = 0; i < methods.length; i++) {
+ methodMap.put(methods[i].getName(), methods[i]);
+ }
+ }
+
+ /**
+ * Create a java reflection adapter
+ *
+ * @param clazz
+ */
+ static synchronized JavaReflectionAdapter createJavaReflectionAdapter(Class clazz) {
+ JavaReflectionAdapter adapter = (JavaReflectionAdapter)adapters.get(clazz);
+ if (adapter == null) {
+ adapter = new JavaReflectionAdapter(clazz);
+ adapters.put(clazz, adapter);
+ }
+ return adapter;
+ }
+
+ /**
+ * Return the specified method
+ *
+ * @param methodName
+ * @return
+ * @throws NoSuchMethodException
+ */
+ Method getMethod(String methodName) throws NoSuchMethodException {
+
+ Method method = (Method)methodMap.get(methodName);
+ if (method == null) {
+ throw new NoSuchMethodException(methodName);
+ }
+ return method;
+ }
+
+ /**
+ * Returns a map containing the methods on the class, keyed by name
+ *
+ * @return
+ */
+ Map getMethods() {
+ return methodMap;
+ }
+
+ /**
+ * Invoke a method using Java reflection.
+ *
+ * @param method
+ * @param object
+ * @param args
+ * @return
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ */
+ 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_VALUES.get(parameterType);
+ }
+ }
+ return method.invoke(object, args);
+ }
+
+ /**
+ * Set the java bean property
+ *
+ * @param bean
+ * @param propertyName
+ * @param value
+ * @return
+ */
+ 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-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/MethodInfo.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/MethodInfo.java
new file mode 100644
index 0000000000..e7ea7c9077
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/MethodInfo.java
@@ -0,0 +1,189 @@
+/*
+ * 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
+ *
+ * @version $Rev$ $Date$
+ */
+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;
+
+ private transient Method method;
+
+ /**
+ * 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 static final 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);
+ }
+
+ MethodInfo(Method method) {
+ this.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;
+ }
+
+ 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
+ */
+ String getName() {
+ return name;
+ }
+
+ /**
+ * @return
+ */
+ String[] getParameterTypes() {
+ return parameterTypes;
+ }
+
+ /**
+ * @return
+ */
+ String getReturnType() {
+ return returnType;
+ }
+
+ /**
+ * @return
+ */
+ String[] getExceptionTypes() {
+ return exceptionTypes;
+ }
+
+ @Override
+ 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.
+ */
+ String getIDLName() {
+ return IDLName;
+ }
+
+ /**
+ * @param name The iDLName to set.
+ */
+ void setIDLName(String name) {
+ IDLName = name;
+ }
+
+ /**
+ * @return the method
+ */
+ Method getMethod() {
+ return method;
+ }
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/NamingEndpoint.java b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/NamingEndpoint.java
new file mode 100644
index 0000000000..346b7c5cf6
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/java/org/apache/tuscany/sca/binding/ejb/util/NamingEndpoint.java
@@ -0,0 +1,124 @@
+/*
+ * 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
+ */
+ final String managedEnv = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return System.getProperty("managed");
+ }
+ });
+
+ if (managedEnv != null) {
+ managed = Boolean.valueOf(managedEnv);
+ }
+
+ if ((!managed) && name.startsWith("corbaname:iiop:")) {
+ /**
+ * if (name.startsWith("corbaname:iiop:")) { corbaname:iiop:<hostName>:<port>/<root>#name
+ * For example,
+ * "corbaname:iiop:localhost:2809/NameServiceServerRoot#ejb/MyEJBHome";
+ */
+
+ String[] parts = split(name, '#');
+ if (parts.length != 2) {
+ throw new IllegalArgumentException("Invalid corbaname: " + name);
+ }
+
+ this.jndiName = name; // 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)
+ */
+ @Override
+ 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()
+ */
+ @Override
+ public int hashCode() {
+ return jndiName.hashCode();
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return jndiName;
+ }
+}
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory
new file mode 100644
index 0000000000..a89f711da9
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/resources/META-INF/services/org.apache.tuscany.sca.provider.BindingProviderFactory
@@ -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 binding extension
+org.apache.tuscany.sca.binding.ejb.provider.EJBBindingProviderFactory;model=org.apache.tuscany.sca.binding.ejb.EJBBinding
diff --git a/branches/sca-equinox/modules/binding-ejb-runtime/src/main/resources/binding-ejb-validation-messages.properties b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/resources/binding-ejb-validation-messages.properties
new file mode 100644
index 0000000000..28477dd3ac
--- /dev/null
+++ b/branches/sca-equinox/modules/binding-ejb-runtime/src/main/resources/binding-ejb-validation-messages.properties
@@ -0,0 +1,23 @@
+#
+#
+# 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.
+#
+#
+UnknownEJBSessionType = Unknown EJB Session Type of {0} for {1}
+UnknownEJBVersion = Unknown EJB Version of {0} for {1}
+