summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2010-05-28 18:09:29 -0700
committerShawn O. Pearce <sop@google.com>2010-05-28 18:56:14 -0700
commit97d147d4d73d864e302e7430e77cd158e2938c9f (patch)
tree6ecef4e63c0602693ac7c3968a366d606e3f2ee8
parente264bdd33ce7e60f8461127cbb7e95176847a2a4 (diff)
downloadgwtorm-97d147d4d73d864e302e7430e77cd158e2938c9f.tar.gz
Refactor SchemaConstructorGen to be reused
Rather than repeat this code for every backend, allow the backend to reuse our existing code and just initialize any state within the Schema implementation's constructor, and not in the SchemaFactory open() method. Change-Id: Ie4509c61d85cf38fdb1159647bbc2dbd5b85f5d5 Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r--src/main/java/com/google/gwtorm/jdbc/AbstractSchemaFactory.java39
-rw-r--r--src/main/java/com/google/gwtorm/jdbc/Database.java23
-rw-r--r--src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java4
-rw-r--r--src/main/java/com/google/gwtorm/jdbc/gen/SchemaFactoryGen.java115
-rw-r--r--src/main/java/com/google/gwtorm/jdbc/gen/SchemaGen.java19
-rw-r--r--src/main/java/com/google/gwtorm/server/SchemaConstructorGen.java143
6 files changed, 172 insertions, 171 deletions
diff --git a/src/main/java/com/google/gwtorm/jdbc/AbstractSchemaFactory.java b/src/main/java/com/google/gwtorm/jdbc/AbstractSchemaFactory.java
deleted file mode 100644
index 2db0290..0000000
--- a/src/main/java/com/google/gwtorm/jdbc/AbstractSchemaFactory.java
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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;
-
-import com.google.gwtorm.client.Schema;
-
-import java.sql.Connection;
-
-/**
- * Internal interface to quickly create Schema instances.
- * <p>
- * Applications should not use this interface. It is automatically implemented
- * at runtime to provide fast construction for new Schema instances within
- * {@link Database#open()}.
- *
- * @param <T> type of the application schema.
- */
-public abstract class AbstractSchemaFactory<T extends Schema> {
- /**
- * Create a new schema instance.
- *
- * @param db the database instance which created the connection.
- * @param c the JDBC connection the instance will talk to the database on.
- * @return the new schema instance, wrapping the connection.
- */
- public abstract T create(Database<T> db, Connection c);
-}
diff --git a/src/main/java/com/google/gwtorm/jdbc/Database.java b/src/main/java/com/google/gwtorm/jdbc/Database.java
index 6d4e137..a38974f 100644
--- a/src/main/java/com/google/gwtorm/jdbc/Database.java
+++ b/src/main/java/com/google/gwtorm/jdbc/Database.java
@@ -18,7 +18,6 @@ import com.google.gwtorm.client.KeyUtil;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.Schema;
import com.google.gwtorm.client.SchemaFactory;
-import com.google.gwtorm.jdbc.gen.SchemaFactoryGen;
import com.google.gwtorm.jdbc.gen.SchemaGen;
import com.google.gwtorm.schema.SchemaModel;
import com.google.gwtorm.schema.java.JavaSchemaModel;
@@ -27,6 +26,7 @@ import com.google.gwtorm.schema.sql.DialectMySQL;
import com.google.gwtorm.schema.sql.DialectPostgreSQL;
import com.google.gwtorm.schema.sql.SqlDialect;
import com.google.gwtorm.server.GeneratedClassLoader;
+import com.google.gwtorm.server.SchemaConstructorGen;
import com.google.gwtorm.server.StandardKeyEncoder;
import java.sql.Connection;
@@ -89,7 +89,7 @@ public class Database<T extends Schema> implements SchemaFactory<T> {
private final DataSource dataSource;
private final JavaSchemaModel schemaModel;
- private final AbstractSchemaFactory<T> implFactory;
+ private final SchemaFactory<T> implFactory;
private final SqlDialect implDialect;
/**
@@ -134,14 +134,14 @@ public class Database<T extends Schema> implements SchemaFactory<T> {
final GeneratedClassLoader loader = newLoader(schema);
final SchemaKey key = new SchemaKey(schema, dialect);
final String cachedName = schemaFactoryNames.get(key);
- AbstractSchemaFactory<T> factory = null;
+ SchemaFactory<T> factory = null;
if (cachedName != null) {
factory = newFactory(loader, cachedName);
}
if (factory == null) {
- final SchemaGen gen = new SchemaGen(loader, schemaModel, dialect);
- gen.defineClass();
- factory = new SchemaFactoryGen<T>(loader, gen).create();
+ Class<T> impl =
+ (Class<T>) new SchemaGen(loader, schemaModel, dialect).create();
+ factory = new SchemaConstructorGen<T>(loader, impl, this).create();
schemaFactoryNames.put(key, factory.getClass().getName());
}
implFactory = factory;
@@ -149,11 +149,11 @@ public class Database<T extends Schema> implements SchemaFactory<T> {
}
@SuppressWarnings("unchecked")
- private AbstractSchemaFactory<T> newFactory(final ClassLoader cl,
+ private SchemaFactory<T> newFactory(final ClassLoader cl,
final String name) {
try {
final Class<?> ft = Class.forName(name, true, cl);
- return (AbstractSchemaFactory<T>) ft.newInstance();
+ return (SchemaFactory<T>) ft.newInstance();
} catch (InstantiationException e) {
return null;
} catch (IllegalAccessException e) {
@@ -180,6 +180,10 @@ public class Database<T extends Schema> implements SchemaFactory<T> {
* cause of the connection failure.
*/
public T open() throws OrmException {
+ return implFactory.open();
+ }
+
+ Connection newConnection() throws OrmException {
final Connection conn;
try {
conn = dataSource.getConnection();
@@ -198,8 +202,7 @@ public class Database<T extends Schema> implements SchemaFactory<T> {
}
throw new OrmException("Cannot force auto-commit on connection", e);
}
-
- return implFactory.create(this, conn);
+ return conn;
}
private static <T> GeneratedClassLoader newLoader(final Class<T> schema) {
diff --git a/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java b/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java
index 997ed08..9603edd 100644
--- a/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java
+++ b/src/main/java/com/google/gwtorm/jdbc/JdbcSchema.java
@@ -34,9 +34,9 @@ public abstract class JdbcSchema implements Schema {
private final Database<?> dbDef;
private Connection conn;
- protected JdbcSchema(final Database<?> d, final Connection c) {
+ protected JdbcSchema(final Database<?> d) throws OrmException {
dbDef = d;
- conn = c;
+ conn = dbDef.newConnection();
}
public final Connection getConnection() {
diff --git a/src/main/java/com/google/gwtorm/jdbc/gen/SchemaFactoryGen.java b/src/main/java/com/google/gwtorm/jdbc/gen/SchemaFactoryGen.java
deleted file mode 100644
index 1c66e96..0000000
--- a/src/main/java/com/google/gwtorm/jdbc/gen/SchemaFactoryGen.java
+++ /dev/null
@@ -1,115 +0,0 @@
-// 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 com.google.gwtorm.server.GeneratedClassLoader;
-
-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();
- }
-}
diff --git a/src/main/java/com/google/gwtorm/jdbc/gen/SchemaGen.java b/src/main/java/com/google/gwtorm/jdbc/gen/SchemaGen.java
index 70b99d0..f5d32e7 100644
--- a/src/main/java/com/google/gwtorm/jdbc/gen/SchemaGen.java
+++ b/src/main/java/com/google/gwtorm/jdbc/gen/SchemaGen.java
@@ -30,7 +30,6 @@ import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
-import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
@@ -52,7 +51,7 @@ public class SchemaGen implements Opcodes {
dialect = sqlDialect;
}
- public void defineClass() throws OrmException {
+ public Class<Schema> create() throws OrmException {
defineRelationClasses();
init();
@@ -62,6 +61,17 @@ public class SchemaGen implements Opcodes {
implementRelationMethods();
cw.visitEnd();
classLoader.defineClass(getImplClassName(), cw.toByteArray());
+ return loadClass();
+ }
+
+ @SuppressWarnings("unchecked")
+ private Class<Schema> loadClass() throws OrmException {
+ try {
+ final Class<?> c = Class.forName(getImplClassName(), false, classLoader);
+ return (Class<Schema>) c;
+ } catch (ClassNotFoundException err) {
+ throw new OrmException("Cannot load generated class", err);
+ }
}
String getSchemaClassName() {
@@ -104,15 +114,14 @@ public class SchemaGen implements Opcodes {
private void implementConstructor() {
final String consName = "<init>";
final String consDesc =
- Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {
- Type.getType(Database.class), Type.getType(Connection.class)});
+ Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {Type
+ .getType(Database.class)});
final MethodVisitor mv =
cw.visitMethod(ACC_PUBLIC, consName, consDesc, null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
- mv.visitVarInsn(ALOAD, 2);
mv.visitMethodInsn(INVOKESPECIAL, superTypeName, consName, consDesc);
for (final RelationGen info : relations) {
diff --git a/src/main/java/com/google/gwtorm/server/SchemaConstructorGen.java b/src/main/java/com/google/gwtorm/server/SchemaConstructorGen.java
new file mode 100644
index 0000000..1761348
--- /dev/null
+++ b/src/main/java/com/google/gwtorm/server/SchemaConstructorGen.java
@@ -0,0 +1,143 @@
+// 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.client.OrmException;
+import com.google.gwtorm.client.Schema;
+import com.google.gwtorm.client.SchemaFactory;
+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();
+ }
+}