Source Code Cross Referenced for ClassFile.java in  » XML » jibx-1.1.5 » org » jibx » binding » classes » 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 » XML » jibx 1.1.5 » org.jibx.binding.classes 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:        Copyright (c) 2003-2005, Dennis M. Sosnoski
0003:        All rights reserved.
0004:
0005:        Redistribution and use in source and binary forms, with or without modification,
0006:        are permitted provided that the following conditions are met:
0007:
0008:         * Redistributions of source code must retain the above copyright notice, this
0009:           list of conditions and the following disclaimer.
0010:         * Redistributions in binary form must reproduce the above copyright notice,
0011:           this list of conditions and the following disclaimer in the documentation
0012:           and/or other materials provided with the distribution.
0013:         * Neither the name of JiBX nor the names of its contributors may be used
0014:           to endorse or promote products derived from this software without specific
0015:           prior written permission.
0016:
0017:        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
0018:        ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0019:        WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0020:        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
0021:        ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0022:        (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0023:        LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
0024:        ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0025:        (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0026:        SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0027:         */
0028:
0029:        package org.jibx.binding.classes;
0030:
0031:        import java.io.BufferedOutputStream;
0032:        import java.io.File;
0033:        import java.io.FileInputStream;
0034:        import java.io.FileOutputStream;
0035:        import java.io.IOException;
0036:        import java.io.InputStream;
0037:        import java.io.OutputStream;
0038:        import java.net.MalformedURLException;
0039:        import java.net.URL;
0040:        import java.net.URLClassLoader;
0041:        import java.util.ArrayList;
0042:        import java.util.Arrays;
0043:        import java.util.HashMap;
0044:
0045:        import org.apache.bcel.Constants;
0046:        import org.apache.bcel.classfile.ClassParser;
0047:        import org.apache.bcel.classfile.Code;
0048:        import org.apache.bcel.classfile.CodeException;
0049:        import org.apache.bcel.classfile.Constant;
0050:        import org.apache.bcel.classfile.ConstantDouble;
0051:        import org.apache.bcel.classfile.ConstantFloat;
0052:        import org.apache.bcel.classfile.ConstantInteger;
0053:        import org.apache.bcel.classfile.ConstantLong;
0054:        import org.apache.bcel.classfile.ConstantPool;
0055:        import org.apache.bcel.classfile.ConstantString;
0056:        import org.apache.bcel.classfile.ConstantUtf8;
0057:        import org.apache.bcel.classfile.ConstantValue;
0058:        import org.apache.bcel.classfile.ExceptionTable;
0059:        import org.apache.bcel.classfile.Field;
0060:        import org.apache.bcel.classfile.FieldOrMethod;
0061:        import org.apache.bcel.classfile.JavaClass;
0062:        import org.apache.bcel.classfile.Method;
0063:        import org.apache.bcel.classfile.Synthetic;
0064:        import org.apache.bcel.classfile.Utility;
0065:        import org.apache.bcel.generic.ClassGen;
0066:        import org.apache.bcel.generic.ConstantPoolGen;
0067:        import org.apache.bcel.generic.FieldGen;
0068:        import org.apache.bcel.generic.Type;
0069:        import org.apache.bcel.util.ClassPath;
0070:        import org.jibx.runtime.JiBXException;
0071:
0072:        /**
0073:         * Class file information. Wraps the actual class file data as well as
0074:         * associated management information.
0075:         *
0076:         * @author Dennis M. Sosnoski
0077:         * @version 1.0
0078:         */
0079:
0080:        public class ClassFile {
0081:            //
0082:            // Constants for code generation.
0083:
0084:            public static final int PRIVATE_ACCESS = 0;
0085:            public static final int PACKAGE_ACCESS = 1;
0086:            public static final int PROTECTED_ACCESS = 2;
0087:            public static final int PUBLIC_ACCESS = 3;
0088:
0089:            public static final int SYNTHETIC_ACCESS_FLAG = 0x1000;
0090:
0091:            protected static final int PRIVATEFIELD_ACCESS = Constants.ACC_PRIVATE
0092:                    | SYNTHETIC_ACCESS_FLAG;
0093:            protected static final ExistingMethod[] EMPTY_METHOD_ARRAY = {};
0094:            protected static final byte[] EMPTY_BYTES = new byte[0];
0095:
0096:            public static final ClassItem[] EMPTY_CLASS_ITEMS = new ClassItem[0];
0097:
0098:            //
0099:            // Class data.
0100:
0101:            /** Singleton loader from classpath. */
0102:            private static ClassPath s_loader;
0103:
0104:            /** Direct class loader. */
0105:            private static ClassLoader s_directLoader;
0106:
0107:            //
0108:            // Actual instance data.
0109:
0110:            /** Fully qualified class name. */
0111:            private String m_name;
0112:
0113:            /** Signature for class as type. */
0114:            private String m_signature;
0115:
0116:            /** Class as type. */
0117:            private Type m_type;
0118:
0119:            /** Directory root for class. */
0120:            private File m_root;
0121:
0122:            /** Actual class file information. */
0123:            private File m_file;
0124:
0125:            /** Class in same package as superclass flag. */
0126:            private boolean m_isSamePackage;
0127:
0128:            /** File is writable flag. */
0129:            private boolean m_isWritable;
0130:
0131:            /** Super class of this class (set by caller, since it may require
0132:             additional information to find the class file). */
0133:            protected ClassFile m_super Class;
0134:
0135:            /** Names of all interfaces directly implemented by this class. */
0136:            protected String[] m_interfaceNames;
0137:
0138:            /** Class files of interfaces extended by interface. */
0139:            private ClassFile[] m_super Interfaces;
0140:
0141:            /** All classes and interfaces of which this is an instance (lazy create,
0142:             only if needed. */
0143:            private String[] m_instanceOfs;
0144:
0145:            /** All methods defined by this class or interface (lazy create, only if
0146:             needed. */
0147:            private Method[] m_methods;
0148:
0149:            /** Base class information as loaded by BCEL. */
0150:            private JavaClass m_curClass;
0151:
0152:            /** Modified class generator (lazy create, only if needed). */
0153:            private ClassGen m_genClass;
0154:
0155:            /** Constant pool generator for modified class (lazy create, only if
0156:             needed). */
0157:            private ConstantPoolGen m_genPool;
0158:
0159:            /** Instruction factory for modified class (lazy create, only if needed). */
0160:            protected InstructionBuilder m_instBuilder;
0161:
0162:            /** Map for method names with possibly generated suffixes (lazy create, only
0163:             if needed). */
0164:            private HashMap m_suffixMap;
0165:
0166:            /** Map to class item information. */
0167:            private HashMap m_itemMap;
0168:
0169:            /** Flag for class modified. */
0170:            private boolean m_isModified;
0171:
0172:            /** Usage count for this class. */
0173:            private int m_useCount;
0174:
0175:            /** Hash code computation for class is current flag. */
0176:            private boolean m_isHashCurrent;
0177:
0178:            /** Cached hash code value for class. */
0179:            private int m_hashCode;
0180:
0181:            /** Depth of superclass hierarchy for class (lazy computation). */
0182:            private int m_inheritDepth;
0183:
0184:            /** Suffix number for making method names unique (lazy computation). */
0185:            private int m_uniqueIndex;
0186:
0187:            /** Added default constructor for class. */
0188:            private ClassItem m_defaultConstructor;
0189:
0190:            /**
0191:             * Constructor for class file loaded from a stream. Loads the class data
0192:             * and prepares it for use.
0193:             *
0194:             * @param name fully qualified class name
0195:             * @param path class file path
0196:             * @param ins input stream for class file data
0197:             * @throws JiBXException if unable to load class file
0198:             */
0199:
0200:            public ClassFile(String name, String path, InputStream ins)
0201:                    throws JiBXException {
0202:                init(name, path, ins);
0203:            }
0204:
0205:            /**
0206:             * Constructor for preexisting class file. Loads the class data and
0207:             * prepares it for use.
0208:             *
0209:             * @param name fully qualified class name
0210:             * @param root directory root from class loading path list
0211:             * @param file actual class file
0212:             * @throws IOException if unable to open file
0213:             * @throws JiBXException if error in reading class file
0214:             */
0215:
0216:            public ClassFile(String name, File root, File file)
0217:                    throws IOException, JiBXException {
0218:                init(name, root.getPath(), new FileInputStream(file));
0219:                m_root = root;
0220:                m_file = file;
0221:                m_isWritable = file.canWrite();
0222:            }
0223:
0224:            /**
0225:             * Constructor for preexisting class file from classpath. Loads the class
0226:             * data and prepares it for use.
0227:             *
0228:             * @param name fully qualified class name
0229:             * @throws IOException if unable to open file
0230:             * @throws JiBXException if error in reading class file
0231:             */
0232:
0233:            public ClassFile(String name) throws IOException, JiBXException {
0234:
0235:                // try out class path first, then BCEL system path
0236:                ClassPath.ClassFile cf = null;
0237:                try {
0238:                    cf = s_loader.getClassFile(name);
0239:                } catch (IOException ex) {
0240:                    try {
0241:                        cf = ClassPath.SYSTEM_CLASS_PATH.getClassFile(name);
0242:                    } catch (IOException ex1) { /* deliberately left empty */
0243:                    }
0244:                }
0245:                if (cf == null) {
0246:                    throw new JiBXException("Class " + name
0247:                            + " not found in any classpath");
0248:                } else {
0249:                    init(name, cf.getPath(), cf.getInputStream());
0250:                }
0251:            }
0252:
0253:            /**
0254:             * Constructor for synthetic placeholder classfile with no backing class
0255:             * data.
0256:             *
0257:             * @param name fully qualified class name
0258:             * @param sig corresponding class signature
0259:             */
0260:
0261:            public ClassFile(String name, String sig) {
0262:                m_name = name;
0263:                m_signature = sig;
0264:                m_type = Type.getType(sig);
0265:                m_interfaceNames = new String[0];
0266:                m_super Interfaces = new ClassFile[0];
0267:                m_itemMap = new HashMap();
0268:            }
0269:
0270:            /**
0271:             * Constructor for new class file. Initializes the class data and
0272:             * prepares it for use.
0273:             *
0274:             * @param name fully qualified class name
0275:             * @param root directory root from class loading path list
0276:             * @param sclas superclass of new class
0277:             * @param access access flags for class
0278:             * @param impls array of interfaces implemented by new class
0279:             * @throws JiBXException on error loading interface information
0280:             */
0281:
0282:            public ClassFile(String name, File root, ClassFile sclas,
0283:                    int access, String[] impls) throws JiBXException {
0284:                String fname = name.replace('.', File.separatorChar) + ".class";
0285:                File file = new File(root, fname);
0286:                m_name = name;
0287:                m_signature = Utility.getSignature(name);
0288:                m_type = ClassItem.typeFromName(name);
0289:                m_root = root;
0290:                m_super Class = sclas;
0291:                m_interfaceNames = impls;
0292:                m_file = file;
0293:                m_isWritable = true;
0294:                m_genClass = new ClassGen(name, sclas.getName(), "", access
0295:                        | SYNTHETIC_ACCESS_FLAG, impls);
0296:                m_genPool = m_genClass.getConstantPool();
0297:                int index = m_genPool.addUtf8("Synthetic");
0298:                m_genClass.addAttribute(new Synthetic(index, 0, EMPTY_BYTES,
0299:                        m_genPool.getConstantPool()));
0300:                m_instBuilder = new InstructionBuilder(m_genClass, m_genPool);
0301:                m_itemMap = new HashMap();
0302:                initInterface();
0303:                ClassCache.addClassFile(this );
0304:            }
0305:
0306:            /**
0307:             * Internal initialization method. This is used to handle common
0308:             * initialization for the constructors.
0309:             *
0310:             * @param name fully qualified class name
0311:             * @param path class file path
0312:             * @param ins input stream for class file data
0313:             * @throws JiBXException if unable to load class file
0314:             */
0315:
0316:            private void init(String name, String path, InputStream ins)
0317:                    throws JiBXException {
0318:                m_name = name;
0319:                m_signature = Utility.getSignature(name);
0320:                m_type = ClassItem.typeFromName(name);
0321:                m_itemMap = new HashMap();
0322:                if (path == null) {
0323:                    m_interfaceNames = new String[0];
0324:                } else {
0325:                    String fname = name.replace('.', File.separatorChar)
0326:                            + ".class";
0327:                    ClassParser parser = new ClassParser(ins, fname);
0328:                    try {
0329:                        m_curClass = parser.parse();
0330:                        m_interfaceNames = m_curClass.getInterfaceNames();
0331:                    } catch (Exception ex) {
0332:                        throw new JiBXException("Error reading path " + path
0333:                                + " for class " + name);
0334:                    }
0335:                }
0336:                initInterface();
0337:            }
0338:
0339:            /**
0340:             * Retrieve superinterfaces for an interface class. These are collected at
0341:             * initialization so that we can support getting the full set of methods
0342:             * later without worrying about throwing an exception.
0343:             * 
0344:             * @throws JiBXException on error loading interface information
0345:             */
0346:            private void initInterface() throws JiBXException {
0347:                if (isInterface() && m_interfaceNames.length > 0) {
0348:                    ClassFile[] super s = new ClassFile[m_interfaceNames.length];
0349:                    for (int i = 0; i < m_interfaceNames.length; i++) {
0350:                        super s[i] = ClassCache
0351:                                .getClassFile(m_interfaceNames[i]);
0352:                    }
0353:                    m_super Interfaces = super s;
0354:                } else {
0355:                    m_super Interfaces = new ClassFile[0];
0356:                }
0357:            }
0358:
0359:            /**
0360:             * Check if class is an interface. This only checks existing classes,
0361:             * assuming that no generated classes are interfaces.
0362:             *
0363:             * @return <code>true</code> if an interface, <code>false</code> if not
0364:             */
0365:
0366:            public boolean isInterface() {
0367:                return m_curClass != null && m_curClass.isInterface();
0368:            }
0369:
0370:            /**
0371:             * Check if class is abstract. This only checks existing classes,
0372:             * assuming that no generated classes are abstract.
0373:             *
0374:             * @return <code>true</code> if an abstract class, <code>false</code> if not
0375:             */
0376:
0377:            public boolean isAbstract() {
0378:                return m_curClass != null && m_curClass.isAbstract();
0379:            }
0380:
0381:            /**
0382:             * Check if class is an array. This only checks existing classes,
0383:             * assuming that no generated classes are arrays.
0384:             *
0385:             * @return <code>true</code> if an array class, <code>false</code> if not
0386:             */
0387:
0388:            public boolean isArray() {
0389:                return m_name.endsWith("[]");
0390:            }
0391:
0392:            /**
0393:             * Check if class is modifiable.
0394:             *
0395:             * @return <code>true</code> if class is modifiable, <code>false</code> if
0396:             * not
0397:             */
0398:
0399:            public boolean isModifiable() {
0400:                return m_isWritable && !isInterface();
0401:            }
0402:
0403:            /**
0404:             * Get fully qualified class name.
0405:             *
0406:             * @return fully qualified name for class
0407:             */
0408:
0409:            public String getName() {
0410:                return m_name;
0411:            }
0412:
0413:            /**
0414:             * Get signature for class as type.
0415:             *
0416:             * @return signature for class used as type
0417:             */
0418:
0419:            public String getSignature() {
0420:                return m_signature;
0421:            }
0422:
0423:            /**
0424:             * Get class as type.
0425:             *
0426:             * @return class as type
0427:             */
0428:
0429:            public Type getType() {
0430:                return m_type;
0431:            }
0432:
0433:            /**
0434:             * Get package name.
0435:             *
0436:             * @return package name for class
0437:             */
0438:
0439:            public String getPackage() {
0440:                int split = m_name.lastIndexOf('.');
0441:                if (split >= 0) {
0442:                    return m_name.substring(0, split);
0443:                } else {
0444:                    return "";
0445:                }
0446:            }
0447:
0448:            /**
0449:             * Get root directory for load path.
0450:             *
0451:             * @return root directory in path used for loading file
0452:             */
0453:
0454:            public File getRoot() {
0455:                return m_root;
0456:            }
0457:
0458:            /**
0459:             * Get actual file for class.
0460:             *
0461:             * @return file used for class
0462:             */
0463:
0464:            public File getFile() {
0465:                return m_file;
0466:            }
0467:
0468:            /**
0469:             * Get raw current class information.
0470:             *
0471:             * @return raw current class information
0472:             */
0473:
0474:            public JavaClass getRawClass() {
0475:                if (m_curClass == null) {
0476:                    throw new IllegalStateException(
0477:                            "No loadable class information for " + m_name);
0478:                } else {
0479:                    return m_curClass;
0480:                }
0481:            }
0482:
0483:            /**
0484:             * Get superclass name.
0485:             *
0486:             * @return fully qualified name of superclass
0487:             */
0488:
0489:            public String getSuperName() {
0490:                if (m_curClass == null) {
0491:                    return null;
0492:                } else {
0493:                    return m_curClass.getSuperclassName();
0494:                }
0495:            }
0496:
0497:            /**
0498:             * Set superclass information.
0499:             *
0500:             * @param sclas superclass information
0501:             */
0502:
0503:            public void setSuperFile(ClassFile sclas) {
0504:                m_super Class = sclas;
0505:                m_isSamePackage = getPackage().equals(sclas.getPackage());
0506:            }
0507:
0508:            /**
0509:             * Get superclass information.
0510:             *
0511:             * @return super class information as loaded (<code>null</code> if no
0512:             * superclass - java.lang.Object, interface, or primitive)
0513:             */
0514:
0515:            public ClassFile getSuperFile() {
0516:                return m_super Class;
0517:            }
0518:
0519:            /**
0520:             * Get names of all interfaces implemented by class.
0521:             *
0522:             * @return names of all interfaces implemented directly by class
0523:             */
0524:
0525:            public String[] getInterfaces() {
0526:                return m_interfaceNames;
0527:            }
0528:
0529:            /**
0530:             * Add interface to class. The interface is added to the class if not
0531:             * already defined.
0532:             *
0533:             * @param intf fully qualified interface name
0534:             * @return <code>true</code> if added, <code>false</code> if already present
0535:             * @throws JiBXException on configuration error
0536:             */
0537:
0538:            public boolean addInterface(String intf) throws JiBXException {
0539:                ClassGen gen = getClassGen();
0540:                String[] intfs = gen.getInterfaceNames();
0541:                for (int i = 0; i < intfs.length; i++) {
0542:                    if (intf.equals(intfs[i])) {
0543:                        return false;
0544:                    }
0545:                }
0546:                gen.addInterface(intf);
0547:                m_isModified = true;
0548:                m_instanceOfs = null;
0549:                return true;
0550:            }
0551:
0552:            /**
0553:             * Accumulate interface signatures recursively.
0554:             *
0555:             * @param intfs names of interfaces implemented
0556:             * @param map map for interfaces already accumulated
0557:             * @param accs accumulated interface names
0558:             * @throws JiBXException if configuration error
0559:             */
0560:
0561:            protected void accumulateInterfaces(String[] intfs, HashMap map,
0562:                    ArrayList accs) throws JiBXException {
0563:                for (int i = 0; i < intfs.length; i++) {
0564:                    String name = intfs[i];
0565:                    if (map.get(name) == null) {
0566:                        ClassFile cf = ClassCache.getClassFile(name);
0567:                        String sig = cf.getSignature();
0568:                        map.put(name, sig);
0569:                        accs.add(sig);
0570:                        String[] inherits = cf.m_curClass.getInterfaceNames();
0571:                        accumulateInterfaces(inherits, map, accs);
0572:                    }
0573:                }
0574:            }
0575:
0576:            /**
0577:             * Get signatures for all types of which instances of this type are
0578:             * instances.
0579:             *
0580:             * @return all signatures suppored by instances
0581:             * @throws JiBXException if configuration error
0582:             */
0583:
0584:            public String[] getInstanceSigs() throws JiBXException {
0585:                if (m_instanceOfs == null) {
0586:
0587:                    // check for an array class
0588:                    String name = getName();
0589:                    if (name.endsWith("[]")) {
0590:
0591:                        // accumulate prefix by stripping suffixes
0592:                        String prefix = "";
0593:                        do {
0594:                            name = name.substring(0, name.length() - 2);
0595:                            prefix = prefix + '[';
0596:                        } while (name.endsWith("[]"));
0597:
0598:                        // check for a primitive base type on array
0599:                        String[] bsigs;
0600:                        if (ClassItem.isPrimitive(name)) {
0601:                            bsigs = new String[1];
0602:                            bsigs[0] = ClassItem.getPrimitiveSignature(name);
0603:                        } else {
0604:                            ClassFile bcf = ClassCache.getClassFile(name);
0605:                            bsigs = bcf.getInstanceSigs();
0606:                        }
0607:
0608:                        // derive array signatures from signatures for base type
0609:                        String[] asigs = new String[bsigs.length + 1];
0610:                        for (int i = 0; i < bsigs.length; i++) {
0611:                            asigs[i] = prefix + bsigs[i];
0612:                        }
0613:                        asigs[bsigs.length] = "Ljava/lang/Object;";
0614:                        m_instanceOfs = asigs;
0615:
0616:                    } else {
0617:
0618:                        // walk all classes and interfaces to find signatures
0619:                        HashMap map = new HashMap();
0620:                        ArrayList iofs = new ArrayList();
0621:                        ClassFile cur = this ;
0622:                        while (cur != null) {
0623:                            String sig = cur.getSignature();
0624:                            map.put(name, sig);
0625:                            iofs.add(sig);
0626:                            accumulateInterfaces(cur.getInterfaces(), map, iofs);
0627:                            cur = cur.getSuperFile();
0628:                        }
0629:                        String[] sigs = new String[iofs.size()];
0630:                        m_instanceOfs = (String[]) iofs.toArray(sigs);
0631:
0632:                    }
0633:                }
0634:                return m_instanceOfs;
0635:            }
0636:
0637:            /**
0638:             * Check if class implements an interface.
0639:             *
0640:             * @param sig signature of interface to be checked
0641:             * @return <code>true</code> if interface is implemented by class,
0642:             * <code>false</code> if not
0643:             * @throws JiBXException if configuration error
0644:             */
0645:
0646:            public boolean isImplements(String sig) throws JiBXException {
0647:                String[] sigs = getInstanceSigs();
0648:                for (int i = 0; i < sigs.length; i++) {
0649:                    if (sig.equals(sigs[i])) {
0650:                        return true;
0651:                    }
0652:                }
0653:                return false;
0654:            }
0655:
0656:            /**
0657:             * Check if another class is a superclass of this one.
0658:             *
0659:             * @param name of superclass to be checked
0660:             * @return <code>true</code> if named class is a superclass of this one,
0661:             * <code>false</code> if not
0662:             */
0663:
0664:            public boolean isSuperclass(String name) {
0665:                ClassFile cur = this ;
0666:                while (cur != null) {
0667:                    if (cur.getName().equals(name)) {
0668:                        return true;
0669:                    } else {
0670:                        cur = cur.getSuperFile();
0671:                    }
0672:                }
0673:                return false;
0674:            }
0675:
0676:            /**
0677:             * Get array of fields defined by class.
0678:             * 
0679:             * @return array of fields defined by class
0680:             */
0681:            public ClassItem[] getFieldItems() {
0682:                if (m_curClass == null) {
0683:                    return EMPTY_CLASS_ITEMS;
0684:                } else {
0685:                    Field[] fields = m_curClass.getFields();
0686:                    ClassItem[] items = new ClassItem[fields.length];
0687:                    for (int i = 0; i < fields.length; i++) {
0688:                        Field field = fields[i];
0689:                        items[i] = new ClassItem(field.getName(), this , field);
0690:                    }
0691:                    return items;
0692:                }
0693:            }
0694:
0695:            /**
0696:             * Get internal information for field. This can only be used with
0697:             * existing classes, and only checks for fields that are actually members
0698:             * of the class (not superclasses).
0699:             *
0700:             * @param name field name
0701:             * @return field information, or <code>null</code> if field not found
0702:             */
0703:
0704:            protected Field getDefinedField(String name) {
0705:
0706:                // check for match to field name defined in class
0707:                Field[] fields = m_curClass.getFields();
0708:                for (int i = 0; i < fields.length; i++) {
0709:                    if (fields[i].getName().equals(name)) {
0710:                        return fields[i];
0711:                    }
0712:                }
0713:                return null;
0714:            }
0715:
0716:            /**
0717:             * Get internal information for field. This can only be used with existing
0718:             * classes. If the field is not found directly, superclasses are checked for
0719:             * inherited fields matching the supplied name.
0720:             *
0721:             * @param name field name
0722:             * @return field information, or <code>null</code> if field not found
0723:             */
0724:
0725:            protected Field getAccessibleField(String name) {
0726:
0727:                // always return not found for unloadable class
0728:                if (m_curClass == null) {
0729:                    return null;
0730:                } else {
0731:
0732:                    // check for match to field name defined in class
0733:                    Field field = getDefinedField(name);
0734:                    if (field == null) {
0735:
0736:                        // try match to field inherited from superclass
0737:                        if (m_super Class != null) {
0738:                            field = m_super Class.getAccessibleField(name);
0739:                            if (field != null
0740:                                    && (!m_isSamePackage || field.isPrivate())
0741:                                    && !field.isPublic()
0742:                                    && !field.isProtected()) {
0743:                                field = null;
0744:                            }
0745:                        }
0746:
0747:                    }
0748:                    return field;
0749:                }
0750:            }
0751:
0752:            /**
0753:             * Get information for field. This can only be used with existing classes,
0754:             * and only checks for fields that are actually members of the class (not
0755:             * superclasses).
0756:             *
0757:             * @param name field name
0758:             * @return field information, or <code>null</code> if field not found
0759:             */
0760:
0761:            public ClassItem getDirectField(String name) {
0762:                Field field = getAccessibleField(name);
0763:                if (field == null) {
0764:                    return null;
0765:                } else {
0766:                    ClassItem item = (ClassItem) m_itemMap.get(field);
0767:                    if (item == null) {
0768:                        item = new ClassItem(name, this , field);
0769:                        m_itemMap.put(field, item);
0770:                    }
0771:                    return item;
0772:                }
0773:            }
0774:
0775:            /**
0776:             * Get information for field. This can only be used with existing classes.
0777:             * If the field is not found directly, superclasses are checked for
0778:             * inherited fields matching the supplied name.
0779:             *
0780:             * @param name field name
0781:             * @return field information
0782:             * @throws JiBXException if field not found
0783:             */
0784:
0785:            public ClassItem getField(String name) throws JiBXException {
0786:                Field field = getAccessibleField(name);
0787:                if (field == null) {
0788:                    throw new JiBXException("Field " + name
0789:                            + " not found in class " + m_name);
0790:                } else {
0791:                    ClassItem item = (ClassItem) m_itemMap.get(field);
0792:                    if (item == null) {
0793:                        item = new ClassItem(name, this , field);
0794:                        m_itemMap.put(field, item);
0795:                    }
0796:                    return item;
0797:                }
0798:            }
0799:
0800:            /**
0801:             * Get array of methods defined by class or interface. In the case of an
0802:             * interface, this merges all methods from superinterfaces in the array
0803:             * returned.
0804:             * 
0805:             * @return array of methods defined by class
0806:             */
0807:            private Method[] getMethods() {
0808:                if (m_methods == null) {
0809:
0810:                    // start with methods defined directly
0811:                    Method[] methods = m_curClass.getMethods();
0812:                    if (m_curClass.isInterface()
0813:                            && m_super Interfaces.length > 0) {
0814:
0815:                        // for interface extending other interfaces, merge methods
0816:                        ArrayList merges = new ArrayList();
0817:                        for (int i = 0; i < methods.length; i++) {
0818:                            merges.add(methods[i]);
0819:                        }
0820:                        for (int i = 0; i < m_super Interfaces.length; i++) {
0821:                            methods = m_super Interfaces[i].getMethods();
0822:                            for (int j = 0; j < methods.length; j++) {
0823:                                merges.add(methods[j]);
0824:                            }
0825:                        }
0826:
0827:                        // set merged array
0828:                        methods = (Method[]) merges.toArray(new Method[merges
0829:                                .size()]);
0830:                    }
0831:
0832:                    // cache the created method array
0833:                    m_methods = methods;
0834:                }
0835:                return m_methods;
0836:            }
0837:
0838:            /**
0839:             * Get array of methods defined by class.
0840:             * 
0841:             * @return array of methods defined by class
0842:             */
0843:            public ClassItem[] getMethodItems() {
0844:                if (m_curClass == null) {
0845:                    return EMPTY_CLASS_ITEMS;
0846:                } else {
0847:                    Method[] methods = getMethods();
0848:                    ClassItem[] items = new ClassItem[methods.length];
0849:                    for (int i = 0; i < methods.length; i++) {
0850:                        Method method = methods[i];
0851:                        items[i] = new ClassItem(method.getName(), this , method);
0852:                    }
0853:                    return items;
0854:                }
0855:            }
0856:
0857:            /**
0858:             * Get internal information for method without respect to potential trailing
0859:             * arguments or return value. This can only be used with existing classes.
0860:             * If the method is not found directly, superclasses are checked for
0861:             * inherited methods matching the supplied name. This compares the supplied
0862:             * partial signature against the actual method signature, and considers it
0863:             * a match if the actual sigature starts with the supplied signature..
0864:             *
0865:             * @param name method name
0866:             * @param sig partial method signature to be matched
0867:             * @return method information, or <code>null</code> if method not found
0868:             */
0869:
0870:            protected Method getAccessibleMethod(String name, String sig) {
0871:
0872:                // only check loadable classes
0873:                if (m_curClass != null) {
0874:
0875:                    // check for match to method defined in class
0876:                    Method[] methods = getMethods();
0877:                    for (int i = 0; i < methods.length; i++) {
0878:                        Method method = methods[i];
0879:                        if (method.getName().equals(name)) {
0880:                            if (method.getSignature().startsWith(sig)) {
0881:                                return method;
0882:                            }
0883:                        }
0884:                    }
0885:
0886:                    // try match to method inherited from superclass
0887:                    if (m_super Class != null) {
0888:                        Method method = m_super Class.getAccessibleMethod(name,
0889:                                sig);
0890:                        if (method != null
0891:                                && ((m_isSamePackage && !method.isPrivate())
0892:                                        || method.isPublic() || method
0893:                                        .isProtected())) {
0894:                            return method;
0895:                        }
0896:                    }
0897:
0898:                }
0899:                return null;
0900:            }
0901:
0902:            /**
0903:             * Get information for method without respect to potential trailing
0904:             * arguments or return value. This can only be used with existing classes.
0905:             * If the method is not found directly, superclasses are checked for
0906:             * inherited methods matching the supplied name. This compares the supplied
0907:             * partial signature against the actual method signature, and considers it
0908:             * a match if the actual sigature starts with the supplied signature..
0909:             *
0910:             * @param name method name
0911:             * @param sig partial method signature to be matched
0912:             * @return method information, or <code>null</code> if method not found
0913:             */
0914:
0915:            public ClassItem getMethod(String name, String sig) {
0916:                Method method = getAccessibleMethod(name, sig);
0917:                if (method == null) {
0918:                    return null;
0919:                } else {
0920:                    ClassItem item = (ClassItem) m_itemMap.get(method);
0921:                    if (item == null) {
0922:                        item = new ClassItem(name, this , method);
0923:                        m_itemMap.put(method, item);
0924:                    }
0925:                    return item;
0926:                }
0927:            }
0928:
0929:            /**
0930:             * Get information for method matching one of several possible signatures.
0931:             * This can only be used with existing classes. If a match is not found
0932:             * directly, superclasses are checked for inherited methods matching the
0933:             * supplied name and signatures. The signature variations are checked in
0934:             * the order supplied.
0935:             *
0936:             * @param name method name
0937:             * @param sigs possible signatures for method (including return type)
0938:             * @return method information, or <code>null</code> if method not found
0939:             */
0940:
0941:            public ClassItem getMethod(String name, String[] sigs) {
0942:                Method method = null;
0943:                for (int i = 0; method == null && i < sigs.length; i++) {
0944:                    method = getAccessibleMethod(name, sigs[i]);
0945:                }
0946:                if (method == null) {
0947:                    return null;
0948:                } else {
0949:                    ClassItem item = (ClassItem) m_itemMap.get(method);
0950:                    if (item == null) {
0951:                        item = new ClassItem(name, this , method);
0952:                        m_itemMap.put(method, item);
0953:                    }
0954:                    return item;
0955:                }
0956:            }
0957:
0958:            /**
0959:             * Check for match to specified access level. This treats a field or method
0960:             * as matching if the access level is the same as or more open than the
0961:             * required level.
0962:             * 
0963:             * @param item information for field or method to be checked
0964:             * @param access required access level for match
0965:             * @return <code>true</code> if access level match, <code>false</code> if
0966:             * not
0967:             */
0968:
0969:            private static boolean matchAccess(FieldOrMethod item, int access) {
0970:                if (item.isPublic()) {
0971:                    return true;
0972:                } else if (item.isProtected()) {
0973:                    return access <= PROTECTED_ACCESS;
0974:                } else if (item.isPrivate()) {
0975:                    return access == PRIVATE_ACCESS;
0976:                } else {
0977:                    return access <= PACKAGE_ACCESS;
0978:                }
0979:            }
0980:
0981:            /**
0982:             * Check if one type is assignment compatible with another type. This is an
0983:             * ugly replacement for apparently broken BCEL code.
0984:             * 
0985:             * @param have type being checked
0986:             * @param need type needed
0987:             * @return <code>true</code> if compatible, <code>false</code> if not
0988:             */
0989:            private static boolean isAssignmentCompatible(Type have, Type need) {
0990:                if (have.equals(need)) {
0991:                    return true;
0992:                } else {
0993:                    try {
0994:                        return ClassItem.isAssignable(have.toString(), need
0995:                                .toString());
0996:                    } catch (JiBXException e) {
0997:                        throw new IllegalStateException(
0998:                                "Internal error: Unable to access data for "
0999:                                        + have.toString() + " or "
1000:                                        + need.toString() + ":\n"
1001:                                        + e.getMessage());
1002:                    }
1003:                }
1004:            }
1005:
1006:            /**
1007:             * Get information for best matching method. This tries to find a method
1008:             * which matches the specified name, return type, and argument types. If an
1009:             * exact match is not found it looks for a method with a return type that
1010:             * is extended or implemented by the specified type and arguments that are
1011:             * extended or implemented by the specified types. This can only be used
1012:             * with existing classes. If the method is not found directly, superclasses
1013:             * are checked for inherited methods.
1014:             *
1015:             * @param name method name
1016:             * @param access access level required for matching methods
1017:             * @param ret return value type (<code>null</code> if indeterminant)
1018:             * @param args argument value types
1019:             * @return method information, or <code>null</code> if method not found
1020:             */
1021:
1022:            private Method getBestAccessibleMethod(String name, int access,
1023:                    Type ret, Type[] args) {
1024:
1025:                // just fail for classes that aren't loadable
1026:                if (m_curClass == null) {
1027:                    return null;
1028:                }
1029:
1030:                // check for match to method defined in class
1031:                Method[] methods = getMethods();
1032:                Method best = null;
1033:                int diff = Integer.MAX_VALUE;
1034:                for (int i = 0; i < methods.length; i++) {
1035:                    Method method = methods[i];
1036:                    if (method.getName().equals(name)
1037:                            && matchAccess(method, access)) {
1038:
1039:                        // make sure the return type is compatible
1040:                        boolean match = true;
1041:                        int ndiff = 0;
1042:                        if (ret != null) {
1043:                            Type type = method.getReturnType();
1044:                            match = isAssignmentCompatible(ret, type);
1045:                        }
1046:                        if (match) {
1047:
1048:                            // check closeness of argument types
1049:                            Type[] types = method.getArgumentTypes();
1050:                            if (args.length == types.length) {
1051:                                for (int j = 0; j < args.length; j++) {
1052:                                    Type type = types[j];
1053:                                    Type arg = args[j];
1054:                                    if (!type.equals(arg)) {
1055:                                        ndiff++;
1056:                                        match = isAssignmentCompatible(arg,
1057:                                                type);
1058:                                        if (!match) {
1059:                                            break;
1060:                                        }
1061:                                    }
1062:                                }
1063:                            } else {
1064:                                match = false;
1065:                            }
1066:                        }
1067:                        if (match && ndiff < diff) {
1068:                            best = method;
1069:                        }
1070:                    }
1071:                }
1072:                if (best != null) {
1073:                    return best;
1074:                }
1075:
1076:                // try methods inherited from superclass if no match found
1077:                if (m_super Class != null) {
1078:                    if (access < PROTECTED_ACCESS) {
1079:                        if (m_isSamePackage) {
1080:                            access = PACKAGE_ACCESS;
1081:                        } else {
1082:                            access = PROTECTED_ACCESS;
1083:                        }
1084:                    }
1085:                    return m_super Class.getBestAccessibleMethod(name, access,
1086:                            ret, args);
1087:                } else {
1088:                    return null;
1089:                }
1090:            }
1091:
1092:            /**
1093:             * Get information for best matching method. This tries to find a method
1094:             * which matches the specified name, return type, and argument types. If an
1095:             * exact match is not found it looks for a method with a return type that
1096:             * is extended or implemented by the specified type and arguments that are
1097:             * extended or implemented by the specified types. This can only be used
1098:             * with existing classes. If the method is not found directly, superclasses
1099:             * are checked for inherited methods.
1100:             *
1101:             * @param name method name
1102:             * @param ret return value type (<code>null</code> if indeterminant)
1103:             * @param args argument value types
1104:             * @return method information, or <code>null</code> if method not found
1105:             */
1106:
1107:            public ClassItem getBestMethod(String name, String ret,
1108:                    String[] args) {
1109:                Type rtype = null;
1110:                if (ret != null) {
1111:                    rtype = ClassItem.typeFromName(ret);
1112:                }
1113:                Type[] atypes = new Type[args.length];
1114:                for (int i = 0; i < args.length; i++) {
1115:                    atypes[i] = ClassItem.typeFromName(args[i]);
1116:                }
1117:                Method method = getBestAccessibleMethod(name, PRIVATE_ACCESS,
1118:                        rtype, atypes);
1119:                if (method == null) {
1120:                    return null;
1121:                }
1122:                ClassItem item = (ClassItem) m_itemMap.get(method);
1123:                if (item == null) {
1124:                    item = new ClassItem(name, this , method);
1125:                    m_itemMap.put(method, item);
1126:                }
1127:                return item;
1128:            }
1129:
1130:            /**
1131:             * Get information for initializer. This can only be used with existing
1132:             * classes. Only the class itself is checked for an initializer matching
1133:             * the argument list signature.
1134:             *
1135:             * @param sig encoded argument list signature
1136:             * @return method information, or <code>null</code> if method not found
1137:             */
1138:
1139:            public ClassItem getInitializerMethod(String sig) {
1140:
1141:                // only check if loadable class
1142:                if (m_curClass != null) {
1143:
1144:                    // check for match to method defined in class
1145:                    Method[] methods = getMethods();
1146:                    for (int i = 0; i < methods.length; i++) {
1147:                        Method method = methods[i];
1148:                        if (method.getName().equals("<init>")) {
1149:                            if (method.getSignature().startsWith(sig)) {
1150:                                ClassItem item = (ClassItem) m_itemMap
1151:                                        .get(method);
1152:                                if (item == null) {
1153:                                    item = new ClassItem("<init>", this , method);
1154:                                    m_itemMap.put(method, item);
1155:                                }
1156:                                return item;
1157:                            }
1158:                        }
1159:                    }
1160:
1161:                }
1162:                return null;
1163:            }
1164:
1165:            /**
1166:             * Get information for static method without respect to return value. This
1167:             * can only be used with existing classes. Only the class itself is checked
1168:             * for a method matching the supplied name and argument list signature.
1169:             *
1170:             * @param name method name
1171:             * @param sig encoded argument list signature
1172:             * @return method information, or <code>null</code> if method not found
1173:             */
1174:
1175:            public ClassItem getStaticMethod(String name, String sig) {
1176:
1177:                // only check if loadable class
1178:                if (m_curClass != null) {
1179:
1180:                    // check for match to method defined in class
1181:                    Method[] methods = getMethods();
1182:                    for (int i = 0; i < methods.length; i++) {
1183:                        Method method = methods[i];
1184:                        if (method.getName().equals(name) && method.isStatic()) {
1185:                            if (method.getSignature().startsWith(sig)) {
1186:                                ClassItem item = (ClassItem) m_itemMap
1187:                                        .get(method);
1188:                                if (item == null) {
1189:                                    item = new ClassItem(name, this , method);
1190:                                    m_itemMap.put(method, item);
1191:                                }
1192:                                return item;
1193:                            }
1194:                        }
1195:                    }
1196:
1197:                }
1198:                return null;
1199:            }
1200:
1201:            /**
1202:             * Get all binding methods currently defined in class. Binding methods are
1203:             * generally identified by a supplied prefix, but additional methods
1204:             * can be specified the the combination of exact name and signature. This
1205:             * is a little kludgy, but necessary to handle the "marshal" method added
1206:             * to mapped classes.
1207:             *
1208:             * @param prefix identifying prefix for binding methods
1209:             * @param matches pairs of method name and signature to be matched as
1210:             * exceptions to the prefix matching
1211:             * @return existing binding methods
1212:             */
1213:
1214:            public ExistingMethod[] getBindingMethods(String prefix,
1215:                    String[] matches) {
1216:
1217:                // return empty array if newly created class or unloadable class
1218:                if (m_curClass == null) {
1219:                    return EMPTY_METHOD_ARRAY;
1220:                }
1221:
1222:                // check for binding methods defined in class
1223:                Method[] methods = getMethods();
1224:                int count = 0;
1225:                for (int i = 0; i < methods.length; i++) {
1226:                    Method method = methods[i];
1227:                    String name = method.getName();
1228:                    if (name.startsWith(prefix)) {
1229:                        count++;
1230:                    } else {
1231:                        String sig = method.getSignature();
1232:                        for (int j = 0; j < matches.length; j += 2) {
1233:                            if (name.equals(matches[j])
1234:                                    && sig.equals(matches[j + 1])) {
1235:                                count++;
1236:                                break;
1237:                            }
1238:                        }
1239:                    }
1240:                }
1241:
1242:                // generate array of methods found
1243:                if (count == 0) {
1244:                    return EMPTY_METHOD_ARRAY;
1245:                } else {
1246:                    ExistingMethod[] exists = new ExistingMethod[count];
1247:                    int fill = 0;
1248:                    for (int i = 0; i < methods.length; i++) {
1249:                        Method method = methods[i];
1250:                        String name = method.getName();
1251:                        boolean match = name.startsWith(prefix);
1252:                        if (!match) {
1253:                            String sig = method.getSignature();
1254:                            for (int j = 0; j < matches.length; j += 2) {
1255:                                if (name.equals(matches[j])
1256:                                        && sig.equals(matches[j + 1])) {
1257:                                    match = true;
1258:                                    break;
1259:                                }
1260:                            }
1261:                        }
1262:                        if (match) {
1263:                            ClassItem item = (ClassItem) m_itemMap.get(method);
1264:                            if (item == null) {
1265:                                item = new ClassItem(name, this , method);
1266:                                m_itemMap.put(method, item);
1267:                            }
1268:                            exists[fill++] = new ExistingMethod(method, item,
1269:                                    this );
1270:                        }
1271:                    }
1272:                    return exists;
1273:                }
1274:            }
1275:
1276:            /**
1277:             * Check accessible method. Check if a field or method in another class is
1278:             * accessible from within this class.
1279:             *
1280:             * @param item field or method information
1281:             * @return <code>true</code> if accessible, <code>false</code> if not
1282:             */
1283:
1284:            public boolean isAccessible(ClassItem item) {
1285:                if (item.getClassFile() == this ) {
1286:                    return true;
1287:                } else {
1288:                    int access = item.getAccessFlags();
1289:                    if ((access & Constants.ACC_PUBLIC) != 0) {
1290:                        return true;
1291:                    } else if ((access & Constants.ACC_PRIVATE) != 0) {
1292:                        return false;
1293:                    } else if (getPackage().equals(
1294:                            item.getClassFile().getPackage())) {
1295:                        return true;
1296:                    } else if ((access & Constants.ACC_PROTECTED) != 0) {
1297:                        ClassFile target = item.getClassFile();
1298:                        ClassFile ancestor = this ;
1299:                        while ((ancestor = ancestor.getSuperFile()) != null) {
1300:                            if (ancestor == target) {
1301:                                return true;
1302:                            }
1303:                        }
1304:                        return false;
1305:                    } else {
1306:                        return false;
1307:                    }
1308:                }
1309:            }
1310:
1311:            /**
1312:             * Get generator for modifying class.
1313:             *
1314:             * @return generator for class
1315:             * @throws JiBXException if class not modifiable
1316:             */
1317:
1318:            private ClassGen getClassGen() throws JiBXException {
1319:                if (m_genClass == null) {
1320:                    if (m_isWritable) {
1321:                        m_genClass = new ClassGen(m_curClass);
1322:                        m_genPool = m_genClass.getConstantPool();
1323:                        m_instBuilder = new InstructionBuilder(m_genClass,
1324:                                m_genPool);
1325:                        m_isHashCurrent = false;
1326:                    } else {
1327:                        throw new JiBXException("Cannot modify class " + m_name);
1328:                    }
1329:                }
1330:                return m_genClass;
1331:            }
1332:
1333:            /**
1334:             * Get constant pool generator for modifying class.
1335:             *
1336:             * @return constant pool generator for class
1337:             * @throws JiBXException if class not modifiable
1338:             */
1339:
1340:            public ConstantPoolGen getConstPoolGen() throws JiBXException {
1341:                if (m_genPool == null) {
1342:                    getClassGen();
1343:                }
1344:                return m_genPool;
1345:            }
1346:
1347:            /**
1348:             * Get instruction builder for modifying class.
1349:             *
1350:             * @return instruction builder for class
1351:             * @throws JiBXException if class not modifiable
1352:             */
1353:
1354:            public InstructionBuilder getInstructionBuilder()
1355:                    throws JiBXException {
1356:                if (m_instBuilder == null) {
1357:                    getClassGen();
1358:                }
1359:                return m_instBuilder;
1360:            }
1361:
1362:            /**
1363:             * Add method to class.
1364:             * 
1365:             * @param method method to be added
1366:             * @return added method information
1367:             * @throws JiBXException on error in adding method
1368:             */
1369:
1370:            public ClassItem addMethod(Method method) throws JiBXException {
1371:                getClassGen().addMethod(method);
1372:                setModified();
1373:                String mname = method.getName();
1374:                if (m_suffixMap != null && isSuffixName(mname)) {
1375:                    m_suffixMap.put(mname, method);
1376:                }
1377:                return new ClassItem(mname, this , method);
1378:            }
1379:
1380:            /**
1381:             * Remove method from class.
1382:             * 
1383:             * @param method method to be removed
1384:             * @throws JiBXException on error in removing method
1385:             */
1386:
1387:            public void removeMethod(Method method) throws JiBXException {
1388:                getClassGen().removeMethod(method);
1389:                setModified();
1390:                String mname = method.getName();
1391:                if (m_suffixMap != null && isSuffixName(mname)) {
1392:                    m_suffixMap.remove(mname);
1393:                }
1394:            }
1395:
1396:            /**
1397:             * Add field to class with initial <code>String</code> value. If a field
1398:             * with the same name already exists, it is overwritten.
1399:             *
1400:             * @param type fully qualified class name of field type
1401:             * @param name field name
1402:             * @param access access flags for field
1403:             * @param init initial value for field
1404:             * @return field information
1405:             * @throws JiBXException if unable to add field
1406:             */
1407:
1408:            public ClassItem addField(String type, String name, int access,
1409:                    String init) throws JiBXException {
1410:                deleteField(name);
1411:                FieldGen fgen = new FieldGen(access, Type.getType(Utility
1412:                        .getSignature(type)), name, getConstPoolGen());
1413:                fgen.setInitValue(init);
1414:                Field field = fgen.getField();
1415:                getClassGen().addField(field);
1416:                m_isModified = true;
1417:                m_isHashCurrent = false;
1418:                return new ClassItem(name, this , field);
1419:            }
1420:
1421:            /**
1422:             * Update class field with initial <code>String</code> value. If the field
1423:             * already exists with the same characteristics it is left unchanged;
1424:             * otherwise any existing field with the same name is overwritten.
1425:             *
1426:             * @param type fully qualified class name of field type
1427:             * @param name field name
1428:             * @param access access flags for field
1429:             * @param init initial value for field
1430:             * @return field information
1431:             * @throws JiBXException if unable to add field
1432:             */
1433:
1434:            public ClassItem updateField(String type, String name, int access,
1435:                    String init) throws JiBXException {
1436:
1437:                // first check for match with existing field
1438:                Field[] fields = m_curClass.getFields();
1439:                for (int i = 0; i < fields.length; i++) {
1440:                    Field field = fields[i];
1441:                    if (field.getName().equals(name)
1442:                            && field.getAccessFlags() == access) {
1443:                        String sig = field.getSignature();
1444:                        if (type.equals(Utility.signatureToString(sig, false))) {
1445:                            ConstantValue cval = field.getConstantValue();
1446:                            if (cval != null) {
1447:                                int index = cval.getConstantValueIndex();
1448:                                ConstantPool cp = m_curClass.getConstantPool();
1449:                                Constant cnst = cp.getConstant(index);
1450:                                if (cnst instanceof  ConstantString) {
1451:                                    Object value = ((ConstantString) cnst)
1452:                                            .getConstantValue(cp);
1453:                                    if (init.equals(value)) {
1454:                                        return new ClassItem(name, this , field);
1455:                                    }
1456:                                }
1457:                            }
1458:                        }
1459:                    }
1460:                }
1461:
1462:                // no exact match, so replace any existing field with same name
1463:                deleteField(name);
1464:                FieldGen fgen = new FieldGen(access, Type.getType(Utility
1465:                        .getSignature(type)), name, getConstPoolGen());
1466:                fgen.setInitValue(init);
1467:                Field field = fgen.getField();
1468:                getClassGen().addField(field);
1469:                m_isModified = true;
1470:                m_isHashCurrent = false;
1471:                return new ClassItem(name, this , field);
1472:            }
1473:
1474:            /**
1475:             * Add field to class without initialization. If a field with the same name
1476:             * already exists, it is overwritten.
1477:             *
1478:             * @param type fully qualified class name of field type
1479:             * @param name field name
1480:             * @param access access flags for field
1481:             * @return field information
1482:             * @throws JiBXException if unable to add field
1483:             */
1484:
1485:            public ClassItem addField(String type, String name, int access)
1486:                    throws JiBXException {
1487:                deleteField(name);
1488:                FieldGen fgen = new FieldGen(access, Type.getType(Utility
1489:                        .getSignature(type)), name, getConstPoolGen());
1490:                Field field = fgen.getField();
1491:                getClassGen().addField(field);
1492:                m_isModified = true;
1493:                m_isHashCurrent = false;
1494:                return new ClassItem(name, this , field);
1495:            }
1496:
1497:            /**
1498:             * Add private field to class without initialization. If a field
1499:             * with the same name already exists, it is overwritten.
1500:             *
1501:             * @param type fully qualified class name of field type
1502:             * @param name field name
1503:             * @return field information
1504:             * @throws JiBXException if unable to add field
1505:             */
1506:
1507:            public ClassItem addPrivateField(String type, String name)
1508:                    throws JiBXException {
1509:                return addField(type, name, PRIVATEFIELD_ACCESS);
1510:            }
1511:
1512:            /**
1513:             * Add default constructor to a class. The added default constructor just
1514:             * calls the default constructor for the superclass. If the superclass
1515:             * doesn't have a default constructor, this method is called recursively to
1516:             * add one if possible.
1517:             *
1518:             * @return constructor information
1519:             * @throws JiBXException if unable to add constructor
1520:             */
1521:
1522:            public ClassItem addDefaultConstructor() throws JiBXException {
1523:                if (m_defaultConstructor == null) {
1524:
1525:                    // check for default constructor in superclass
1526:                    ClassItem cons = m_super Class.getInitializerMethod("()V");
1527:                    if (cons == null) {
1528:                        if (m_super Class.addDefaultConstructor() == null) {
1529:                            return null;
1530:                        }
1531:                    } else {
1532:                        cons.makeAccessible(this );
1533:                    }
1534:
1535:                    // add the public constructor method
1536:                    ExceptionMethodBuilder mb = new ExceptionMethodBuilder(
1537:                            "<init>", Type.VOID, new Type[0], this ,
1538:                            Constants.ACC_PUBLIC);
1539:
1540:                    // call the superclass constructor
1541:                    mb.appendLoadLocal(0);
1542:                    mb.appendCallInit(m_super Class.getName(), "()V");
1543:
1544:                    // finish with return
1545:                    mb.appendReturn();
1546:                    mb.codeComplete(false);
1547:                    m_defaultConstructor = mb.addMethod();
1548:
1549:                }
1550:                return m_defaultConstructor;
1551:            }
1552:
1553:            /**
1554:             * Check if a method name matches the pattern for a generated unique suffix.
1555:             *
1556:             * @param name method name to be checked
1557:             * @return <code>true</code> if name matches suffix pattern,
1558:             * <code>false</code> if not
1559:             */
1560:
1561:            private static boolean isSuffixName(String name) {
1562:                int last = name.length() - 1;
1563:                for (int i = last; i > 0; i--) {
1564:                    char chr = name.charAt(i);
1565:                    if (chr == '_') {
1566:                        return i < last;
1567:                    } else if (!Character.isDigit(chr)) {
1568:                        break;
1569:                    }
1570:                }
1571:                return false;
1572:            }
1573:
1574:            /**
1575:             * Make method name unique with generated suffix. The suffixed method name
1576:             * is tracked so that it will not be used again.
1577:             *
1578:             * @param name base name before suffix is appended
1579:             * @return name with unique suffix appended
1580:             */
1581:
1582:            public String makeUniqueMethodName(String name) {
1583:
1584:                // check if map creation is needed
1585:                if (m_suffixMap == null) {
1586:                    m_suffixMap = new HashMap();
1587:                    if (m_curClass != null) {
1588:                        Method[] methods = getMethods();
1589:                        for (int i = 0; i < methods.length; i++) {
1590:                            Method method = methods[i];
1591:                            String mname = method.getName();
1592:                            if (isSuffixName(mname)) {
1593:                                m_suffixMap.put(mname, method);
1594:                            }
1595:                        }
1596:                    }
1597:                }
1598:
1599:                // check if inheritance depth is needed
1600:                if (m_inheritDepth == 0) {
1601:                    ClassFile cf = this ;
1602:                    while ((cf = cf.getSuperFile()) != null) {
1603:                        m_inheritDepth++;
1604:                    }
1605:                }
1606:
1607:                // generate suffix to make name unique, trying low values first
1608:                while (true) {
1609:                    String uname = name + '_' + m_inheritDepth + '_'
1610:                            + m_uniqueIndex;
1611:                    if (m_suffixMap.get(uname) == null) {
1612:                        return uname;
1613:                    } else {
1614:                        m_uniqueIndex++;
1615:                    }
1616:                }
1617:            }
1618:
1619:            /**
1620:             * Delete field from class.
1621:             *
1622:             * @param name field name
1623:             * @return <code>true</code> if field was present, <code>false</code> if not
1624:             * @throws JiBXException if unable to delete field
1625:             */
1626:
1627:            public boolean deleteField(String name) throws JiBXException {
1628:                ClassGen cg = getClassGen();
1629:                Field field = cg.containsField(name);
1630:                if (field == null) {
1631:                    return false;
1632:                } else {
1633:                    cg.removeField(field);
1634:                    m_isModified = true;
1635:                    m_isHashCurrent = false;
1636:                    return true;
1637:                }
1638:            }
1639:
1640:            /**
1641:             * Get use count for class.
1642:             *
1643:             * @return use count for this class
1644:             */
1645:
1646:            public int getUseCount() {
1647:                return m_useCount;
1648:            }
1649:
1650:            /**
1651:             * Increment use count for class.
1652:             *
1653:             * @return use count (after increment)
1654:             */
1655:
1656:            public int incrementUseCount() {
1657:                return ++m_useCount;
1658:            }
1659:
1660:            /**
1661:             * Check if class has been modified.
1662:             *
1663:             * @return <code>true</code> if class is modified, <code>false</code> if not
1664:             */
1665:
1666:            public boolean isModified() {
1667:                return m_isModified;
1668:            }
1669:
1670:            /**
1671:             * Set class modified flag.
1672:             */
1673:
1674:            public void setModified() {
1675:                m_isModified = true;
1676:                MungedClass.addModifiedClass(this );
1677:            }
1678:
1679:            /**
1680:             * Check if class is in complete state.
1681:             *
1682:             * @return <code>true</code> if class is complete, <code>false</code> if not
1683:             */
1684:
1685:            public boolean isComplete() {
1686:                return m_genClass == null;
1687:            }
1688:
1689:            /**
1690:             * Computes a hash code based on characteristics of the class. The 
1691:             * characteristics used in computing the hash code include the base class,
1692:             * implemented interfaces, method names, field names, and package, but not
1693:             * the actual class name or signature. The current static version of the
1694:             * class is used for this computation, so if the class is being modified
1695:             * {@link #codeComplete} should be called before this method. Note that this
1696:             * is designed for use with the classes generated by JiBX, and is not
1697:             * necessarily a good model for general usage.
1698:             * 
1699:             * @return computed hash code value
1700:             */
1701:
1702:            protected int computeHashCode() {
1703:
1704:                // start with basic characteristics of class
1705:                int hash = getPackage().hashCode();
1706:                ClassFile sfile = getSuperFile();
1707:                if (sfile != null) {
1708:                    hash += sfile.getName().hashCode();
1709:                }
1710:                String[] intfs = getInterfaces();
1711:                for (int i = 0; i < intfs.length; i++) {
1712:                    hash += intfs[i].hashCode();
1713:                }
1714:                hash += m_curClass.getAccessFlags();
1715:
1716:                // include field and method names
1717:                Field[] fields = m_curClass.getFields();
1718:                for (int i = 0; i < fields.length; i++) {
1719:                    hash = hash * 49 + fields[i].getName().hashCode();
1720:                }
1721:                Method[] methods = m_curClass.getMethods();
1722:                for (int i = 0; i < methods.length; i++) {
1723:                    hash = hash * 49 + methods[i].getName().hashCode();
1724:                }
1725:
1726:                // finish with constant table simple values (except name and signature)
1727:                Constant[] cnsts = m_curClass.getConstantPool()
1728:                        .getConstantPool();
1729:                for (int i = m_curClass.getClassNameIndex() + 1; i < cnsts.length; i++) {
1730:                    Constant cnst = cnsts[i];
1731:                    if (cnst != null) {
1732:                        int value = 0;
1733:                        switch (cnst.getTag()) {
1734:                        case Constants.CONSTANT_Double:
1735:                            value = (int) Double
1736:                                    .doubleToRawLongBits(((ConstantDouble) cnst)
1737:                                            .getBytes());
1738:                            break;
1739:                        case Constants.CONSTANT_Float:
1740:                            value = Float
1741:                                    .floatToRawIntBits(((ConstantFloat) cnst)
1742:                                            .getBytes());
1743:                            break;
1744:                        case Constants.CONSTANT_Integer:
1745:                            value = ((ConstantInteger) cnst).getBytes();
1746:                            break;
1747:                        case Constants.CONSTANT_Long:
1748:                            value = (int) ((ConstantLong) cnst).getBytes();
1749:                            break;
1750:                        case Constants.CONSTANT_Utf8:
1751:                            String text = ((ConstantUtf8) cnst).getBytes();
1752:                            if (!text.equals(m_signature)) {
1753:                                value = text.hashCode();
1754:                            }
1755:                            break;
1756:                        default:
1757:                            break;
1758:                        }
1759:                        hash = hash * 49 + value;
1760:                    }
1761:                }
1762:                //      System.out.println("Hashed " + m_name + " to value " + hash);
1763:                return hash;
1764:            }
1765:
1766:            /**
1767:             * Finalize current modified state of class. This converts the modified
1768:             * class state into a static form, then computes a hash code based on 
1769:             * characteristics of the class. If the class has not been modified it
1770:             * just computes the hash code. Note that this won't initialize the array
1771:             * of superinterfaces if used with an interface, but that shouldn't be a
1772:             * problem since we don't create any interfaces.
1773:             */
1774:
1775:            public void codeComplete() {
1776:                if (m_genClass != null) {
1777:                    m_curClass = m_genClass.getJavaClass();
1778:                    m_interfaceNames = m_curClass.getInterfaceNames();
1779:                    m_super Interfaces = new ClassFile[0];
1780:                    m_genClass = null;
1781:                }
1782:            }
1783:
1784:            /**
1785:             * Get hash code. This is based on most characteristics of the class,
1786:             * including the actual methods, but excluding the class name. It is only
1787:             * valid after the {@link #codeComplete} method is called.
1788:             * 
1789:             * @return hash code based on code sequence
1790:             */
1791:
1792:            public int hashCode() {
1793:                if (!m_isHashCurrent) {
1794:                    if (m_genClass != null) {
1795:                        throw new IllegalStateException(
1796:                                "Class still being constructed");
1797:                    }
1798:                    m_hashCode = computeHashCode();
1799:                    m_isHashCurrent = true;
1800:                }
1801:                return m_hashCode;
1802:            }
1803:
1804:            /**
1805:             * Compare two field or method items to see if they're equal. This handles
1806:             * only the comparisons that apply to both fields and methods. It does not
1807:             * include comparing access flags, since these may be different due to
1808:             * access requirements.
1809:             * 
1810:             * @param a first field or method item
1811:             * @param b second field or method item
1812:             * @return <code>true</code> if the equal, <code>false</code> if not
1813:             */
1814:
1815:            public static boolean equalFieldOrMethods(FieldOrMethod a,
1816:                    FieldOrMethod b) {
1817:                return a.getName().equals(b.getName())
1818:                        && a.getSignature().equals(b.getSignature());
1819:            }
1820:
1821:            /**
1822:             * Compare two methods to see if they're equal. This checks only the details
1823:             * of the exception handling and actual code, not the name or signature.
1824:             * 
1825:             * @param a first method
1826:             * @param b second method
1827:             * @return <code>true</code> if the equal, <code>false</code> if not
1828:             */
1829:
1830:            public static boolean equalMethods(Method a, Method b) {
1831:
1832:                // check the exceptions thrown by the method
1833:                ExceptionTable etaba = a.getExceptionTable();
1834:                ExceptionTable etabb = b.getExceptionTable();
1835:                if (etaba != null && etabb != null) {
1836:                    String[] aexcepts = etaba.getExceptionNames();
1837:                    String[] bexcepts = etabb.getExceptionNames();
1838:                    if (!Arrays.equals(aexcepts, bexcepts)) {
1839:                        return false;
1840:                    }
1841:                } else if (etaba != null || etabb != null) {
1842:                    return false;
1843:                }
1844:
1845:                // compare the exception handling details
1846:                Code acode = a.getCode();
1847:                Code bcode = b.getCode();
1848:                CodeException[] acexs = acode.getExceptionTable();
1849:                CodeException[] bcexs = bcode.getExceptionTable();
1850:                if (acexs.length == bcexs.length) {
1851:                    for (int i = 0; i < acexs.length; i++) {
1852:                        CodeException acex = acexs[i];
1853:                        CodeException bcex = bcexs[i];
1854:                        if (acex.getCatchType() != bcex.getCatchType()
1855:                                || acex.getStartPC() != bcex.getStartPC()
1856:                                || acex.getEndPC() != bcex.getEndPC()
1857:                                || acex.getHandlerPC() != bcex.getHandlerPC()) {
1858:                            return false;
1859:                        }
1860:                    }
1861:                }
1862:
1863:                // finally compare the actual byte codes
1864:                return Arrays.equals(acode.getCode(), bcode.getCode());
1865:            }
1866:
1867:            /**
1868:             * Check if objects are equal. Compares first based on hash code, then on
1869:             * the actual contents of the class, including package, implemented
1870:             * interfaces, superclass, methods, and fields (but not the actual class
1871:             * name). It is only valid after the {@link #codeComplete} method is called.
1872:             * 
1873:             * @return <code>true</code> if equal objects, <code>false</code> if not
1874:             */
1875:
1876:            public boolean equals(Object obj) {
1877:                if (obj instanceof  ClassFile && obj.hashCode() == hashCode()) {
1878:
1879:                    // check basic details of the classes
1880:                    ClassFile comp = (ClassFile) obj;
1881:                    if (!org.jibx.runtime.Utility.isEqual(getPackage(), comp
1882:                            .getPackage())
1883:                            || getSuperFile() != comp.getSuperFile()
1884:                            || !Arrays.equals(getInterfaces(), comp
1885:                                    .getInterfaces())) {
1886:                        return false;
1887:                    }
1888:                    JavaClass tjc = m_curClass;
1889:                    JavaClass cjc = comp.m_curClass;
1890:                    if (tjc.getAccessFlags() != cjc.getAccessFlags()) {
1891:                        return false;
1892:                    }
1893:
1894:                    // compare the defined fields
1895:                    Field[] tfields = tjc.getFields();
1896:                    Field[] cfields = cjc.getFields();
1897:                    if (tfields.length != cfields.length) {
1898:                        return false;
1899:                    }
1900:                    for (int i = 0; i < tfields.length; i++) {
1901:                        if (!equalFieldOrMethods(tfields[i], cfields[i])) {
1902:                            return false;
1903:                        }
1904:                    }
1905:
1906:                    // compare the defined methods
1907:                    Method[] tmethods = tjc.getMethods();
1908:                    Method[] cmethods = cjc.getMethods();
1909:                    if (tmethods.length != cmethods.length) {
1910:                        return false;
1911:                    }
1912:                    for (int i = 0; i < tmethods.length; i++) {
1913:                        Method tmethod = tmethods[i];
1914:                        Method cmethod = cmethods[i];
1915:                        if (!equalFieldOrMethods(tmethod, cmethod)
1916:                                || !equalMethods(tmethod, cmethod)) {
1917:                            return false;
1918:                        }
1919:                    }
1920:
1921:                    // finish with constant table values (correcting name and signature)
1922:                    Constant[] tcnsts = tjc.getConstantPool().getConstantPool();
1923:                    Constant[] ccnsts = cjc.getConstantPool().getConstantPool();
1924:                    if (tcnsts.length != ccnsts.length) {
1925:                        return false;
1926:                    }
1927:                    for (int i = tjc.getClassNameIndex() + 1; i < tcnsts.length; i++) {
1928:                        Constant tcnst = tcnsts[i];
1929:                        Constant ccnst = ccnsts[i];
1930:                        if (tcnst != null && ccnst != null) {
1931:                            int tag = tcnst.getTag();
1932:                            if (tag != ccnst.getTag()) {
1933:                                return false;
1934:                            }
1935:                            boolean equal = true;
1936:                            switch (tag) {
1937:                            case Constants.CONSTANT_Double:
1938:                                equal = ((ConstantDouble) tcnst).getBytes() == ((ConstantDouble) ccnst)
1939:                                        .getBytes();
1940:                                break;
1941:                            case Constants.CONSTANT_Float:
1942:                                equal = ((ConstantFloat) tcnst).getBytes() == ((ConstantFloat) ccnst)
1943:                                        .getBytes();
1944:                                break;
1945:                            case Constants.CONSTANT_Integer:
1946:                                equal = ((ConstantInteger) tcnst).getBytes() == ((ConstantInteger) ccnst)
1947:                                        .getBytes();
1948:                                break;
1949:                            case Constants.CONSTANT_Long:
1950:                                equal = ((ConstantLong) tcnst).getBytes() == ((ConstantLong) ccnst)
1951:                                        .getBytes();
1952:                                break;
1953:                            case Constants.CONSTANT_Utf8:
1954:                                String ttext = ((ConstantUtf8) tcnst)
1955:                                        .getBytes();
1956:                                String ctext = ((ConstantUtf8) ccnst)
1957:                                        .getBytes();
1958:                                if (ttext.equals(m_signature)) {
1959:                                    equal = ctext.equals(comp.m_signature);
1960:                                } else {
1961:                                    equal = ttext.equals(ctext);
1962:                                }
1963:                                break;
1964:                            default:
1965:                                break;
1966:                            }
1967:                            if (!equal) {
1968:                                return false;
1969:                            }
1970:                        } else if (tcnst != null || ccnst != null) {
1971:                            return false;
1972:                        }
1973:                    }
1974:
1975:                    // if nothing failed, the classes are equal
1976:                    return true;
1977:
1978:                } else {
1979:                    return false;
1980:                }
1981:            }
1982:
1983:            /**
1984:             * Delete class file information. Deletes the class file for this class,
1985:             * if it exists. Does nothing if no class file has been generated.
1986:             */
1987:
1988:            public void delete() {
1989:                if (m_file.exists()) {
1990:                    m_file.delete();
1991:                }
1992:            }
1993:
1994:            /**
1995:             * Write out modified class information. Writes the modified class file to
1996:             * an output stream.
1997:             *
1998:             * @param os output stream for writing modified class
1999:             * @throws IOException if error writing to file
2000:             */
2001:
2002:            public void writeFile(OutputStream os) throws IOException {
2003:                codeComplete();
2004:                m_curClass.dump(new BufferedOutputStream(os));
2005:                os.close();
2006:            }
2007:
2008:            /**
2009:             * Write out modified class information. Writes the modified class file
2010:             * back out to the original file. If the class file has not been modified,
2011:             * the original file is kept unchanged.
2012:             *
2013:             * @throws IOException if error writing to file
2014:             */
2015:
2016:            public void writeFile() throws IOException {
2017:                if (m_isModified) {
2018:                    OutputStream os = new FileOutputStream(m_file);
2019:                    writeFile(os);
2020:                }
2021:            }
2022:
2023:            /**
2024:             * Derive generated class name. This generates a JiBX class name from the
2025:             * name of this class, using the supplied prefix and suffix information. The
2026:             * derived class name is always in the same package as this class.
2027:             *
2028:             * @param prefix generated class name prefix
2029:             * @param suffix generated class name suffix
2030:             * @return derived class name
2031:             */
2032:
2033:            public String deriveClassName(String prefix, String suffix) {
2034:                String pack = "";
2035:                String tname = m_name;
2036:                int split = tname.lastIndexOf('.');
2037:                if (split >= 0) {
2038:                    pack = tname.substring(0, split + 1);
2039:                    tname = tname.substring(split + 1);
2040:                }
2041:                return pack + prefix + tname + suffix;
2042:            }
2043:
2044:            /**
2045:             * Set class paths to be searched.
2046:             *
2047:             * @param paths ordered set of paths to be searched for class files
2048:             */
2049:
2050:            public static void setPaths(String[] paths) {
2051:
2052:                // create full path string with separators for BCEL loader
2053:                StringBuffer full = new StringBuffer();
2054:                for (int i = 0; i < paths.length; i++) {
2055:                    if (i > 0) {
2056:                        full.append(File.pathSeparatorChar);
2057:                    }
2058:                    full.append(paths[i]);
2059:                }
2060:                s_loader = new ClassPath(full.toString());
2061:
2062:                // create direct classloader for access to classes during binding
2063:                URL[] urls = new URL[paths.length];
2064:                try {
2065:
2066:                    // generate array of component file or directory URLs
2067:                    for (int i = 0; i < urls.length; i++) {
2068:
2069:                        // append trailing slash on directory paths
2070:                        String path = paths[i];
2071:                        int mark = path.lastIndexOf('/');
2072:                        if (path.indexOf('.', mark) < 0) {
2073:                            path = path + '/';
2074:                        }
2075:                        urls[i] = new URL("file:" + path);
2076:                    }
2077:
2078:                    // initialize classloader with full array of paths
2079:                    s_directLoader = new URLClassLoader(urls);
2080:
2081:                } catch (MalformedURLException ex) {
2082:                    throw new IllegalArgumentException(
2083:                            "Error initializing classloading: "
2084:                                    + ex.getMessage());
2085:                }
2086:            }
2087:
2088:            /**
2089:             * Try loading class from classpath.
2090:             *
2091:             * @param name fully qualified name of class to be loaded
2092:             * @return loaded class, or <code>null</code> if not found
2093:             */
2094:
2095:            public static Class loadClass(String name) {
2096:                try {
2097:                    return s_directLoader.loadClass(name);
2098:                } catch (ClassNotFoundException ex) {
2099:                    return null;
2100:                }
2101:            }
2102:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.