Source Code Cross Referenced for ApplicationIdTool.java in  » Database-ORM » openjpa » org » apache » openjpa » enhance » 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 » openjpa » org.apache.openjpa.enhance 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one
0003:         * or more contributor license agreements.  See the NOTICE file
0004:         * distributed with this work for additional information
0005:         * regarding copyright ownership.  The ASF licenses this file
0006:         * to you under the Apache License, Version 2.0 (the
0007:         * "License"); you may not use this file except in compliance
0008:         * with the License.  You may obtain a copy of the License at
0009:         *
0010:         * http://www.apache.org/licenses/LICENSE-2.0
0011:         *
0012:         * Unless required by applicable law or agreed to in writing,
0013:         * software distributed under the License is distributed on an
0014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015:         * KIND, either express or implied.  See the License for the
0016:         * specific language governing permissions and limitations
0017:         * under the License.    
0018:         */
0019:        package org.apache.openjpa.enhance;
0020:
0021:        import java.io.File;
0022:        import java.io.FileWriter;
0023:        import java.io.IOException;
0024:        import java.io.PrintWriter;
0025:        import java.io.Writer;
0026:        import java.lang.reflect.Modifier;
0027:        import java.security.AccessController;
0028:        import java.util.ArrayList;
0029:        import java.util.Arrays;
0030:        import java.util.Collection;
0031:        import java.util.Date;
0032:        import java.util.HashSet;
0033:        import java.util.Iterator;
0034:        import java.util.List;
0035:        import java.util.Map;
0036:        import java.util.Set;
0037:        import java.util.TreeSet;
0038:
0039:        import org.apache.commons.lang.StringUtils;
0040:        import org.apache.openjpa.conf.OpenJPAConfiguration;
0041:        import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
0042:        import org.apache.openjpa.lib.conf.Configuration;
0043:        import org.apache.openjpa.lib.conf.Configurations;
0044:        import org.apache.openjpa.lib.log.Log;
0045:        import org.apache.openjpa.lib.meta.ClassArgParser;
0046:        import org.apache.openjpa.lib.util.CodeFormat;
0047:        import org.apache.openjpa.lib.util.Files;
0048:        import org.apache.openjpa.lib.util.J2DoPrivHelper;
0049:        import org.apache.openjpa.lib.util.JavaVersions;
0050:        import org.apache.openjpa.lib.util.Localizer;
0051:        import org.apache.openjpa.lib.util.Options;
0052:        import org.apache.openjpa.meta.ClassMetaData;
0053:        import org.apache.openjpa.meta.DelegatingMetaDataFactory;
0054:        import org.apache.openjpa.meta.FieldMetaData;
0055:        import org.apache.openjpa.meta.JavaTypes;
0056:        import org.apache.openjpa.meta.MetaDataFactory;
0057:        import org.apache.openjpa.meta.MetaDataRepository;
0058:        import org.apache.openjpa.util.InvalidStateException;
0059:        import org.apache.openjpa.util.UserException;
0060:        import serp.bytecode.BCClass;
0061:        import serp.bytecode.BCClassLoader;
0062:        import serp.bytecode.Project;
0063:        import serp.util.Strings;
0064:
0065:        /**
0066:         * Generates a class appropriate for use as an application identity class.
0067:         *
0068:         * @author Patrick Linskey
0069:         * @author Abe White
0070:         */
0071:        public class ApplicationIdTool {
0072:
0073:            public static final String TOKEN_DEFAULT = "::";
0074:
0075:            private static final String TOKENIZER_CUSTOM = "Tokenizer";
0076:            private static final String TOKENIZER_STD = "StringTokenizer";
0077:
0078:            private static final Localizer _loc = Localizer
0079:                    .forPackage(ApplicationIdTool.class);
0080:
0081:            private final Log _log;
0082:            private final Class _type;
0083:            private final ClassMetaData _meta;
0084:            private boolean _abstract = false;
0085:            private FieldMetaData[] _fields = null;
0086:            private boolean _ignore = true;
0087:            private File _dir = null;
0088:            private Writer _writer = null;
0089:            private String _code = null;
0090:            private String _token = TOKEN_DEFAULT;
0091:            private CodeFormat _format = null;
0092:
0093:            /**
0094:             * Constructs a new ApplicationIdTool capable of generating an
0095:             * object id class for <code>type</code>.
0096:             */
0097:            public ApplicationIdTool(OpenJPAConfiguration conf, Class type) {
0098:                _log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE);
0099:                _type = type;
0100:
0101:                MetaDataRepository repos = conf.newMetaDataRepositoryInstance();
0102:                repos.setValidate(repos.VALIDATE_NONE);
0103:                repos.setSourceMode(repos.MODE_MAPPING, false);
0104:                loadObjectIds(repos, true);
0105:                _meta = repos.getMetaData(type, null, false);
0106:                if (_meta != null) {
0107:                    _abstract = Modifier.isAbstract(_meta.getDescribedType()
0108:                            .getModifiers());
0109:                    _fields = getDeclaredPrimaryKeyFields(_meta);
0110:                }
0111:            }
0112:
0113:            /**
0114:             * Constructs a new tool instance capable of generating an
0115:             * object id class for <code>meta</code>.
0116:             */
0117:            public ApplicationIdTool(OpenJPAConfiguration conf, Class type,
0118:                    ClassMetaData meta) {
0119:                _log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE);
0120:
0121:                _type = type;
0122:                _meta = meta;
0123:                if (_meta != null) {
0124:                    _abstract = Modifier.isAbstract(_meta.getDescribedType()
0125:                            .getModifiers());
0126:                    _fields = getDeclaredPrimaryKeyFields(_meta);
0127:                }
0128:            }
0129:
0130:            /**
0131:             * Return metadata for primary key fields declared in the given class.
0132:             */
0133:            private static FieldMetaData[] getDeclaredPrimaryKeyFields(
0134:                    ClassMetaData meta) {
0135:                if (meta.getPCSuperclass() == null)
0136:                    return meta.getPrimaryKeyFields();
0137:
0138:                // remove the primary key fields that are not declared
0139:                // in the current class
0140:                FieldMetaData[] fields = meta.getPrimaryKeyFields();
0141:                List decs = new ArrayList(fields.length);
0142:                for (int i = 0; i < fields.length; i++)
0143:                    if (fields[i].getDeclaringType() == meta.getDescribedType())
0144:                        decs.add(fields[i]);
0145:                return (FieldMetaData[]) decs.toArray(new FieldMetaData[decs
0146:                        .size()]);
0147:            }
0148:
0149:            /**
0150:             * Return false if this tool is configured to throw an exception on
0151:             * an attempt to generate an id class for a type that does not use
0152:             * application identity.
0153:             */
0154:            public boolean getIgnoreErrors() {
0155:                return _ignore;
0156:            }
0157:
0158:            /**
0159:             * Set to false if this tool should throw an exception on
0160:             * an attempt to generate an id class for a type that does not use
0161:             * application identity.
0162:             */
0163:            public void setIgnoreErrors(boolean ignore) {
0164:                _ignore = ignore;
0165:            }
0166:
0167:            /**
0168:             * The code formatter for the generated Java code.
0169:             */
0170:            public CodeFormat getCodeFormat() {
0171:                return _format;
0172:            }
0173:
0174:            /**
0175:             * Set the code formatter for the generated Java code.
0176:             */
0177:            public void setCodeFormat(CodeFormat format) {
0178:                _format = format;
0179:            }
0180:
0181:            /**
0182:             * The directory to write source to. Defaults to the directory
0183:             * of the Java file for the set type. If the given directory does not
0184:             * match the package of the object id, the package structure will be
0185:             * created below the directory.
0186:             */
0187:            public File getDirectory() {
0188:                return _dir;
0189:            }
0190:
0191:            /**
0192:             * The directory to write source to. Defaults to the directory
0193:             * of the Java file for the set type. If the given directory does not
0194:             * match the package of the object id, the package structure will be
0195:             * created below the directory.
0196:             */
0197:            public void setDirectory(File dir) {
0198:                _dir = dir;
0199:            }
0200:
0201:            /**
0202:             * The token to use to separate stringified primary key field values.
0203:             */
0204:            public String getToken() {
0205:                return _token;
0206:            }
0207:
0208:            /**
0209:             * The token to use to separate stringified primary key field values.
0210:             */
0211:            public void setToken(String token) {
0212:                _token = token;
0213:            }
0214:
0215:            /**
0216:             * The writer to write source to, or null to write to default file.
0217:             */
0218:            public Writer getWriter() {
0219:                return _writer;
0220:            }
0221:
0222:            /**
0223:             * The writer to write source to, or null to write to default file.
0224:             */
0225:            public void setWriter(Writer writer) {
0226:                _writer = writer;
0227:            }
0228:
0229:            /**
0230:             * Return the type we are generating an application id for.
0231:             */
0232:            public Class getType() {
0233:                return _type;
0234:            }
0235:
0236:            /**
0237:             * Return metadata for the type we are generating an application id for.
0238:             */
0239:            public ClassMetaData getMetaData() {
0240:                return _meta;
0241:            }
0242:
0243:            /**
0244:             * Return the code generated for the application id, or null
0245:             * if invalid class or the {@link #run} method has not been called.
0246:             */
0247:            public String getCode() {
0248:                return _code;
0249:            }
0250:
0251:            /**
0252:             * Returns true if the application identity class should be an inner class.
0253:             */
0254:            public boolean isInnerClass() {
0255:                Class oidClass = _meta.getObjectIdType();
0256:                return oidClass.getName().indexOf('$') != -1;
0257:            }
0258:
0259:            /**
0260:             * Returns the short class name for the object id class.
0261:             */
0262:            private String getClassName() {
0263:                if (_meta.isOpenJPAIdentity())
0264:                    return null;
0265:
0266:                // convert from SomeClass$ID to ID
0267:                String className = Strings
0268:                        .getClassName(_meta.getObjectIdType());
0269:                if (isInnerClass())
0270:                    className = className
0271:                            .substring(className.lastIndexOf('$') + 1);
0272:                return className;
0273:            }
0274:
0275:            /**
0276:             * Generates the sourcecode for the application id class; returns
0277:             * false if the class is invalid.
0278:             */
0279:            public boolean run() {
0280:                if (_log.isInfoEnabled())
0281:                    _log.info(_loc.get("appid-start", _type));
0282:
0283:                // ensure that this type is a candidate for application identity
0284:                if (_meta == null
0285:                        || _meta.getIdentityType() != ClassMetaData.ID_APPLICATION
0286:                        || _meta.isOpenJPAIdentity()) {
0287:                    if (!_ignore)
0288:                        throw new UserException(_loc
0289:                                .get("appid-invalid", _type));
0290:
0291:                    // else just warn
0292:                    if (_log.isWarnEnabled())
0293:                        _log.warn(_loc.get("appid-warn", _type));
0294:                    return false;
0295:                }
0296:
0297:                Class oidClass = _meta.getObjectIdType();
0298:                Class super OidClass = null;
0299:
0300:                // allow diff oid class in subclass (horizontal)
0301:                if (_meta.getPCSuperclass() != null) {
0302:                    super OidClass = _meta.getPCSuperclassMetaData()
0303:                            .getObjectIdType();
0304:                    if (oidClass == null || oidClass.equals(super OidClass)) {
0305:                        // just warn
0306:                        if (_log.isWarnEnabled())
0307:                            _log.warn(_loc.get("appid-warn", _type));
0308:                        return false;
0309:                    }
0310:                }
0311:
0312:                // ensure that an id class is declared
0313:                if (oidClass == null)
0314:                    throw new UserException(_loc.get("no-id-class", _type))
0315:                            .setFatal(true);
0316:
0317:                // ensure there is at least one pk field if we are
0318:                // non-absract, and see if we have any byte[]
0319:                boolean bytes = false;
0320:                for (int i = 0; !bytes && i < _fields.length; i++)
0321:                    bytes = _fields[i].getDeclaredType() == byte[].class;
0322:
0323:                // collect info on id type
0324:                String className = getClassName();
0325:                String packageName = Strings.getPackageName(oidClass);
0326:                String packageDec = "";
0327:                if (packageName.length() > 0)
0328:                    packageDec = "package " + packageName + ";";
0329:
0330:                String imports = getImports();
0331:                String fieldDecs = getFieldDeclarations();
0332:                String constructor = getConstructor(super OidClass != null);
0333:                String properties = getProperties();
0334:                String fromStringCode = getFromStringCode(super OidClass != null);
0335:                String toStringCode = getToStringCode(super OidClass != null);
0336:                String equalsCode = getEqualsCode(super OidClass != null);
0337:                String hashCodeCode = getHashCodeCode(super OidClass != null);
0338:
0339:                // build the java code
0340:                CodeFormat code = newCodeFormat();
0341:                if (!isInnerClass() && packageDec.length() > 0)
0342:                    code.append(packageDec).afterSection();
0343:
0344:                if (!isInnerClass() && imports.length() > 0)
0345:                    code.append(imports).afterSection();
0346:
0347:                code.append("/**").endl().append(" * ").append(
0348:                        _loc.get("appid-comment-for", _type.getName())).endl()
0349:                        .append(" *").endl().append(" * ").append(
0350:                                _loc.get("appid-comment-gen")).endl().append(
0351:                                " * ").append(getClass().getName()).endl()
0352:                        .append(" */").endl();
0353:                code.append("public ");
0354:                if (isInnerClass())
0355:                    code.append("static ");
0356:                code.append("class ").append(className);
0357:                if (code.getBraceOnSameLine())
0358:                    code.append(" ");
0359:                else
0360:                    code.endl().tab();
0361:
0362:                if (super OidClass != null) {
0363:                    code.append("extends "
0364:                            + Strings.getClassName(super OidClass));
0365:                    if (code.getBraceOnSameLine())
0366:                        code.append(" ");
0367:                    else
0368:                        code.endl().tab();
0369:                }
0370:                code.append("implements Serializable").openBrace(1).endl();
0371:
0372:                // if we use a byte array we need a static array for encoding to string
0373:                if (bytes) {
0374:                    code.tab().append("private static final char[] HEX = ")
0375:                            .append("new char[] {").endl();
0376:                    code.tab(2).append(
0377:                            "'0', '1', '2', '3', '4', '5', '6', '7',").endl();
0378:                    code.tab(2)
0379:                            .append("'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'")
0380:                            .endl();
0381:                    code.tab().append("};").endl(2);
0382:                }
0383:
0384:                // static block to register class
0385:                code.tab().append("static").openBrace(2).endl();
0386:                code.tab(2).append("// register persistent class in JVM")
0387:                        .endl();
0388:                if (JavaVersions.VERSION >= 5) {
0389:                    code.tab(2).append("try { Class.forName").openParen(true)
0390:                            .append("\"").append(_type.getName()).append("\"")
0391:                            .closeParen().append(";").append(" }").endl();
0392:                    code.tab(2).append("catch").openParen(true).append(
0393:                            "Exception e").closeParen().append(" {}").endl();
0394:                } else
0395:                    code.tab(2).append("Class c = ").append(_type.getName())
0396:                            .append(".class;").endl();
0397:                code.closeBrace(2);
0398:
0399:                // field declarations
0400:                if (fieldDecs.length() > 0)
0401:                    code.endl(2).append(fieldDecs);
0402:
0403:                // default constructor
0404:                code.afterSection().tab().append("public ").append(className)
0405:                        .parens().openBrace(2).endl();
0406:                code.closeBrace(2);
0407:
0408:                // string constructor
0409:                code.afterSection().append(constructor);
0410:
0411:                // properties
0412:                if (properties.length() > 0)
0413:                    code.afterSection().append(properties);
0414:
0415:                // toString, equals, hashCode methods
0416:                if (toStringCode.length() > 0)
0417:                    code.afterSection().append(toStringCode);
0418:                if (hashCodeCode.length() > 0)
0419:                    code.afterSection().append(hashCodeCode);
0420:                if (equalsCode.length() > 0)
0421:                    code.afterSection().append(equalsCode);
0422:                if (fromStringCode.length() > 0)
0423:                    code.afterSection().append(fromStringCode);
0424:
0425:                // if we have any byte array fields, we have to add the extra
0426:                // methods for handling byte arrays
0427:                if (bytes) {
0428:                    code.afterSection().append(getToBytesByteArrayCode());
0429:                    code.afterSection().append(getToStringByteArrayCode());
0430:                    code.afterSection().append(getEqualsByteArrayCode());
0431:                    code.afterSection().append(getHashCodeByteArrayCode());
0432:                }
0433:
0434:                // base classes might need to define a custom tokenizer
0435:                if (super OidClass == null
0436:                        && getTokenizer(false) == TOKENIZER_CUSTOM)
0437:                    code.afterSection().append(getCustomTokenizerClass());
0438:
0439:                code.endl();
0440:                code.closeBrace(1);
0441:
0442:                _code = code.toString();
0443:
0444:                // if this is an inner class, then indent the entire
0445:                // code unit one tab level
0446:                if (isInnerClass()) {
0447:                    // indent the entire code block one level to make it
0448:                    // a propertly indented innder class
0449:                    _code = code.getTab()
0450:                            + Strings.replace(_code, J2DoPrivHelper
0451:                                    .getLineSeparator(), J2DoPrivHelper
0452:                                    .getLineSeparator()
0453:                                    + code.getTab());
0454:                }
0455:
0456:                return true;
0457:            }
0458:
0459:            /**
0460:             * Writes the generated code to the proper file.
0461:             */
0462:            public void record() throws IOException {
0463:                if (_code == null)
0464:                    return;
0465:
0466:                Writer writer = _writer;
0467:                if (writer == null) {
0468:                    File file = getFile();
0469:                    Files.backup(file, false);
0470:                    writer = new FileWriter(file);
0471:                }
0472:
0473:                PrintWriter printer = new PrintWriter(writer);
0474:                printer.print(_code);
0475:                printer.flush();
0476:
0477:                if (_writer == null)
0478:                    writer.close();
0479:            }
0480:
0481:            /**
0482:             * Return the necessary imports for the class.
0483:             */
0484:            private String getImports() {
0485:                Set pkgs = getImportPackages();
0486:
0487:                CodeFormat imports = newCodeFormat();
0488:                String base = Strings.getPackageName(_meta.getObjectIdType());
0489:                String pkg;
0490:                for (Iterator itr = pkgs.iterator(); itr.hasNext();) {
0491:                    pkg = (String) itr.next();
0492:                    if (pkg.length() > 0 && !"java.lang".equals(pkg)
0493:                            && !base.equals(pkg)) {
0494:                        if (imports.length() > 0)
0495:                            imports.endl();
0496:                        imports.append("import ").append(pkg).append(".*;");
0497:                    }
0498:                }
0499:                return imports.toString();
0500:            }
0501:
0502:            /**
0503:             * Returns the collection of packages that need to be imported.
0504:             */
0505:            public Set getImportPackages() {
0506:                Set pkgs = new TreeSet();
0507:                pkgs.add(Strings.getPackageName(_type));
0508:
0509:                Class super OidClass = null;
0510:                if (_meta != null && _meta.getPCSuperclassMetaData() != null)
0511:                    super OidClass = _meta.getPCSuperclassMetaData()
0512:                            .getObjectIdType();
0513:                if (super OidClass != null)
0514:                    pkgs.add(Strings.getPackageName(super OidClass));
0515:
0516:                pkgs.add("java.io");
0517:                pkgs.add("java.util");
0518:                Class type;
0519:                for (int i = 0; i < _fields.length; i++) {
0520:                    type = _fields[i].getObjectIdFieldType();
0521:                    if (type != byte[].class && type != char[].class
0522:                            && !type.getName().startsWith("java.sql.")) {
0523:                        pkgs.add(Strings.getPackageName(type));
0524:                    }
0525:                }
0526:                return pkgs;
0527:            }
0528:
0529:            /**
0530:             * Return the code to declare all primary key fields.
0531:             */
0532:            private String getFieldDeclarations() {
0533:                CodeFormat code = newCodeFormat();
0534:                for (int i = 0; i < _fields.length; i++) {
0535:                    if (i > 0)
0536:                        code.endl();
0537:                    code.tab().append("public ")
0538:                            .append(getTypeName(_fields[i])).append(" ")
0539:                            .append(_fields[i].getName()).append(";");
0540:                }
0541:                return code.toString();
0542:            }
0543:
0544:            /**
0545:             * Return the type name to declare the given field as.
0546:             */
0547:            private String getTypeName(FieldMetaData fmd) {
0548:                Class type = fmd.getObjectIdFieldType();
0549:                if (type == byte[].class)
0550:                    return "byte[]";
0551:                if (type == char[].class)
0552:                    return "char[]";
0553:                if (type.getName().startsWith("java.sql."))
0554:                    return type.getName();
0555:                return Strings.getClassName(type);
0556:            }
0557:
0558:            /**
0559:             * Return the getters and setters for all primary key fields.
0560:             */
0561:            private String getProperties() {
0562:                if (_meta.getAccessType() == ClassMetaData.ACCESS_FIELD)
0563:                    return "";
0564:
0565:                CodeFormat code = newCodeFormat();
0566:                String propName;
0567:                String typeName;
0568:                for (int i = 0; i < _fields.length; i++) {
0569:                    if (i > 0)
0570:                        code.afterSection();
0571:                    typeName = getTypeName(_fields[i]);
0572:                    propName = StringUtils.capitalize(_fields[i].getName());
0573:
0574:                    code.tab().append("public ").append(typeName).append(" ");
0575:                    if (_fields[i].getDeclaredTypeCode() == JavaTypes.BOOLEAN
0576:                            || _fields[i].getDeclaredTypeCode() == JavaTypes.BOOLEAN_OBJ)
0577:                        code.append("is");
0578:                    else
0579:                        code.append("get");
0580:                    code.append(propName).parens().openBrace(2).endl();
0581:                    code.tab(2).append("return ").append(_fields[i].getName())
0582:                            .append(";").endl();
0583:                    code.closeBrace(2);
0584:                    code.afterSection();
0585:
0586:                    code.tab().append("public void set").append(propName);
0587:                    code.openParen(true).append(typeName).append(" ").append(
0588:                            _fields[i].getName()).closeParen();
0589:                    code.openBrace(2).endl();
0590:                    code.tab(2).append("this.").append(_fields[i].getName())
0591:                            .append(" = ").append(_fields[i].getName()).append(
0592:                                    ";").endl();
0593:                    code.closeBrace(2);
0594:                }
0595:                return code.toString();
0596:            }
0597:
0598:            /**
0599:             * Return the string constructor code.
0600:             */
0601:            private String getConstructor(boolean hasSuperclass) {
0602:                CodeFormat code = newCodeFormat();
0603:                code.tab().append("public ");
0604:                code.append(getClassName());
0605:                code.openParen(true).append("String str").closeParen();
0606:                code.openBrace(2).endl();
0607:
0608:                if (_fields.length != 0
0609:                        || (hasSuperclass && _meta.getPrimaryKeyFields().length > 0)) {
0610:                    code.tab(2).append("fromString").openParen(true).append(
0611:                            "str").closeParen().append(";").endl();
0612:                }
0613:
0614:                code.closeBrace(2);
0615:                return code.toString();
0616:            }
0617:
0618:            /**
0619:             * Create the fromString method that parses the result of our toString
0620:             * method. If we have superclasses with id fields, this will call
0621:             * super.fromString() so that the parent class can parse its own fields.
0622:             */
0623:            private String getFromStringCode(boolean hasSuperclass) {
0624:                // if we are below a concrete class then we cannot declare any
0625:                // more primary key fields; thus, just use the parent invocation
0626:                if (hasConcreteSuperclass())
0627:                    return "";
0628:                if (_fields.length == 0)
0629:                    return "";
0630:                hasSuperclass = hasSuperclass
0631:                        && getDeclaredPrimaryKeyFields(_meta
0632:                                .getPCSuperclassMetaData()).length > 0;
0633:
0634:                String toke = getTokenizer(hasSuperclass);
0635:                CodeFormat code = newCodeFormat();
0636:                if (_abstract || hasSuperclass)
0637:                    code.tab().append("protected ").append(toke).append(
0638:                            " fromString");
0639:                else
0640:                    code.tab().append("private void fromString");
0641:                code.openParen(true).append("String str").closeParen();
0642:                code.openBrace(2).endl();
0643:
0644:                // if we have any Object-type fields, die immediately 
0645:                for (int i = 0; i < _fields.length; i++) {
0646:                    if (_fields[i].getObjectIdFieldType() != Object.class)
0647:                        continue;
0648:                    code.tab(2).append(
0649:                            "throw new UnsupportedOperationException").parens()
0650:                            .append(";").endl();
0651:                    code.closeBrace(2);
0652:                    return code.toString();
0653:                }
0654:
0655:                if (toke != null) {
0656:                    code.tab(2).append(toke).append(" toke = ");
0657:                    if (hasSuperclass) {
0658:                        // call super.fromString(str) to get the tokenizer that was
0659:                        // used to parse the superclass
0660:                        code.append("super.fromString").openParen(true).append(
0661:                                "str").closeParen();
0662:                    } else {
0663:                        // otherwise construct a new tokenizer with the string
0664:                        code.append("new ").append(toke).openParen(true)
0665:                                .append("str");
0666:                        if (toke == TOKENIZER_STD)
0667:                            code.append(", \"").append(_token).append("\"");
0668:                        code.closeParen();
0669:                    }
0670:                    code.append(";").endl();
0671:                }
0672:
0673:                for (int i = 0; i < _fields.length; i++) {
0674:                    if (toke != null) {
0675:                        code.tab(2).append("str = toke.nextToken").parens()
0676:                                .append(";").endl();
0677:                    }
0678:                    code.tab(2).append(getConversionCode(_fields[i], "str"))
0679:                            .endl();
0680:                }
0681:                if (_abstract || hasSuperclass)
0682:                    code.tab(2).append("return toke;").endl();
0683:                code.closeBrace(2);
0684:                return code.toString();
0685:            }
0686:
0687:            /**
0688:             * Returns the type of tokenizer to use, or null if none.
0689:             */
0690:            private String getTokenizer(boolean hasSuperclass) {
0691:                if (!_abstract && !hasSuperclass && _fields.length == 1)
0692:                    return null;
0693:                if (_token.length() == 1)
0694:                    return TOKENIZER_STD;
0695:                return TOKENIZER_CUSTOM;
0696:            }
0697:
0698:            /**
0699:             * Get parsing code for the given field.
0700:             */
0701:            private String getConversionCode(FieldMetaData field, String var) {
0702:                CodeFormat parse = newCodeFormat();
0703:                if (field.getName().equals(var))
0704:                    parse.append("this.");
0705:                parse.append(field.getName()).append(" = ");
0706:
0707:                Class type = field.getObjectIdFieldType();
0708:                if (type == Date.class) {
0709:                    parse.append("new Date").openParen(true).append(
0710:                            "Long.parseLong").openParen(true).append(var)
0711:                            .closeParen().closeParen();
0712:                } else if (type == java.sql.Date.class
0713:                        || type == java.sql.Timestamp.class
0714:                        || type == java.sql.Time.class) {
0715:                    parse.append(type.getName()).append(".valueOf").openParen(
0716:                            true).append(var).closeParen();
0717:                } else if (type == String.class)
0718:                    parse.append(var);
0719:                else if (type == Character.class) {
0720:                    parse.append("new Character").openParen(true).append(var)
0721:                            .append(".charAt").openParen(true).append(0)
0722:                            .closeParen().closeParen();
0723:                } else if (type == byte[].class)
0724:                    parse.append("toBytes").openParen(true).append(var)
0725:                            .closeParen();
0726:                else if (type == char[].class)
0727:                    parse.append(var).append(".toCharArray").parens();
0728:                else if (!type.isPrimitive()) {
0729:                    parse.append("new ").append(Strings.getClassName(type))
0730:                            .openParen(true).append(var).closeParen();
0731:                } else // primitive
0732:                {
0733:                    switch (type.getName().charAt(0)) {
0734:                    case 'b':
0735:                        if (type == boolean.class)
0736:                            parse.append("\"true\".equals").openParen(true)
0737:                                    .append(var).closeParen();
0738:                        else
0739:                            parse.append("Byte.parseByte").openParen(true)
0740:                                    .append(var).closeParen();
0741:                        break;
0742:                    case 'c':
0743:                        parse.append(var).append(".charAt").openParen(true)
0744:                                .append(0).closeParen();
0745:                        break;
0746:                    case 'd':
0747:                        parse.append("Double.parseDouble").openParen(true)
0748:                                .append(var).closeParen();
0749:                        break;
0750:                    case 'f':
0751:                        parse.append("Float.parseFloat").openParen(true)
0752:                                .append(var).closeParen();
0753:                        break;
0754:                    case 'i':
0755:                        parse.append("Integer.parseInt").openParen(true)
0756:                                .append(var).closeParen();
0757:                        break;
0758:                    case 'l':
0759:                        parse.append("Long.parseLong").openParen(true).append(
0760:                                var).closeParen();
0761:                        break;
0762:                    case 's':
0763:                        parse.append("Short.parseShort").openParen(true)
0764:                                .append(var).closeParen();
0765:                        break;
0766:                    }
0767:                }
0768:
0769:                if (!type.isPrimitive() && type != byte[].class) {
0770:                    CodeFormat isNull = newCodeFormat();
0771:                    isNull.append("if").openParen(true).append(
0772:                            "\"null\".equals").openParen(true).append(var)
0773:                            .closeParen().closeParen().endl().tab(3);
0774:                    if (field.getName().equals(var))
0775:                        isNull.append("this.");
0776:                    isNull.append(field.getName()).append(" = null;").endl();
0777:                    isNull.tab(2).append("else").endl();
0778:                    isNull.tab(3).append(parse);
0779:                    parse = isNull;
0780:                }
0781:
0782:                return parse.append(";").toString();
0783:            }
0784:
0785:            /**
0786:             * Return an equality method that compares all pk variables.
0787:             * Must deal correctly with both primitives and objects.
0788:             */
0789:            private String getEqualsCode(boolean hasSuperclass) {
0790:                // if we are below a concrete class then we cannot declare any
0791:                // more primary key fields; thus, just use the parent invocation
0792:                if (hasConcreteSuperclass()
0793:                        || (hasSuperclass && _fields.length == 0))
0794:                    return "";
0795:
0796:                CodeFormat code = newCodeFormat();
0797:                code.tab().append("public boolean equals").openParen(true)
0798:                        .append("Object obj").closeParen().openBrace(2).endl();
0799:
0800:                code.tab(2).append("if").openParen(true).append("this == obj")
0801:                        .closeParen().endl();
0802:                code.tab(3).append("return true;").endl();
0803:
0804:                // call super.equals() if we have a superclass
0805:                String className = getClassName();
0806:                if (hasSuperclass) {
0807:                    code.tab(2).append("if").openParen(true).append(
0808:                            "!super.equals").openParen(true).append("obj")
0809:                            .closeParen().closeParen().endl();
0810:                    code.tab(3).append("return false;").endl();
0811:                } else {
0812:                    code.tab(2).append("if").openParen(true).append(
0813:                            "obj == null || obj.getClass").parens().append(
0814:                            " != ").append("getClass").parens().closeParen()
0815:                            .endl();
0816:                    code.tab(3).append("return false;").endl();
0817:                }
0818:
0819:                String name;
0820:                Class type;
0821:                for (int i = 0; i < _fields.length; i++) {
0822:                    if (i == 0) {
0823:                        code.endl().tab(2).append(className)
0824:                                .append(" other = ").openParen(false).append(
0825:                                        className).closeParen().append(" obj;")
0826:                                .endl();
0827:                    }
0828:
0829:                    // if this is not the first field, add an &&
0830:                    if (i == 0)
0831:                        code.tab(2).append("return ");
0832:                    else
0833:                        code.endl().tab(3).append("&& ");
0834:
0835:                    name = _fields[i].getName();
0836:                    type = _fields[i].getObjectIdFieldType();
0837:                    if (type.isPrimitive()) {
0838:                        code.openParen(false).append(name).append(" == ")
0839:                                .append("other.").append(name).closeParen();
0840:                    } else if (type == byte[].class) {
0841:                        code.openParen(false).append("equals").openParen(true)
0842:                                .append(name).append(", ").append("other.")
0843:                                .append(name).closeParen().closeParen();
0844:                    } else if (type == char[].class) {
0845:                        // ((name == null && other.name == null)
0846:                        //	|| (name != null && String.valueOf (name).
0847:                        //	equals (String.valueOf (other.name))))
0848:                        code.append("(").openParen(false).append(name).append(
0849:                                " == null && other.").append(name).append(
0850:                                " == null").closeParen().endl();
0851:                        code.tab(3).append("|| ");
0852:                        code.openParen(false).append(name).append(" != null ")
0853:                                .append("&& String.valueOf").openParen(true)
0854:                                .append(name).closeParen().append(".").endl();
0855:                        code.tab(3).append("equals").openParen(true).append(
0856:                                "String.valueOf").openParen(true).append(
0857:                                "other.").append(name).closeParen()
0858:                                .closeParen().closeParen().append(")");
0859:                    } else {
0860:                        // ((name == null && other.name == null)
0861:                        //	|| (name != null && name.equals (other.name)))
0862:                        code.append("(").openParen(false).append(name).append(
0863:                                " == null && other.").append(name).append(
0864:                                " == null").closeParen().endl();
0865:                        code.tab(3).append("|| ");
0866:                        code.openParen(false).append(name).append(" != null ")
0867:                                .append("&& ").append(name).append(".equals")
0868:                                .openParen(true).append("other.").append(name)
0869:                                .closeParen().closeParen().append(")");
0870:                    }
0871:                }
0872:
0873:                // no _fields: just return true after checking instanceof
0874:                if (_fields.length == 0)
0875:                    code.tab(2).append("return true;").endl();
0876:                else
0877:                    code.append(";").endl();
0878:
0879:                code.closeBrace(2);
0880:                return code.toString();
0881:            }
0882:
0883:            /**
0884:             * Return a hashCode method that takes into account all
0885:             * primary key values. Must deal correctly with both primitives and objects.
0886:             */
0887:            private String getHashCodeCode(boolean hasSuperclass) {
0888:                // if we are below a concrete class then we cannot declare any
0889:                // more primary key fields; thus, just use the parent invocation
0890:                if (hasConcreteSuperclass()
0891:                        || (hasSuperclass && _fields.length == 0))
0892:                    return "";
0893:
0894:                CodeFormat code = newCodeFormat();
0895:                code.tab().append("public int hashCode").parens().openBrace(2)
0896:                        .endl();
0897:
0898:                if (_fields.length == 0)
0899:                    code.tab(2).append("return 17;").endl();
0900:                else if (_fields.length == 1 && !hasSuperclass) {
0901:                    code.tab(2).append("return ");
0902:                    appendHashCodeCode(_fields[0], code);
0903:                    code.append(";").endl();
0904:                } else {
0905:                    code.tab(2).append("int rs = ");
0906:                    if (hasSuperclass) {
0907:                        // call super.hashCode() if we have a superclass
0908:                        code.append("super.hashCode").openParen(true)
0909:                                .closeParen().append(";");
0910:                    } else
0911:                        code.append("17;");
0912:                    code.endl();
0913:
0914:                    for (int i = 0; i < _fields.length; i++) {
0915:                        code.tab(2).append("rs = rs * 37 + ");
0916:                        appendHashCodeCode(_fields[i], code);
0917:                        code.append(";").endl();
0918:                    }
0919:                    code.tab(2).append("return rs;").endl();
0920:                }
0921:                code.closeBrace(2);
0922:                return code.toString();
0923:            }
0924:
0925:            /**
0926:             * Return true if this class has a concrete superclass.
0927:             */
0928:            private boolean hasConcreteSuperclass() {
0929:                for (ClassMetaData sup = _meta.getPCSuperclassMetaData(); sup != null; sup = sup
0930:                        .getPCSuperclassMetaData()) {
0931:                    if (!Modifier.isAbstract(sup.getDescribedType()
0932:                            .getModifiers()))
0933:                        return true;
0934:                }
0935:                return false;
0936:            }
0937:
0938:            /**
0939:             * Append code calculating the hashcode for the given field.
0940:             */
0941:            private void appendHashCodeCode(FieldMetaData field, CodeFormat code) {
0942:                String name = field.getName();
0943:                if ("rs".equals(name))
0944:                    name = "this." + name;
0945:                Class type = field.getObjectIdFieldType();
0946:                if (type.isPrimitive()) {
0947:                    if (type == boolean.class) {
0948:                        // ((name) ? 1 : 0)
0949:                        code.append("(").openParen(false).append(name)
0950:                                .closeParen().append(" ? 1 : 0").append(")");
0951:                    } else if (type == long.class) {
0952:                        // (int) (name ^ (name >>> 32))
0953:                        code.openParen(false).append("int").closeParen()
0954:                                .append(" ").openParen(false).append(name)
0955:                                .append(" ^ ").openParen(false).append(name)
0956:                                .append(" >>> 32").closeParen().closeParen();
0957:                    } else if (type == double.class) {
0958:                        // (int) (Double.doubleToLongBits (name)
0959:                        //     ^ (Double.doubleToLongBits (name) >>> 32))
0960:                        code.openParen(false).append("int").closeParen()
0961:                                .append(" ").openParen(false).append(
0962:                                        "Double.doubleToLongBits").openParen(
0963:                                        true).append(name).closeParen().endl();
0964:                        code.tab(3).append("^ ").openParen(false).append(
0965:                                "Double.doubleToLongBits").openParen(true)
0966:                                .append(name).closeParen().append(" >>> 32")
0967:                                .closeParen().closeParen();
0968:                    } else if (type == float.class) {
0969:                        // Float.floatToIntBits (name)
0970:                        code.append("Float.floatToIntBits").openParen(true)
0971:                                .append(name).closeParen();
0972:                    } else if (type == int.class)
0973:                        code.append(name);
0974:                    else {
0975:                        // (int) name
0976:                        code.openParen(false).append("int").closeParen()
0977:                                .append(" ").append(name);
0978:                    }
0979:                } else if (type == byte[].class) {
0980:                    // hashCode (name);
0981:                    code.append("hashCode").openParen(true).append(name)
0982:                            .closeParen();
0983:                } else if (type == char[].class) {
0984:                    // ((name == null) ? 0 : String.valueOf (name).hashCode ())
0985:                    code.append("(").openParen(false).append(name).append(
0986:                            " == null").closeParen().append(" ? 0 : ").append(
0987:                            "String.valueOf").openParen(true).append(name)
0988:                            .closeParen().append(".hashCode").parens().append(
0989:                                    ")");
0990:                } else {
0991:                    // ((name == null) ? 0 : name.hashCode ())
0992:                    code.append("(").openParen(false).append(name).append(
0993:                            " == null").closeParen().append(" ? 0 : ").append(
0994:                            name).append(".hashCode").parens().append(")");
0995:                }
0996:            }
0997:
0998:            /**
0999:             * Return a method to create a string containing the primary key
1000:             * values that define the application id object.
1001:             */
1002:            private String getToStringCode(boolean hasSuperclass) {
1003:                // if we are below a concrete class then we cannot declare any
1004:                // more primary key fields; thus, just use the parent invocation
1005:                if (hasConcreteSuperclass()
1006:                        || (hasSuperclass && _fields.length == 0))
1007:                    return "";
1008:
1009:                CodeFormat code = newCodeFormat();
1010:                code.tab().append("public String toString").parens().openBrace(
1011:                        2).endl();
1012:
1013:                String name;
1014:                Class type;
1015:                String appendDelimiter = "+ \"" + _token + "\" + ";
1016:                for (int i = 0; i < _fields.length; i++) {
1017:                    // if this is not the first field, add a +
1018:                    if (i == 0) {
1019:                        code.tab(2).append("return ");
1020:
1021:                        // add in the super.toString() if we have a parent
1022:                        if (hasSuperclass
1023:                                && getDeclaredPrimaryKeyFields(_meta
1024:                                        .getPCSuperclassMetaData()).length > 0) {
1025:                            code.append("super.toString").parens();
1026:                            code.endl().tab(3).append(appendDelimiter);
1027:                        }
1028:                    } else
1029:                        code.endl().tab(3).append(appendDelimiter);
1030:
1031:                    name = _fields[i].getName();
1032:                    type = _fields[i].getObjectIdFieldType();
1033:                    if (type == String.class)
1034:                        code.append(name);
1035:                    else if (type == byte[].class)
1036:                        code.append("toString").openParen(true).append(name)
1037:                                .closeParen();
1038:                    else if (type == char[].class)
1039:                        code.openParen(true).openParen(true).append(name)
1040:                                .append(" == null").closeParen().append(
1041:                                        " ? \"null\"").append(
1042:                                        ": String.valueOf").openParen(true)
1043:                                .append(name).closeParen().closeParen();
1044:                    else if (type == Date.class)
1045:                        code.openParen(true).openParen(true).append(name)
1046:                                .append(" == null").closeParen().append(
1047:                                        " ? \"null\"").endl().tab(4).append(
1048:                                        ": String.valueOf").openParen(true)
1049:                                .append(name).append(".getTime").parens()
1050:                                .closeParen().closeParen();
1051:                    else
1052:                        code.append("String.valueOf").openParen(true).append(
1053:                                name).closeParen();
1054:                }
1055:
1056:                // no fields; just use ""
1057:                if (_fields.length == 0)
1058:                    code.tab(2).append("return \"\"");
1059:                code.append(";").endl();
1060:                code.closeBrace(2);
1061:                return code.toString();
1062:            }
1063:
1064:            /**
1065:             * Code to convert a string to a byte array.
1066:             *
1067:             * @see org.apache.openjpa.lib.util.Base16Encoder#decode
1068:             */
1069:            private String getToBytesByteArrayCode() {
1070:                CodeFormat code = newCodeFormat();
1071:                code.tab().append("private static byte[] toBytes").openParen(
1072:                        true).append("String s").closeParen().openBrace(2)
1073:                        .endl();
1074:
1075:                code.tab(2).append("if").openParen(true).append(
1076:                        "\"null\".equals").openParen(true).append("s")
1077:                        .closeParen().closeParen().endl();
1078:                code.tab(3).append("return null;").endl(2);
1079:
1080:                code.tab(2).append("int len = s.length").parens().append(";")
1081:                        .endl();
1082:                code.tab(2).append("byte[] r = new byte[len / 2];").endl();
1083:                code.tab(2).append("for").openParen(true).append(
1084:                        "int i = 0; i < r.length; i++").closeParen().openBrace(
1085:                        3).endl();
1086:                code.tab(3).append("int digit1 = s.charAt").openParen(true)
1087:                        .append("i * 2").closeParen().append(", ").append(
1088:                                "digit2 = s.charAt").openParen(true).append(
1089:                                "i * 2 + 1").closeParen().append(";").endl();
1090:                code.tab(3).append("if").openParen(true).append(
1091:                        "digit1 >= '0' && digit1 <= '9'").closeParen().endl();
1092:                code.tab(4).append("digit1 -= '0';").endl();
1093:                code.tab(3).append("else if").openParen(true).append(
1094:                        "digit1 >= 'A' && digit1 <= 'F'").closeParen().endl();
1095:                code.tab(4).append("digit1 -= 'A' - 10;").endl();
1096:                code.tab(3).append("if").openParen(true).append(
1097:                        "digit2 >= '0' && digit2 <= '9'").closeParen().endl();
1098:                code.tab(4).append("digit2 -= '0';").endl();
1099:                code.tab(3).append("else if").openParen(true).append(
1100:                        "digit2 >= 'A' && digit2 <= 'F'").closeParen().endl();
1101:                code.tab(4).append("digit2 -= 'A' - 10;").endl(2);
1102:                code.tab(3).append("r[i] = (byte) ").openParen(false)
1103:                        .openParen(false).append("digit1 << 4").closeParen()
1104:                        .append(" + digit2").closeParen().append(";").endl();
1105:                code.closeBrace(3).endl();
1106:                code.tab(2).append("return r;").endl();
1107:
1108:                code.closeBrace(2);
1109:                return code.toString();
1110:            }
1111:
1112:            /**
1113:             * Code to convert a byte array to a string.
1114:             *
1115:             * @see org.apache.openjpa.lib.util.Base16Encoder#encode
1116:             */
1117:            private String getToStringByteArrayCode() {
1118:                CodeFormat code = newCodeFormat();
1119:                code.tab().append("private static String toString").openParen(
1120:                        true).append("byte[] b").closeParen().openBrace(2)
1121:                        .endl();
1122:
1123:                code.tab(2).append("if").openParen(true).append("b == null")
1124:                        .closeParen().endl();
1125:                code.tab(3).append("return \"null\";").endl(2);
1126:
1127:                code.tab(2).append("StringBuffer r = new StringBuffer")
1128:                        .openParen(true).append("b.length * 2").closeParen()
1129:                        .append(";").endl();
1130:                code.tab(2).append("for").openParen(true).append(
1131:                        "int i = 0; i < b.length; i++").closeParen().endl();
1132:                code.tab(3).append("for").openParen(true).append(
1133:                        "int j = 1; j >= 0; j--").closeParen().endl();
1134:                code.tab(4).append("r.append").openParen(true).append("HEX[")
1135:                        .openParen(false).append("b[i] >> ").openParen(false)
1136:                        .append("j * 4").closeParen().closeParen().append(
1137:                                " & 0xF]").closeParen().append(";").endl();
1138:                code.tab(2).append("return r.toString").parens().append(";")
1139:                        .endl();
1140:
1141:                code.closeBrace(2);
1142:                return code.toString();
1143:            }
1144:
1145:            /**
1146:             * Code to test if two byte arrays are equal.
1147:             */
1148:            private String getEqualsByteArrayCode() {
1149:                CodeFormat code = newCodeFormat();
1150:                code.tab().append("private static boolean equals").openParen(
1151:                        true).append("byte[] b1, byte[] b2").closeParen()
1152:                        .openBrace(2).endl();
1153:
1154:                code.tab(2).append("if").openParen(true).append(
1155:                        "b1 == null && b2 == null").closeParen().endl();
1156:                code.tab(3).append("return true;").endl();
1157:                code.tab(2).append("if").openParen(true).append(
1158:                        "b1 == null || b2 == null").closeParen().endl();
1159:                code.tab(3).append("return false;").endl();
1160:                code.tab(2).append("if").openParen(true).append(
1161:                        "b1.length != b2.length").closeParen().endl();
1162:                code.tab(3).append("return false;").endl();
1163:                code.tab(2).append("for").openParen(true).append(
1164:                        "int i = 0; i < b1.length; i++").closeParen().endl();
1165:                code.tab(3).append("if").openParen(true).append(
1166:                        "b1[i] != b2[i]").closeParen().endl();
1167:                code.tab(4).append("return false;").endl();
1168:                code.tab(2).append("return true;").endl();
1169:
1170:                code.closeBrace(2);
1171:                return code.toString();
1172:            }
1173:
1174:            private String getHashCodeByteArrayCode() {
1175:                CodeFormat code = newCodeFormat();
1176:                code.tab().append("private static int hashCode")
1177:                        .openParen(true).append("byte[] b").closeParen()
1178:                        .openBrace(2).endl();
1179:
1180:                code.tab(2).append("if").openParen(true).append("b == null")
1181:                        .closeParen().endl();
1182:                code.tab(3).append("return 0;").endl();
1183:                code.tab(2).append("int sum = 0;").endl();
1184:                code.tab(2).append("for").openParen(true).append(
1185:                        "int i = 0; i < b.length; i++").closeParen().endl();
1186:                code.tab(3).append("sum += b[i];").endl();
1187:                code.tab(2).append("return sum;").endl();
1188:
1189:                code.closeBrace(2);
1190:                return code.toString();
1191:            }
1192:
1193:            /**
1194:             * Code defining a tokenizer class.
1195:             */
1196:            private String getCustomTokenizerClass() {
1197:                CodeFormat code = newCodeFormat();
1198:                code.tab().append("protected static class ").append(
1199:                        TOKENIZER_CUSTOM).openBrace(2).endl();
1200:
1201:                code.tab(2).append("private final String str;").endl();
1202:                code.tab(2).append("private int last;").afterSection();
1203:
1204:                code.tab(2).append("public Tokenizer (String str)")
1205:                        .openBrace(3).endl();
1206:                code.tab(3).append("this.str = str;").endl();
1207:                code.closeBrace(3).afterSection();
1208:
1209:                code.tab(2).append("public String nextToken ()").openBrace(3)
1210:                        .endl();
1211:                code.tab(3).append("int next = str.indexOf").openParen(true)
1212:                        .append("\"").append(_token).append("\", last")
1213:                        .closeParen().append(";").endl();
1214:                code.tab(3).append("String part;").endl();
1215:                code.tab(3).append("if").openParen(true).append("next == -1")
1216:                        .closeParen().openBrace(4).endl();
1217:                code.tab(4).append("part = str.substring").openParen(true)
1218:                        .append("last").closeParen().append(";").endl();
1219:                code.tab(4).append("last = str.length").parens().append(";")
1220:                        .endl().closeBrace(4);
1221:                if (!code.getBraceOnSameLine())
1222:                    code.endl().tab(3);
1223:                else
1224:                    code.append(" ");
1225:                code.append("else").openBrace(4).endl();
1226:                code.tab(4).append("part = str.substring").openParen(true)
1227:                        .append("last, next").closeParen().append(";").endl();
1228:                code.tab(4).append("last = next + ").append(_token.length())
1229:                        .append(";").endl().closeBrace(4).endl();
1230:
1231:                code.tab(3).append("return part;").endl();
1232:                code.closeBrace(3);
1233:                code.endl().closeBrace(2);
1234:                return code.toString();
1235:            }
1236:
1237:            /**
1238:             * Return the file that this tool should output to.
1239:             */
1240:            private File getFile() {
1241:                if (_meta == null)
1242:                    return null;
1243:
1244:                String packageName = Strings.getPackageName(_meta
1245:                        .getObjectIdType());
1246:                String fileName = Strings.getClassName(_meta.getObjectIdType())
1247:                        + ".java";
1248:
1249:                // if pc class in same package as oid class, try to find pc .java file
1250:                File dir = null;
1251:                if (_dir == null
1252:                        && Strings.getPackageName(_type).equals(packageName)) {
1253:                    dir = Files.getSourceFile(_type);
1254:                    if (dir != null)
1255:                        dir = dir.getParentFile();
1256:                }
1257:                if (dir == null)
1258:                    dir = Files.getPackageFile(_dir, packageName, true);
1259:                return new File(dir, fileName);
1260:            }
1261:
1262:            /**
1263:             * Return a copy of the correct code format.
1264:             */
1265:            private CodeFormat newCodeFormat() {
1266:                return (_format == null) ? new CodeFormat()
1267:                        : (CodeFormat) _format.clone();
1268:            }
1269:
1270:            /**
1271:             * Usage: java org.apache.openjpa.enhance.ApplicationIdTool [option]*
1272:             * &lt;class name | .java file | .class file | .jdo file&gt;+
1273:             *  Where the following options are recognized.
1274:             * <ul>
1275:             * <li><i>-properties/-p &lt;properties file&gt;</i>: The path to a OpenJPA
1276:             * properties file containing information as outlined in
1277:             * {@link Configuration}; optional.</li>
1278:             * <li><i>-&lt;property name&gt; &lt;property value&gt;</i>: All bean
1279:             * properties of the standard OpenJPA {@link OpenJPAConfiguration} can be
1280:             * set by using their names and supplying a value.</li>
1281:             * <li><i>-directory/-d &lt;output directory&gt;</i>: Path to the base
1282:             * source directory. The package structure will be created beneath
1283:             * this directory if necessary. If not specified, the tool will try
1284:             * to locate the .java file in the CLASSPATH and output to the same
1285:             * directory; failing that, it will use the current directory as
1286:             * the base directory.
1287:             * <li><i>-ignoreErrors/-i &lt;true/t | false/f&gt;</i>: If false, an
1288:             * exception will be thrown if the tool encounters any class that
1289:             * does not use application identity or uses the identity class of
1290:             * its superclass; defaults to true.</li>
1291:             * <li><i>-token/-t &lt;token&gt;</i>: The token to use to separate
1292:             * stingified primary key field values in the stringified oid.</li>
1293:             * <li><i>-name/-n &lt;id class name&gt;</i>: The name of the identity
1294:             * class to generate. If this option is specified, you must only
1295:             * give a single class argument. If the class metadata names an object
1296:             * id class, this argument is ignored.</li>
1297:             * <li><i>-suffix/-s &lt;id class suffix&gt;</i>: A string to suffix each
1298:             * persistent class with to create the identity class name. This is
1299:             * overridden by <code>-name</code> or by any identity class name
1300:             * specified in metadata.</li>
1301:             * <li><i>-codeFormat/-cf.&lt;property name&gt; &lt; property value&gt;</i>
1302:             * : Arguments like this will be used to configure the bean
1303:             * properties of the internal {@link CodeFormat}.</li>
1304:             * </ul>
1305:             *  Each additional argument can be either the full class name of the
1306:             * type to create an id class for, the path to the .java file for the type,
1307:             * the path to the .class file for the type, or the path to a .jdo file
1308:             * listing one or more types. If a .java file already exists for an
1309:             * application id, it will be backed up to a file named
1310:             * &lt;orig file name&gt;~.
1311:             */
1312:            public static void main(String[] args) throws IOException,
1313:                    ClassNotFoundException {
1314:                Options opts = new Options();
1315:                final String[] arguments = opts.setFromCmdLine(args);
1316:                boolean ret = Configurations.runAgainstAllAnchors(opts,
1317:                        new Configurations.Runnable() {
1318:                            public boolean run(Options opts)
1319:                                    throws ClassNotFoundException, IOException {
1320:                                OpenJPAConfiguration conf = new OpenJPAConfigurationImpl();
1321:                                try {
1322:                                    return ApplicationIdTool.run(conf,
1323:                                            arguments, opts);
1324:                                } finally {
1325:                                    conf.close();
1326:                                }
1327:                            }
1328:                        });
1329:                if (!ret)
1330:                    System.err.println(_loc.get("appid-usage"));
1331:            }
1332:
1333:            /**
1334:             * Run the application id tool with the given command-line and
1335:             * given configuration. Returns false if invalid options were given.
1336:             */
1337:            public static boolean run(OpenJPAConfiguration conf, String[] args,
1338:                    Options opts) throws IOException, ClassNotFoundException {
1339:                Flags flags = new Flags();
1340:                flags.ignoreErrors = opts.removeBooleanProperty("ignoreErrors",
1341:                        "i", flags.ignoreErrors);
1342:                flags.directory = Files.getFile(opts.removeProperty(
1343:                        "directory", "d", null), null);
1344:                flags.token = opts.removeProperty("token", "t", flags.token);
1345:                flags.name = opts.removeProperty("name", "n", flags.name);
1346:                flags.suffix = opts.removeProperty("suffix", "s", flags.suffix);
1347:
1348:                // separate the properties for the customizer and code format
1349:                Options formatOpts = new Options();
1350:                Map.Entry entry;
1351:                String key;
1352:                for (Iterator itr = opts.entrySet().iterator(); itr.hasNext();) {
1353:                    entry = (Map.Entry) itr.next();
1354:                    key = (String) entry.getKey();
1355:                    if (key.startsWith("codeFormat.")) {
1356:                        formatOpts.put(key.substring(11), entry.getValue());
1357:                        itr.remove();
1358:                    } else if (key.startsWith("cf.")) {
1359:                        formatOpts.put(key.substring(3), entry.getValue());
1360:                        itr.remove();
1361:                    }
1362:                }
1363:                if (!formatOpts.isEmpty()) {
1364:                    flags.format = new CodeFormat();
1365:                    formatOpts.setInto(flags.format);
1366:                }
1367:
1368:                Configurations.populateConfiguration(conf, opts);
1369:                ClassLoader loader = conf.getClassResolverInstance()
1370:                        .getClassLoader(ApplicationIdTool.class, null);
1371:                return run(conf, args, flags, loader);
1372:            }
1373:
1374:            /**
1375:             * Run the tool. Returns false if invalid options were given.
1376:             */
1377:            public static boolean run(OpenJPAConfiguration conf, String[] args,
1378:                    Flags flags, ClassLoader loader) throws IOException,
1379:                    ClassNotFoundException {
1380:                MetaDataRepository repos = conf.newMetaDataRepositoryInstance();
1381:                repos.setValidate(repos.VALIDATE_NONE, true);
1382:                loadObjectIds(repos, flags.name == null && flags.suffix == null);
1383:
1384:                Log log = conf.getLog(OpenJPAConfiguration.LOG_TOOL);
1385:                Collection classes;
1386:                if (args.length == 0) {
1387:                    log.info(_loc.get("running-all-classes"));
1388:                    classes = repos.loadPersistentTypes(true, loader);
1389:                } else {
1390:                    ClassArgParser cap = conf.getMetaDataRepositoryInstance()
1391:                            .getMetaDataFactory().newClassArgParser();
1392:                    cap.setClassLoader(loader);
1393:                    classes = new HashSet();
1394:                    for (int i = 0; i < args.length; i++)
1395:                        classes.addAll(Arrays.asList(cap.parseTypes(args[i])));
1396:                }
1397:                if (flags.name != null && classes.size() > 1)
1398:                    throw new UserException(_loc.get("name-mult-args", classes));
1399:
1400:                ApplicationIdTool tool;
1401:                Class cls;
1402:                ClassMetaData meta;
1403:                BCClassLoader bc = (BCClassLoader) AccessController
1404:                        .doPrivileged(J2DoPrivHelper
1405:                                .newBCClassLoaderAction(new Project()));
1406:                for (Iterator itr = classes.iterator(); itr.hasNext();) {
1407:                    cls = (Class) itr.next();
1408:                    log.info(_loc.get("appid-running", cls));
1409:
1410:                    meta = repos.getMetaData(cls, null, false);
1411:                    setObjectIdType(meta, flags, bc);
1412:
1413:                    tool = new ApplicationIdTool(conf, cls, meta);
1414:                    tool.setDirectory(flags.directory);
1415:                    tool.setIgnoreErrors(flags.ignoreErrors);
1416:                    tool.setToken(flags.token);
1417:                    tool.setCodeFormat(flags.format);
1418:                    if (tool.run()) {
1419:                        log.info(_loc.get("appid-output", tool.getFile()));
1420:                        tool.record();
1421:                    } else
1422:                        log.info(_loc.get("appid-norun"));
1423:                }
1424:                bc.getProject().clear();
1425:                return true;
1426:            }
1427:
1428:            /**
1429:             * Set the object id type of the given metadata.
1430:             */
1431:            private static void setObjectIdType(ClassMetaData meta,
1432:                    Flags flags, BCClassLoader bc)
1433:                    throws ClassNotFoundException {
1434:                if (meta == null
1435:                        || (meta.getObjectIdType() != null && (!meta
1436:                                .isOpenJPAIdentity() || flags.name == null))
1437:                        || getDeclaredPrimaryKeyFields(meta).length == 0)
1438:                    return;
1439:
1440:                Class desc = meta.getDescribedType();
1441:                Class cls = null;
1442:                if (flags.name != null)
1443:                    cls = loadClass(desc, flags.name, bc);
1444:                else if (flags.suffix != null)
1445:                    cls = loadClass(desc, desc.getName() + flags.suffix, bc);
1446:                meta.setObjectIdType(cls, false);
1447:            }
1448:
1449:            /**
1450:             * Load the given class name even if it does not exist.
1451:             */
1452:            private static Class loadClass(Class context, String name,
1453:                    BCClassLoader bc) throws ClassNotFoundException {
1454:                if (name.indexOf('.') == -1
1455:                        && context.getName().indexOf('.') != -1)
1456:                    name = Strings.getPackageName(context) + "." + name;
1457:
1458:                // first try with regular class loader
1459:                ClassLoader loader = (ClassLoader) AccessController
1460:                        .doPrivileged(J2DoPrivHelper
1461:                                .getClassLoaderAction(context));
1462:                if (loader == null)
1463:                    loader = (ClassLoader) AccessController
1464:                            .doPrivileged(J2DoPrivHelper
1465:                                    .getContextClassLoaderAction());
1466:                try {
1467:                    return Class.forName(name, false, loader);
1468:                } catch (Throwable t) {
1469:                }
1470:
1471:                // create class
1472:                BCClass oid = bc.getProject().loadClass(name, null);
1473:                oid.addDefaultConstructor();
1474:                return Class.forName(name, false, bc);
1475:            }
1476:
1477:            /**
1478:             * Tell the metadata factory to load object id classes even if they don't
1479:             * exist.
1480:             */
1481:            private static void loadObjectIds(MetaDataRepository repos,
1482:                    boolean fatal) {
1483:                MetaDataFactory mdf = repos.getMetaDataFactory();
1484:                if (mdf instanceof  DelegatingMetaDataFactory)
1485:                    mdf = ((DelegatingMetaDataFactory) mdf)
1486:                            .getInnermostDelegate();
1487:                if (mdf instanceof  ObjectIdLoader)
1488:                    ((ObjectIdLoader) mdf).setLoadObjectIds();
1489:                else if (fatal)
1490:                    throw new InvalidStateException(_loc
1491:                            .get("factory-not-oidloader")).setFatal(true);
1492:            }
1493:
1494:            /**
1495:             * Run flags.
1496:             */
1497:            public static class Flags {
1498:
1499:                public File directory = null;
1500:                public boolean ignoreErrors = true;
1501:                public String token = TOKEN_DEFAULT;
1502:                public CodeFormat format = null;
1503:                public String name = null;
1504:                public String suffix = null;
1505:            }
1506:
1507:            /**
1508:             * Interface implemented by metadata factories that can load non-existant
1509:             * object id classes.
1510:             */
1511:            public static interface ObjectIdLoader {
1512:                /**
1513:                 * Turn on the loading of all identity classes, even if they don't 
1514:                 * exist.
1515:                 */
1516:                public void setLoadObjectIds();
1517:            }
1518:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.