diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2010-08-29 02:55:29 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2010-08-29 02:55:29 +0000 |
commit | 88bf2a256b02e1858993bf097f4dc743d389e3f0 (patch) | |
tree | 298073eb40da33624a95f820e576e049c279e463 /sandbox/sebastien/java/extend/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java | |
parent | 490374326cf57b0161d053aea3a9f0cedd7d2228 (diff) |
Sandbox to experiment and extend the runtime.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@990479 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sandbox/sebastien/java/extend/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java')
-rw-r--r-- | sandbox/sebastien/java/extend/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/sandbox/sebastien/java/extend/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java b/sandbox/sebastien/java/extend/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java new file mode 100644 index 0000000000..8ee34e79f4 --- /dev/null +++ b/sandbox/sebastien/java/extend/modules/interface-java-jaxrs/src/main/java/org/apache/tuscany/sca/interfacedef/java/jaxrs/RootResourceClassGenerator.java @@ -0,0 +1,210 @@ +/* + * 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.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, String consumes, String produces) + throws Exception { + if (!interfaze.isInterface()) { + throw new IllegalArgumentException(interfaze + " is not an interface."); + } + 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, consumes, produces); + Class<?> cls = classLoader.getGeneratedClass(className, content); + return cls; + } + + public static void injectProxy(Class<?> generatedResourceClass, Object proxy) throws Exception { + Field field = generatedResourceClass.getField("delegate"); + field.set(null, proxy); + } + + public static byte[] generate(Class<?> interfaze, String path, String consumes, String produces) 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); + annotateContentTypes(cw, consumes, produces); + declareField(cw, interfaceName); + declareConstructor(cw, className); + + for (Method method : interfaze.getMethods()) { + if (!(method.getDeclaringClass() == Object.class)) { + generateMethod(cw, interfaceName, className, method, consumes, produces); + } + } + 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 consumes, + String produces) { + 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(); + } + + // @Consumes(<contentTypes>) + // @Provides(<contentTypes>) + private static void annotateContentTypes(ClassWriter cw, String consumes, String produces) { + AnnotationVisitor av = null; + if (consumes != null) { + av = cw.visitAnnotation("Ljavax/ws/rs/Consumes;", true); + AnnotationVisitor av1 = av.visitArray("value"); + for (String s : consumes.split("(,| )")) { + av1.visit(null, s.trim()); + } + av1.visitEnd(); + av.visitEnd(); + } + if (produces != null) { + av = cw.visitAnnotation("Ljavax/ws/rs/Produces;", true); + AnnotationVisitor av1 = av.visitArray("value"); + for (String s : produces.split("(,| )")) { + av1.visit(null, s.trim()); + } + av1.visitEnd(); + av.visitEnd(); + } + } + + // @Consumes(<contentTypes>) + // @Provides(<contentTypes>) + private static void annotateContentTypes(MethodVisitor mv, String consumes, String produces) { + AnnotationVisitor av = null; + if (consumes != null) { + av = mv.visitAnnotation("Ljavax/ws/rs/Consumes;", true); + AnnotationVisitor av1 = av.visitArray("value"); + for (String s : consumes.split("(,| )")) { + av1.visit(null, s.trim()); + } + av1.visitEnd(); + av.visitEnd(); + } + if (produces != null) { + av = mv.visitAnnotation("Ljavax/ws/rs/Produces;", true); + AnnotationVisitor av1 = av.visitArray("value"); + for (String s : produces.split("(,| )")) { + av1.visit(null, s.trim()); + } + av1.visitEnd(); + av.visitEnd(); + } + } +} |