/*
* Copyright (c) 2005
* XDoclet Team
* All rights reserved.
*/
package org.xdoclet.plugin.ejb.entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.generama.GeneramaException;
import org.generama.MergeableVelocityTemplateEngine;
import org.generama.QDoxCapableMetadataProvider;
import org.generama.WriterMapper;
import org.xdoclet.plugin.ejb.EjbBeanResolver;
import org.xdoclet.plugin.ejb.EjbConfig;
import org.xdoclet.plugin.ejb.EjbJavaClassBuilder;
import org.xdoclet.plugin.ejb.EjbJavaGeneratingPlugin;
import org.xdoclet.plugin.ejb.EjbRuntime;
import org.xdoclet.plugin.ejb.EjbUtils;
import org.xdoclet.plugin.ejb.Relation;
import org.xdoclet.plugin.ejb.RelationManager;
import org.xdoclet.plugin.ejb.interfaces.LocalInterfacePlugin;
import org.xdoclet.plugin.ejb.interfaces.RemoteInterfacePlugin;
import org.xdoclet.plugin.ejb.qtags.EjbValueObjectFieldTag;
import org.xdoclet.plugin.ejb.qtags.EjbValueObjectTag;
import org.xdoclet.plugin.ejb.qtags.TagLibrary;
import org.xdoclet.plugin.ejb.util.DuplicatedJavaClass;
import org.xdoclet.plugin.ejb.util.QDoxCachedMetadataProvider;
import com.thoughtworks.qdox.model.BeanProperty;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;
import com.thoughtworks.qdox.model.Type;
/**
* Plugin for ValueObjects generation for Entity EJBs.
*
* @author Diogo Quintela
*/
public class ValueObjectPlugin extends EjbJavaGeneratingPlugin implements EjbJavaClassBuilder {
public static final Type SET_TYPE = new Type(Set.class.getName());
public static final Type COLLECTION_TYPE = new Type(Collection.class.getName());
private static final Map immutableKnownTypes;
static {
Map typeMap = new HashMap();
typeMap.put(Boolean.class.getName(), Boolean.TRUE);
typeMap.put(Boolean.TYPE.getName(), Boolean.TRUE);
typeMap.put(Byte.class.getName(), Boolean.TRUE);
typeMap.put(Byte.TYPE.getName(), Boolean.TRUE);
typeMap.put(Character.class.getName(), Boolean.TRUE);
typeMap.put(Character.TYPE.getName(), Boolean.TRUE);
typeMap.put(Short.class.getName(), Boolean.TRUE);
typeMap.put(Short.TYPE.getName(), Boolean.TRUE);
typeMap.put(Integer.class.getName(), Boolean.TRUE);
typeMap.put(Integer.TYPE.getName(), Boolean.TRUE);
typeMap.put(Float.class.getName(), Boolean.TRUE);
typeMap.put(Float.TYPE.getName(), Boolean.TRUE);
typeMap.put(Long.class.getName(), Boolean.TRUE);
typeMap.put(Long.TYPE.getName(), Boolean.TRUE);
typeMap.put(Double.class.getName(), Boolean.TRUE);
typeMap.put(Double.TYPE.getName(), Boolean.TRUE);
typeMap.put(String.class.getName(), Boolean.TRUE);
immutableKnownTypes = Collections.unmodifiableMap(typeMap);
}
/**
* Resolver of beans by name
*/
private EjbBeanResolver beanResolver;
/**
* Relation manager
*/
private RelationManager relationManager;
/** Cache for value object resolver */
private Map metaVoCache = new HashMap();
public ValueObjectPlugin(MergeableVelocityTemplateEngine templateEngine,
WriterMapper writerMapper, EjbConfig config)
throws ClassNotFoundException {
super(templateEngine, writerMapper,
new EjbConfig(
new QDoxValueObjectExpanderFilterMetadataProvider(
config.getMetadataProvider()), writerMapper)
);
// Set the plugin for callback reference, as QDoxValueObjectExpanderFilterMetadataProvider must be static
getValueObjectMetadataProvider().setPlugin(this);
// EjbRuntime.setPlugin(this);
setPackageregex("beans");
setPackagereplace("util");
super.setFileregex(config.getEjbReplaceRegex());
setFilereplace("ValueObject");
super.setMultioutput(true);
//try {
// ((QDoxValueObjectExpanderFilterMetadataProvider) getMetadataProvider()).getMetadata();
// System.out.println("=============================");
// System.out.println("ORIGINAL");
// System.out.println("=============================");
// System.out.println(ejbUtils.createRelationManager(
// ((QDoxValueObjectExpanderFilterMetadataProvider) getMetadataProvider()).getOriginalMetadata()));
// System.out.println("=============================");
// System.out.println("TAMPERED");
// System.out.println("=============================");
// System.out.println(ejbUtils.createRelationManager(
// ((QDoxValueObjectExpanderFilterMetadataProvider) getMetadataProvider()).getTamperedMetadata()));
//} catch (Throwable t) {
// t.printStackTrace(System.out);
//}
}
/**
* JavaClass that describes the generated artifacts
*
* @return The generated artifacts JavaClass otherwise null
*/
public JavaClass[] buildFor(JavaClass metadata_) {
JavaClass[] expandedClasses = expandClass(metadata_);
List retLst = new ArrayList();
for (int i = 0; i < expandedClasses.length; i++) {
JavaClass metadata = expandedClasses[i];
if (!shouldGenerate(metadata)) {
continue;
}
ValueObjectMetadata metaVo = getMetaVO(metadata);
BeanProperty pkProperty = metaVo.getPkProperty();
JavaField field;
JavaMethod method;
JavaClass retVal = createDynamicJavaClass(getDestinationClassname(metadata), getDestinationPackage(metadata), null, getMetadataProvider());
String[] modifiers = new String[isAbstract(metadata) ? 2 : 1];
modifiers[0] = "public";
if (isAbstract(metadata)) {
modifiers[1] = "abstract";
}
retVal.setModifiers(modifiers);
retVal.setSuperClass(new Type(getExtends(metadata)));
String[] implementz = getImplements(metadata);
Type[] implementzTypes = new Type[implementz.length];
for (int j = 0; j < implementz.length; j++) {
implementzTypes[j] = new Type(implementz[j]);
}
retVal.setImplementz(implementzTypes);
if (getEjbUtils().isUseSoftLocking(metadata)) {
field = new JavaField(new Type("int"), "_version");
field.setModifiers(new String[] { "private" });
retVal.addField(field);
}
ValueObjectFieldMetadata[] nonPkFields = metaVo.getNonPkFields();
for (int j = 0; j < nonPkFields.length; j++) {
ValueObjectFieldMetadata vField = nonPkFields[j];
field = new JavaField(vField.getProperty().getType(), vField.getProperty().getName());
field.setModifiers(new String[] { "private" });
retVal.addField(field);
field = new JavaField(new Type("boolean"), vField.getProperty().getName()+"HasBeenSet");
field.setModifiers(new String[] { "private" });
retVal.addField(field);
}
ValueObjectFieldMetadata[] pkFields = metaVo.getPkFields();
for (int j = 0; j < pkFields.length; j++) {
ValueObjectFieldMetadata vField = pkFields[j];
field = new JavaField(vField.getProperty().getType(), vField.getProperty().getName());
field.setModifiers(new String[] { "private" });
retVal.addField(field);
field = new JavaField(new Type("boolean"), vField.getProperty().getName()+"HasBeenSet");
field.setModifiers(new String[] { "private" });
retVal.addField(field);
}
ValueObjectRelationMetadata[] nonCollectionRel = metaVo.getNonCollectionRelations();
for (int j = 0; j < nonCollectionRel.length; j++) {
ValueObjectRelationMetadata vRelation = nonCollectionRel[j];
field = new JavaField(vRelation.getProperty().getType(), vRelation.getProperty().getName());
field.setModifiers(new String[] { "private" });
retVal.addField(field);
field = new JavaField(new Type("boolean"), vRelation.getProperty().getName()+"HasBeenSet");
field.setModifiers(new String[] { "private" });
retVal.addField(field);
}
ValueObjectRelationMetadata[] collectionRel = metaVo.getCollectionRelations();
for (int j = 0; j < collectionRel.length; j++) {
ValueObjectRelationMetadata vRelation = collectionRel[j];
field = new JavaField(vRelation.getProperty().getType(), vRelation.getProperty().getName());
field.setModifiers(new String[] { "private" });
retVal.addField(field);
}
method = new JavaMethod(getDestinationClassname(metadata));
method.setConstructor(true);
method.setModifiers(new String[] { "public" });
retVal.addMethod(method);
if (metaVo.isGeneratePKConstructor() && metaVo.hasPk()) {
if(!isEmpty(nonPkFields) || !metaVo.isSimplePkProperty()) {
method = new JavaMethod(getDestinationClassname(metadata));
method.setConstructor(true);
method.setModifiers(new String[] { "public" });
method.setParameters(new JavaParameter[]{new JavaParameter(pkProperty.getType(), pkProperty.getName())});
retVal.addMethod(method);
}
if(!isEmpty(nonPkFields) && !metaVo.isSimplePkProperty()) {
method = new JavaMethod(getDestinationClassname(metadata));
method.setConstructor(true);
method.setModifiers(new String[] { "public" });
JavaParameter[] params = new JavaParameter[nonPkFields.length + 1];
params[0] = new JavaParameter(pkProperty.getType(), pkProperty.getName());
for (int j = 0; j < nonPkFields.length; j++) {
ValueObjectFieldMetadata nonPkField = nonPkFields[j];
params[j+1] = new JavaParameter(nonPkField.getProperty().getType(), nonPkField.getProperty().getName());
}
method.setParameters(params);
retVal.addMethod(method);
}
}
ValueObjectFieldMetadata[] fields = metaVo.getFields();
if (!isEmpty(fields)) {
method = new JavaMethod(getDestinationClassname(metadata));
method.setConstructor(true);
method.setModifiers(new String[] { "public" });
JavaParameter[] params = new JavaParameter[fields.length];
for (int j = 0; j < fields.length; j++) {
ValueObjectFieldMetadata vField = fields[j];
params[j] = new JavaParameter(vField.getProperty().getType(), vField.getProperty().getName());
}
method.setParameters(params);
retVal.addMethod(method);
}
if (metaVo.hasPk() && !metaVo.isSimplePkProperty()) {
method = new JavaMethod(pkProperty.getType(), pkProperty.getAccessor().getName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod(pkProperty.getMutator().getName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
method.setParameters(new JavaParameter[]{new JavaParameter(pkProperty.getType(), pkProperty.getName())});
retVal.addMethod(method);
}
if (getEjbUtils().isUseSoftLocking(metadata)) {
method = new JavaMethod(new Type("int"), "getVersion");
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod("setVersion");
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
method.setParameters(new JavaParameter[]{new JavaParameter(new Type("int"), "version")});
retVal.addMethod(method);
}
for (int j = 0; (fields != null) && (j < fields.length); j++) {
ValueObjectFieldMetadata vField = fields[j];
method = new JavaMethod(vField.getProperty().getType(), vField.getProperty().getAccessor().getName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod(vField.getProperty().getMutator().getName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
method.setParameters(new JavaParameter[]{new JavaParameter(vField.getProperty().getType(), vField.getProperty().getName())});
retVal.addMethod(method);
method = new JavaMethod(new Type("boolean"), vField.getProperty().getName()+"HasBeenSet");
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
}
for (int k = 0; k < nonCollectionRel.length; k++) {
ValueObjectRelationMetadata nonColRel = nonCollectionRel[k];
method = new JavaMethod(nonColRel.getProperty().getType(), nonColRel.getProperty().getAccessor().getName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod(nonColRel.getProperty().getMutator().getName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
method.setParameters(new JavaParameter[]{new JavaParameter(nonColRel.getProperty().getType(), nonColRel.getProperty().getName())});
retVal.addMethod(method);
method = new JavaMethod(new Type("boolean"), nonColRel.getProperty().getName()+"HasBeenSet");
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
}
for (int k = 0; k < collectionRel.length; k++) {
ValueObjectRelationMetadata colRel = collectionRel[k];
field = new JavaField(colRel.getProperty().getType(), "added" + colRel.getProperty().getName());
field.setModifiers(new String[]{"protected"});
retVal.addField(field);
field = new JavaField(colRel.getProperty().getType(), "onceAdded" + colRel.getProperty().getName());
field.setModifiers(new String[]{"protected"});
retVal.addField(field);
field = new JavaField(colRel.getProperty().getType(), "removed" + colRel.getProperty().getName());
field.setModifiers(new String[]{"protected"});
retVal.addField(field);
field = new JavaField(colRel.getProperty().getType(), "updated" + colRel.getProperty().getName());
field.setModifiers(new String[]{"protected"});
retVal.addField(field);
method = new JavaMethod(colRel.getProperty().getType(), "getAdded" + colRel.getProperty().getName());
method.setModifiers(new String[]{"public"});
retVal.addMethod(method);
method = new JavaMethod(colRel.getProperty().getType(), "getOnceAdded" + colRel.getProperty().getName());
method.setModifiers(new String[]{"public"});
retVal.addMethod(method);
method = new JavaMethod(colRel.getProperty().getType(), "getRemoved" + colRel.getProperty().getName());
method.setModifiers(new String[]{"public"});
retVal.addMethod(method);
method = new JavaMethod(colRel.getProperty().getType(), "getUpdated" + colRel.getProperty().getName());
method.setModifiers(new String[]{"public"});
retVal.addMethod(method);
method = new JavaMethod(colRel.getProperty().getType(), colRel.getProperty().getAccessor().getName()+"Collection");
method.setModifiers(new String[]{"public"});
retVal.addMethod(method);
method = new JavaMethod(new Type(colRel.getAggregate(),1), colRel.getProperty().getAccessor().getName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod(colRel.getProperty().getMutator().getName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
method.setParameters(new JavaParameter[]{new JavaParameter(new Type(colRel.getAggregate(),1), colRel.getProperty().getName())});
retVal.addMethod(method);
method = new JavaMethod("clear"+colRel.getProperty().getName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod("add"+colRel.getAggregateName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
method.setParameters(new JavaParameter[]{new JavaParameter(new Type(colRel.getAggregate()), "other")});
retVal.addMethod(method);
method = new JavaMethod("remove"+colRel.getAggregateName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
method.setParameters(new JavaParameter[]{new JavaParameter(new Type(colRel.getAggregate()), "other")});
retVal.addMethod(method);
method = new JavaMethod("update"+colRel.getAggregateName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
method.setParameters(new JavaParameter[]{new JavaParameter(new Type(colRel.getAggregate()), "other")});
retVal.addMethod(method);
method = new JavaMethod("clean"+colRel.getAggregateName());
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod("copy"+colRel.getProperty().getName()+"From");
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
method.setParameters(new JavaParameter[]{new JavaParameter(new Type(getDestinationFullyQualifiedClassName(metadata)), "other")});
retVal.addMethod(method);
}
method = new JavaMethod(new Type("java.lang.String"), "toString");
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod(new Type("boolean"), "hasIdentity");
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "protected";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod(new Type("boolean"), "equals");
method.setModifiers(new String[]{"public"});
method.setParameters(new JavaParameter[]{new JavaParameter(new Type("java.lang.Object"), "other")});
retVal.addMethod(method);
if (metaVo.isStrictOrdering()) {
method = new JavaMethod(new Type("int"), "compareTo");
method.setModifiers(new String[]{"public"});
method.setParameters(new JavaParameter[]{new JavaParameter(new Type("java.lang.Object"), "other")});
retVal.addMethod(method);
}
method = new JavaMethod(new Type("java.lang.Object"), "clone");
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
method = new JavaMethod(new Type("int"), "hashCode");
modifiers = new String[metaVo.isFullSynchronization() ? 2 : 1];
modifiers[0] = "public";
if (metaVo.isFullSynchronization()) {
modifiers[1] = "synchronized";
}
method.setModifiers(modifiers);
retVal.addMethod(method);
JavaClass innerClass = createDynamicJavaClass("ReadOnly" + getDestinationClassname(metadata), getDestinationPackage(metadata), null, getMetadataProvider());
innerClass.setModifiers(new String[]{"final","private"});
retVal.addClass(innerClass);
method = new JavaMethod(innerClass.asType(), "getReadOnly"+getDestinationClassname(metadata));
method.setModifiers(new String[]{"public"});
retVal.addMethod(method);
method = new JavaMethod(new Type("java.util.Collection"), "wrapCollection");
method.setModifiers(new String[]{"private", "static"});
method.setParameters(new JavaParameter[]{new JavaParameter(new Type("java.util.Collection"), "input")});
retVal.addMethod(method);
method = new JavaMethod(new Type("java.util.Set"), "wrapCollection");
method.setModifiers(new String[]{"private", "static"});
method.setParameters(new JavaParameter[]{new JavaParameter(new Type("java.util.Set"), "input")});
retVal.addMethod(method);
method = new JavaMethod(new Type("java.util.Collection"), "wrapReadOnly");
method.setModifiers(new String[]{"private", "static"});
method.setParameters(new JavaParameter[]{new JavaParameter(new Type("java.util.Collection"), "input")});
retVal.addMethod(method);
method = new JavaMethod(new Type("java.util.Set"), "wrapReadOnly");
method.setModifiers(new String[]{"private", "static"});
method.setParameters(new JavaParameter[]{new JavaParameter(new Type("java.util.Set"), "input")});
retVal.addMethod(method);
// handle inner class
implementz = getImplements(metadata);
implementzTypes = new Type[implementz.length];
for (int j = 0; j < implementz.length; j++) {
implementzTypes[j] = new Type(implementz[j]);
}
innerClass.setImplementz(implementzTypes);
method = new JavaMethod(retVal.asType(), "underlying");
method.setModifiers(new String[]{"private"});
innerClass.addMethod(method);
for (int j = 0; (fields != null) && (j < fields.length); j++) {
ValueObjectFieldMetadata vField = fields[j];
method = new JavaMethod(vField.getProperty().getType(), vField.getProperty().getAccessor().getName());
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
method = new JavaMethod(new Type("boolean"), vField.getProperty().getName()+"HasBeenSet");
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
}
for (int k = 0; k < nonCollectionRel.length; k++) {
ValueObjectRelationMetadata nonColRel = nonCollectionRel[k];
method = new JavaMethod(nonColRel.getProperty().getType(), nonColRel.getProperty().getAccessor().getName());
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
method = new JavaMethod(new Type("boolean"), nonColRel.getProperty().getName()+"HasBeenSet");
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
}
for (int k = 0; k < collectionRel.length; k++) {
ValueObjectRelationMetadata colRel = collectionRel[k];
method = new JavaMethod(colRel.getProperty().getType(), "getAdded" + colRel.getProperty().getName());
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
method = new JavaMethod(colRel.getProperty().getType(), "getOnceAdded" + colRel.getProperty().getName());
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
method = new JavaMethod(colRel.getProperty().getType(), "getRemoved" + colRel.getProperty().getName());
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
method = new JavaMethod(colRel.getProperty().getType(), "getUpdated" + colRel.getProperty().getName());
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
method = new JavaMethod(colRel.getProperty().getType(), colRel.getProperty().getAccessor().getName()+"Collection");
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
method = new JavaMethod(new Type(colRel.getAggregate(),1), colRel.getProperty().getAccessor().getName());
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
}
method = new JavaMethod(new Type("int"), "hashCode");
method.setModifiers(new String[]{"public"});
innerClass.addMethod(method);
method = new JavaMethod(new Type("boolean"), "equals");
method.setModifiers(new String[]{"public"});
method.setParameters(new JavaParameter[]{new JavaParameter(new Type("java.lang.Object"), "other")});
innerClass.addMethod(method);
if (metaVo.isStrictOrdering()) {
method = new JavaMethod(new Type("int"), "compareTo");
method.setModifiers(new String[]{"public"});
method.setParameters(new JavaParameter[]{new JavaParameter(new Type("java.lang.Object"), "other")});
innerClass.addMethod(method);
}
// add to list
retLst.add(retVal);
}
return (retLst.size() == 0) ? null : (JavaClass[])retLst.toArray(new JavaClass[0]);
}
private QDoxValueObjectExpanderFilterMetadataProvider getValueObjectMetadataProvider() {
QDoxCachedMetadataProvider cached = (QDoxCachedMetadataProvider) getMetadataProvider();
return (QDoxValueObjectExpanderFilterMetadataProvider) cached.getFilteredMetadataProvider();
}
private Collection getOriginalMetadata() {
return getValueObjectMetadataProvider().getOriginalMetadata();
}
// We are ignoring arrays for this, it's handled at .vm level
public boolean isImmutable(Type type) {
return immutableKnownTypes.containsKey(type.getValue());
}
public boolean isCloneable(Type type) {
// JavaMethod cloneMethod = type.getJavaClass().getMethodBySignature("clone", null);
return type.isA(new Type(Cloneable.class.getName())); // && cloneMethod != null && cloneMethod.isPublic();
}
public class ValueObjectRelationMetadata {
private final Log log = LogFactory.getLog(ValueObjectRelationMetadata.class);
private final JavaClass relationEjb;
private final boolean isAggregate;
private final EjbValueObjectFieldTag vTag;
private Type relationCollectionType;
public ValueObjectRelationMetadata(JavaClass relationEjb, Type relationCollectionType, boolean isAggregate,
EjbValueObjectFieldTag vTag) {
this.relationEjb = relationEjb;
this.relationCollectionType = relationCollectionType;
this.isAggregate = isAggregate;
this.vTag = vTag;
}
public BeanProperty getProperty() {
BeanProperty retVal;
String propName;
Type propType;
if (isCollection()) {
propName = getAggregateNamePlural();
propType = getCollectionType();
} else {
propName = getAggregateName();
propType = new Type(getAggregate());
}
retVal = new BeanProperty(propName);
retVal.setType(propType);
JavaMethod getter = new JavaMethod(propType, getGetterName(retVal));
JavaMethod setter = new JavaMethod(propType, getSetterName(retVal));
setter.setParameters(new JavaParameter[] {new JavaParameter(propType, propName)});
retVal.setAccessor(getter);
retVal.setMutator(setter);
return retVal;
}
public boolean isCollection() {
boolean isCollection = false;
isCollection |= (relationCollectionType != null) && relationCollectionType.isA(COLLECTION_TYPE);
isCollection |= (relationCollectionType != null) && relationCollectionType.isA(SET_TYPE);
return isCollection;
}
public Type getCollectionType() {
Type retVal = null;
if (relationCollectionType != null) {
if (relationCollectionType.isA(COLLECTION_TYPE)) {
retVal = COLLECTION_TYPE;
} else if (relationCollectionType.isA(SET_TYPE)) {
retVal = SET_TYPE;
}
}
return retVal;
}
public Type getCollectionTypeImpl() {
String concreteType = vTag.getConcreteType();
if (concreteType == null) {
Type colType = getCollectionType();
if ((colType != null) && relationCollectionType.isA(COLLECTION_TYPE)) {
concreteType = ArrayList.class.getName();
} else if ((colType != null) && relationCollectionType.isA(SET_TYPE)) {
concreteType = HashSet.class.getName();
} else if (log.isErrorEnabled()) {
log.error(EjbUtils.getMessageWithTagLocation(vTag, "Couldn't resolve concrete type for relation"));
}
}
return (concreteType != null) ? new Type(concreteType) : null;
}
public boolean isAggregate() {
return isAggregate;
}
public boolean isCompose() {
return !isAggregate;
}
public String getAggregate() {
String aggName = isAggregate ? "aggregate" : "compose";
return vTag.getNamedParameter(aggName);
}
public String getAggregateName() {
String aggName = isAggregate ? "aggregate" : "compose";
return vTag.getNamedParameter(aggName + "-name");
}
public String getAggregateNamePlural() {
String aggName = isAggregate ? "aggregate" : "compose";
String aggregateNamePlural = vTag.getNamedParameter(aggName + "s-name");
if (aggregateNamePlural == null) {
String aggregateName = getAggregateName();
if (aggregateName != null) {
log.debug("Agregate's s-name not found. Appending 's' aggregate name");
aggregateNamePlural = aggregateName + "s";
}
}
return aggregateNamePlural;
}
public String toString() {
StringBuffer retBuf = new StringBuffer();
retBuf.append("[ValueObjectRelationMetadata: ");
retBuf.append("relationEjb=" + ((relationEjb != null) ? relationEjb.getFullyQualifiedName() : null));
retBuf.append(", isAggregate=" + isAggregate);
retBuf.append(", vTag=" + EjbUtils.tagToString(vTag));
retBuf.append(", aggregate=" + getAggregate());
retBuf.append(", aggregateName=" + getAggregateName());
retBuf.append(", aggregateNamePlural=" + getAggregateNamePlural());
retBuf.append("]");
return retBuf.toString();
}
}
public class ValueObjectFieldMetadata {
private Log log = LogFactory.getLog(ValueObjectFieldMetadata.class);
private final BeanProperty property;
private final int metaFlags;
public ValueObjectFieldMetadata(Type propertyType, String propertyName, int metaFlags) {
this.metaFlags = metaFlags;
this.property = new BeanProperty(propertyName);
this.property.setType(propertyType);
JavaMethod getter = new JavaMethod(propertyType, getGetterName(this.property));
JavaMethod setter = new JavaMethod(propertyType, getSetterName(this.property));
setter.setParameters(new JavaParameter[] {new JavaParameter(propertyType, propertyName)});
this.property.setAccessor(getter);
this.property.setMutator(setter);
}
public BeanProperty getProperty() {
return this.property;
}
public boolean isPrimaryKeyField() {
return EjbUtils.hasFlag(metaFlags, EjbUtils.METADATA_METHOD_PRIMARY_KEY_FIELD);
}
}
public class ValueObjectMetadata {
private Log log = LogFactory.getLog(ValueObjectMetadata.class);
private Collection fieldLst;
private Collection relationLst;
// private boolean updatable;
private final PkMetadata pkMetadata;
private final JavaClass javaClass;
private final EjbValueObjectTag valueTag;
public ValueObjectMetadata(JavaClass javaClass, EjbValueObjectTag valueTag, PkMetadata pkMetadata) {
this.javaClass = javaClass;
this.fieldLst = new ArrayList();
this.relationLst = new ArrayList();
this.valueTag = valueTag;
this.pkMetadata = pkMetadata;
}
public EjbValueObjectTag getValueTag() {
return valueTag;
}
public boolean isStrictOrdering() {
return "strict".equals(valueTag.getOrdering());
}
public boolean isFullSynchronization() {
return "full".equals(valueTag.getSynchronization());
}
public boolean isPartialSynchronization() {
return "partial".equals(valueTag.getSynchronization());
}
public boolean isNoSynchronization() {
return "none".equals(valueTag.getSynchronization());
}
public boolean isGeneratePKConstructor() {
return valueTag.isGeneratePkConstructor();
}
public boolean isFullClone() {
return valueTag.isFullClone();
}
// public void setUpdatable(boolean updatable) {
// this.updatable = updatable;
// }
//
// public boolean isUpdatable() {
// return this.updatable;
// }
public ValueObjectRelationMetadata[] getRelations() {
return (ValueObjectRelationMetadata[]) relationLst.toArray(new ValueObjectRelationMetadata[0]);
}
public ValueObjectRelationMetadata[] getCollectionRelations() {
Collection relations = CollectionUtils.select(relationLst,
new Predicate() {
public boolean evaluate(Object arg0) {
ValueObjectRelationMetadata relation = (ValueObjectRelationMetadata) arg0;
return relation.isCollection();
}
});
return (ValueObjectRelationMetadata[]) relations.toArray(new ValueObjectRelationMetadata[0]);
}
public ValueObjectRelationMetadata[] getNonCollectionRelations() {
Collection relations = CollectionUtils.select(relationLst,
new Predicate() {
public boolean evaluate(Object arg0) {
ValueObjectRelationMetadata relation = (ValueObjectRelationMetadata) arg0;
return !relation.isCollection();
}
});
return (ValueObjectRelationMetadata[]) relations.toArray(new ValueObjectRelationMetadata[0]);
}
public ValueObjectFieldMetadata[] getFields() {
return (ValueObjectFieldMetadata[]) fieldLst.toArray(new ValueObjectFieldMetadata[0]);
}
public ValueObjectFieldMetadata[] getPkFields() {
Collection fields = CollectionUtils.select(fieldLst,
new Predicate() {
public boolean evaluate(Object arg0) {
ValueObjectFieldMetadata field = (ValueObjectFieldMetadata) arg0;
return field.isPrimaryKeyField();
}
});
return (ValueObjectFieldMetadata[]) fields.toArray(new ValueObjectFieldMetadata[0]);
}
public ValueObjectFieldMetadata[] getNonPkFields() {
Collection fields = CollectionUtils.select(fieldLst,
new Predicate() {
public boolean evaluate(Object arg0) {
ValueObjectFieldMetadata field = (ValueObjectFieldMetadata) arg0;
return !field.isPrimaryKeyField();
}
});
return (ValueObjectFieldMetadata[]) fields.toArray(new ValueObjectFieldMetadata[0]);
}
public void addField(ValueObjectFieldMetadata field) {
fieldLst.add(field);
}
public void addRelation(ValueObjectRelationMetadata relation) {
relationLst.add(relation);
}
public boolean isSimplePkProperty() {
return pkMetadata.isSimpleProperty();
}
public boolean hasPk() {
return (getPkProperty() != null);
}
public BeanProperty getPkProperty() {
Type pkType = null;
String propName = null;
if (!pkMetadata.isSimpleProperty()) {
if (pkMetadata.isEmptyWithParent()) {
PkMetadata pkMeta = pkMetadata.getParent();
pkType = pkMeta.getType().getType();
propName = "primaryKey";
} else {
if (log.isErrorEnabled()) {
log.error("Cannot resolve primary key class name (" + javaClass.getFullyQualifiedName() +
"). Have you forgot to set @ejb.bean \"primkey-field\" or @ejb.pk-field ? (" + pkMetadata +
")");
}
}
} else {
BeanProperty singleProp = pkMetadata.getProperties()[0];
pkType = singleProp.getType();
propName = singleProp.getName();
}
BeanProperty prop = null;
if (pkType != null && propName != null) {
prop = new BeanProperty(propName);
prop.setType(pkType);
JavaMethod getter = new JavaMethod(pkType, getGetterName(prop));
JavaMethod setter = new JavaMethod(pkType, getSetterName(prop));
setter.setParameters(new JavaParameter[] {new JavaParameter(pkType, prop.getName())});
prop.setAccessor(getter);
prop.setMutator(setter);
}
return prop;
}
}
private JavaClass findBeanByInterface(Collection metadata, Type type) {
JavaClass retVal = null;
LocalInterfacePlugin localPlugin = EjbRuntime.getLocalInterfacePlugin();
RemoteInterfacePlugin remotePlugin = EjbRuntime.getRemoteInterfacePlugin();
if (log.isDebugEnabled()) {
log.debug("Looking for bean with local|remote interface named " + type);
}
for (Iterator iter = metadata.iterator(); retVal == null && iter.hasNext();) {
JavaClass javaClass = (JavaClass) iter.next();
Type localType = localPlugin.getVirtualType(javaClass).getType();
Type remoteType = remotePlugin.getVirtualType(javaClass).getType();
if (localType.equals(type) || remoteType.equals(type)) {
if (log.isDebugEnabled()) {
log.debug("Match found for " + javaClass.getFullyQualifiedName());
log.debug("Local Interface " + localType);
log.debug("Remote Interface " + remoteType);
}
retVal = javaClass;
}
}
if ((retVal == null) && log.isDebugEnabled()) {
log.debug("bean with local|remote interface named " + type + " wasn't found");
} else if (log.isDebugEnabled()) {
log.debug("bean with local|remote interface named " + type + " found: " + retVal.getFullyQualifiedName());
}
return retVal;
}
public ValueObjectMetadata getMetaVO(JavaClass javaClass) {
ValueObjectMetadata retVal = null;
DocletTag[] valueTags = javaClass.getTagsByName(TagLibrary.EJB_VALUE_OBJECT);
if (valueTags.length > 0 && log.isDebugEnabled()) {
StringBuffer retBuf = new StringBuffer();
retBuf.append("The list of @ejb.value-object for ").append(javaClass.getFullyQualifiedName()).append(" is {");
for (int i = 0; i < valueTags.length; i++) {
if (i > 0) {
retBuf.append(";");
}
retBuf.append(EjbUtils.tagToString(valueTags[i]));
}
retBuf.append("}");
log.debug(retBuf.toString());
}
if (log.isTraceEnabled()) {
log.trace("getMetaVO is working in " + javaClass.getFullyQualifiedName());
}
if (valueTags.length > 0) {
String cacheKey = javaClass.getFullyQualifiedName() + "-" + getDestinationClassname(javaClass);
if (log.isDebugEnabled()) {
log.debug("I'll be using cacheKey='"+cacheKey+"' for VO of "+javaClass.getFullyQualifiedName());
}
if (metaVoCache.containsKey(cacheKey)) {
if (log.isDebugEnabled()) {
log.debug("I found cache entry for cacheKey='"+cacheKey+"'");
}
retVal = (ValueObjectMetadata) metaVoCache.get(cacheKey);
} else {
if (log.isDebugEnabled()) {
log.debug("I DIDN't found cache entry for cacheKey='"+cacheKey+"'");
}
// By the use of MyQDoxFilterMetadataProvider, we are sure that if a ejb.value-object tag exists
// It can only be one (at least in the normal run of this plugin
EjbValueObjectTag valueTag = (EjbValueObjectTag) valueTags[0];
retVal = new ValueObjectMetadata(javaClass, valueTag,
EjbRuntime.getPrimaryKeyClassPlugin().collectPkHierarchy(javaClass));
// Lets start rolling
// retVal.setUpdatable(valueTag.isUpdatable());
// TODO: Are we supporting hierarchaly generated files
// similar to PrimaryKeys ?
JavaMethod[] methods = javaClass.getMethods(true);
JavaMethod method;
for (int i = 0; i < methods.length; i++) {
method = methods[i];
if (log.isTraceEnabled()) {
// log.trace(method.getName() + " = " + method);
log.trace(method.getName() + " seeing if this is a value-object-field");
}
// Obtain extra method flags
int metaFlags = ejbUtils.getMethodMetadata(javaClass, method);
if (EjbUtils.hasFlag(metaFlags, EjbUtils.METADATA_METHOD_PRIMARY_KEY_FIELD) ||
EjbUtils.hasFlag(metaFlags, EjbUtils.METADATA_METHOD_PERSISTENCE_FIELD) ||
EjbUtils.hasFlag(metaFlags, EjbUtils.METADATA_METHOD_RELATION_FIELD)) {
if (log.isDebugEnabled()) {
log.debug(method.getName() +
" is candidate for checking. It's a persistence field, relation field or primary key field");
}
// Por aqui o resto das valida��es e l�gica
boolean isValueObjectField = isSelectedValueObjectField(valueTag.getMatch(), method);
// Primary key field must ALLWAYS be included ! (or then they must be checked if ....)
isValueObjectField = isValueObjectField ||
EjbUtils.hasFlag(metaFlags, EjbUtils.METADATA_METHOD_PRIMARY_KEY_FIELD);
if (isValueObjectField) {
EjbValueObjectFieldTag vTag = findMatchedTag(valueTag.getMatch(), method);
BeanProperty prop = javaClass.getBeanProperty(method.getPropertyName(), true);
if (log.isDebugEnabled()) {
log.debug(method.getName() + " is a value-object-field: matches or is a pk-field.");
}
// XXX: Todo, if we have a relation found by the RelationManager, then we must have
// it's treatment as such, or should be ignored
// Maybe just check if is a EjbUtils.METADATA_METHOD_RELATION_FIELD
Relation relation = getRelationManager().getRelationFor(method, javaClass);
if ((relation != null) ||
((vTag != null) && ((vTag.getAggregate() != null) || (vTag.getCompose() != null)))) {
// This is a value-object relation
// vTag must be non-null, because we need values from it
if ((vTag != null) && ((vTag.getAggregate() != null) ^ (vTag.getCompose() != null))) {
JavaClass relationEjb = null;
Type collectionType = null;
if (relation != null) {
if (!method.equals(relation.getLeftMethod())) {
log.debug(
"Current method doesn't match relations' left method. Reversing relation");
relation = relation.reverse();
if (log.isDebugEnabled()) {
log.debug("Reversed relation is relation=" + relation);
}
}
if (log.isDebugEnabled()) {
log.debug("Using relation information. relation=" + relation);
log.debug("1# Left bean=" +
((relation.getLeftBean() != null)
? relation.getLeftBean().getFullyQualifiedName() : null));
log.debug("1# Rigth bean=" +
((relation.getRightBean() != null)
? relation.getRightBean().getFullyQualifiedName() : null));
}
String relationEjbName = relation.getRightEJBName();
relationEjb = getBeanResolver().findEjbByName(relationEjbName);
collectionType = relation.getLeftMethod().getReturns();
} else {
log.debug("We don't have relation information for this method");
Type returnType = method.getReturns();
Type relationType = null;
if (returnType.isA(COLLECTION_TYPE) || returnType.isA(SET_TYPE)) {
String members = vTag.getMembers();
if (log.isDebugEnabled()) {
log.debug(returnType + ": Is a Set or Collection. Using members='" +
members + "'");
}
if (members == null) {
if (log.isWarnEnabled()) {
log.warn(EjbUtils.getMessageWithTagLocation(vTag,
"members is null. Skipping."));
}
continue;
}
relationType = new Type(members);
collectionType = returnType.isA(COLLECTION_TYPE) ? COLLECTION_TYPE : SET_TYPE;
} else {
if (log.isDebugEnabled()) {
log.debug(returnType + ": Using it to find it's match!");
}
relationType = returnType;
}
relationEjb = findBeanByInterface(getOriginalMetadata(), relationType);
}
if (relationEjb == null) {
log.warn("Couldn't find the related Ejb! Skipping.");
continue;
}
ValueObjectRelationMetadata vObjRelation = new ValueObjectRelationMetadata(relationEjb,
collectionType, (vTag.getAggregate() != null), vTag);
if (log.isDebugEnabled()) {
log.debug("Relation is " + vObjRelation);
}
if (vObjRelation.getAggregateName() == null) {
String aggName = vObjRelation.isAggregate() ? "aggregate" : "compose";
if (log.isWarnEnabled()) {
log.warn(EjbUtils.getMessageWithTagLocation(vTag,
aggName + "-name can't be null. Ignoring."));
}
// Ignore field
continue;
}
// add it
retVal.addRelation(vObjRelation);
} else {
// It can only be an aggregate or a composition. Not both!
if (vTag != null && log.isWarnEnabled()) {
log.warn(EjbUtils.getMessageWithTagLocation(vTag,
"Can't be an aggregate and a composition simultaneous! Skipping."));
}
// Skip to next method
}
} else {
// Simple value-object property
ValueObjectFieldMetadata vObjField = new ValueObjectFieldMetadata(prop.getType(),
prop.getName(), metaFlags);
retVal.addField(vObjField);
}
}
}
}
if (log.isDebugEnabled()) {
log.debug("I am setting a cache entry for cacheKey='"+cacheKey+"'.");
}
metaVoCache.put(cacheKey, retVal);
}
}
return retVal;
}
protected String getPatternBasedUnqualifiedName(JavaClass javaClass) {
EjbValueObjectTag valueObjectTag = (EjbValueObjectTag) javaClass.getTagByName(TagLibrary.EJB_VALUE_OBJECT);
return ejbUtils.expandPattern(getPattern(valueObjectTag), valueObjectTag.getName_());
}
private String getPattern(EjbValueObjectTag valueTag) {
return (valueTag.getPattern() != null) ? valueTag.getPattern() : "{0}" + filereplace;
}
/**
* Does this method matches as a property for the value object ?
* @param match The group match ('null'/'*' for any)
* @param method The method
* @return true, if it matches, false, otherwise
*/
private boolean isSelectedValueObjectField(String match, JavaMethod method) {
// A blind match with 'null' is equals to a match with '*'
if (null == match) {
match = "*";
}
// The method must be a property accessor
if (!method.isPropertyAccessor()) {
if (log.isDebugEnabled()) {
log.debug(method.getName() +
" is a not a value-object-field because method is not a property-accessor");
}
return false;
}
// It's a value object field if we use a blind match
if ("*".equals(match)) {
if (log.isDebugEnabled()) {
log.debug(method.getName() + " is a value-object-field because we used a blind match '" + match + "'");
}
return true;
}
// We aren't using a blind match
// Let's search for match tags
if (findMatchedTag(match, method) != null) {
// If we found a match, then it's a value-object-field
return true;
}
if (log.isDebugEnabled()) {
log.debug(method.getName() + " doesn't have any compatible match. Searching for match '" + match + "'");
}
return false;
}
private EjbValueObjectFieldTag findMatchedTag(String match, JavaMethod method) {
// A blind match with 'null' is equals to a match with '*'
if (null == match) {
match = "*";
}
DocletTag[] tags = method.getTagsByName(TagLibrary.EJB_VALUE_OBJECT_FIELD);
// Remote duplicate @ejb.value-object-match tags by 'match'
// It will help warning duplicates
Map matchValues = new HashMap();
for (int i = 0; i < tags.length; i++) {
EjbValueObjectFieldTag valueMethodMatchTag = (EjbValueObjectFieldTag) tags[i];
String methodMatch = valueMethodMatchTag.getMatch();
if (matchValues.containsKey(methodMatch)) {
EjbValueObjectFieldTag savedTag = (EjbValueObjectFieldTag) matchValues.get(methodMatch);
if (log.isWarnEnabled()) {
log.warn(EjbUtils.tagToString(valueMethodMatchTag) +
" is being ignored because there is already another tag for same match " +
EjbUtils.tagToString(savedTag));
}
} else {
matchValues.put(methodMatch, valueMethodMatchTag);
}
}
// Get matched @ejb.value-object-field tag
EjbValueObjectFieldTag savedTag = (EjbValueObjectFieldTag) matchValues.get(match);
// If there wasn't a tag for that match, search for one that matches all value objects
if (savedTag == null) {
savedTag = (EjbValueObjectFieldTag) matchValues.get("*");
}
return savedTag;
}
protected static JavaClass[] expandClass(JavaClass javaClass) {
List retLst = new ArrayList();
DocletTag[] valueTags = javaClass.getTagsByName(TagLibrary.EJB_VALUE_OBJECT);
int countTags;
if ((countTags = valueTags.length) > 0) {
for (int i = 0; i < countTags; i++) {
JavaClass newClass = new DuplicatedJavaClass(javaClass);
DocletTag[] tags = newClass.getTags();
List newTags = new ArrayList();
int tagIdx = 0;
for (int j = 0; j < tags.length; j++) {
DocletTag tag = tags[j];
if (TagLibrary.EJB_VALUE_OBJECT.equals(tag.getName())) {
if (tagIdx++ == i) {
newTags.add(tag);
}
} else {
newTags.add(tag);
}
}
// Set class tags
newClass.setTags(newTags);
// -----------------------------------------------------------------------
// We'll validate at 'QDoxValueObjectExpanderFilterMetadataProvider' if we
// have overlapping value objects
// -----------------------------------------------------------------------
// Add it to return list
retLst.add(newClass);
}
} else {
// Add it to return list
retLst.add(javaClass);
}
return (JavaClass[]) retLst.toArray(new JavaClass[0]);
}
/**
* Don't let fileregex be changed
*/
public void setFileregex(String fileregex) {
throw new RuntimeException("Can't set fileregex for plugin. Try setting it in " + EjbConfig.class.getName());
}
public boolean shouldGenerate(Object metadata) {
JavaClass javaClass = (JavaClass) metadata;
boolean generate = ejbUtils.shouldGenerate(javaClass);
generate = generate && ejbUtils.isEntityBean(javaClass);
generate = generate && (getMetaVO(javaClass) != null);
if (generate) generate = isDestinationDirty(javaClass);
if (generate && verbose) System.out.println(
"Generating Value Object for " + javaClass.getName());
return generate;
}
public boolean isAbstract(JavaClass javaClass) {
ValueObjectMetadata metaVo = getMetaVO(javaClass);
return metaVo.getValueTag().isAbstract();
}
public String getExtends(JavaClass javaClass) {
ValueObjectMetadata metaVo = getMetaVO(javaClass);
String extendz = metaVo.getValueTag().getExtends();
if (extendz == null) {
extendz = Object.class.getName();
}
return extendz;
}
public String[] getImplements(JavaClass javaClass) {
ValueObjectMetadata metaVo = getMetaVO(javaClass);
Collection implementsLst = new ArrayList();
if (metaVo.getValueTag().getImplements() != null) {
implementsLst.addAll(Arrays.asList(metaVo.getValueTag().getImplements()));
}
if (metaVo.isStrictOrdering() && !implementsLst.contains(Comparable.class.getName())) {
implementsLst.add(Comparable.class.getName());
}
if (!implementsLst.contains(Serializable.class.getName())) {
implementsLst.add(Serializable.class.getName());
}
if (!implementsLst.contains(Cloneable.class.getName())) {
implementsLst.add(Cloneable.class.getName());
}
return (String[]) implementsLst.toArray(new String[0]);
}
private static class QDoxValueObjectExpanderFilterMetadataProvider extends QDoxCachedMetadataProvider {
protected final Log log = LogFactory.getLog(QDoxValueObjectExpanderFilterMetadataProvider.class);
private Collection tamperedMetadata;
protected ValueObjectPlugin vObjPlugin;
public QDoxValueObjectExpanderFilterMetadataProvider(QDoxCapableMetadataProvider wrapper) {
super(wrapper);
}
void setPlugin(ValueObjectPlugin vObjPlugin) {
this.vObjPlugin = vObjPlugin;
}
public Collection getMetadata() throws GeneramaException {
if (log.isTraceEnabled()) {
log.trace("getMetadata() called");
}
// For each JavaClass in source metadata, we may need to generate N classes, where N is the number
// of "ejb.value-object" class tags
if (tamperedMetadata == null) {
Collection meta = getOriginalMetadata();
if (meta != null) {
List newMetadata = new ArrayList();
for (Iterator iter = meta.iterator(); iter.hasNext();) {
JavaClass javaClass = (JavaClass) iter.next();
newMetadata.addAll(Arrays.asList(expandClass(javaClass)));
}
// We now have to filter the collection to eliminate duplicate value objects
/*
* A map cointaining a cache of value objects under generation: It will be used for detect when overlapping
* value-objects are trying to be generated
*/
final Map vObjsNames = new HashMap();
tamperedMetadata = CollectionUtils.select(newMetadata,
new Predicate() {
public boolean evaluate(Object arg0) {
JavaClass javaClass = (JavaClass) arg0;
boolean retVal = true;
if (vObjPlugin.shouldGenerate(javaClass)) {
// Let's try to detect if overlapping value-objects are being generated
String vObjectType = vObjPlugin.getVirtualType(javaClass).toString();
if (vObjsNames.containsKey(vObjectType)) {
if (log.isWarnEnabled()) {
log.warn("There is already an value-object generate with same type '" +
vObjectType + "'. Ignoring new one.");
}
retVal = false;
} else {
vObjsNames.put(vObjectType, vObjectType);
}
}
return retVal;
}
});
}
}
return tamperedMetadata;
}
public Collection getOriginalMetadata() {
if (log.isTraceEnabled()) {
log.trace("getOriginalMetadata() called");
}
return super.getMetadata();
}
public String getOriginalFileName(Object meta) {
JavaClass javaClass = (JavaClass) meta;
String retVal = super.getOriginalFileName(meta);
if (log.isTraceEnabled()) {
log.trace("getOriginalFileName() javaClass=" + javaClass.getFullyQualifiedName() + " ==> " + retVal);
}
return retVal;
}
public String getOriginalPackageName(Object meta) {
JavaClass javaClass = (JavaClass) meta;
String retVal;
retVal = super.getOriginalPackageName(meta);
if (log.isTraceEnabled()) {
log.trace("getOriginalPackageName() javaClass=" + javaClass.getFullyQualifiedName() + " ==> " + retVal);
}
return retVal;
}
}
/**
* Returns the beanResolver, lazily loaded to allow all plugins to register
* their tags before the beanResolver is created for the first time.
*/
public final EjbBeanResolver getBeanResolver() {
if (beanResolver == null) {
beanResolver = ejbUtils.createEjbBeanResolver(getOriginalMetadata());
}
return beanResolver;
}
/**
* Returns the relationManager, lazily loaded to allow all plugins to register
* their tags before the relationManager is created for the first time.
*/
public final RelationManager getRelationManager() {
if (relationManager == null) {
relationManager = ejbUtils.createRelationManager(getOriginalMetadata());
}
return relationManager;
}
}