blob: 094888c239283907f4a997e8fc0240bc88f863e4 [file] [log] [blame]
// 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.jdbc.gen;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.Schema;
import com.google.gwtorm.jdbc.AbstractSchemaFactory;
import com.google.gwtorm.jdbc.Database;
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.sql.Connection;
/** Generates a factory to efficiently create new Schema instances. */
public class SchemaFactoryGen<T extends Schema> implements Opcodes {
private final GeneratedClassLoader classLoader;
private final SchemaGen schemaGen;
private ClassWriter cw;
private String superTypeName;
private String implClassName;
private String implTypeName;
public SchemaFactoryGen(final GeneratedClassLoader loader, final SchemaGen gen) {
classLoader = loader;
schemaGen = gen;
}
public void defineClass() throws OrmException {
init();
implementEmptyConstructor();
implementCreate();
cw.visitEnd();
classLoader.defineClass(implClassName, cw.toByteArray());
}
public AbstractSchemaFactory<T> create() throws OrmException {
defineClass();
try {
return cast(Class.forName(implClassName, true, classLoader).newInstance());
} 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);
}
}
@SuppressWarnings("unchecked")
private AbstractSchemaFactory<T> cast(final Object newInstance) {
return (AbstractSchemaFactory<T>) newInstance;
}
private void init() {
superTypeName = Type.getInternalName(AbstractSchemaFactory.class);
implClassName =
schemaGen.getSchemaClassName() + "_Factory_" + Util.createRandomName();
implTypeName = implClassName.replace('.', '/');
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cw.visit(V1_3, ACC_PUBLIC | ACC_FINAL | ACC_SUPER, implTypeName, null,
superTypeName, null);
}
private void implementEmptyConstructor() {
final String consName = "<init>";
final String consDesc =
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {});
final MethodVisitor mv;
mv = cw.visitMethod(ACC_PUBLIC, consName, consDesc, null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, superTypeName, consName, consDesc);
mv.visitInsn(RETURN);
mv.visitMaxs(-1, -1);
mv.visitEnd();
}
private void implementCreate() {
final MethodVisitor mv =
cw.visitMethod(ACC_PUBLIC | ACC_FINAL, "create", Type
.getMethodDescriptor(Type.getType(Schema.class), new Type[] {
Type.getType(Database.class), Type.getType(Connection.class)}),
null, null);
mv.visitCode();
mv.visitTypeInsn(NEW, schemaGen.getImplTypeName());
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKESPECIAL, schemaGen.getImplTypeName(), "<init>",
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {
Type.getType(Database.class), Type.getType(Connection.class)}));
mv.visitInsn(ARETURN);
mv.visitMaxs(-1, -1);
mv.visitEnd();
}
}