com.google.gwtorm.server.SchemaConstructorGen.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwtorm.server.SchemaConstructorGen.java

Source

// Copyright 2008 Google Inc.
//
// Licensed 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 com.google.gwtorm.server;

import com.google.gwtorm.schema.Util;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/** Generates a factory to efficiently create new Schema instances. */
public class SchemaConstructorGen<T extends Schema> implements Opcodes {
    private static final String CTX = "schemaArg";

    private final GeneratedClassLoader classLoader;
    private final Class<T> schemaImpl;
    private final Object schemaArg;
    private ClassWriter cw;
    private String implClassName;
    private String implTypeName;

    public SchemaConstructorGen(final GeneratedClassLoader loader, final Class<T> c, final Object f) {
        classLoader = loader;
        schemaImpl = c;
        schemaArg = f;
    }

    public void defineClass() throws OrmException {
        init();
        declareFactoryField();
        implementConstructor();
        implementNewInstance();
        cw.visitEnd();
        classLoader.defineClass(implClassName, cw.toByteArray());
    }

    public SchemaFactory<T> create() throws OrmException {
        defineClass();
        try {
            final Class<?> c = Class.forName(implClassName, true, classLoader);
            final Constructor<?> n = c.getDeclaredConstructors()[0];
            return cast(n.newInstance(new Object[] { schemaArg }));
        } catch (InstantiationException e) {
            throw new OrmException("Cannot create schema factory", e);
        } catch (IllegalAccessException e) {
            throw new OrmException("Cannot create schema factory", e);
        } catch (ClassNotFoundException e) {
            throw new OrmException("Cannot create schema factory", e);
        } catch (IllegalArgumentException e) {
            throw new OrmException("Cannot create schema factory", e);
        } catch (InvocationTargetException e) {
            throw new OrmException("Cannot create schema factory", e);
        }
    }

    @SuppressWarnings("unchecked")
    private SchemaFactory<T> cast(final Object newInstance) {
        return (SchemaFactory<T>) newInstance;
    }

    private void init() {
        implClassName = schemaImpl.getName() + "_Factory_" + Util.createRandomName();
        implTypeName = implClassName.replace('.', '/');

        cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        cw.visit(V1_3, ACC_PUBLIC | ACC_FINAL | ACC_SUPER, implTypeName, null, Type.getInternalName(Object.class),
                new String[] { Type.getInternalName(SchemaFactory.class) });
    }

    private void declareFactoryField() {
        cw.visitField(ACC_PRIVATE | ACC_FINAL, CTX, Type.getType(schemaArg.getClass()).getDescriptor(), null, null)
                .visitEnd();
    }

    private void implementConstructor() {
        final Type ft = Type.getType(schemaArg.getClass());
        final String consName = "<init>";
        final String consDesc = Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { ft });
        final MethodVisitor mv;
        mv = cw.visitMethod(ACC_PUBLIC, consName, consDesc, null, null);
        mv.visitCode();

        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(Object.class), consName,
                Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}));

        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitFieldInsn(PUTFIELD, implTypeName, CTX, ft.getDescriptor());

        mv.visitInsn(RETURN);
        mv.visitMaxs(-1, -1);
        mv.visitEnd();
    }

    private void implementNewInstance() {
        final Type ft = Type.getType(schemaArg.getClass());
        final String typeName = Type.getType(schemaImpl).getInternalName();
        final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, "open",
                Type.getMethodDescriptor(Type.getType(Schema.class), new Type[] {}), null, null);
        mv.visitCode();

        Constructor<?> c = schemaImpl.getDeclaredConstructors()[0];
        Type argType = Type.getType(c.getParameterTypes()[0]);

        mv.visitTypeInsn(NEW, typeName);
        mv.visitInsn(DUP);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, implTypeName, CTX, ft.getDescriptor());
        mv.visitMethodInsn(INVOKESPECIAL, typeName, "<init>",
                Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { argType }));
        mv.visitInsn(ARETURN);
        mv.visitMaxs(-1, -1);
        mv.visitEnd();
    }
}