Source Code Cross Referenced for EJBAnnotationParser.java in  » Database-ORM » Speedo_1.4.5 » org » objectweb » speedo » generation » parser » ejb » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » Speedo_1.4.5 » org.objectweb.speedo.generation.parser.ejb 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.