Author: rickmcguire
Date: Tue Jul 8 08:13:24 2008
New Revision: 674853
URL: http://svn.apache.org/viewvc?rev=674853&view=rev
Log:
GERONIMO-842 CMP2Generator is not generating "is" methods.
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/CmpJpaConversion.java
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp1Generator.java
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp2Generator.java
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/CmpField.java
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/PostCreateGenerator.java
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java?rev=674853&r1=674852&r2=674853&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java
Tue Jul 8 08:13:24 2008
@@ -424,6 +424,8 @@
logger.info("createApplication.start", appInfo.jarPath);
+ // To start out, ensure we don't already have any beans deployed with
duplicate IDs. This
+ // is a conflict we can't handle.
List<String> used = new ArrayList<String>();
for (EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
for (EnterpriseBeanInfo beanInfo : ejbJarInfo.enterpriseBeans) {
@@ -443,7 +445,7 @@
}
try {
- // Generate the cmp2 concrete subclasses
+ // Generate the cmp2/cmp1 concrete subclasses
CmpJarBuilder cmpJarBuilder = new CmpJarBuilder(appInfo,
classLoader);
File generatedJar = cmpJarBuilder.getJarFile();
if (generatedJar != null) {
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java?rev=674853&r1=674852&r2=674853&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/CmpJarBuilder.java
Tue Jul 8 08:13:24 2008
@@ -55,9 +55,20 @@
return jarFile;
}
+ /**
+ * Generate the CMP jar file associated with this
+ * deployed application. The generated jar file will
+ * contain generated classes and metadata that will
+ * allow the JPA engine to manage the bean persistence.
+ *
+ * @exception IOException
+ */
private void generate() throws IOException {
- // Don't generate an empty jar
- if (!hasCmpBeans()) return;
+ // Don't generate an empty jar. If there are no container-managed
beans defined in this
+ // application deployment, there's nothing to do.
+ if (!hasCmpBeans()) {
+ return;
+ }
boolean threwException = false;
JarOutputStream jarOutputStream = openJarFile();
@@ -89,6 +100,16 @@
}
}
+ /**
+ * Test if an application contains and CMP beans that
+ * need to be mapped to the JPA persistence engine. This
+ * will search all of the ejb jars contained within
+ * the application looking for Entity beans with
+ * a CONTAINER persistence type.
+ *
+ * @return true if the application uses container managed beans,
+ * false if none are found.
+ */
private boolean hasCmpBeans() {
for (EjbJarInfo ejbJar : appInfo.ejbJars) {
for (EnterpriseBeanInfo beanInfo : ejbJar.enterpriseBeans) {
@@ -103,6 +124,18 @@
return false;
}
+ /**
+ * Generate a class file for a CMP bean, writing the
+ * byte data for the generated class into the jar file
+ * we're constructing.
+ *
+ * @param jarOutputStream
+ * The target jarfile.
+ * @param entityBeanInfo
+ * The descriptor for the entity bean we need to wrapper.
+ *
+ * @exception IOException
+ */
private void generateClass(JarOutputStream jarOutputStream, EntityBeanInfo
entityBeanInfo) throws IOException {
// don't generate if there is aleady an implementation class
String cmpImplClass =
CmpUtil.getCmpImplClassName(entityBeanInfo.abstractSchemaName,
entityBeanInfo.ejbClass);
@@ -119,6 +152,7 @@
throw (IOException)new IOException("Could not find entity bean
class " + beanClass).initCause(e);
}
+ // and the primary key class, if defined.
Class<?> primKeyClass = null;
if (entityBeanInfo.primKeyClass != null) {
try {
@@ -128,22 +162,28 @@
}
}
+ // now generate a class file using the appropriate level of CMP
generator.
byte[] bytes;
+ // NB: We'll need to change this test of CMP 3 is ever defined!
if (entityBeanInfo.cmpVersion != 2) {
Cmp1Generator cmp1Generator = new Cmp1Generator(cmpImplClass,
beanClass);
+ // A primary key class defined as Object is an unknown key. Mark
it that
+ // way so the generator will create the automatically generated
key.
if ("java.lang.Object".equals(entityBeanInfo.primKeyClass)) {
cmp1Generator.setUnknownPk(true);
}
bytes = cmp1Generator.generate();
} else {
- // generte the implementation class
+ // generate the implementation class
Cmp2Generator cmp2Generator = new Cmp2Generator(cmpImplClass,
beanClass,
entityBeanInfo.primKeyField,
primKeyClass,
entityBeanInfo.cmpFieldNames.toArray(new
String[entityBeanInfo.cmpFieldNames.size()]));
+ // we need to have a complete set of the defined CMR fields
available for the
+ // generation process as well.
for (CmrFieldInfo cmrFieldInfo : entityBeanInfo.cmrFields) {
EntityBeanInfo roleSource = cmrFieldInfo.mappedBy.roleSource;
CmrField cmrField = new CmrField(cmrFieldInfo.fieldName,
@@ -161,6 +201,17 @@
addJarEntry(jarOutputStream, entryName, bytes);
}
+
+ /**
+ * Insert a file resource into the generated jar file.
+ *
+ * @param jarOutputStream
+ * The target jar file.
+ * @param fileName The name we're inserting.
+ * @param bytes The file byte data.
+ *
+ * @exception IOException
+ */
private void addJarEntry(JarOutputStream jarOutputStream, String fileName,
byte[] bytes) throws IOException {
// add all missing directory entried
String path = "";
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/CmpJpaConversion.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/CmpJpaConversion.java?rev=674853&r1=674852&r2=674853&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/CmpJpaConversion.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/config/CmpJpaConversion.java
Tue Jul 8 08:13:24 2008
@@ -102,8 +102,7 @@
// todo scan existing persistence module for all entity mappings and
don't generate mappings for them
-
- // create mappings
+ // create mappings if no mappings currently exist
EntityMappings cmpMappings = appModule.getCmpMappings();
if (cmpMappings == null) {
cmpMappings = new EntityMappings();
@@ -111,9 +110,12 @@
appModule.setCmpMappings(cmpMappings);
}
+ // we process this one jar-file at a time...each contributing to the
+ // app mapping data
for (EjbModule ejbModule : appModule.getEjbModules()) {
EjbJar ejbJar = ejbModule.getEjbJar();
+ // scan for CMP entity beans and merge the data into the
collective set
for (EnterpriseBean enterpriseBean : ejbJar.getEnterpriseBeans()) {
if (isCmpEntity(enterpriseBean)) {
processEntityBean(ejbModule, cmpMappings, (EntityBean)
enterpriseBean);
@@ -404,8 +406,10 @@
return;
}
+ // get the real bean class
Class ejbClass = loadClass(ejbModule.getClassLoader(),
bean.getEjbClass());
-
+ // and generate a name for the subclass that will be generated and
handed to the JPA
+ // engine as the managed class.
String jpaEntityClassName =
CmpUtil.getCmpImplClassName(bean.getAbstractSchemaName(), ejbClass.getName());
// We don't use this mapping directly, instead we pull entries from it
@@ -604,11 +608,18 @@
String name = method.getName();
-
if (name.startsWith("get")){
name = name.substring("get".length(), name.length());
} else if (name.startsWith("is")){
- name = name.substring("is".length(), name.length());
+ // Only add this if the return type from an "is" method
+ // boolean.
+ if (method.getReturnType() == Boolean.TYPE) {
+ name = name.substring("is".length(), name.length());
+ }
+ else {
+ // not an acceptable "is" method.
+ continue;
+ }
} else continue;
name = Strings.lcfirst(name);
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp1Generator.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp1Generator.java?rev=674853&r1=674852&r2=674853&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp1Generator.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp1Generator.java
Tue Jul 8 08:13:24 2008
@@ -22,6 +22,10 @@
import org.objectweb.asm.Type;
import org.objectweb.asm.FieldVisitor;
+/**
+ * Class for generating a class file that implements
+ * CMP1 type of persistence.
+ */
public class Cmp1Generator implements Opcodes {
private String implClassName;
private String beanClassName;
@@ -29,6 +33,13 @@
private boolean unknownPk;
private final PostCreateGenerator postCreateGenerator;
+ /**
+ * Constructor for a CMP1 class generator.
+ *
+ * @param cmpImplClass
+ * The name of the generated implementation class.
+ * @param beanClass The source Bean class we're wrappering.
+ */
public Cmp1Generator(String cmpImplClass, Class beanClass) {
beanClassName = Type.getInternalName(beanClass);
implClassName = cmpImplClass.replace('.', '/');
@@ -38,7 +49,15 @@
postCreateGenerator = new PostCreateGenerator(beanClass, cw);
}
+ /**
+ * Generate the class for implementing CMP 1 level of
+ * persistence.
+ *
+ * @return The generated byte-array containing the class data.
+ */
public byte[] generate() {
+ // We're creating a superclass for the implementation. We force this
to implement
+ // EntityBean to allow POJOs to be used as the bean class.
cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, implClassName, null,
beanClassName, new String[]{"javax/ejb/EntityBean"});
// if we have an unknown pk, we need to add a field for the pk
@@ -48,8 +67,10 @@
fv.visitEnd();
}
+ // there's not much to generate here. We create a default
constructor, then generate the
+ // post create methods. A lot of the work is done by having mapped
superclass information that
+ // we pass to the JPA engine.
createConstructor();
-
postCreateGenerator.generate();
cw.visitEnd();
@@ -57,6 +78,12 @@
return cw.toByteArray();
}
+ /**
+ * Create a default constructor for our bean super
+ * class. This is just a forwarding constructor that
+ * calls the superclass (the bean implementation class)
+ * default constructor.
+ */
private void createConstructor() {
MethodVisitor mv = mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V",
null, null);
mv.visitCode();
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp2Generator.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp2Generator.java?rev=674853&r1=674852&r2=674853&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp2Generator.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/Cmp2Generator.java
Tue Jul 8 08:13:24 2008
@@ -73,7 +73,8 @@
* @param cmpFields The list of fields that are managed using cmp.
*/
public Cmp2Generator(String cmpImplClass, Class beanClass, String pkField,
Class<?> primKeyClass, String[] cmpFields) {
-
+
+ this.beanClass = beanClass;
beanClassName = Type.getInternalName(beanClass);
implClassName = cmpImplClass.replace('.', '/');
@@ -89,15 +90,14 @@
// a getter defined and b) that we know the field return type. The
created CmpField
// list will feed into the generation process.
for (String cmpFieldName : cmpFields) {
- String getterName = getterName(cmpFieldName);
- try {
- Method getter = beanClass.getMethod(getterName);
- Type type = Type.getType(getter.getReturnType());
- CmpField cmpField = new CmpField(cmpFieldName, type);
- this.cmpFields.put(cmpFieldName, cmpField);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException("No such property " +
cmpFieldName + " defined on bean class " + beanClassName, e);
+ Method getter = getterMethod(cmpFieldName);
+ if (getter == null) {
+ throw new IllegalArgumentException("No such property " +
cmpFieldName + " defined on bean class " + beanClassName);
}
+
+ Type type = Type.getType(getter.getReturnType());
+ CmpField cmpField = new CmpField(cmpFieldName, type, getter);
+ this.cmpFields.put(cmpFieldName, cmpField);
}
// if a pkField is defined, it MUST be a CMP field. Make sure it
really exists
@@ -118,8 +118,6 @@
}
}
- this.beanClass = beanClass;
-
// The class writer will be used for all generator activies, while the
// postCreateGenerator will be used to add the ejbPostCreatexxxx
methods as a
// last step.
@@ -448,7 +446,7 @@
* @param cmpField The CMP field backing this getter method.
*/
private void createGetter(CmpField cmpField) {
- String methodName = getterName(cmpField.getName());
+ String methodName = cmpField.getGetterMethod().getName();
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, methodName, "()" +
cmpField.getDescriptor(), null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
@@ -458,12 +456,59 @@
mv.visitEnd();
}
+ /**
+ * Generate the getter name for a CMR property.
+ *
+ * @param propertyName
+ * The name of the CMR property.
+ *
+ * @return The string name of the getter method for the
+ * property.
+ */
private static String getterName(String propertyName) {
return "get" + propertyName.substring(0, 1).toUpperCase() +
propertyName.substring(1);
}
/**
+ * Get the getter method for this CMP field. This
+ * will be either get<Name> or is<Name> depending on
+ * what abstract method is defined on the base bean
+ * class.
+ *
+ * @param propertyName The name of the CMP field.
+ *
+ * @return The name to be used for generating this method.
+ */
+ private Method getterMethod(String propertyName) {
+ String getterName = "get" + propertyName.substring(0, 1).toUpperCase()
+ propertyName.substring(1);
+ try {
+ // check to see if we have the getter as an abstract class. This
might be an "is" method.
+ Method method = beanClass.getMethod(getterName, new Class[0]);
+ if (Modifier.isAbstract(method.getModifiers())) {
+ // this is a getter
+ return method;
+ }
+ } catch (NoSuchMethodException e) {
+ }
+
+ // we're just going to assume this is the valid name. Other
validation should already have been
+ // performed prior to this.
+ getterName = "is" + propertyName.substring(0, 1).toUpperCase() +
propertyName.substring(1);
+ try {
+ // check to see if we have the getter as an abstract class. This
might be an "is" method.
+ Method method = beanClass.getMethod(getterName, new Class[0]);
+ if (Modifier.isAbstract(method.getModifiers())) {
+ // this is a getter
+ return method;
+ }
+ } catch (NoSuchMethodException e) {
+ }
+ return null;
+ }
+
+
+ /**
* Generate a concrete setter field for a CMP field.
* At this point, we're just generating a simple
* accessor for the field, given the type. The
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/CmpField.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/CmpField.java?rev=674853&r1=674852&r2=674853&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/CmpField.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/CmpField.java
Tue Jul 8 08:13:24 2008
@@ -17,15 +17,19 @@
*/
package org.apache.openejb.core.cmp.cmp2;
+import java.lang.reflect.Method;
+
import org.objectweb.asm.Type;
public class CmpField {
private final String name;
private final Type type;
+ private final Method getter;
- public CmpField(String name, Type type) {
+ public CmpField(String name, Type type, Method getter) {
this.name = name;
this.type = type;
+ this.getter = getter;
}
public String getName() {
@@ -39,4 +43,8 @@
public String getDescriptor() {
return type.getDescriptor();
}
+
+ public Method getGetterMethod() {
+ return getter;
+ }
}
Modified:
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/PostCreateGenerator.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/PostCreateGenerator.java?rev=674853&r1=674852&r2=674853&view=diff
==============================================================================
---
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/PostCreateGenerator.java
(original)
+++
openejb/trunk/openejb3/container/openejb-core/src/main/java/org/apache/openejb/core/cmp/cmp2/PostCreateGenerator.java
Tue Jul 8 08:13:24 2008
@@ -26,7 +26,8 @@
/**
* Generate concrete implementations of EjbPostCreatexxx
- * methods for a bean class.
+ * methods for a bean class. This is implemented in a separate
+ * class because it is used by both the CMP1 and CMP2 generators.
* @version $Rev$ $Date$
*/
public class PostCreateGenerator {