0001: /**
0002: * Copyright (C) 2001-2005 France Telecom R&D
0003: *
0004: * This library is free software; you can redistribute it and/or
0005: * modify it under the terms of the GNU Lesser General Public
0006: * License as published by the Free Software Foundation; either
0007: * version 2 of the License, or (at your option) any later version.
0008: *
0009: * This library is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012: * Lesser General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU Lesser General Public
0015: * License along with this library; if not, write to the Free Software
0016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0017: */package org.objectweb.speedo.generation.parser.ejb;
0018:
0019: import java.io.Serializable;
0020: import java.lang.annotation.Annotation;
0021: import java.lang.reflect.Field;
0022: import java.lang.reflect.Member;
0023: import java.lang.reflect.Method;
0024: import java.lang.reflect.Modifier;
0025: import java.lang.reflect.ParameterizedType;
0026: import java.net.MalformedURLException;
0027: import java.net.URL;
0028: import java.net.URLClassLoader;
0029: import java.sql.Timestamp;
0030: import java.util.ArrayList;
0031: import java.util.Collection;
0032: import java.util.HashMap;
0033: import java.util.Iterator;
0034: import java.util.List;
0035: import java.util.Map;
0036: import java.util.Set;
0037:
0038: import org.objectweb.asm.Type;
0039: import org.objectweb.speedo.api.SpeedoException;
0040: import org.objectweb.speedo.api.SpeedoProperties;
0041: import org.objectweb.speedo.generation.api.SpeedoXMLError;
0042: import org.objectweb.speedo.generation.lib.AbstractGeneratorComponent;
0043: import org.objectweb.speedo.lib.Personality;
0044: import org.objectweb.speedo.locale.LocaleHelper;
0045: import org.objectweb.speedo.metadata.SpeedoCallback;
0046: import org.objectweb.speedo.metadata.SpeedoClass;
0047: import org.objectweb.speedo.metadata.SpeedoCollection;
0048: import org.objectweb.speedo.metadata.SpeedoColumn;
0049: import org.objectweb.speedo.metadata.SpeedoDiscriminator;
0050: import org.objectweb.speedo.metadata.SpeedoField;
0051: import org.objectweb.speedo.metadata.SpeedoIdentity;
0052: import org.objectweb.speedo.metadata.SpeedoInheritance;
0053: import org.objectweb.speedo.metadata.SpeedoInheritedField;
0054: import org.objectweb.speedo.metadata.SpeedoJoin;
0055: import org.objectweb.speedo.metadata.SpeedoJoinColumn;
0056: import org.objectweb.speedo.metadata.SpeedoMap;
0057: import org.objectweb.speedo.metadata.SpeedoNoFieldColumn;
0058: import org.objectweb.speedo.metadata.SpeedoNullValue;
0059: import org.objectweb.speedo.metadata.SpeedoPackage;
0060: import org.objectweb.speedo.metadata.SpeedoTable;
0061: import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
0062: import org.objectweb.speedo.mim.api.HomeItf;
0063: import org.objectweb.util.monolog.api.BasicLevel;
0064: import org.objectweb.util.monolog.api.Logger;
0065:
0066: import javax.persistence.AttributeOverride;
0067: import javax.persistence.AttributeOverrides;
0068: import javax.persistence.Basic;
0069: import javax.persistence.CascadeType;
0070: import javax.persistence.Column;
0071: import javax.persistence.DiscriminatorColumn;
0072: import javax.persistence.DiscriminatorValue;
0073: import javax.persistence.Embedded;
0074: import javax.persistence.EmbeddedId;
0075: import javax.persistence.Entity;
0076: import javax.persistence.EntityListeners;
0077: import javax.persistence.FetchType;
0078: import javax.persistence.GeneratedValue;
0079: import javax.persistence.Id;
0080: import javax.persistence.IdClass;
0081: import javax.persistence.Inheritance;
0082: import javax.persistence.JoinColumn;
0083: import javax.persistence.JoinColumns;
0084: import javax.persistence.JoinTable;
0085: import javax.persistence.Lob;
0086: import javax.persistence.ManyToMany;
0087: import javax.persistence.ManyToOne;
0088: import javax.persistence.OneToMany;
0089: import javax.persistence.OneToOne;
0090: import javax.persistence.PrePersist;
0091: import javax.persistence.PostPersist;
0092: import javax.persistence.PreRemove;
0093: import javax.persistence.PostRemove;
0094: import javax.persistence.PreUpdate;
0095: import javax.persistence.PostUpdate;
0096: import javax.persistence.PostLoad;
0097: import javax.persistence.PrimaryKeyJoinColumn;
0098: import javax.persistence.PrimaryKeyJoinColumns;
0099: import javax.persistence.SecondaryTable;
0100: import javax.persistence.SecondaryTables;
0101: import javax.persistence.Table;
0102: import javax.persistence.Transient;
0103: import javax.persistence.UniqueConstraint;
0104: import javax.persistence.Version;
0105:
0106: public class EJBAnnotationParser extends AbstractGeneratorComponent {
0107: public final static String LOGGER_NAME = SpeedoProperties.LOGGER_NAME
0108: + ".generation.parser.ejb";
0109: private static byte[] ba = new byte[0];
0110: private static Byte[] oba = new Byte[0];
0111: private static char[] bc = new char[0];
0112: private static Character[] obc = new Character[0];
0113: /**
0114: * This is the set of primitive types.
0115: */
0116: private static final String[] PRIMITIVETYPES = {
0117: Type.getDescriptor(Boolean.TYPE),
0118: Type.getDescriptor(Byte.TYPE),
0119: Type.getDescriptor(Character.TYPE),
0120: Type.getDescriptor(Short.TYPE),
0121: Type.getDescriptor(Integer.TYPE),
0122: Type.getDescriptor(Long.TYPE) };
0123: /**
0124: * This is the set of supported types for persistent fields.
0125: */
0126: private static final String[] FIELDTYPES = {
0127: Type.getDescriptor(Boolean.TYPE),
0128: Type.getDescriptor(Boolean.class),
0129: Type.getDescriptor(Byte.TYPE),
0130: Type.getDescriptor(Byte.class),
0131: Type.getDescriptor(Character.TYPE),
0132: Type.getDescriptor(Character.class),
0133: Type.getDescriptor(Short.TYPE),
0134: Type.getDescriptor(Short.class),
0135: Type.getDescriptor(Integer.TYPE),
0136: Type.getDescriptor(Integer.class),
0137: Type.getDescriptor(Long.TYPE),
0138: Type.getDescriptor(Long.class),
0139: Type.getDescriptor(Float.TYPE),
0140: Type.getDescriptor(Float.class),
0141: Type.getDescriptor(Double.TYPE),
0142: Type.getDescriptor(Double.class),
0143: Type.getDescriptor(String.class),
0144: Type.getDescriptor(java.util.Date.class),
0145: Type.getDescriptor(java.util.Calendar.class),
0146: Type.getDescriptor(java.sql.Date.class),
0147: Type.getDescriptor(java.sql.Time.class),
0148: Type.getDescriptor(java.sql.Timestamp.class),
0149: Type.getDescriptor(java.math.BigInteger.class),
0150: Type.getDescriptor(java.math.BigDecimal.class),
0151: Type.getDescriptor(ba.getClass()),
0152: Type.getDescriptor(oba.getClass()),
0153: Type.getDescriptor(bc.getClass()),
0154: Type.getDescriptor(obc.getClass()), };
0155: /**
0156: * This is the set of supported types for fields that compose a composite
0157: * primary key.
0158: */
0159: private static final String[] COMPPKFIELDTYPES = {
0160: Type.getDescriptor(Boolean.TYPE),
0161: Type.getDescriptor(Boolean.class),
0162: Type.getDescriptor(Byte.TYPE),
0163: Type.getDescriptor(Byte.class),
0164: Type.getDescriptor(Character.TYPE),
0165: Type.getDescriptor(Character.class),
0166: Type.getDescriptor(Short.TYPE),
0167: Type.getDescriptor(Short.class),
0168: Type.getDescriptor(Integer.TYPE),
0169: Type.getDescriptor(Integer.class),
0170: Type.getDescriptor(Long.TYPE),
0171: Type.getDescriptor(Long.class),
0172: Type.getDescriptor(String.class),
0173: Type.getDescriptor(java.util.Date.class),
0174: Type.getDescriptor(java.sql.Date.class) };
0175: /**
0176: * This is the set of supported types for Version field.
0177: */
0178: private static final String[] VERSIONTYPES = {
0179: Type.getDescriptor(Short.TYPE),
0180: Type.getDescriptor(Short.class),
0181: Type.getDescriptor(Integer.TYPE),
0182: Type.getDescriptor(Integer.class),
0183: Type.getDescriptor(Long.TYPE),
0184: Type.getDescriptor(Long.class),
0185: Type.getDescriptor(Timestamp.class) };
0186: int parsedFiles;
0187: int nbErrors;
0188: LoaderForAnnotAccess annotCL;
0189:
0190: public EJBAnnotationParser() {
0191: super (Personality.EJB);
0192: }
0193:
0194: static String getter2attribute(String getter) {
0195: return Character.toLowerCase(getter.charAt(3))
0196: + getter.substring(4, getter.length());
0197: }
0198:
0199: public String getTitle() {
0200: return LocaleHelper.getEJBParsingRB().getString("ejbannotpar");
0201: }
0202:
0203: /**
0204: * The parser instance is reused at each process method call
0205: */
0206:
0207: // IMPLEMENTATION OF THE GeneratorComponent INTERFACE //
0208: // ---------------------------------------------------//
0209: @Override
0210: public boolean init() throws SpeedoException {
0211: logger = scp.loggerFactory.getLogger(LOGGER_NAME);
0212: logger.log(BasicLevel.DEBUG, "- ejb Annotation Parsing -");
0213: if (scp.xml.isEmpty())
0214: return false;
0215: parsedFiles = 0;
0216: annotCL = new LoaderForAnnotAccess(logger, this .getClass()
0217: .getClassLoader());
0218: annotCL.addDirURL(scp.output);
0219: return true;
0220: }
0221:
0222: /**
0223: * Look for annotated EJB entity classes in the class paths and parse them.
0224: */
0225: @Override
0226: public void process() throws SpeedoException {
0227: logger
0228: .log(BasicLevel.DEBUG, scp.xml.size()
0229: + " files to parse");
0230: for (Object xmldesc : scp.getXmldescriptor().values()) {
0231: logger.log(BasicLevel.INFO, LocaleHelper.getEJBParsingRB()
0232: .getString("ejbpfile")
0233: + ((SpeedoXMLDescriptor) xmldesc).xmlFile);
0234: List<SpeedoClass> parselist = new ArrayList<SpeedoClass>();
0235: for (Object pac : ((SpeedoXMLDescriptor) xmldesc).packages
0236: .values()) {
0237: for (Object cl : ((SpeedoPackage) pac).classes.values()) {
0238: Class clazz;
0239: try {
0240: clazz = (Class) Class.forName(
0241: ((SpeedoClass) cl).getFQName(), false,
0242: annotCL);
0243: } catch (ClassNotFoundException e) {
0244: logger.log(BasicLevel.WARN, LocaleHelper
0245: .getEJBParsingRB().getString(
0246: "ejbclnotfnd")
0247: + ((SpeedoClass) cl).getFQName());
0248: continue;
0249: }
0250: if (!isAnnotatedEntityClass(clazz)) {
0251: logger.log(BasicLevel.WARN, LocaleHelper
0252: .getEJBParsingRB().getString(
0253: "ejbclnotannot")
0254: + ((SpeedoClass) cl).getFQName());
0255: continue;
0256: }
0257: ((SpeedoClass) cl).mainTable = new SpeedoTable();
0258: ((SpeedoClass) cl).mainTable.name = "main_table_to_be_defined_later";
0259: ((SpeedoClass) cl).inheritance = new SpeedoInheritance();
0260: ((SpeedoClass) cl).inheritance.clazz = null;
0261: ((SpeedoClass) cl).inheritance.super ClassName = null;
0262: Class super c = clazz.getSuperclass();
0263: if (super c == null) { // No superclass
0264: parselist.add((SpeedoClass) cl);
0265: continue;
0266: } else {
0267: ((SpeedoClass) cl).inheritance.super ClassName = super c
0268: .getName();
0269: }
0270: // Look for the superclass in the parse list and insert
0271: // new class after (should parse superclass before
0272: // subclass).
0273: int i = -1;
0274: boolean found = false;
0275: for (SpeedoClass sc : parselist) {
0276: if (!found) {
0277: i++;
0278: }
0279: // Is superc an existing class?
0280: if (super c.getName().equals(sc.getFQName())) {
0281: ((SpeedoClass) cl).inheritance.clazz = sc;
0282: found = true;
0283: // i is now fixed for the insertion position
0284: continue;
0285: }
0286: // Is cl a superclass of an existing class?
0287: if (((SpeedoClass) cl).getFQName().equals(
0288: sc.inheritance.super ClassName)) {
0289: sc.inheritance.clazz = sc;
0290: }
0291: }
0292: if (found) {
0293: parselist.add(i + 1, (SpeedoClass) cl);
0294: } else {
0295: parselist.add(0, (SpeedoClass) cl);
0296: }
0297: }
0298: }
0299: // Remove inheritance info that cannot have been built entirely
0300: for (SpeedoClass sc : parselist) {
0301: if (sc.inheritance.clazz == null) {
0302: sc.inheritance = null;
0303: }
0304: }
0305: // The parsing order as been defined such that super-classes are
0306: // parsed before sub-classes.
0307: nbErrors = 0;
0308: for (SpeedoClass sc : parselist) {
0309: try {
0310: logger.log(BasicLevel.DEBUG, "");
0311: parseEntityClass(Class.forName(sc.getFQName(),
0312: false, annotCL), sc);
0313: parsedFiles++;
0314: } catch (ClassNotFoundException e) {
0315: nbErrors++;
0316: logger.log(BasicLevel.ERROR,
0317: "Class not found - should never happen here: "
0318: + sc.getFQName());
0319: }
0320: }
0321: if (nbErrors > 0) {
0322: if (nbErrors == 1) {
0323: logger
0324: .log(
0325: BasicLevel.ERROR,
0326: "Abort EJB enhancement: 1 error found while parsing Entity classes defined in '"
0327: + ((SpeedoXMLDescriptor) xmldesc).xmlFile
0328: + "'.");
0329: } else {
0330: logger
0331: .log(
0332: BasicLevel.ERROR,
0333: "Abort EJB enhancement: "
0334: + nbErrors
0335: + " errors found while parsing Entity classes defined in '"
0336: + ((SpeedoXMLDescriptor) xmldesc).xmlFile
0337: + "'.");
0338: }
0339: throw new SpeedoException("EJB parsing error.");
0340: }
0341: }
0342: }
0343:
0344: /**
0345: * Determine if this is an EJB3 annotated entity class.
0346: */
0347: private boolean isAnnotatedEntityClass(Class clazz)
0348: throws SpeedoException {
0349: Entity e = (Entity) clazz.getAnnotation(Entity.class);
0350: return (e != null);
0351: }
0352:
0353: /**
0354: * Parse an EJB3 Entity class.
0355: *
0356: * @param c The Class to be parsed.
0357: * @param sc The SpeedoClass to be constructed.
0358: * @throws SpeedoException
0359: */
0360: private void parseEntityClass(Class c, SpeedoClass sc)
0361: throws SpeedoException {
0362: Entity e = (Entity) c.getAnnotation(Entity.class);
0363: if (e == null) { // This is not an Entity class
0364: throw new SpeedoException(c.getName()
0365: + ": should be an annotated EJB3 entity class!");
0366: }
0367: logger.log(BasicLevel.DEBUG, "Parse annotation of class: "
0368: + c.getName());
0369: // name of the Entity when used in a query
0370: sc.nameForQuery = e.name();
0371: // kind of access to persistent information (variables ou
0372: // accessors)
0373: for (Class itf : c.getInterfaces()) {
0374: if (itf == Serializable.class) {
0375: sc.isSerializable = true;
0376: break;
0377: }
0378: }
0379:
0380: // ---------------------------------------------------------------------
0381: // Define name for Primary Table (parse definition later...)
0382: Table t = (Table) c.getAnnotation(Table.class);
0383: if (t == null) { // There is no Table annotation: use defaults
0384: sc.mainTable.name = sc.name;
0385: } else {
0386: sc.mainTable.name = t.name();
0387: }
0388:
0389: // ---------------------------------------------------------------------
0390: // Parse the attribute information for retrieving mapping information
0391: if (c.getAnnotation(IdClass.class) != null) {
0392: sc.identity = new SpeedoIdentity();
0393: sc.identity.objectidJClass = ((IdClass) c
0394: .getAnnotation(IdClass.class)).value();
0395: sc.identity.objectidClass = sc.identity.objectidJClass
0396: .getName();
0397: sc.identity.strategy = SpeedoIdentity.USER_ID;
0398: parsePkClass(sc);
0399: }
0400: // look for persistent attributes represented by methods
0401: // (getters/setters)
0402: for (Method m : c.getMethods()) {
0403: if (!isRelevantAttribute(m, c)) {
0404: continue;
0405: }
0406: SpeedoField sf = new SpeedoField();
0407: sf.name = getter2attribute(m.getName());
0408: // sf.visibility;
0409: sf.moClass = sc;
0410: sc.fields.put(sf.name, sf);
0411: logger.log(BasicLevel.DEBUG,
0412: "New SpeedoField for EJB property: " + sf.name
0413: + ", TYPE: " + sf.type);
0414: parseManyToOne(m.getAnnotation(ManyToOne.class), sc, sf);
0415: parseOneToOne(m.getAnnotation(OneToOne.class), sc, sf);
0416: parseOneToMany(m.getAnnotation(OneToMany.class), sc, sf);
0417: parseManyToMany(m.getAnnotation(ManyToMany.class), sc, sf);
0418: parseType((Class) m.getReturnType(), m
0419: .getGenericReturnType(), sc, sf);
0420: if (sf.relationType == SpeedoField.NO_BI_RELATION) {
0421: excludeAnnotation(new Object[] {
0422: m.getAnnotation(JoinColumns.class),
0423: m.getAnnotation(JoinColumn.class),
0424: m.getAnnotation(JoinTable.class) }, sc,
0425: sf.name, "property");
0426: parseVersion(m.getAnnotation(Version.class), sc, sf);
0427: parseColumn(m.getAnnotation(Column.class), sc, sf);
0428: parseBasic(m.getAnnotation(Basic.class), sc, sf, true);
0429: parseLob(m.getAnnotation(Lob.class), sc, sf, true);
0430: if (m.getAnnotation(Embedded.class) != null) {
0431: parseEmbeddedOverriding(
0432: (AttributeOverride) m
0433: .getAnnotation(AttributeOverride.class),
0434: (AttributeOverrides) m
0435: .getAnnotation(AttributeOverrides.class),
0436: sc, sf);
0437: }
0438: } else {
0439: excludeAnnotation(new Object[] {
0440: m.getAnnotation(Version.class),
0441: m.getAnnotation(Column.class),
0442: m.getAnnotation(Basic.class),
0443: m.getAnnotation(Lob.class) }, sc, sf.name,
0444: "association property");
0445: if (m.getAnnotation(JoinColumns.class) != null) {
0446: if (m.getAnnotation(JoinColumn.class) != null) {
0447: nbErrors++;
0448: logger
0449: .log(
0450: BasicLevel.ERROR,
0451: sc.getSourceDescShort()
0452: + ": cannot define both 'JoinColumns' and'JoinColumn' annotation for property ("
0453: + sf.name + ").");
0454: } else {
0455: parseJoinColumns(m.getAnnotation(
0456: JoinColumns.class).value(), sc, sf);
0457: }
0458: } else {
0459: if (m.getAnnotation(JoinColumn.class) != null) {
0460: parseJoinColumns(new JoinColumn[] { m
0461: .getAnnotation(JoinColumn.class) }, sc,
0462: sf);
0463: }
0464: }
0465: }
0466: parseEmbeddedId(m.getAnnotation(EmbeddedId.class), sc, sf);
0467: if (parseId(m.getAnnotation(Id.class), sc, sf)) {
0468: // ---------------------------------------------------------------------
0469: // In case of Long identifier, try parsing Id generator
0470: parseGeneratedValue((GeneratedValue) m
0471: .getAnnotation(GeneratedValue.class), sc);
0472: } else {
0473: if (m.getAnnotation(GeneratedValue.class) != null) {
0474: logger
0475: .log(
0476: BasicLevel.WARN,
0477: sc.getSourceDescShort()
0478: + ": can only associate an identifier generator to a Long ID - ignored!");
0479: }
0480: }
0481: }
0482: // look for persistent attributes represented by variables
0483: for (Field f : c.getDeclaredFields()) {
0484: if (!isRelevantAttribute(f, c)) {
0485: continue;
0486: }
0487: SpeedoField sf = new SpeedoField();
0488: sf.name = f.getName();
0489: // sf.visibility;
0490: sf.moClass = sc;
0491: sc.fields.put(sf.name, sf);
0492: logger.log(BasicLevel.DEBUG,
0493: "New SpeedoField for EJB field: " + sf.name
0494: + ", TYPE: " + sf.type);
0495: parseManyToOne(f.getAnnotation(ManyToOne.class), sc, sf);
0496: parseOneToOne(f.getAnnotation(OneToOne.class), sc, sf);
0497: parseOneToMany(f.getAnnotation(OneToMany.class), sc, sf);
0498: parseManyToMany(f.getAnnotation(ManyToMany.class), sc, sf);
0499: parseType((Class) f.getType(), f.getGenericType(), sc, sf);
0500: if (sf.relationType == SpeedoField.NO_BI_RELATION) {
0501: excludeAnnotation(new Object[] {
0502: f.getAnnotation(JoinColumns.class),
0503: f.getAnnotation(JoinColumn.class),
0504: f.getAnnotation(JoinTable.class) }, sc,
0505: sf.name, "field");
0506: parseVersion(f.getAnnotation(Version.class), sc, sf);
0507: parseColumn(f.getAnnotation(Column.class), sc, sf);
0508: parseBasic(f.getAnnotation(Basic.class), sc, sf, false);
0509: parseLob(f.getAnnotation(Lob.class), sc, sf, false);
0510: if (f.getAnnotation(Embedded.class) != null) {
0511: parseEmbeddedOverriding(
0512: (AttributeOverride) f
0513: .getAnnotation(AttributeOverride.class),
0514: (AttributeOverrides) f
0515: .getAnnotation(AttributeOverrides.class),
0516: sc, sf);
0517: }
0518: } else {
0519: excludeAnnotation(new Object[] {
0520: f.getAnnotation(Version.class),
0521: f.getAnnotation(Column.class),
0522: f.getAnnotation(Basic.class),
0523: f.getAnnotation(Lob.class) }, sc, sf.name,
0524: "association field");
0525: if (f.getAnnotation(JoinColumns.class) != null) {
0526: if (f.getAnnotation(JoinColumn.class) != null) {
0527: nbErrors++;
0528: logger
0529: .log(
0530: BasicLevel.ERROR,
0531: sc.getSourceDescShort()
0532: + ": cannot define both 'JoinColumns' and'JoinColumn' annotation at the same time for field ("
0533: + sf.name + ").");
0534: } else {
0535: parseJoinColumns(f.getAnnotation(
0536: JoinColumns.class).value(), sc, sf);
0537: }
0538: } else {
0539: if (f.getAnnotation(JoinColumn.class) != null) {
0540: parseJoinColumns(new JoinColumn[] { f
0541: .getAnnotation(JoinColumn.class) }, sc,
0542: sf);
0543: }
0544: }
0545: }
0546: parseEmbeddedId(f.getAnnotation(EmbeddedId.class), sc, sf);
0547: if (parseId(f.getAnnotation(Id.class), sc, sf)) {
0548: // ---------------------------------------------------------------------
0549: // In case of Long identifier, try parsing Id generator
0550: parseGeneratedValue((GeneratedValue) f
0551: .getAnnotation(GeneratedValue.class), sc);
0552: } else {
0553: if (f.getAnnotation(GeneratedValue.class) != null) {
0554: logger
0555: .log(
0556: BasicLevel.WARN,
0557: sc.getSourceDescShort()
0558: + ": can only associate an identifier generator to a Long ID - ignored!");
0559: }
0560: }
0561: }
0562: // Verify that a mapping has been defined for each field when needed
0563: for (SpeedoField sf : (Collection<SpeedoField>) sc.fields
0564: .values()) {
0565: if (sf.mappedByReversefield) {
0566: sf.relationType = SpeedoField.NO_BI_RELATION;
0567: continue;
0568: }
0569: if (sf.relationType == SpeedoField.NO_BI_RELATION) {
0570: continue;
0571: }
0572: if (sf.relationType == SpeedoField.MANY_REFERENCE) {
0573: if (sf.join == null) {
0574: nbErrors++;
0575: logger
0576: .log(
0577: BasicLevel.ERROR,
0578: sc.getSourceDescShort()
0579: + ": a mapping must be associated with the n-ary association field ("
0580: + sf.name + ").");
0581: }
0582: } else { // sf.relationType == SpeedoField.ONE_REFERENCE
0583: if (sf.columns.length == 0) {
0584: nbErrors++;
0585: logger
0586: .log(
0587: BasicLevel.ERROR,
0588: sc.getSourceDescShort()
0589: + ": a mapping must be associated with the unary association field ("
0590: + sf.name + ").");
0591: }
0592: }
0593: // The real type of relation will be calculated later (@see ReverseFieldAdder).
0594: sf.relationType = SpeedoField.NO_BI_RELATION;
0595: }
0596: // Verify that there is an identifier definition
0597: if (sc.getPKFields().size() == 0) {
0598: SpeedoClass sch = sc.getSuper();
0599: while (sch != null) {
0600: if (sch.getPKFields().size() != 0) {
0601: break;
0602: }
0603: sch = sch.getSuper();
0604: }
0605: if (sch == null) {
0606: nbErrors++;
0607: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
0608: + ": no identity defined for the class.");
0609: }
0610: }
0611:
0612: // ---------------------------------------------------------------------
0613: // Parse table definitions
0614: // - Primary table
0615: if (t != null) {
0616: parseTable(t, sc, sc.mainTable);
0617: }
0618: // - Secondary tables
0619: SecondaryTable st = (SecondaryTable) c
0620: .getAnnotation(SecondaryTable.class);
0621: SecondaryTables sts = (SecondaryTables) c
0622: .getAnnotation(SecondaryTables.class);
0623: if (sts != null) {
0624: if (st != null) {
0625: nbErrors++;
0626: logger
0627: .log(
0628: BasicLevel.ERROR,
0629: sc.getSourceDescShort()
0630: + ": cannot define both 'SecondaryTable' and 'SecondaryTables' annotations at the same time.");
0631: } else {
0632: for (SecondaryTable st2 : sts.value()) {
0633: parseSecondaryTable(st2, sc);
0634: }
0635: }
0636: } else {
0637: if (st != null) {
0638: parseSecondaryTable(st, sc);
0639: }
0640: }
0641:
0642: // Parse inheritance strategy information
0643: parseDiscriminatorColumn(c, sc);
0644: parseDiscriminatorValue(c, sc);
0645: parseInheritanceJoin(c, sc);
0646: parseInheritance(c, sc);
0647: if (sc.identity == null) {
0648: nbErrors++;
0649: logger
0650: .log(
0651: BasicLevel.ERROR,
0652: sc.getSourceDescShort()
0653: + ": an identifier must be defined for this Entity class.");
0654: }
0655:
0656: // Parse attributes overriding
0657: AttributeOverride ao = (AttributeOverride) c
0658: .getAnnotation(AttributeOverride.class);
0659: AttributeOverrides aos = (AttributeOverrides) c
0660: .getAnnotation(AttributeOverrides.class);
0661: parseAttributeOverriding(ao, aos, sc);
0662: for (Method m : c.getMethods()) {
0663: ao = (AttributeOverride) m
0664: .getAnnotation(AttributeOverride.class);
0665: aos = (AttributeOverrides) m
0666: .getAnnotation(AttributeOverrides.class);
0667: if (m.getAnnotation(Embedded.class) == null) {
0668: parseAttributeOverriding(ao, aos, sc);
0669: }
0670: }
0671: for (Field f : c.getDeclaredFields()) {
0672: ao = (AttributeOverride) f
0673: .getAnnotation(AttributeOverride.class);
0674: aos = (AttributeOverrides) f
0675: .getAnnotation(AttributeOverrides.class);
0676: if (f.getAnnotation(Embedded.class) == null) {
0677: parseAttributeOverriding(ao, aos, sc);
0678: }
0679: }
0680:
0681: // ---------------------------------------------------------------------
0682: // Parse the callback associated to Entity lifecycle:
0683: // could be present inside the Entity class itself or
0684: // inside associated EntityListener classes.
0685: EntityListeners els = (EntityListeners) c
0686: .getAnnotation(EntityListeners.class);
0687: if (els != null) {
0688: // Parse the listener classes for callbacks
0689: for (Class elc : els.value()) {
0690: parseCallBacks(elc.getMethods(), sc, elc);
0691: }
0692: }
0693: // Parse the class for callbacks
0694: parseCallBacks(c.getMethods(), sc, null);
0695: }
0696:
0697: /**
0698: * Verify if it is a relevant attribute definition to be parsed.
0699: *
0700: * @param methorfield The attribute definition (Method or Field).
0701: * @param c The Java class under parsing.
0702: * @return true if it must be parsed.
0703: */
0704: private boolean isRelevantAttribute(Object methorfield, Class c) {
0705: if (methorfield instanceof Field) {
0706: Field f = (Field) methorfield;
0707: if ((f.getAnnotation(Column.class) == null)
0708: && (f.getAnnotation(Basic.class) == null)
0709: && (f.getAnnotation(OneToOne.class) == null)
0710: && (f.getAnnotation(OneToMany.class) == null)
0711: && (f.getAnnotation(ManyToOne.class) == null)
0712: && (f.getAnnotation(ManyToMany.class) == null)
0713: && (f.getAnnotation(Id.class) == null)
0714: && (f.getAnnotation(JoinColumn.class) == null)
0715: && (f.getAnnotation(Version.class) == null)) {
0716: return false;
0717: }
0718: if (f.getDeclaringClass() != c) {
0719: return false;
0720: }
0721: if ((f.getModifiers() & Modifier.TRANSIENT) == Modifier.TRANSIENT) {
0722: return false;
0723: }
0724: if (f.getAnnotation(Transient.class) != null) {
0725: return false;
0726: }
0727: } else {
0728: Method m = (Method) methorfield;
0729: if ((m.getAnnotation(Column.class) == null)
0730: && (m.getAnnotation(Basic.class) == null)
0731: && (m.getAnnotation(OneToOne.class) == null)
0732: && (m.getAnnotation(OneToMany.class) == null)
0733: && (m.getAnnotation(ManyToOne.class) == null)
0734: && (m.getAnnotation(ManyToMany.class) == null)
0735: && (m.getAnnotation(Id.class) == null)
0736: && (m.getAnnotation(JoinColumn.class) == null)
0737: && (m.getAnnotation(Version.class) == null)) {
0738: return false;
0739: }
0740: if (m.getDeclaringClass() != c) {
0741: return false;
0742: }
0743: if (!m.getName().startsWith("get")) { // Could it be a getter
0744: return false;
0745: }
0746: try {
0747: c.getDeclaredMethod(m.getName().replaceFirst("g", "s"),
0748: new Class[] { m.getReturnType() });
0749: } catch (NoSuchMethodException e1) {
0750: return false;
0751: }
0752: if (m.getParameterTypes().length != 0) { // Getter => no arg
0753: return false;
0754: }
0755: if (m.getReturnType() == null) { // Getter => return type must exist
0756: return false;
0757: }
0758: if (m.getAnnotation(Transient.class) != null) {
0759: return false;
0760: }
0761: }
0762: return true;
0763: }
0764:
0765: /**
0766: * Parse the DiscriminatorColumn annotation associated with an Entity class.
0767: *
0768: * @param c The Entity class to be parsed.
0769: * @param sc The SpeedoClass under construction.
0770: */
0771: private void parseDiscriminatorColumn(Class c, SpeedoClass sc) {
0772: DiscriminatorColumn a = (DiscriminatorColumn) c
0773: .getAnnotation(DiscriminatorColumn.class);
0774: if (a == null) {
0775: return;
0776: }
0777: if (sc.inheritance == null) {
0778: // This is a root class in an inheritance hierarchy
0779: sc.inheritance = new SpeedoInheritance();
0780: sc.inheritance.clazz = sc;
0781: sc.inheritance.super ClassName = null;
0782: sc.inheritance.discriminator = new SpeedoDiscriminator();
0783: String cn = a.name();
0784: if (cn.equals("")) {
0785: cn = "TYPE"; // Default name of the discriminator column
0786: }
0787: SpeedoNoFieldColumn snofc = new SpeedoNoFieldColumn();
0788: SpeedoColumn scol = sc.getColumn(cn, true);
0789: if (scol == null) {
0790: // There is no existing column: create one
0791: scol = new SpeedoColumn();
0792: scol.name = cn;
0793: scol.allowNull = false;
0794: if (!a.columnDefinition().equals("")) {
0795: scol.sqlType = a.columnDefinition();
0796: }
0797: scol.length = a.length();
0798: scol.table = sc.mainTable;
0799: }
0800: snofc.column = scol;
0801: switch (a.discriminatorType()) {
0802: case STRING:
0803: snofc.type = Type.getDescriptor(String.class);
0804: break;
0805: case CHAR:
0806: snofc.type = Type.getDescriptor(Character.TYPE);
0807: break;
0808: case INTEGER:
0809: snofc.type = Type.getDescriptor(Integer.TYPE);
0810: break;
0811: }
0812: sc.inheritance.discriminator.elements.add(snofc);
0813: } else {
0814: nbErrors++;
0815: logger
0816: .log(
0817: BasicLevel.ERROR,
0818: sc.getSourceDescShort()
0819: + ": discriminator column can only be defined in the root class of an inheritance hierarchy!");
0820: return;
0821: }
0822: }
0823:
0824: /**
0825: * Parse the DiscriminatorValue annotation associated with an Entity class.
0826: *
0827: * @param c The Entity class to be parsed.
0828: * @param sc The SpeedoClass under construction.
0829: */
0830: private void parseDiscriminatorValue(Class c, SpeedoClass sc) {
0831: DiscriminatorValue a = (DiscriminatorValue) c
0832: .getAnnotation(DiscriminatorValue.class);
0833: if (a == null) {
0834: return;
0835: }
0836: SpeedoNoFieldColumn snofc = (SpeedoNoFieldColumn) sc
0837: .getAncestor().inheritance.discriminator.elements
0838: .get(0);
0839: if (a.value().equals("")) {
0840: sc.inheritance.discriminatorValues
0841: .put(
0842: snofc,
0843: SpeedoInheritance.SPEEDO_DEFAULT_DISCRIMINENT_VALUE);
0844: } else {
0845: sc.inheritance.discriminatorValues.put(snofc, a.value());
0846: }
0847: }
0848:
0849: /**
0850: * Parse the inheritance join in case of JOINED inheritance mapping
0851: * strategy.
0852: *
0853: * @param c The Entity class to be parsed.
0854: * @param sc The SpeedoClass under construction.
0855: */
0856: private void parseInheritanceJoin(Class c, SpeedoClass sc) {
0857: if (sc.inheritance == null) {
0858: return;
0859: }
0860: PrimaryKeyJoinColumn a1 = (PrimaryKeyJoinColumn) c
0861: .getAnnotation(PrimaryKeyJoinColumn.class);
0862: PrimaryKeyJoinColumns a2 = (PrimaryKeyJoinColumns) c
0863: .getAnnotation(PrimaryKeyJoinColumns.class);
0864: if ((a1 == null) && (a2 == null)) {
0865: return;
0866: }
0867: if ((a1 != null) && (a2 != null)) {
0868: nbErrors++;
0869: logger
0870: .log(
0871: BasicLevel.ERROR,
0872: sc.getSourceDescShort()
0873: + ": can only support a unique join description - two found (a join column and a set of join columns)!");
0874: return;
0875: }
0876: if (a2.value().length == 1) {
0877: a1 = a2.value()[0];
0878: }
0879: sc.inheritance.join = new SpeedoJoin();
0880: sc.inheritance.join.mainTable = sc.mainTable;
0881: sc.inheritance.join.extTable = sc.getSuper().mainTable;
0882: // First parse PrimaryKeyJoinColumn
0883: if (a1 != null) {
0884: SpeedoJoinColumn jcol = new SpeedoJoinColumn();
0885: jcol.column = sc.getColumn(a1.name(), true);
0886: if (jcol.column == null) {
0887: nbErrors++;
0888: logger
0889: .log(
0890: BasicLevel.ERROR,
0891: sc.getSourceDescShort()
0892: + ": inheritance join define with a column that does not exist - ("
0893: + a1.name() + ") not found!");
0894: return;
0895: }
0896: if (a1.referencedColumnName().equals("")) {
0897: nbErrors++;
0898: logger
0899: .log(
0900: BasicLevel.ERROR,
0901: sc.getSourceDescShort()
0902: + ": inheritance join define with no column associated in superclass!");
0903: return;
0904: }
0905: jcol.targetColumn = a1.referencedColumnName();
0906: sc.inheritance.join.columns.add(jcol);
0907: return;
0908: }
0909: // Now parse PrimaryKeyJoinColumns: the PrimaryKeyJoinColmun from the "pkjcs" array
0910: for (PrimaryKeyJoinColumn pkjc : a2.value()) {
0911: SpeedoJoinColumn jcol = new SpeedoJoinColumn();
0912: jcol.column = sc.getColumn(pkjc.name(), true);
0913: if (jcol.column == null) {
0914: nbErrors++;
0915: logger
0916: .log(
0917: BasicLevel.ERROR,
0918: sc.getSourceDescShort()
0919: + ": inheritance join define with a column that does not exist - ("
0920: + pkjc.name() + ") not found!");
0921: continue;
0922: }
0923: // Define the referenced column in the super class of this jcol
0924: if (pkjc.referencedColumnName().equals("")) {
0925: nbErrors++;
0926: logger
0927: .log(
0928: BasicLevel.ERROR,
0929: sc.getSourceDescShort()
0930: + ": inheritance join define with no column associated in superclass!");
0931: continue;
0932: }
0933: jcol.targetColumn = pkjc.referencedColumnName();
0934: sc.inheritance.join.columns.add(jcol);
0935: }
0936: }
0937:
0938: /**
0939: * Parse the Inheritance annotation associated with an Entity class.
0940: *
0941: * @param c The Entity class to be parsed.
0942: * @param sc The SpeedoClass under construction.
0943: */
0944: private void parseInheritance(Class c, SpeedoClass sc) {
0945: Inheritance a = (Inheritance) c
0946: .getAnnotation(Inheritance.class);
0947: if (a == null) {
0948: return;
0949: }
0950: if (sc.inheritance == null) {
0951: // This is a root class in an inheritance hierarchy
0952: sc.inheritance = new SpeedoInheritance();
0953: sc.inheritance.clazz = sc;
0954: sc.inheritance.super ClassName = null;
0955: }
0956: switch (a.strategy()) {
0957: case SINGLE_TABLE: // filtered inheritance mapping
0958: SpeedoNoFieldColumn snofc;
0959: if (sc.inheritance.join != null) {
0960: logger
0961: .log(
0962: BasicLevel.ERROR,
0963: sc.getSourceDescShort()
0964: + ": no join column definition required for SINGLE_TABLE strategy inheritance - ignored!");
0965: sc.inheritance.join = null;
0966: }
0967: if (sc.getAncestor() == null) {
0968: // This is the root class of the inheritance hierarchy
0969: sc.inheritance.strategy = SpeedoInheritance.STRATEGY_NEW_TABLE;
0970: if (sc.inheritance.discriminator == null) {
0971: nbErrors++;
0972: logger
0973: .log(
0974: BasicLevel.ERROR,
0975: sc.getSourceDescShort()
0976: + ": SINGLE_TABLE strategy inheritance requires discriminator description - none found!");
0977: return;
0978: }
0979: snofc = (SpeedoNoFieldColumn) sc.inheritance.discriminator.elements
0980: .get(0);
0981: } else {
0982: sc.inheritance.strategy = SpeedoInheritance.STRATEGY_SUPERCLASS_TABLE;
0983: if (sc.inheritance.discriminator != null) {
0984: logger
0985: .log(
0986: BasicLevel.WARN,
0987: sc.getSourceDescShort()
0988: + ": discriminator column should be defined only in root class of inheritance hiereachy - ignored!");
0989: sc.inheritance.discriminator = null;
0990: }
0991: snofc = (SpeedoNoFieldColumn) sc.getAncestor().inheritance.discriminator.elements
0992: .get(0);
0993: if (sc.identity != null) {
0994: logger
0995: .log(
0996: BasicLevel.WARN,
0997: sc.getSourceDescShort()
0998: + ": identity cannot be redefined into subclasses when SINGLE_TABLE strategy is used - ignored!");
0999: }
1000: sc.identity = sc.getAncestor().identity;
1001: }
1002: sc.inheritance.discriminatorValues = new HashMap();
1003: break;
1004: case TABLE_PER_CLASS: // horizontal inheritance mapping
1005: if (sc.inheritance.join != null) {
1006: logger
1007: .log(
1008: BasicLevel.WARN,
1009: sc.getSourceDescShort()
1010: + ": no join column definition required for TABLE_PER_CLASS inheritance strategy - ignored!");
1011: sc.inheritance.join = null;
1012: }
1013: sc.inheritance.strategy = SpeedoInheritance.STRATEGY_NEW_TABLE;
1014: if (sc.inheritance.discriminator != null) {
1015: logger
1016: .log(
1017: BasicLevel.WARN,
1018: sc.getSourceDescShort()
1019: + ": no discriminator column definition required for TABLE_PER_CLASS inheritance strategy - ignored!");
1020: sc.inheritance.discriminator = null;
1021: }
1022: // Define attribute mapping for attributes of the superclasses
1023: SpeedoClass inhsc = sc.getSuper();
1024: while (inhsc != null) {
1025: for (Object inhsf : inhsc.fields.values()) {
1026: if (inhsf instanceof SpeedoInheritedField) {
1027: continue;
1028: }
1029: SpeedoInheritedField sif = sc.inheritance
1030: .newSpeedoInheritedField((SpeedoField) inhsf);
1031: for (SpeedoColumn scol : sif.inheritedField.columns) {
1032: SpeedoColumn nscol = (SpeedoColumn) scol
1033: .clone();
1034: nscol.table = sc.mainTable;
1035: sif.addColumn(nscol);
1036: }
1037: }
1038: inhsc = inhsc.getSuper();
1039: }
1040: break;
1041: case JOINED: // vertical inheritance mapping
1042: sc.inheritance.strategy = SpeedoInheritance.STRATEGY_NEW_TABLE;
1043: if (sc.getAncestor() == null) {
1044: // This is the root class of the inheritance hierarchy
1045: if (sc.inheritance.join != null) {
1046: logger
1047: .log(
1048: BasicLevel.WARN,
1049: sc.getSourceDescShort()
1050: + ": no join column definition required for root class for JOINED inheritance strategy - ignored!");
1051: sc.inheritance.join = null;
1052: }
1053: if (sc.inheritance.discriminator == null) {
1054: nbErrors++;
1055: logger
1056: .log(
1057: BasicLevel.ERROR,
1058: sc.getSourceDescShort()
1059: + ": JOINED strategy inheritance requires discriminator description - none found!");
1060: return;
1061: }
1062: snofc = (SpeedoNoFieldColumn) sc.inheritance.discriminator.elements
1063: .get(0);
1064: } else {
1065: if (sc.inheritance.join == null) {
1066: nbErrors++;
1067: logger
1068: .log(
1069: BasicLevel.ERROR,
1070: sc.getSourceDescShort()
1071: + ": JOINED strategy inheritance requires a join description - none found!");
1072: return;
1073: }
1074: if (sc.inheritance.discriminator != null) {
1075: logger
1076: .log(
1077: BasicLevel.WARN,
1078: sc.getSourceDescShort()
1079: + ": discriminator column should be defined only in root class of inheritance hiereachy - ignored!");
1080: sc.inheritance.discriminator = null;
1081: }
1082: snofc = (SpeedoNoFieldColumn) sc.getAncestor().inheritance.discriminator.elements
1083: .get(0);
1084: sc.identity = sc.getAncestor().identity;
1085: }
1086: sc.inheritance.discriminatorValues = new HashMap();
1087: break;
1088: }
1089: }
1090:
1091: static final Class[] OBJSIGN = { Object.class };
1092: static final Class[] EMPTYSIGN = {};
1093:
1094: /**
1095: * Verify if the given Class may be used as an EJB3 PK class.
1096: *
1097: * @param sc The SpeedoClass under construction. The identity field
1098: * defines a PK class that has be verified as compliant wrt
1099: * EJB3.
1100: * @return true if the PK class is conform.
1101: */
1102: private boolean parsePkClass(SpeedoClass sc) {
1103: if ((sc.identity.objectidJClass.getModifiers() & Member.PUBLIC) != Member.PUBLIC) {
1104: nbErrors++;
1105: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1106: + ": PK class ("
1107: + sc.identity.objectidJClass.getName()
1108: + ") must be public.");
1109: return false;
1110: }
1111: try {
1112: sc.identity.objectidJClass.getConstructor(EMPTYSIGN);
1113: } catch (NoSuchMethodException e) {
1114: nbErrors++;
1115: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1116: + ": PK class ("
1117: + sc.identity.objectidJClass.getName()
1118: + ") must have a public constructor with no arg.");
1119: return false;
1120: }
1121: if (!Serializable.class
1122: .isAssignableFrom(sc.identity.objectidJClass)) {
1123: nbErrors++;
1124: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1125: + ": PK class ("
1126: + sc.identity.objectidJClass.getName()
1127: + ") must be Serializable.");
1128: return false;
1129: }
1130: Method meq, mha;
1131: try {
1132: meq = sc.identity.objectidJClass.getDeclaredMethod(
1133: "equals", OBJSIGN);
1134: } catch (NoSuchMethodException e) {
1135: nbErrors++;
1136: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1137: + ": PK class ("
1138: + sc.identity.objectidJClass.getName()
1139: + ") must implement 'equals'.");
1140: return false;
1141: }
1142: try {
1143: mha = sc.identity.objectidJClass.getDeclaredMethod(
1144: "hashCode", EMPTYSIGN);
1145: } catch (NoSuchMethodException e) {
1146: nbErrors++;
1147: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1148: + ": PK class ("
1149: + sc.identity.objectidJClass.getName()
1150: + ") must implement 'hashCode'.");
1151: return false;
1152: }
1153: for (Method m : sc.identity.objectidJClass.getDeclaredMethods()) {
1154: if ((m == meq) || (m == mha)) {
1155: continue;
1156: }
1157: if (m.getName().startsWith("get")) {
1158: if (m.getParameterTypes().length != 0) {
1159: nbErrors++;
1160: logger
1161: .log(
1162: BasicLevel.ERROR,
1163: sc.getSourceDescShort()
1164: + ": PK class ("
1165: + sc.identity.objectidJClass
1166: .getName()
1167: + ") define primary key getter with arguments ("
1168: + m.getName() + ").");
1169: continue;
1170: }
1171: if (!isValidType(Type.getDescriptor(m.getReturnType()),
1172: COMPPKFIELDTYPES)) {
1173: nbErrors++;
1174: logger
1175: .log(
1176: BasicLevel.ERROR,
1177: sc.getSourceDescShort()
1178: + ": PK class ("
1179: + sc.identity.objectidJClass
1180: .getName()
1181: + ") define primary key getter with invalid type ("
1182: + m.getName() + ").");
1183: continue;
1184: }
1185: } else if (m.getName().startsWith("set")) {
1186: if (m.getParameterTypes().length != 1) {
1187: nbErrors++;
1188: logger
1189: .log(
1190: BasicLevel.ERROR,
1191: sc.getSourceDescShort()
1192: + ": PK class ("
1193: + sc.identity.objectidJClass
1194: .getName()
1195: + ") not define primary key setter one argument ("
1196: + m.getName() + ").");
1197: continue;
1198: }
1199: if (m.getReturnType() != Void.TYPE) {
1200: nbErrors++;
1201: logger
1202: .log(
1203: BasicLevel.ERROR,
1204: sc.getSourceDescShort()
1205: + ": PK class ("
1206: + sc.identity.objectidJClass
1207: .getName()
1208: + ") define primary key setter with non void return type ("
1209: + m.getName() + ").");
1210: continue;
1211: }
1212: if (!isValidType(Type.getDescriptor(m
1213: .getParameterTypes()[0]), COMPPKFIELDTYPES)) {
1214: nbErrors++;
1215: logger
1216: .log(
1217: BasicLevel.ERROR,
1218: sc.getSourceDescShort()
1219: + ": PK class ("
1220: + sc.identity.objectidJClass
1221: .getName()
1222: + ") define primary key setter with invalid argument type ("
1223: + m.getName() + ").");
1224: continue;
1225: }
1226: }
1227: }
1228: for (Field f : sc.identity.objectidJClass.getDeclaredFields()) {
1229: if (!isValidType(Type.getDescriptor(f.getType()),
1230: COMPPKFIELDTYPES)) {
1231: nbErrors++;
1232: logger
1233: .log(
1234: BasicLevel.ERROR,
1235: sc.getSourceDescShort()
1236: + ": PK class ("
1237: + sc.identity.objectidJClass
1238: .getName()
1239: + ") define primary key field with invalid type ("
1240: + f.getName() + ").");
1241: }
1242: }
1243: return true;
1244: }
1245:
1246: /**
1247: * Parse the type associated with a field.
1248: * "type" field may temporarily stores type name of target association entity
1249: * for verification purpose at type parsing.
1250: *
1251: * @param t The type that has to be parsed.
1252: * @param sc The SpeedoClass under construction.
1253: * @param sf The SpeedoField under construction.
1254: */
1255: private void parseType(Class t, java.lang.reflect.Type gt,
1256: SpeedoClass sc, SpeedoField sf) {
1257: if (t == null) {
1258: logger
1259: .log(
1260: BasicLevel.WARN,
1261: sc.getSourceDescShort()
1262: + ": unknown type for element of collection for field ("
1263: + sf.name + ").");
1264: return;
1265: }
1266: SpeedoClass scf = scp.smi.getSpeedoClass(t.getName());
1267: if (scf != null) {
1268: // This is en Entity class.
1269: sf.relationType = SpeedoField.ONE_REFERENCE;
1270: if (sf.type != null) { // defined at association definition time
1271: if (!sf.type.equals(t.getName())) {
1272: logger
1273: .log(
1274: BasicLevel.WARN,
1275: sc.getSourceDescShort()
1276: + ": type for field ("
1277: + sf.name
1278: + ") is different from the one defined in association - association type ignored.");
1279: }
1280: }
1281: sf.type = Type.getDescriptor(t);
1282: return;
1283: }
1284: if (isValidType(Type.getDescriptor(t), FIELDTYPES)
1285: || t.isEnum()) {
1286: // This a basic valid type or an enum type. Nothing to do.
1287: sf.type = Type.getDescriptor(t);
1288: return;
1289: }
1290: // Verifies if it is a Collection or a Serializable type.
1291: if (Set.class.isAssignableFrom(t)
1292: || List.class.isAssignableFrom(t)
1293: || Collection.class.isAssignableFrom(t)) {
1294: // This is a valid type: a Set, List or Collection of Entity class.
1295: sf.jdoTuple = new SpeedoCollection();
1296: sf.jdoTuple.moField = sf;
1297: if (t == gt) {
1298: // No generic type defined.
1299: if (sf.type == null) {
1300: nbErrors++;
1301: logger
1302: .log(
1303: BasicLevel.ERROR,
1304: sc.getSourceDescShort()
1305: + ": unknown type for element of Set/List/Collection for field ("
1306: + sf.name + ").");
1307: return;
1308: }
1309: ((SpeedoCollection) sf.jdoTuple).elementType = sf.type;
1310: sf.type = Type.getDescriptor(t);
1311: return;
1312: }
1313: // The Java generic type is completely defined.
1314: sf.relationType = SpeedoField.MANY_REFERENCE;
1315: SpeedoClass escf = scp.smi
1316: .getSpeedoClass(((Class) ((ParameterizedType) gt)
1317: .getActualTypeArguments()[0]).getName());
1318: if (escf == null) {
1319: nbErrors++;
1320: logger
1321: .log(
1322: BasicLevel.ERROR,
1323: sc.getSourceDescShort()
1324: + ": element of collection should belong to an Entity class (found "
1325: + Type
1326: .getDescriptor((Class) ((ParameterizedType) gt)
1327: .getActualTypeArguments()[0])
1328: + ") for field (" + sf.name
1329: + ").");
1330: return;
1331: }
1332: if (!sf.type.equals(escf.name)) {
1333: logger
1334: .log(
1335: BasicLevel.WARN,
1336: sc.getSourceDescShort()
1337: + ": type for element of collection field ("
1338: + sf.name
1339: + ") is different from the one defined in association - association type ignored.");
1340: }
1341: ((SpeedoCollection) sf.jdoTuple).elementType = ((Class) ((ParameterizedType) gt)
1342: .getActualTypeArguments()[0]).getName();
1343: sf.type = Type.getDescriptor(t);
1344: return;
1345: }
1346: if (Map.class.isAssignableFrom(t)) {
1347: // This is a Map valid type.
1348: sf.jdoTuple = new SpeedoMap();
1349: sf.jdoTuple.moField = sf;
1350: if (t == gt) {
1351: logger
1352: .log(
1353: BasicLevel.WARN,
1354: sc.getSourceDescShort()
1355: + ": unknown type for element of Map for field ("
1356: + sf.name + ").");
1357: return;
1358: }
1359: // The Java generic type is completely defined.
1360: sf.relationType = SpeedoField.MANY_REFERENCE;
1361: SpeedoClass escf = scp.smi
1362: .getSpeedoClass(((Class) ((ParameterizedType) gt)
1363: .getActualTypeArguments()[1]).getName());
1364: if (escf == null) {
1365: nbErrors++;
1366: logger
1367: .log(
1368: BasicLevel.ERROR,
1369: sc.getSourceDescShort()
1370: + ": element of Map should belong to an Entity class (found "
1371: + Type
1372: .getDescriptor((Class) ((ParameterizedType) gt)
1373: .getActualTypeArguments()[1])
1374: + ") for field (" + sf.name
1375: + ").");
1376: return;
1377: }
1378: ((SpeedoMap) sf.jdoTuple).keyType = ((Class) ((ParameterizedType) gt)
1379: .getActualTypeArguments()[0]).getName();
1380: ((SpeedoMap) sf.jdoTuple).valueType = ((Class) ((ParameterizedType) gt)
1381: .getActualTypeArguments()[1]).getName();
1382: sf.type = Type.getDescriptor(t);
1383: return;
1384: }
1385: if (Serializable.class.isAssignableFrom(t)) {
1386: // This is a Serializable valid type. Nothing to do.
1387: sf.type = Type.getDescriptor(t);
1388: return;
1389: }
1390: // All other types are not supported.
1391: nbErrors++;
1392: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1393: + ": unsupported type (" + Type.getDescriptor(t)
1394: + ") for field (" + sf.name + ").");
1395: }
1396:
1397: /**
1398: * Parse the version field associated to a class for supporting database
1399: * optimistic locking policy.
1400: *
1401: * @param a The Version annotation to be parsed.
1402: * @param sc The SpeedoClass under construction.
1403: * @param sf The SpeedoField to be associated as the version field.
1404: */
1405: private void parseVersion(Version a, SpeedoClass sc, SpeedoField sf) {
1406: if (a == null) {
1407: return;
1408: }
1409: if (sc.versionField == null) {
1410: if (!isValidType(sf.type, VERSIONTYPES)) {
1411: nbErrors++;
1412: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1413: + ": try to define a field version (" + sf.name
1414: + ") - unsupported type (" + sf.type + ").");
1415: }
1416: sc.versionField = sf;
1417: } else {
1418: nbErrors++;
1419: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1420: + ": a field version has already been defined ("
1421: + sc.versionField.name
1422: + ") - cannot associate a second one (" + sf.name
1423: + ").");
1424: }
1425: }
1426:
1427: /**
1428: * Parse field meta-information from the Column annotation.
1429: *
1430: * @param col The annotation to extract information from.
1431: * @param sc The SpeedoClass under construction.
1432: * @param sf The SpeedoField under construction.
1433: */
1434: private void parseColumn(Column col, SpeedoClass sc, SpeedoField sf) {
1435: SpeedoColumn scol = new SpeedoColumn();
1436: if (col == null) {
1437: if (sf.relationType != SpeedoField.NO_BI_RELATION) {
1438: return;
1439: }
1440: scol.name = sf.name;
1441: scol.table = sc.mainTable;
1442: sf.addColumn(scol);
1443: logger.log(BasicLevel.DEBUG, sc.getSourceDescShort()
1444: + ": add a default column definition for field '"
1445: + sf.name + "'.");
1446: return;
1447: } else {
1448: if (sf.relationType != SpeedoField.NO_BI_RELATION) {
1449: logger
1450: .log(
1451: BasicLevel.WARN,
1452: sc.getSourceDescShort()
1453: + ": try to define a column associated with an association field - ignored.");
1454: return;
1455: }
1456: }
1457: if (!col.table().equals("")) {
1458: if (col.table().equals(sc.mainTable.name)) {
1459: scol.table = sc.mainTable;
1460: } else {
1461: scol.table = sc.getExtTable(col.table(), true);
1462: }
1463: } else {
1464: scol.table = sc.mainTable;
1465: }
1466: if (col.unique()) {
1467: ArrayList<SpeedoColumn> cols = new ArrayList<SpeedoColumn>(
1468: 1);
1469: cols.add(scol);
1470: scol.table.addUniqueConstraint(cols);
1471: logger.log(BasicLevel.DEBUG, sc.getSourceDescShort()
1472: + ": add a unique constraint [" + cols
1473: + "] to table (" + scol.table.name + ").");
1474: }
1475: if (col.name().equals("")) {
1476: scol.name = sf.name;
1477: } else {
1478: scol.name = col.name();
1479: }
1480: scol.allowNull = col.nullable();
1481: // TODO: have a clean assignment of Speedo length/scale wrt
1482: // EJB3 length/precision/scale
1483: scol.length = col.length();
1484: scol.scale = col.scale();
1485: // ? = col.precision();
1486: scol.insertable = col.insertable();
1487: scol.updatable = col.updatable();
1488: if (!col.columnDefinition().equals("")) {
1489: scol.sqlType = col.columnDefinition();
1490: }
1491: sf.addColumn(scol);
1492: logger.log(BasicLevel.DEBUG, sc.getSourceDescShort()
1493: + ": add a column definition for field '" + sf.name
1494: + "' (tabName=" + scol.table.name + ", colName="
1495: + scol.name + ").");
1496: }
1497:
1498: /**
1499: * Parse field meta-information from the Column annotation.
1500: *
1501: * @param col The annotation to extract information from.
1502: * @param sc The SpeedoClass under construction.
1503: * @param sf The SpeedoInheritedField under construction.
1504: */
1505: private void parseOverrideColumn(Column col, SpeedoClass sc,
1506: SpeedoInheritedField sf) {
1507: // TODO: code copy from parseColumn->implement!!
1508: if (col == null) {
1509: return;
1510: }
1511: SpeedoColumn scol = new SpeedoColumn();
1512: if (!col.table().equals("")) {
1513: scol.table = sc.getExtTable(col.table(), true);
1514: } else {
1515: scol.table = sc.mainTable;
1516: }
1517: if (col.unique()) {
1518: ArrayList<SpeedoColumn> cols = new ArrayList<SpeedoColumn>(
1519: 1);
1520: cols.add(scol);
1521: scol.table.addUniqueConstraint(cols);
1522: logger.log(BasicLevel.DEBUG, sc.getSourceDescShort()
1523: + ": add a unique constraint [" + cols
1524: + "] to table (" + scol.table.name + ").");
1525: }
1526: if (col.name().equals("")) {
1527: scol.name = sf.name;
1528: } else {
1529: scol.name = col.name();
1530: }
1531: scol.allowNull = col.nullable();
1532: // TODO: have a clean assignment of Speedo length/scale wrt
1533: // EJB3 length/precision/scale
1534: scol.length = col.length();
1535: scol.scale = col.scale();
1536: // ? = col.precision();
1537: scol.insertable = col.insertable();
1538: scol.updatable = col.updatable();
1539: if (!col.columnDefinition().equals("")) {
1540: scol.sqlType = col.columnDefinition();
1541: }
1542: sf.addColumn(scol);
1543: logger.log(BasicLevel.DEBUG, sc.getSourceDescShort()
1544: + ": add a column definition overriding for field '"
1545: + sf.name + "' (tabName=" + scol.table.name
1546: + ", colName=" + scol.name + ").");
1547: }
1548:
1549: /**
1550: * Parse an Id annotation to define the SpeedoIdentifier associated with a
1551: * SpeedoClass.
1552: *
1553: * @param ida The Id annotation.
1554: * @param sc The SpeedoClass under construction.
1555: * @param sf The SpeedoField under construction.
1556: * @return true if the parsed Id is a correctly defined unique field
1557: * identifier with a Long type.
1558: */
1559: private boolean parseId(Id ida, SpeedoClass sc, SpeedoField sf) {
1560: if (ida == null) {
1561: return false;
1562: }
1563: if ((sc.identity != null)
1564: && (sc.identity.objectidJClass != null)) {
1565: // There is an IdClass: verify field conformance
1566: try {
1567: Field f = sc.identity.objectidJClass
1568: .getDeclaredField(sf.name);
1569: if (sf.type.equals(Type.getDescriptor(f.getType()))) {
1570: sf.primaryKey = true;
1571: return false;
1572: }
1573: logger
1574: .log(
1575: BasicLevel.WARN,
1576: sc.getSourceDescShort()
1577: + ": try to define field ("
1578: + sf.name
1579: + ") as an Id field - has not the same type in IdClass ("
1580: + sc.identity.objectidJClass
1581: .getName() + ").");
1582: } catch (NoSuchFieldException e) {
1583: // Field does not exist:
1584: }
1585: // There is no public field in PK class. Look for public accessors
1586: // (getter & setter) for accessing this field.
1587: try {
1588: Method m = sc.identity.objectidJClass
1589: .getDeclaredMethod(toJavaBean("get", sf.name),
1590: EMPTYSIGN);
1591: if (!sf.type.equals(Type.getDescriptor(m
1592: .getReturnType()))) {
1593: nbErrors++;
1594: logger
1595: .log(
1596: BasicLevel.ERROR,
1597: sc.getSourceDescShort()
1598: + ": try to define field getter ("
1599: + m.getName()
1600: + ") for an Id field - has not the same type in IdClass ("
1601: + sc.identity.objectidJClass
1602: .getName() + ").");
1603: return false;
1604: }
1605: } catch (NoSuchMethodException e) {
1606: nbErrors++;
1607: logger
1608: .log(
1609: BasicLevel.ERROR,
1610: sc.getSourceDescShort()
1611: + ": try to find field getter ("
1612: + toJavaBean("get", sf.name)
1613: + ") for an Id field - does not exist in IdClass ("
1614: + sc.identity.objectidJClass
1615: .getName() + ").");
1616: return false;
1617: }
1618: // The getter is OK. Look for the setter.
1619: String mn = toJavaBean("set", sf.name);
1620: for (Method m : sc.identity.objectidJClass
1621: .getDeclaredMethods()) {
1622: if (mn.equals(m.getName())) {
1623: if (m.getParameterTypes().length != 1) {
1624: continue;
1625: }
1626: if (!sf.type.equals(Type.getDescriptor(m
1627: .getParameterTypes()[0]))) {
1628: continue;
1629: }
1630: if (m.getReturnType() != Void.TYPE) {
1631: continue;
1632: }
1633: // The field is a valid primary key element with well-formed
1634: // getter/setter.
1635: sf.primaryKey = true;
1636: return false;
1637: }
1638: }
1639: nbErrors++;
1640: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1641: + ": try to find field setter (" + mn
1642: + ") for an Id field - does not exist in IdClass ("
1643: + sc.identity.objectidJClass.getName() + ").");
1644: return false;
1645: }
1646: // There is no IdClass. Then it should be a unique Long identifier.
1647: if (!sf.type.equals("Ljava/lang/Long;")) {
1648: nbErrors++;
1649: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1650: + ": try to define field (" + sf.name
1651: + ") as an Id - should be 'java.lang.Long'.");
1652: return false;
1653: }
1654: if (sc.identity != null) {
1655: nbErrors++;
1656: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
1657: + ": try to define field (" + sf.name
1658: + ") as an Id - an Id already exist.");
1659: return false;
1660: }
1661: sc.identity = new SpeedoIdentity();
1662: sc.identity.objectidClass = null;
1663: sf.primaryKey = true;
1664: logger.log(BasicLevel.DEBUG, sc.getSourceDescShort()
1665: + ": define field (" + sf.name
1666: + ") as an Id - strategy = "
1667: + sc.identity.getStrategyName() + ".");
1668: return true;
1669: }
1670:
1671: private void parseGeneratedValue(GeneratedValue a, SpeedoClass sc) {
1672: if (a == null) {
1673: sc.identity.strategy = SpeedoIdentity.USER_ID;
1674: return;
1675: }
1676: switch (a.strategy()) {
1677: case TABLE:
1678: sc.identity.strategy = SpeedoIdentity.DATASTORE_OLONG;
1679: break;
1680: case SEQUENCE:
1681: sc.identity.strategy = SpeedoIdentity.DATASTORE_SEQUENCE;
1682: sc.identity.sequenceName = a.generator();
1683: break;
1684: case IDENTITY:
1685: sc.identity.strategy = SpeedoIdentity.DATASTORE_AUTO_ASSIGN;
1686: break;
1687: case AUTO:
1688: sc.identity.strategy = SpeedoIdentity.DATASTORE_OLONG;
1689: break;
1690: default:
1691: sc.identity.strategy = SpeedoIdentity.USER_ID;
1692: break;
1693: }
1694: }
1695:
1696: /**
1697: * Parse a Basic annotation to define complementary information associated
1698: * with a Field.
1699: *
1700: * @param b The Basic annotation.
1701: * @param sc The SpeedoClass under construction.
1702: * @param sf The SpeedoField under construction.
1703: * @param jb true if the field is accessed using the JavaBean model.
1704: */
1705: private void parseBasic(Basic b, SpeedoClass sc, SpeedoField sf,
1706: boolean jb) {
1707: if (b == null) {
1708: return;
1709: }
1710: if (sf.relationType != SpeedoField.NO_BI_RELATION) {
1711: nbErrors++;
1712: logger
1713: .log(
1714: BasicLevel.ERROR,
1715: sc.getSourceDescShort()
1716: + ": an association has already been defined for field ("
1717: + sf.name
1718: + ") - cannot define a Basic mapping.");
1719: return;
1720: }
1721: if (b.fetch() == FetchType.LAZY) {
1722: if (jb) {
1723: parseFetchType(b.fetch(), sc, sf);
1724: }
1725: }
1726: if (!b.optional()) {
1727: if (isValidType(sf.type, PRIMITIVETYPES)) {
1728: sf.nullValue = SpeedoNullValue.NONE;
1729: logger
1730: .log(
1731: BasicLevel.WARN,
1732: sc.getSourceDescShort()
1733: + ": try to define not null constraint on field ("
1734: + sf.name
1735: + ") - cannot apply to primitive types.");
1736: } else {
1737: sf.nullValue = SpeedoNullValue.EXCEPTION;
1738: }
1739: } else {
1740: sf.nullValue = SpeedoNullValue.NONE;
1741: }
1742: }
1743:
1744: /**
1745: * Parse a FetchType associated to a given field.
1746: *
1747: * @param ft The FetchType to parse.
1748: * @param sc The SpeedoClass under construction.
1749: * @param sf The SpeedoField under construction.
1750: */
1751: void parseFetchType(FetchType ft, SpeedoClass sc, SpeedoField sf) {
1752: //TODO: support of fetch type for field (LAZY or EAGER).
1753: }
1754:
1755: /**
1756: * Parse a Lob annotation to define complementary information associated
1757: * with a Field.
1758: *
1759: * @param l The Lob annotation.
1760: * @param sc The SpeedoClass under construction.
1761: * @param sf The SpeedoField under construction.
1762: * @param jb true if the field is accessed using the JavaBean model.
1763: */
1764: private void parseLob(Lob l, SpeedoClass sc, SpeedoField sf,
1765: boolean jb) {
1766: if (l == null) {
1767: return;
1768: }
1769: }
1770:
1771: /**
1772: * Parse a CascadeType annotation associated to a given field.
1773: *
1774: * @param a The CascadeType.
1775: * @param sf The SpeedoField under construction.
1776: */
1777: private void parseCascadeType(CascadeType aa[], SpeedoField sf) {
1778: for (CascadeType a : aa) {
1779: switch (a) {
1780: case ALL:
1781: sf.propagate |= SpeedoField.PROPAG_ALL;
1782: return;
1783: case PERSIST:
1784: sf.propagate |= SpeedoField.PROPAG_PERSIST;
1785: break;
1786: case MERGE:
1787: sf.propagate |= SpeedoField.PROPAG_MERGE;
1788: break;
1789: case REMOVE:
1790: sf.propagate |= SpeedoField.PROPAG_REMOVE;
1791: break;
1792: case REFRESH:
1793: sf.propagate |= SpeedoField.PROPAG_REFRESH;
1794: break;
1795: default:
1796: break;
1797: }
1798: }
1799: }
1800:
1801: /**
1802: * Parse a ManyToOne annotation to define information related to the
1803: * association.
1804: *
1805: * @param a The ManyToOne annotation to be parsed.
1806: * @param sc The SpeedoClass under construction.
1807: * @param sf The SpeedoField under construction.
1808: */
1809: private void parseManyToOne(ManyToOne a, SpeedoClass sc,
1810: SpeedoField sf) {
1811: if (a == null) {
1812: return;
1813: }
1814: if (a.targetEntity() != null) {
1815: // Temporarily stores type name of target association entity into
1816: // field type for verification purpose at type parsing.
1817: sf.type = a.targetEntity().getName();
1818: }
1819: parseCascadeType(a.cascade(), sf);
1820: if (a.fetch() == FetchType.LAZY) {
1821: parseFetchType(a.fetch(), sc, sf);
1822: }
1823: if (!a.optional()) {
1824: sf.nullValue = SpeedoNullValue.EXCEPTION;
1825: } else {
1826: sf.nullValue = SpeedoNullValue.NONE;
1827: }
1828: }
1829:
1830: /**
1831: * Parse a OneToOne annotation to define information related to the
1832: * association.
1833: *
1834: * @param a The OneToOne annotation to be parsed.
1835: * @param sc The SpeedoClass under construction.
1836: * @param sf The SpeedoField under construction.
1837: */
1838: private void parseOneToOne(OneToOne a, SpeedoClass sc,
1839: SpeedoField sf) {
1840: if (a == null) {
1841: return;
1842: }
1843: if (a.targetEntity() != null) {
1844: // Temporarily stores type name of target association entity into
1845: // field type for verification purpose at type parsing.
1846: sf.type = a.targetEntity().getName();
1847: }
1848: parseCascadeType(a.cascade(), sf);
1849: if (a.fetch() == FetchType.LAZY) {
1850: parseFetchType(a.fetch(), sc, sf);
1851: }
1852: if (!a.optional()) {
1853: sf.nullValue = SpeedoNullValue.EXCEPTION;
1854: } else {
1855: sf.nullValue = SpeedoNullValue.NONE;
1856: }
1857: if (!a.mappedBy().equals("")) {
1858: sf.reverseField = a.mappedBy();
1859: sf.mappedByReversefield = true;
1860: }
1861: }
1862:
1863: /**
1864: * Parse a OneToMany annotation to define information related to the
1865: * association.
1866: *
1867: * @param a The OneToMany annotation to be parsed.
1868: * @param sc The SpeedoClass under construction.
1869: * @param sf The SpeedoField under construction.
1870: */
1871: private void parseOneToMany(OneToMany a, SpeedoClass sc,
1872: SpeedoField sf) {
1873: if (a == null) {
1874: return;
1875: }
1876: if (a.targetEntity() != null) {
1877: // Temporarily stores type name of target association entity into
1878: // field type for verification purpose at type parsing.
1879: sf.type = a.targetEntity().getName();
1880: }
1881: parseCascadeType(a.cascade(), sf);
1882: if (a.fetch() == FetchType.LAZY) {
1883: parseFetchType(a.fetch(), sc, sf);
1884: }
1885: sf.nullValue = SpeedoNullValue.NONE;
1886: if (a.mappedBy().equals("")) {
1887: nbErrors++;
1888: logger
1889: .log(
1890: BasicLevel.ERROR,
1891: sc.getSourceDescShort()
1892: + ": OneToMany association must define the reverse field that specify the mapping for field ("
1893: + sf.name + ").");
1894: return;
1895: }
1896: sf.reverseField = a.mappedBy();
1897: sf.mappedByReversefield = true;
1898: }
1899:
1900: /**
1901: * Parse a ManyToMany annotation to define information related to the
1902: * association.
1903: *
1904: * @param a The ManyToMany annotation to be parsed.
1905: * @param sc The SpeedoClass under construction.
1906: * @param sf The SpeedoField under construction.
1907: */
1908: private void parseManyToMany(ManyToMany a, SpeedoClass sc,
1909: SpeedoField sf) {
1910: if (a == null) {
1911: return;
1912: }
1913: if (a.targetEntity() != null) {
1914: // Temporarily stores type name of target association entity into
1915: // field type for verification purpose at type parsing.
1916: sf.type = a.targetEntity().getName();
1917: }
1918: parseCascadeType(a.cascade(), sf);
1919: if (a.fetch() == FetchType.LAZY) {
1920: parseFetchType(a.fetch(), sc, sf);
1921: }
1922: sf.nullValue = SpeedoNullValue.NONE;
1923: if (!a.mappedBy().equals("")) {
1924: sf.reverseField = a.mappedBy();
1925: sf.mappedByReversefield = true;
1926: }
1927: }
1928:
1929: /**
1930: * Parse a JoinTable annotation to define the mapping of a "m-n"
1931: * association field.
1932: *
1933: * @param jt The JoinTable annotation to be parsed.
1934: * @param sc The SpeedoClass under construction.
1935: * @param sf The SpeedoField under construction.
1936: */
1937: private void parseJoinTable(JoinTable jt, SpeedoClass sc,
1938: SpeedoField sf) {
1939: if (sf.mappedByReversefield) {
1940: nbErrors++;
1941: logger
1942: .log(
1943: BasicLevel.ERROR,
1944: sc.getSourceDescShort()
1945: + ": mapping is supposed to be defined by the reverse field for field ("
1946: + sf.name
1947: + ") - mapping information ignored.");
1948: return;
1949: }
1950: sf.join = new SpeedoJoin();
1951: /*TODO sf.join.extTable = parseTable(jt.table(), sc, null);*/
1952: sf.join.mainTable = sc.mainTable;
1953: // Parse joinColumns from JoinTable (may be empty)
1954: for (JoinColumn jc : jt.joinColumns()) {
1955: SpeedoJoinColumn sjcol = new SpeedoJoinColumn();
1956: sjcol.column = new SpeedoColumn();
1957: if (jc.referencedColumnName().equals("")) {
1958: if (jc.name().equals("")) {
1959: nbErrors++;
1960: logger
1961: .log(
1962: BasicLevel.ERROR,
1963: sc.getSourceDescShort()
1964: + ": must define at least columnName or referencedColumnName for m-n relationship field ("
1965: + sf.name
1966: + ") - mapping information ignored.");
1967: continue;
1968: }
1969: sjcol.column.name = jc.name();
1970: sjcol.column.targetColumn = sjcol.column.name;
1971: } else {
1972: sjcol.column.targetColumn = jc.referencedColumnName();
1973: if (jc.name().equals("")) {
1974: sjcol.column.name = sjcol.column.targetColumn;
1975: } else {
1976: sjcol.column.name = jc.name();
1977: }
1978: }
1979: sjcol.targetColumn = sjcol.column.targetColumn;
1980: sjcol.column.table = sf.join.mainTable;
1981: sf.join.columns.add(sjcol);
1982: }
1983: // parse inverseJoinColumns from JoinTable
1984: for (JoinColumn jc : jt.inverseJoinColumns()) {
1985: SpeedoColumn scol = new SpeedoColumn();
1986: if (jc.referencedColumnName().equals("")) {
1987: if (jc.name().equals("")) {
1988: nbErrors++;
1989: logger
1990: .log(
1991: BasicLevel.ERROR,
1992: sc.getSourceDescShort()
1993: + ": must define at least columnName or referencedColumnName for m-n relationship field ("
1994: + sf.name
1995: + ") - mapping information ignored.");
1996: continue;
1997: }
1998: scol.name = jc.name();
1999: scol.targetColumn = scol.name;
2000: } else {
2001: scol.targetColumn = jc.referencedColumnName();
2002: if (jc.name().equals("")) {
2003: scol.name = scol.targetColumn;
2004: } else {
2005: scol.name = jc.name();
2006: }
2007: }
2008: sf.addColumn(scol);
2009: }
2010: }
2011:
2012: /**
2013: * Parse an array of JoinColumn annotations to define the mapping of a
2014: * reference or association field with a one or many cardinality.
2015: *
2016: * @param jcs The array of JoinColumn annotation to be parsed.
2017: * @param sc The SpeedoClass under construction.
2018: * @param sf The SpeedoField under construction.
2019: */
2020: private void parseJoinColumns(JoinColumn[] jcs, SpeedoClass sc,
2021: SpeedoField sf) {
2022: if (sf.mappedByReversefield) {
2023: nbErrors++;
2024: logger
2025: .log(
2026: BasicLevel.ERROR,
2027: sc.getSourceDescShort()
2028: + ": mapping is supposed to be defined by the reverse field for field ("
2029: + sf.name
2030: + ") - mapping information ignored.");
2031: return;
2032: }
2033: if (sf.relationType == SpeedoField.MANY_REFERENCE) {
2034: sf.join = new SpeedoJoin();
2035: }
2036: for (JoinColumn jc : jcs) {
2037: SpeedoColumn scol = new SpeedoColumn();
2038: scol.targetColumn = jc.referencedColumnName();
2039: if (scol.targetColumn.equals("")) {
2040: if (jcs.length > 1) {
2041: nbErrors++;
2042: logger
2043: .log(
2044: BasicLevel.ERROR,
2045: sc.getSourceDescShort()
2046: + ": try to define the join of a reference or association field ("
2047: + sf.name
2048: + ") without defining names of referenced columns.");
2049: continue;
2050: }
2051: }
2052: if (jc.name().equals("")) {
2053: if (jcs.length > 1) {
2054: nbErrors++;
2055: logger
2056: .log(
2057: BasicLevel.ERROR,
2058: sc.getSourceDescShort()
2059: + ": try to define the join of a reference or association field ("
2060: + sf.name
2061: + ") without defining names of join columns.");
2062: continue;
2063: }
2064: scol.name = sf.name + "_" + scol.targetColumn;
2065: } else {
2066: scol.name = jc.name();
2067: }
2068: if (!jc.table().equals("")) {
2069: scol.table = sc.getExtTable(jc.table(), true);
2070: } else {
2071: scol.table = sc.mainTable;
2072: }
2073: if (sf.relationType == SpeedoField.MANY_REFERENCE) {
2074: if (sf.join.mainTable == null) {
2075: sf.join.mainTable = scol.table;
2076: } else if (sf.join.mainTable != scol.table) {
2077: nbErrors++;
2078: logger
2079: .log(
2080: BasicLevel.ERROR,
2081: sc.getSourceDescShort()
2082: + ": cannot map the reference field ("
2083: + sf.name
2084: + ") to columns belonging to several tables.");
2085: continue;
2086: }
2087: }
2088: SpeedoColumn fscol = sc.getColumn(scol.name, false);
2089: if ((fscol != null) && (fscol.table == scol.table)) {
2090: nbErrors++;
2091: logger
2092: .log(
2093: BasicLevel.ERROR,
2094: sc.getSourceDescShort()
2095: + ": cannot define a column twice for column named ("
2096: + scol.name + ").");
2097: continue;
2098: }
2099: if (sf.relationType == SpeedoField.MANY_REFERENCE) {
2100: sf.join.columns.add(scol);
2101: } else {
2102: sf.addColumn(scol);
2103: }
2104: }
2105: }
2106:
2107: /**
2108: * Parse an EmbeddedId annotation to define the SpeedoIdentifier associated with a
2109: * SpeedoClass.
2110: *
2111: * @param ida The Id annotation to be parsed.
2112: * @param sc The SpeedoClass under construction.
2113: * @param sf The SpeedoField under construction.
2114: */
2115: private void parseEmbeddedId(EmbeddedId ida, SpeedoClass sc,
2116: SpeedoField sf) {
2117: if (ida == null) {
2118: return;
2119: }
2120: if (sc.identity != null) {
2121: nbErrors++;
2122: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
2123: + ": try to define field (" + sf.name
2124: + ") as an EmbeededId - an Id already exist.");
2125: return;
2126: }
2127: try {
2128: sc.identity = new SpeedoIdentity();
2129: sc.identity.objectidClass = sf.getClassName();
2130: sc.identity.objectidJClass = Class.forName(Type.getType(
2131: sf.type).getClassName(), false, annotCL);
2132: sc.identity.strategy = SpeedoIdentity.USER_ID;
2133: if (parsePkClass(sc)) {
2134: logger.log(BasicLevel.DEBUG, sc.getSourceDescShort()
2135: + ": define field (" + sf.name
2136: + ") as an EmbeddedId - Id class= '"
2137: + sc.identity.objectidClass + "'.");
2138: }
2139: } catch (ClassNotFoundException e) {
2140: nbErrors++;
2141: logger.log(BasicLevel.ERROR, sc.getSourceDescShort()
2142: + ": try to define field (" + sf.name
2143: + ") as an EmbeddedId - Id class not found("
2144: + Type.getType(sf.type).getClassName() + ").");
2145: return;
2146: }
2147: }
2148:
2149: /**
2150: * Parse the unique constraints definition for a particular table.
2151: * @param ucs The constraints to be parsed.
2152: * @param sc The SpeedoClass under construction.
2153: * @param t The SpeedoTable to which the constraints should be associated.
2154: */
2155: private void parseUniqueConstraints(UniqueConstraint[] ucs,
2156: SpeedoClass sc, SpeedoTable t) {
2157: for (int i = 0; i < ucs.length; i++) { // iterate over constraints
2158: ArrayList cols = new ArrayList();
2159: int j;
2160: for (j = 0; j < ucs[i].columnNames().length; j++) {
2161: // Look for the column in those defined within the SpeedoClass
2162: SpeedoColumn c = searchColumn(sc,
2163: ucs[i].columnNames()[j], t);
2164: // Did not find the column
2165: if (c == null) {
2166: nbErrors++;
2167: logger
2168: .log(
2169: BasicLevel.ERROR,
2170: sc.getSourceDescShort()
2171: + ": try to associate a unique constraint with a column ("
2172: + ucs[i].columnNames()[j]
2173: + ") that does not exist (ignored).");
2174: break;
2175: }
2176: // Insert (sorted) the column into the list specifying the constraint
2177: Iterator itc = cols.iterator();
2178: int pos = 0;
2179: while (itc.hasNext()) {
2180: SpeedoColumn ct = (SpeedoColumn) itc.next();
2181: if (c == ct) { // already present: ignored
2182: pos = -1;
2183: break;
2184: }
2185: if (c.name.compareTo(ct.name) > 0) {
2186: pos++;
2187: continue;
2188: }
2189: break;
2190: }
2191: if (pos != -1) {
2192: cols.add(pos, c);
2193: }
2194: }
2195: if (cols.size() == 0) { // empty constraint: ignore
2196: logger
2197: .log(
2198: BasicLevel.WARN,
2199: sc.getSourceDescShort()
2200: + ": table ("
2201: + t.name
2202: + ") has an empty unique constraint (ignored).");
2203: continue;
2204: }
2205: if (j == ucs[i].columnNames().length) {
2206: // The list of columns is consistent: create the constraint.
2207: if (!t.addUniqueConstraint(cols)) {
2208: logger.log(BasicLevel.WARN, sc.getSourceDescShort()
2209: + ": unique constraint " + cols
2210: + " already defined (ignored).");
2211: } else {
2212: logger.log(BasicLevel.DEBUG, sc
2213: .getSourceDescShort()
2214: + ": add a unique constraint "
2215: + cols
2216: + " to table (" + t.name + ").");
2217: }
2218: }
2219: }
2220: }
2221:
2222: /**
2223: * Parse a table definition.
2224: *
2225: * @param t The Table annotation to be parsed.
2226: * @param sc The SpeedoClass under construction.
2227: * @param st The SpeedoTable under construction.
2228: */
2229: private SpeedoTable parseTable(Table t, SpeedoClass sc,
2230: SpeedoTable st) {
2231: if (st == null) {
2232: st = new SpeedoTable();
2233: }
2234: if (!t.name().equals("")) {
2235: st.name = t.name();
2236: }
2237: if (!t.catalog().equals("")) {
2238: st.catalog = t.catalog();
2239: }
2240: if (!t.schema().equals("")) {
2241: st.schema = t.schema();
2242: }
2243: parseUniqueConstraints(t.uniqueConstraints(), sc, st);
2244: return st;
2245: }
2246:
2247: /**
2248: * Parse a secondary table definition.
2249: *
2250: * @param st The SecondaryTable annotation definition.
2251: * @param sc The SpeedoClass under construction.
2252: */
2253: private void parseSecondaryTable(SecondaryTable st, SpeedoClass sc) {
2254: for (SpeedoJoin sj : sc.joinToExtTables) {
2255: if (!sj.extTable.name.equals(st.name())) {
2256: continue;
2257: }
2258: if (!st.catalog().equals("")) {
2259: sj.extTable.catalog = st.catalog();
2260: }
2261: if (!st.schema().equals("")) {
2262: sj.extTable.schema = st.schema();
2263: }
2264: for (PrimaryKeyJoinColumn jc : st.pkJoinColumns()) {
2265: SpeedoJoinColumn sjc = new SpeedoJoinColumn();
2266: // Parse the colum name within the secondary table under definition
2267: if (jc.name().equals("")) {
2268: nbErrors++;
2269: logger
2270: .log(
2271: BasicLevel.ERROR,
2272: sc.getSourceDescShort()
2273: + ": try to define the secondary table ("
2274: + st.name()
2275: + ") without defining names of FK join columns.");
2276: continue;
2277: } else {
2278: sjc.column = searchColumn(sc, jc.name(),
2279: sj.extTable);
2280: if (sjc.column == null) {
2281: // Unknown column: define a new one
2282: sjc.column = new SpeedoColumn();
2283: sjc.column.name = jc.name();
2284: sjc.column.sqlType = jc.columnDefinition();
2285: sjc.column.table = sj.extTable;
2286: }
2287: }
2288: // Parse the target column within the main table
2289: sjc.targetColumn = jc.referencedColumnName();
2290: if (sjc.targetColumn.equals("")) {
2291: if (st.pkJoinColumns().length > 1) {
2292: nbErrors++;
2293: logger
2294: .log(
2295: BasicLevel.ERROR,
2296: sc.getSourceDescShort()
2297: + ": try to define a secondary table ("
2298: + st.name()
2299: + ") without defining names of referenced columns in main table.");
2300: continue;
2301: }
2302: SpeedoField sf;
2303: try {
2304: sf = sc.getUniquePKField();
2305: } catch (SpeedoException e) {
2306: nbErrors++;
2307: logger
2308: .log(
2309: BasicLevel.ERROR,
2310: sc.getSourceDescShort()
2311: + ": cannot find a unique PK column to define referenced column for secondary table ("
2312: + st.name() + ").");
2313: continue;
2314: }
2315: if (sf.columns.length != 1) {
2316: nbErrors++;
2317: logger
2318: .log(
2319: BasicLevel.ERROR,
2320: sc.getSourceDescShort()
2321: + ": cannot find a unique PK column to define referenced column for secondary table ("
2322: + st.name() + ").");
2323: continue;
2324: }
2325: sjc.targetColumn = sf.columns[0].name;
2326: } else {
2327: if (sc.getColumn(sjc.targetColumn, true) == null) {
2328: nbErrors++;
2329: logger
2330: .log(
2331: BasicLevel.ERROR,
2332: sc.getSourceDescShort()
2333: + ": referenced column ("
2334: + sjc.targetColumn
2335: + ") is not a column of the main table for secondary table ("
2336: + st.name() + ").");
2337: continue;
2338: }
2339: }
2340: sj.columns.add(sjc);
2341: }
2342: logger.log(BasicLevel.DEBUG, sc.getSourceDescShort()
2343: + ": secondary table (" + sj.extTable.name
2344: + ") - define join columns [" + sj.columns + "].");
2345: parseUniqueConstraints(st.uniqueConstraints(), sc,
2346: sj.extTable);
2347: return;
2348: }
2349: logger
2350: .log(
2351: BasicLevel.WARN,
2352: sc.getSourceDescShort()
2353: + ": try to define a secondary table ("
2354: + st.name()
2355: + ") that is unused for the mapping of this class - ignored.");
2356: }
2357:
2358: /**
2359: *
2360: *
2361: * @param ao
2362: * @param aos
2363: * @param sc
2364: */
2365: private void parseAttributeOverriding(AttributeOverride ao,
2366: AttributeOverrides aos, SpeedoClass sc) {
2367: if ((aos == null) && (ao == null)) {
2368: return;
2369: }
2370: if (sc.inheritance == null) {
2371: nbErrors++;
2372: logger
2373: .log(
2374: BasicLevel.ERROR,
2375: sc.getSourceDescShort()
2376: + ": cannot override attribute if no inheritance defined for this class - overriding ignored");
2377: return;
2378: }
2379: AttributeOverride[] target; // The array of AttributeOverride to be annalysed
2380: if (aos == null) {
2381: target = new AttributeOverride[] { ao };
2382: } else {
2383: if (ao != null) {
2384: target = new AttributeOverride[aos.value().length + 1];
2385: System.arraycopy(aos.value(), 0, target,
2386: aos.value().length, 0);
2387: target[aos.value().length] = ao;
2388: } else {
2389: target = aos.value();
2390: }
2391: }
2392: // target is completed; perform analysis
2393: for (AttributeOverride a : target) {
2394: // TODO:
2395: // Look for the field in inherited classes
2396: SpeedoField inhsf = sc.getInheritedField(a.name());
2397: if (inhsf == null) {
2398: nbErrors++;
2399: logger
2400: .log(
2401: BasicLevel.ERROR,
2402: sc.getSourceDescShort()
2403: + ": overriden attribute does not exist in inherited class - overriding ignored");
2404: continue;
2405: }
2406: SpeedoInheritedField sif = sc.inheritance
2407: .newSpeedoInheritedField(inhsf);
2408: parseOverrideColumn(a.column(), sc, sif);
2409: }
2410: }
2411:
2412: /**
2413: *
2414: *
2415: * @param ao
2416: * @param aos
2417: * @param sc
2418: * @param sf
2419: */
2420: private void parseEmbeddedOverriding(AttributeOverride ao,
2421: AttributeOverrides aos, SpeedoClass sc, SpeedoField sf) {
2422: // TODO:
2423: }
2424:
2425: public static final String[] CBNAMES = { "PrePersist",
2426: "PostPersist", "PreRemove", "PostRemove", "PreUpdate",
2427: "PostUpdate", "PostLoad" };
2428: public static final int[] CBIDS = { HomeItf.PRE_NEW,
2429: HomeItf.POST_CREATE, HomeItf.PRE_REMOVE,
2430: HomeItf.POST_DELETE, HomeItf.PRE_UPDATE,
2431: HomeItf.POST_UPDATE, HomeItf.POST_LOAD };
2432: public static final Class[] CBCLASSES = { PrePersist.class,
2433: PostPersist.class, PreRemove.class, PostRemove.class,
2434: PreUpdate.class, PostUpdate.class, PostLoad.class };
2435:
2436: /**
2437: * Parse the callbacks defined either within the class or within an external
2438: * listener class.
2439: *
2440: * @param meths The methods from which to look for callbacks.
2441: * @param sc The SpeedoClass under construction.
2442: * @param listener The listener class if the callback belongs to such a class.
2443: */
2444: private void parseCallBacks(Method[] meths, SpeedoClass sc,
2445: Class listener) {
2446: // Look for callback methods
2447: SpeedoCallback scb = null;
2448: for (Method m : meths) {
2449: int i = 0;
2450: for (Class annotc : CBCLASSES) {
2451: if (m.getAnnotation(annotc) == null) {
2452: i++;
2453: continue;
2454: }
2455: ArrayList cbl = (ArrayList) sc.callBacks.get(CBIDS[i]);
2456: if (scb == null) {
2457: scb = new SpeedoCallback();
2458: }
2459: if (cbl != null) {
2460: logger.log(BasicLevel.WARN, sc.getSourceDescShort()
2461: + ": " + CBNAMES[i] + " callback - "
2462: + "already defined.");
2463: } else {
2464: cbl = new ArrayList();
2465: sc.callBacks.put(CBIDS[i], cbl);
2466: }
2467: scb.methodByteCodeSignature = isWellFormedCallback(m,
2468: listener, sc, CBNAMES[i]);
2469: if (scb.methodByteCodeSignature == null) {
2470: continue;
2471: }
2472: logger
2473: .log(BasicLevel.DEBUG, sc.getSourceDescShort()
2474: + ": new callback defined ("
2475: + CBNAMES[i]
2476: + ", "
2477: + ((listener == null) ? "" : listener
2478: .getName()) + m.getName() + ")");
2479: scb.callbackName = m.getName();
2480: scb.callbackType = CBIDS[i];
2481: scb.listenerClassName = (listener != null) ? listener
2482: .getName() : null;
2483: cbl.add(scb);
2484: scb = null;
2485: }
2486: }
2487: }
2488:
2489: /**
2490: * Search a column within those associated to this class.
2491: *
2492: * @param sc The SpeedoClass under construction.
2493: * @param cname The name of the column to be searched.
2494: * @param t The SpeedoTable to which it should belong.
2495: * @return The column found or null if none.
2496: */
2497: private SpeedoColumn searchColumn(SpeedoClass sc, String cn,
2498: SpeedoTable t) {
2499: SpeedoColumn c = null;
2500: Iterator itf = sc.fields.values().iterator();
2501: while (itf.hasNext()) {
2502: SpeedoField ft = (SpeedoField) itf.next();
2503: for (int k = 0; k < ft.columns.length; k++) {
2504: if (ft.columns[k].table != t) {
2505: continue;
2506: }
2507: if (ft.columns[k].name.equals(cn)) {
2508: c = ft.columns[k];
2509: break;
2510: }
2511: }
2512: }
2513: return c;
2514: }
2515:
2516: /**
2517: * Verify if the callback method is well formed. If this is a callback from
2518: * the class (prefix is ""), it should be "void CALLBACK()". If it is a
2519: * callback from the listener class, it should be "void CALLBACK(Object)".
2520: *
2521: * @param m The method associated to the callback event.
2522: * @param listener The listener class if the callback belongs to such a class.
2523: * @param sc The SpeedoClass under construction.
2524: * @param cbe The callback event under definition.
2525: * @return Null if malformed. Otherwise, it defines the byte code
2526: * signature of the callback method.
2527: */
2528: private String isWellFormedCallback(Method m, Class listener,
2529: SpeedoClass sc, String cbe) {
2530: String res = "(";
2531: if (m.getReturnType() != Void.TYPE) {
2532: nbErrors++;
2533: logger
2534: .log(
2535: BasicLevel.ERROR,
2536: sc.getSourceDescShort()
2537: + ": "
2538: + cbe
2539: + " callback malformed - return type should be void.");
2540: return null;
2541: }
2542: if (listener == null) {
2543: if (m.getParameterTypes().length != 0) {
2544: nbErrors++;
2545: logger
2546: .log(
2547: BasicLevel.ERROR,
2548: sc.getSourceDescShort()
2549: + ": "
2550: + cbe
2551: + " class callback malformed - should not have parameters.");
2552: return null;
2553: }
2554: } else {
2555: if (m.getParameterTypes().length != 1) {
2556: nbErrors++;
2557: logger
2558: .log(
2559: BasicLevel.ERROR,
2560: sc.getSourceDescShort()
2561: + ": "
2562: + cbe
2563: + " listener class callback malformed - should have a unique parameter.");
2564: return null;
2565: }
2566: Class scc;
2567: try {
2568: scc = (Class) Class.forName(sc.getFQName(), false,
2569: annotCL);
2570: } catch (ClassNotFoundException e) {
2571: // Sure to find it there !!!! NPE otherwise...
2572: scc = null;
2573: }
2574: if (!m.getParameterTypes()[0].isAssignableFrom(scc)) {
2575: nbErrors++;
2576: logger
2577: .log(
2578: BasicLevel.ERROR,
2579: sc.getSourceDescShort()
2580: + ": "
2581: + cbe
2582: + " listener class callback malformed - should have a parameter compliant with type ("
2583: + scc.getName()
2584: + "), found ("
2585: + m.getParameterTypes()[0]
2586: .getName() + ").");
2587: return null;
2588: }
2589: res += Type.getDescriptor(m.getParameterTypes()[0]);
2590: }
2591: return res + ")V";
2592: }
2593:
2594: private String toJavaBean(String prefix, String fieldname) {
2595: prefix += Character.toUpperCase(fieldname.charAt(0));
2596: prefix += fieldname.substring(1, fieldname.length());
2597: return prefix;
2598: }
2599:
2600: /**
2601: * Look if the given type belongs to a set of valid ones.
2602: *
2603: * @param type The typeto be verified.
2604: * @param validtypes The set of valid types.
2605: * @return true if it belongs to the given set of types.
2606: */
2607: private boolean isValidType(String type, String[] validtypes) {
2608: for (String t : validtypes) {
2609: if (t.equals(type)) {
2610: return true;
2611: }
2612: }
2613: return false;
2614: }
2615:
2616: /**
2617: * Log a warning for each defined annotations in the annots array.
2618: *
2619: * @param annots The array of annotation that shoudl not be used at this place.
2620: * @param sc The SpeedoClass under construction.
2621: * @param fieldname The name of the field with which these annotations are associated.
2622: * @param kind The kind of field under parsing.
2623: */
2624: private void excludeAnnotation(Object[] annots, SpeedoClass sc,
2625: String fieldname, String kind) {
2626: for (Object annot : annots) {
2627: if (annot != null) {
2628: logger.log(BasicLevel.WARN, sc.getSourceDescShort()
2629: + ": annotation (" + annot.getClass().getName()
2630: + ") invalid for " + kind + " (" + fieldname
2631: + ") - ignored.");
2632: }
2633: }
2634: }
2635: }
2636:
2637: /**
2638: * This ClassLoader is used to load classes that we want to extract the
2639: * annotations from.
2640: *
2641: * @author P. Dechamboux
2642: *
2643: */
2644: class LoaderForAnnotAccess extends URLClassLoader {
2645: Logger logger;
2646:
2647: LoaderForAnnotAccess(Logger log, ClassLoader pcl) {
2648: super (new URL[0], pcl);
2649: logger = log;
2650: }
2651:
2652: void addDirURL(String dir) throws SpeedoException {
2653: try {
2654: String furl = "file://" + dir + "/";
2655: logger.log(BasicLevel.DEBUG,
2656: "Adding URL to compiler class loader: " + furl);
2657: addURL(new URL(furl));
2658: } catch (MalformedURLException e) {
2659: throw new SpeedoXMLError(e);
2660: }
2661: }
2662: }
|