You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by rf...@apache.org on 2010/05/04 00:02:04 UTC

svn commit: r940652 - in /tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs: ./ META-INF/ src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/ src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/

Author: rfeng
Date: Mon May  3 22:02:04 2010
New Revision: 940652

URL: http://svn.apache.org/viewvc?rev=940652&view=rev
Log:
Add a utility to generate a JAX-RS resource class from the JAX-RS annotated interface

Added:
    tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/CodeGenerationHelper.java
    tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/GeneratedClassLoader.java
    tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java
    tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/MockedResource.java
    tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/Resource.java
    tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/ResourceWrapper.java
    tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGeneratorTestCase.java
Modified:
    tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/META-INF/MANIFEST.MF
    tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/pom.xml

Modified: tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/META-INF/MANIFEST.MF
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/META-INF/MANIFEST.MF?rev=940652&r1=940651&r2=940652&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/META-INF/MANIFEST.MF (original)
+++ tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/META-INF/MANIFEST.MF Mon May  3 22:02:04 2010
@@ -13,4 +13,5 @@ Bundle-RequiredExecutionEnvironment: J2S
 Import-Package: org.apache.tuscany.sca.interfacedef,
  org.apache.tuscany.sca.interfacedef.java,
  org.apache.tuscany.sca.interfacedef.java.impl,
- org.apache.tuscany.sca.interfacedef.java.introspect
+ org.apache.tuscany.sca.interfacedef.java.introspect,
+ org.objectweb.asm;version="3.1.0"

Modified: tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/pom.xml
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/pom.xml?rev=940652&r1=940651&r2=940652&view=diff
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/pom.xml (original)
+++ tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/pom.xml Mon May  3 22:02:04 2010
@@ -53,5 +53,12 @@
             <version>4.8.1</version>
             <scope>test</scope>
         </dependency>        
+        <dependency>
+        	<groupId>asm</groupId>
+        	<artifactId>asm</artifactId>
+        	<version>3.1</version>
+        	<type>jar</type>
+        	<scope>compile</scope>
+        </dependency>
     </dependencies>
 </project>

Added: tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/CodeGenerationHelper.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/CodeGenerationHelper.java?rev=940652&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/CodeGenerationHelper.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/CodeGenerationHelper.java Mon May  3 22:02:04 2010
@@ -0,0 +1,280 @@
+/*
+ * 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.interfacedef.java.jaxrs;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.objectweb.asm.Opcodes;
+
+/**
+ * @version $Rev: 673298 $ $Date: 2008-07-01 23:47:40 -0700 (Tue, 01 Jul 2008) $
+ */
+public class CodeGenerationHelper {
+    /**
+     * @param type
+     * @return
+     */
+    public static Class<?> getErasure(Type type) {
+        if (type instanceof Class) {
+            return (Class<?>)type;
+        } else if (type instanceof GenericArrayType) {
+            GenericArrayType arrayType = (GenericArrayType)type;
+            Class<?> componentType = getErasure(arrayType.getGenericComponentType());
+            return Array.newInstance(componentType, 0).getClass();
+        } else if (type instanceof ParameterizedType) {
+            ParameterizedType pType = (ParameterizedType)type;
+            return getErasure(pType.getRawType());
+        } else if (type instanceof WildcardType) {
+            WildcardType wType = (WildcardType)type;
+            Type[] types = wType.getUpperBounds();
+            if (types.length == 0) {
+                return Object.class;
+            }
+            return getErasure(types[0]);
+        } else if (type instanceof TypeVariable) {
+            TypeVariable<?> var = (TypeVariable<?>)type;
+            Type[] types = var.getBounds();
+            if (types.length == 0) {
+                return Object.class;
+            }
+            return getErasure(types[0]);
+        }
+        return null;
+    }
+
+    /**
+     * @param type
+     * @return
+     */
+    public static String getJAXWSSignature(Type type) {
+        Class<?> cls = getErasure(type);
+        if (Collection.class.isAssignableFrom(cls) && (type instanceof ParameterizedType)) {
+            ParameterizedType pType = (ParameterizedType)type;
+            Type p = pType.getActualTypeArguments()[0];
+            StringBuffer sb = new StringBuffer();
+            sb.append(getSignature(cls));
+            sb.deleteCharAt(sb.length() - 1); // Remove ;
+            sb.append('<').append(getSignature(getErasure(p))).append(">;");
+            return sb.toString();
+        } else if (Map.class.isAssignableFrom(cls) && (type instanceof ParameterizedType)) {
+            ParameterizedType pType = (ParameterizedType)type;
+            Type key = pType.getActualTypeArguments()[0];
+            Type value = pType.getActualTypeArguments()[1];
+            StringBuffer sb = new StringBuffer();
+            sb.append(getSignature(cls));
+            sb.deleteCharAt(sb.length() - 1); // Remove ;
+            sb.append('<').append(getSignature(getErasure(key))).append(getSignature(getErasure(value))).append(">;");
+            return sb.toString();
+        } else {
+            return getSignature(cls);
+        }
+    }
+
+    /**
+     * @param type
+     * @return
+     */
+    public static String getSignature(Type type) {
+        if (!(type instanceof Class)) {
+            if (type instanceof ParameterizedType) {
+                ParameterizedType pType = (ParameterizedType)type;
+                StringBuffer sb = new StringBuffer();
+                String rawType = getSignature(pType.getRawType());
+                sb.append(rawType.substring(0, rawType.length() - 1));
+                sb.append('<');
+                for (Type t : pType.getActualTypeArguments()) {
+                    String argType = getSignature(t);
+                    sb.append(argType);
+                }
+                sb.append('>');
+                sb.append(rawType.substring(rawType.length() - 1));
+                return sb.toString();
+            }
+            if (type instanceof TypeVariable) {
+                return "T" + ((TypeVariable<?>)type).getName() + ";";
+            }
+            if (type instanceof GenericArrayType) {
+                GenericArrayType arrayType = (GenericArrayType)type;
+                return "[" + getSignature(arrayType.getGenericComponentType());
+            }
+            if (type instanceof WildcardType) {
+                WildcardType wType = (WildcardType)type;
+                Type[] types = wType.getUpperBounds();
+                StringBuffer sb = new StringBuffer();
+                if (types.length == 0 || !(types.length == 1 && types[0] == Object.class)) {
+                    sb.append('+');
+                    for (Type t : types) {
+                        sb.append(getSignature(t));
+                    }
+                }
+                types = wType.getLowerBounds();
+                if (types.length != 0) {
+                    sb.append('-');
+                    for (Type t : wType.getLowerBounds()) {
+                        sb.append(getSignature(t));
+                    }
+                }
+                if (sb.length() == 0) {
+                    return "*";
+                }
+                return sb.toString();
+            }
+        }
+        Class<?> cls = (Class<?>)type;
+        return org.objectweb.asm.Type.getDescriptor(cls);
+    }
+
+    /**
+     * Get the actual type arguments a child class has used to extend a generic base class.
+     *
+     * @param baseClass the base class
+     * @param childClass the child class
+     * @return a list of the raw classes for the actual type arguments.
+     */
+    public static <T> List<Class<?>> resovleTypeArguments(Class<T> baseClass, Class<? extends T> childClass) {
+        Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
+        Type type = childClass;
+        // start walking up the inheritance hierarchy until we hit baseClass
+        while (!getErasure(type).equals(baseClass)) {
+            if (type instanceof Class) {
+                // there is no useful information for us in raw types, so just keep going.
+                type = ((Class<?>)type).getGenericSuperclass();
+            } else {
+                ParameterizedType parameterizedType = (ParameterizedType)type;
+                Class<?> rawType = getErasure(parameterizedType.getRawType());
+
+                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+                TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
+                for (int i = 0; i < actualTypeArguments.length; i++) {
+                    resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
+                }
+
+                if (!rawType.equals(baseClass)) {
+                    type = rawType.getGenericSuperclass();
+                }
+            }
+        }
+
+        // finally, for each actual type argument provided to baseClass, determine (if possible)
+        // the raw class for that type argument.
+        Type[] actualTypeArguments;
+        if (type instanceof Class) {
+            actualTypeArguments = ((Class<?>)type).getTypeParameters();
+        } else {
+            actualTypeArguments = ((ParameterizedType)type).getActualTypeArguments();
+        }
+        List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
+        // resolve types by chasing down type variables.
+        for (Type baseType : actualTypeArguments) {
+            while (resolvedTypes.containsKey(baseType)) {
+                baseType = resolvedTypes.get(baseType);
+            }
+            typeArgumentsAsClasses.add(getErasure(baseType));
+        }
+        return typeArgumentsAsClasses;
+    }
+
+    /*
+    signatures.put(boolean.class, "Z");
+    signatures.put(byte.class, "B");
+    signatures.put(char.class, "C");
+    signatures.put(short.class, "S");
+    signatures.put(int.class, "I");
+    signatures.put(long.class, "J");
+    signatures.put(float.class, "F");
+    signatures.put(double.class, "D");
+    */
+    public static int getLoadOPCode(String signature) {
+        if ("Z".equals(signature) || "B".equals(signature)
+            || "C".equals(signature)
+            || "S".equals(signature)
+            || "I".equals(signature)) {
+            return Opcodes.ILOAD;
+        }
+
+        if ("J".equals(signature)) {
+            return Opcodes.LLOAD;
+        }
+
+        if ("F".equals(signature)) {
+            return Opcodes.FLOAD;
+        }
+
+        if ("D".equals(signature)) {
+            return Opcodes.DLOAD;
+        }
+
+        return Opcodes.ALOAD;
+
+    }
+
+    public static int getReturnOPCode(String signature) {
+        if ("Z".equals(signature) || "B".equals(signature)
+            || "C".equals(signature)
+            || "S".equals(signature)
+            || "I".equals(signature)) {
+            return Opcodes.IRETURN;
+        }
+
+        if ("J".equals(signature)) {
+            return Opcodes.LRETURN;
+        }
+
+        if ("F".equals(signature)) {
+            return Opcodes.FRETURN;
+        }
+
+        if ("D".equals(signature)) {
+            return Opcodes.DRETURN;
+        }
+        if ("V".equals(signature)) {
+            return Opcodes.RETURN;
+        }
+
+        return Opcodes.ARETURN;
+
+    }
+    
+    /**
+     * Get the package prefix for generated JAXWS artifacts
+     * @param cls
+     * @return
+     */
+    public static String getPackagePrefix(Class<?> cls) {
+        String name = cls.getName();
+        int index = name.lastIndexOf('.');
+        if (index == -1) {
+            return "jaxws.";
+        } else {
+            return name.substring(0, index) + ".jaxws.";
+        }
+    }
+
+}

Added: tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/GeneratedClassLoader.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/GeneratedClassLoader.java?rev=940652&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/GeneratedClassLoader.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/GeneratedClassLoader.java Mon May  3 22:02:04 2010
@@ -0,0 +1,70 @@
+/*
+ * 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.interfacedef.java.jaxrs;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.HashMap;
+import java.util.Map;
+
+public class GeneratedClassLoader extends URLClassLoader {
+    private class GeneratedClass {
+        private String className;
+        private byte[] byteCode;
+        private Class<?> cls;
+
+        public GeneratedClass(String className, byte[] byteCode) {
+            super();
+            this.className = className;
+            this.byteCode = byteCode;
+        }
+
+        public synchronized Class<?> getGeneratedClass() {
+            if (cls == null) {
+                cls = defineClass(className, byteCode, 0, byteCode.length);
+            }
+            return cls;
+        }
+    }
+
+    private Map<String, GeneratedClass> generatedClasses = new HashMap<String, GeneratedClass>();
+
+    public GeneratedClassLoader(ClassLoader parentLoader) {
+        super(new URL[0], parentLoader);
+    }
+
+    @Override
+    protected Class<?> findClass(String className) throws ClassNotFoundException {
+        GeneratedClass cls = generatedClasses.get(className);
+        if (cls != null) {
+            return cls.getGeneratedClass();
+        }
+        return super.findClass(className);
+    }
+
+    public synchronized Class<?> getGeneratedClass(String className, byte[] byteCode) {
+        GeneratedClass cls = generatedClasses.get(className);
+        if (cls == null) {
+            cls = new GeneratedClass(className, byteCode);
+            generatedClasses.put(className, cls);
+        }
+        return cls.getGeneratedClass();
+    }
+}

Added: tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java?rev=940652&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java Mon May  3 22:02:04 2010
@@ -0,0 +1,145 @@
+/*
+ * 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.interfacedef.java.jaxrs;
+
+import java.lang.reflect.Method;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+public class RootResourceClassGenerator implements Opcodes {
+
+    private static final String DELEGATE_FIELD = "delegate";
+
+    public static Class<?> generateRootResourceClass(Class<?> interfaze, String path) throws Exception {
+        GeneratedClassLoader classLoader = new GeneratedClassLoader(interfaze.getClassLoader());
+        String interfaceName = interfaze.getName();
+        int index = interfaze.getName().lastIndexOf('.');
+        String className =
+            interfaceName.substring(0, index) + ".Generated" + interfaceName.substring(index + 1) + "Impl";
+
+        byte[] content = generate(interfaze, path);
+        Class<?> cls = classLoader.getGeneratedClass(className, content);
+        return cls;
+    }
+
+    public static byte[] generate(Class<?> interfaze, String path) throws Exception {
+        String interfaceName = Type.getInternalName(interfaze);
+        int index = interfaceName.lastIndexOf('/');
+        String className =
+            interfaceName.substring(0, index) + "/Generated" + interfaceName.substring(index + 1) + "Impl";
+
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+
+        declareClass(cw, interfaceName, className);
+
+        annotatePath(cw, path);
+        declareField(cw, interfaceName);
+        declareConstructor(cw, className);
+
+        for (Method method : interfaze.getMethods()) {
+            if (!(method.getDeclaringClass() == Object.class)) {
+                generateMethod(cw, interfaceName, className, method);
+            }
+        }
+        cw.visitEnd();
+
+        return cw.toByteArray();
+    }
+
+    // public <ReturnType> method(<Type0> arg0, ..., <TypeN> argN) throws <ExpectionType0>, ..., <ExceptionTypeK>
+    private static void generateMethod(ClassWriter cw, String interfaceName, String className, Method method) {
+        String methodDescriptor = Type.getMethodDescriptor(method);
+
+        MethodVisitor mv =
+            cw.visitMethod(ACC_PUBLIC, method.getName(), methodDescriptor, null, getExceptionInternalNames(method));
+        mv.visitCode();
+        mv.visitFieldInsn(GETSTATIC, className, DELEGATE_FIELD, getSignature(interfaceName));
+        Class<?>[] paramTypes = method.getParameterTypes();
+        for (int i = 0; i < paramTypes.length; i++) {
+            String signature = Type.getDescriptor(paramTypes[i]);
+            mv.visitVarInsn(CodeGenerationHelper.getLoadOPCode(signature), i + 1);
+        }
+        mv.visitMethodInsn(INVOKEINTERFACE, interfaceName, method.getName(), methodDescriptor);
+
+        Class<?> returnType = method.getReturnType();
+        mv.visitInsn(CodeGenerationHelper.getReturnOPCode(Type.getDescriptor(returnType)));
+        int size = paramTypes.length + 1;
+        mv.visitMaxs(size, size);
+        mv.visitEnd();
+    }
+
+    private static String[] getExceptionInternalNames(Method method) {
+        Class<?>[] types = method.getExceptionTypes();
+        if (types.length == 0) {
+            return null;
+        }
+        String[] names = new String[types.length];
+        for (int i = 0; i < types.length; i++) {
+            names[i] = Type.getInternalName(types[i]);
+        }
+        return names;
+    }
+
+    private static String getSignature(String interfaceName) {
+        return "L" + interfaceName + ";";
+    }
+
+    private static void declareConstructor(ClassWriter cw, String className) {
+        MethodVisitor mv;
+        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitCode();
+        Label l0 = new Label();
+        mv.visitLabel(l0);
+        // mv.visitLineNumber(37, l0);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+        mv.visitInsn(RETURN);
+        Label l1 = new Label();
+        mv.visitLabel(l1);
+        mv.visitLocalVariable("this", getSignature(className), null, l0, l1, 0);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
+    }
+
+    // public static <Interface> delegate;
+    private static void declareField(ClassWriter cw, String interfaceName) {
+        FieldVisitor fv =
+            cw.visitField(ACC_PUBLIC + ACC_STATIC, DELEGATE_FIELD, getSignature(interfaceName), null, null);
+        fv.visitEnd();
+    }
+
+    // public class _<Interface>Impl implements <Interface>
+    private static void declareClass(ClassWriter cw, String interfaceName, String className) {
+        cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, className, null, "java/lang/Object", new String[] {interfaceName});
+    }
+
+    // @Path(<path>)
+    private static void annotatePath(ClassWriter cw, String path) {
+        AnnotationVisitor av = cw.visitAnnotation("Ljavax/ws/rs/Path;", true);
+        av.visit("value", path);
+        av.visitEnd();
+    }
+}

Added: tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/MockedResource.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/MockedResource.java?rev=940652&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/MockedResource.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/MockedResource.java Mon May  3 22:02:04 2010
@@ -0,0 +1,44 @@
+/*
+ * 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.interfacedef.java.jaxrs;
+
+public class MockedResource implements Resource {
+    private String value;
+
+    public MockedResource() {
+        super();
+    }
+
+    public String get() {
+        return value;
+    }
+
+    public void create(String value) {
+        this.value = value;
+    }
+
+    public void delete() {
+        value = null;
+    }
+
+    public void update(String value) {
+        this.value = value;
+    }
+}

Added: tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/Resource.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/Resource.java?rev=940652&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/Resource.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/Resource.java Mon May  3 22:02:04 2010
@@ -0,0 +1,44 @@
+/*
+ * 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.interfacedef.java.jaxrs;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+
+import org.oasisopen.sca.annotation.Remotable;
+
+@Remotable
+public interface Resource {
+
+    @GET
+    String get();
+
+    @PUT
+    void update(String value);
+
+    @POST
+    void create(String value);
+
+    @DELETE
+    void delete();
+
+}

Added: tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/ResourceWrapper.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/ResourceWrapper.java?rev=940652&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/ResourceWrapper.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/ResourceWrapper.java Mon May  3 22:02:04 2010
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.tuscany.sca.interfacedef.java.jaxrs;
+
+import javax.ws.rs.Path;
+
+
+@Path("myURI")
+public class ResourceWrapper implements Resource {
+    public static Resource delegate;
+
+    public ResourceWrapper() {
+        super();
+    }
+
+
+    public String get() {
+        return delegate.get();
+    }
+
+    public void create(String value) {
+        delegate.create(value);
+    }
+
+    public void delete() {
+        delegate.delete();
+    }
+
+    public void update(String value) {
+        delegate.update(value);
+    }
+
+}

Added: tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGeneratorTestCase.java
URL: http://svn.apache.org/viewvc/tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGeneratorTestCase.java?rev=940652&view=auto
==============================================================================
--- tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGeneratorTestCase.java (added)
+++ tuscany/sca-java-2.x/trunk/modules/interface-java-jaxrs/src/test/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGeneratorTestCase.java Mon May  3 22:02:04 2010
@@ -0,0 +1,60 @@
+/*
+ * 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.interfacedef.java.jaxrs;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import javax.ws.rs.Path;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * 
+ */
+public class RootResourceClassGeneratorTestCase {
+    @Test
+    public void testGenerator() throws Exception {
+        Class<?> cls = RootResourceClassGenerator.generateRootResourceClass(Resource.class, "myURI");
+        Assert.assertTrue(cls.isAnnotationPresent(Path.class));
+        Path path = cls.getAnnotation(Path.class);
+        Assert.assertEquals("myURI", path.value());
+        Field field = cls.getField("delegate");
+        Assert.assertSame(Resource.class, field.getType());
+
+        Assert.assertTrue(Modifier.isPublic(field.getModifiers()));
+        Assert.assertTrue(Modifier.isStatic(field.getModifiers()));
+
+        Assert.assertTrue(Resource.class.isAssignableFrom(cls));
+
+        Resource resource = new MockedResource();
+        field.set(null, resource);
+
+        Resource resourceProxy = (Resource)cls.newInstance();
+        Assert.assertNull(resourceProxy.get());
+        resourceProxy.create("123");
+        Assert.assertEquals("123", resourceProxy.get());
+        resourceProxy.update("ABC");
+        Assert.assertEquals("ABC", resourceProxy.get());
+        resourceProxy.delete();
+        Assert.assertNull(resourceProxy.get());
+    }
+}