Source Code Cross Referenced for ClassWrapGen.java in  » Scripting » oscript-2.10.4 » oscript » classwrap » 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 » Scripting » oscript 2.10.4 » oscript.classwrap 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*=============================================================================
0002:         *     Copyright Texas Instruments 2000.  All Rights Reserved.
0003:         *   
0004:         * This program is free software; you can redistribute it and/or
0005:         * modify it under the terms of the GNU Lesser General Public
0006:         * License as published by the Free Software Foundation; either
0007:         * version 2 of the License, or (at your option) any later version.
0008:         * 
0009:         * This program is distributed in the hope that it will be useful,
0010:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012:         * Lesser General Public License for more details.
0013:         * 
0014:         * You should have received a copy of the GNU Lesser General Public
0015:         * License along with this library; if not, write to the Free Software
0016:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0017:         * 
0018:         * $ProjectHeader: OSCRIPT 0.155 Fri, 20 Dec 2002 18:34:22 -0800 rclark $
0019:         */
0020:
0021:        package oscript.classwrap;
0022:
0023:        import oscript.data.*;
0024:        import oscript.exceptions.*;
0025:        import oscript.compiler.*;
0026:
0027:        // The Bytecode Engineerign Library
0028:        import org.apache.bcel.generic.*;
0029:        import org.apache.bcel.Constants;
0030:
0031:        import java.lang.reflect.*;
0032:        import java.util.*;
0033:        import java.util.Map.Entry;
0034:        import java.io.*;
0035:        import java.security.*;
0036:
0037:        /**
0038:         * The <code>classwrap</code> package is used to generate a "wrapper" for
0039:         * a java class.  A wrapper is just a subclass of a given java class, where
0040:         * for each public non-final, non-static method, a wrapper method and an
0041:         * "orig" method are generated.  The wrapper method looks up a property
0042:         * with the same name in the script object, and if it exists, and is a
0043:         * function that takes a compatible number of arguments, calls it,
0044:         * otherwise it calls the same method in the parent (original) java class.
0045:         * The orig method simply calls the same method in the parent class.
0046:         * <p>
0047:         * The "wrapper" class is used any place where a script objects extends
0048:         * a java class (ie. java class, java interface, or builtin-type).  The
0049:         * purpose is to allow the script object to override methods in a java
0050:         * class, or implement methods in a java interface.
0051:         * <p>
0052:         * The "wrapper" class is generated using the Byte Code Engineering Library
0053:         * (BCEL.jar).
0054:         * 
0055:         * @author Rob Clark (rob@ti.com)
0056:         * <!--$Format: " * @version $Revision$"$-->
0057:         * @version 1.34
0058:         */
0059:        public class ClassWrapGen {
0060:            private static java.util.Hashtable wrapperClassTable = new java.util.Hashtable();
0061:
0062:            /**
0063:             * The class that is being built.
0064:             */
0065:            private ClassGen cg;
0066:
0067:            /**
0068:             * The constant-pool of the class that is being built.
0069:             */
0070:            private ConstantPoolGen cp;
0071:
0072:            /**
0073:             */
0074:            private Class origClass;
0075:            private String origClassName;
0076:            private String className;
0077:
0078:            /**
0079:             * Table mapping symbol name to static member idx
0080:             */
0081:            private Hashtable symbolTable = new Hashtable();
0082:
0083:            /**
0084:             * Note, conflict between org.apache.bcel.generic.Type and oscript.data.Type.
0085:             */
0086:            private static final org.apache.bcel.generic.Type SCOPE_TYPE = new ObjectType(
0087:                    "oscript.data.Scope");
0088:            private static final ObjectType EXCEPTION_TYPE = new ObjectType(
0089:                    "oscript.exceptions.PackagedScriptObjectException");
0090:
0091:            /**
0092:             * Used to load a class from a <code>JavaClass</code>.
0093:             */
0094:            private static final CompilerClassLoader loader = CompilerClassLoader
0095:                    .getCompilerClassLoader();
0096:
0097:            /*=======================================================================*/
0098:            /**
0099:             * Check if we can make a wrapper class for the specified class... this
0100:             * is needed by JavaClassWrapper, which needs to know if it can construct
0101:             * a wrapper class... but it wants to defer the act of actually making
0102:             * the wrapper class.
0103:             * 
0104:             * @param origClass    the original class
0105:             * @return <code>true</code> if we can make a wrapper (ie. class isn't
0106:             * final, etc)
0107:             */
0108:            public static boolean canMakeWrapperClass(Class origClass) {
0109:                int m = origClass.getModifiers();
0110:                if (origClass.isPrimitive() || origClass.isArray())
0111:                    throw new ProgrammingErrorException(origClass
0112:                            + " is primitive or array");
0113:                else if (origClass.getName().endsWith("_wrapper"))
0114:                    throw new ProgrammingErrorException(origClass
0115:                            + " is already a wrapper class");
0116:                else if (Modifier.isFinal(m) || !Modifier.isPublic(m))
0117:                    return false;
0118:                else
0119:                    return true;
0120:            }
0121:
0122:            /*=======================================================================*/
0123:            /**
0124:             * Make the wrapper class.  Wrap all public non-final instance methods.
0125:             * 
0126:             * @param origClass    the original class
0127:             * @return the auto-generated wrapper class, or if a wrapper class cannot
0128:             * be generated, the <code>origClass</code>.  This should never return
0129:             * <code>null</code>.
0130:             */
0131:            public static synchronized Class makeWrapperClass(Class origClass) {
0132:                Class tmp;
0133:
0134:                if (!canMakeWrapperClass(origClass)) {
0135:                    return origClass;
0136:                } else if ((tmp = (Class) (wrapperClassTable.get(origClass))) != null) {
0137:                    /* this is ok, because of how JavaInnerClassWrapper works...
0138:                     * there will be a new JavaInnerClassWrapper instance for
0139:                     * each reference to an inner class (because it needs to
0140:                     * store "this" (the outer class instance))... since it
0141:                     * subclasses JavaClassWrapper, the net result is multiple
0142:                     * requests for the same wrapper class!
0143:                     */
0144:                    return tmp;
0145:                } else {
0146:                    String className = "wrap"
0147:                            + oscript.OscriptInterpreter.CACHE_VERSION + "."
0148:                            + origClass.getName() + "_wrapper";
0149:
0150:                    try {
0151:                        tmp = CompilerClassLoader.forName(className, false,
0152:                                null);
0153:                    } catch (ClassNotFoundException e) {
0154:                        tmp = null;
0155:                    }
0156:
0157:                    // if we can result the class, check to see if the serialVersionUID still
0158:                    // matches the wrapper classes' wrappedSerialVersionUID
0159:                    if (tmp != null) {
0160:                        try {
0161:                            if (computeInterfaceVersionUID(origClass) != ((Long) (tmp
0162:                                    .getDeclaredField("__interfaceVersionUID")
0163:                                    .get(null))).longValue())
0164:                                tmp = null;
0165:                        } catch (Throwable t) {
0166:                            tmp = null;
0167:                        }
0168:                    }
0169:
0170:                    if (tmp == null) {
0171:                        tmp = (new ClassWrapGen(origClass, className))
0172:                                .makeWrapperClassImpl();
0173:                    }
0174:
0175:                    if (tmp != null) {
0176:                        wrapperClassTable.put(origClass, tmp);
0177:                    }
0178:
0179:                    return tmp;
0180:                }
0181:            }
0182:
0183:            /*=======================================================================*/
0184:            /**
0185:             * Compute the interface version uid... this works in a manner similar 
0186:             * to the <code>serialVersionUID</code> that java's serialization uses,
0187:             * but since the code to compute the <code>serialVersionUID</code> isn't
0188:             * available to us, we have to recalculate it ourselves.  Since we have
0189:             * to calculate it anyways, we simplify a little by only taking into
0190:             * account things that would change the wrapper class itself (ie. public
0191:             * constructors and public methods), and thus reducing the number of 
0192:             * false negatives w.r.t. changes to the original java class.
0193:             * <p>
0194:             * NOTE: synchronized under the umbrella of {@link #makeWrapperClass}
0195:             */
0196:            private static final long computeInterfaceVersionUID(Class c) {
0197:                try {
0198:                    MessageDigest md = MessageDigest.getInstance("SHA");
0199:                    DataOutputStream dos = new DataOutputStream(
0200:                            new DigestOutputStream(new ByteArrayOutputStream(
0201:                                    512), md));
0202:
0203:                    //////////// Add public constructors:
0204:                    Constructor[] constructors = c.getConstructors();
0205:
0206:                    // sort the constructors, so a change in order doesn't change
0207:                    // the interface-UID:
0208:                    Arrays.sort(constructors, new Comparator() {
0209:
0210:                        public int compare(Object o1, Object o2) {
0211:                            int rc = ((Constructor) o1).getName().compareTo(
0212:                                    ((Constructor) o2).getName());
0213:
0214:                            if (rc == 0)
0215:                                rc = getSignature((Constructor) o1).compareTo(
0216:                                        getSignature((Constructor) o2));
0217:
0218:                            return rc;
0219:                        }
0220:
0221:                    });
0222:
0223:                    for (int i = 0; i < constructors.length; i++) {
0224:                        dos.writeUTF("<init>");
0225:                        dos.writeUTF(getSignature(constructors[i]));
0226:                    }
0227:
0228:                    //////////// Add public methods:
0229:                    Method[] methods = c.getMethods();
0230:
0231:                    // sort the methods, so a change in order doesn't change
0232:                    // the interface-UID:
0233:                    Arrays.sort(methods, new Comparator() {
0234:
0235:                        public int compare(Object o1, Object o2) {
0236:                            int rc = ((Method) o1).getName().compareTo(
0237:                                    ((Method) o2).getName());
0238:
0239:                            if (rc == 0)
0240:                                rc = getSignature((Method) o1).compareTo(
0241:                                        getSignature((Method) o2));
0242:
0243:                            return rc;
0244:                        }
0245:
0246:                    });
0247:
0248:                    for (int i = 0; i < methods.length; i++) {
0249:                        int mod = methods[i].getModifiers();
0250:                        if (!(Modifier.isStatic(mod) || Modifier.isFinal(mod))) {
0251:                            dos.writeUTF(methods[i].getName());
0252:                            dos.writeUTF(getSignature(methods[i]));
0253:                        }
0254:                    }
0255:
0256:                    dos.flush();
0257:                    byte[] hash = md.digest();
0258:
0259:                    // the UID is the first 64 bits of the hash:
0260:                    long uid = 0;
0261:                    for (int i = 0; i < Math.min(8, hash.length); i++)
0262:                        uid += (long) (hash[i] & 0xff) << (i * 8);
0263:
0264:                    return uid;
0265:                } catch (IOException e) {
0266:                    throw new ProgrammingErrorException("shouldn't happen: "
0267:                            + e.getMessage());
0268:                } catch (NoSuchAlgorithmException e) {
0269:                    throw new ProgrammingErrorException("shouldn't happen: "
0270:                            + e.getMessage());
0271:                }
0272:            }
0273:
0274:            private static final Hashtable constructorSignatureCache = new Hashtable();
0275:
0276:            private static final String getSignature(Constructor constructor) {
0277:                String str = (String) (constructorSignatureCache
0278:                        .get(constructor));
0279:                if (str == null) {
0280:                    StringBuffer sb = new StringBuffer();
0281:
0282:                    sb.append('(');
0283:
0284:                    Class[] params = constructor.getParameterTypes();
0285:
0286:                    for (int i = 0; i < params.length; i++)
0287:                        getSignature(params[i], sb);
0288:
0289:                    sb.append(")V");
0290:
0291:                    str = sb.toString();
0292:
0293:                    constructorSignatureCache.put(constructor, str);
0294:                }
0295:                return str;
0296:            }
0297:
0298:            private static final Hashtable methodSignatureCache = new Hashtable();
0299:
0300:            private static final String getSignature(Method method) {
0301:                String str = (String) (methodSignatureCache.get(method));
0302:                if (str == null) {
0303:                    StringBuffer sb = new StringBuffer();
0304:
0305:                    sb.append('(');
0306:
0307:                    Class[] params = method.getParameterTypes();
0308:
0309:                    for (int i = 0; i < params.length; i++)
0310:                        getSignature(params[i], sb);
0311:
0312:                    sb.append(")V");
0313:
0314:                    str = sb.toString();
0315:
0316:                    methodSignatureCache.put(method, str);
0317:                }
0318:                return str;
0319:            }
0320:
0321:            // no point in caching class signatures:
0322:            private static final void getSignature(Class c, StringBuffer sb) {
0323:                if (c.isArray()) {
0324:                    sb.append('[');
0325:                    getSignature(c.getComponentType(), sb);
0326:                } else if (c.isPrimitive()) {
0327:                    if (c == Integer.TYPE)
0328:                        sb.append('I');
0329:                    else if (c == Byte.TYPE)
0330:                        sb.append('B');
0331:                    else if (c == Long.TYPE)
0332:                        sb.append('J');
0333:                    else if (c == Float.TYPE)
0334:                        sb.append('F');
0335:                    else if (c == Double.TYPE)
0336:                        sb.append('D');
0337:                    else if (c == Short.TYPE)
0338:                        sb.append('S');
0339:                    else if (c == Character.TYPE)
0340:                        sb.append('C');
0341:                    else if (c == Boolean.TYPE)
0342:                        sb.append('Z');
0343:                    else if (c == Void.TYPE)
0344:                        sb.append('V');
0345:                    else
0346:                        throw new ProgrammingErrorException(
0347:                                "hmm, I don't know what " + c + " is");
0348:                } else {
0349:                    sb.append('L');
0350:                    sb.append(c.getName().replace('.', '/'));
0351:                    sb.append(';');
0352:                }
0353:            }
0354:
0355:            /*=======================================================================*/
0356:            /**
0357:             * Because the wrapper method looks to the script object first, before
0358:             * calling the wrapped method, there are times when we want to call the
0359:             * original method directly.  To do this, you call the "orig" method.
0360:             * To hide the naming convention, other code should use this method
0361:             * to get the name of the "orig" method for the named method.
0362:             * 
0363:             * @param javaObj      the java object
0364:             * @param methodName   the name of the method in the parent class
0365:             * @return the mangled name of the method that calls the requested
0366:             * method in the parent class, ie. the "orig" method.
0367:             */
0368:            public static String getOrigMethodName(Object javaObj,
0369:                    String methodName) {
0370:                // the java class may have been final, in which case javaObj is just
0371:                // a plain 'ol object:
0372:                if ((javaObj == null/*XXX*/)
0373:                        || (javaObj instanceof  WrappedClass))
0374:                    return "__orig_" + methodName;
0375:                else
0376:                    return methodName;
0377:            }
0378:
0379:            public static String getOrigMethodName(String methodName) {
0380:                return getOrigMethodName(null, methodName);
0381:            }
0382:
0383:            /*=======================================================================*/
0384:            /**
0385:             * Is the specified object an instance of a wrapper class?
0386:             * 
0387:             * @param javaObj      the java object to test
0388:             * @return <code>true</code> if instance of auto-generated wrapper class
0389:             */
0390:            public static boolean isWrapperInstance(Object javaObj) {
0391:                return (javaObj instanceof  WrappedClass)
0392:                        || (javaObj instanceof  WrappedInterface);
0393:            }
0394:
0395:            /*=======================================================================*/
0396:            /**
0397:             * Link the specified java object and script object.  The java object
0398:             * should be an instance of a wrapper class generated by the 
0399:             * <code>makeWrapperClass</code> method.
0400:             * 
0401:             * @param javaObj      the java object
0402:             * @param scriptObj    the script object
0403:             */
0404:            public static void linkObjects(Object javaObj, Scope scriptObj) {
0405:                ((Scope) scriptObj).__setJavaObject(javaObj);
0406:
0407:                // the java class may have been final, in which case javaObj is just
0408:                // a plain 'ol object:
0409:                if (javaObj instanceof  WrappedClass)
0410:                    ((WrappedClass) javaObj).__setScriptObject(scriptObj);
0411:                else if (javaObj instanceof  WrappedInterface)
0412:                    ((WrappedInterface) javaObj).__setScriptObject(scriptObj);
0413:                else if (Value.DEBUG)
0414:                    System.err.println("could not link:  javaObj=" + javaObj
0415:                            + " (" + javaObj.getClass() + "), scriptObj="
0416:                            + scriptObj + " (" + scriptObj.getType() + ")");
0417:            }
0418:
0419:            /*=======================================================================*/
0420:            /**
0421:             * Given a java object, which may be linked to a script object, return
0422:             * the linked script object.
0423:             * 
0424:             * @param javaObj      the java object
0425:             * @return the script object, or <code>null</code>
0426:             */
0427:            public static Value getScriptObject(Object javaObj) {
0428:                // the java class may have been final, in which case javaObj is just
0429:                // a plain 'ol object:
0430:                if (javaObj instanceof  WrappedClass)
0431:                    return ((WrappedClass) javaObj).__getScriptObject();
0432:                else if (javaObj instanceof  WrappedInterface)
0433:                    return ((WrappedInterface) javaObj).__getScriptObject();
0434:
0435:                return null;
0436:            }
0437:
0438:            /*=======================================================================*/
0439:            /**
0440:             * Given a java class that may or may not be a wrapper class, return a
0441:             * java class that is the closest super-class that is not a wrapper
0442:             * class.
0443:             * 
0444:             * @param javaClass    a java class that might be a wrapper class
0445:             * @return a java class that is not a wrapper class
0446:             */
0447:            public static final Class getNonWrapperClass(Class javaClass) {
0448:                Class tmp;
0449:
0450:                if (((tmp = javaClass.getSuperclass()) != null)
0451:                        && ((tmp = (Class) (wrapperClassTable.get(tmp))) != null)
0452:                        && (tmp == javaClass)) {
0453:                    return javaClass.getSuperclass();
0454:                } else {
0455:                    return javaClass;
0456:                }
0457:            }
0458:
0459:            /*=======================================================================*/
0460:            /**
0461:             */
0462:            private ClassWrapGen(Class origClass, String className) {
0463:                this .origClass = origClass;
0464:
0465:                this .origClassName = origClass.getName();
0466:                this .className = loader.makeClassName(className, true);
0467:            }
0468:
0469:            /*=======================================================================*/
0470:            /**
0471:             */
0472:            private Class makeWrapperClassImpl() {
0473:                /* NOTE: BCEL is not thread safe, so synchronize use of the library on
0474:                 *       the ClassGen class... we do the same thing in the script 
0475:                 *       compiler
0476:                 */
0477:                synchronized (ClassGen.class) {
0478:                    try {
0479:                        String super ClassName;
0480:                        String[] interfaceNames;
0481:
0482:                        if (origClass.isInterface()) {
0483:                            super ClassName = "java.lang.Object";
0484:                            interfaceNames = new String[] {
0485:                                    origClass.getName(),
0486:                                    "oscript.classwrap.WrappedInterface" };
0487:                        } else {
0488:                            super ClassName = origClassName;
0489:                            interfaceNames = new String[] { "oscript.classwrap.WrappedClass" };
0490:                        }
0491:
0492:                        cg = new ClassGen(className, super ClassName,
0493:                                "<generated>", Constants.ACC_PUBLIC
0494:                                        | Constants.ACC_SUPER, interfaceNames);
0495:
0496:                        cp = cg.getConstantPool();
0497:
0498:                        Constructor[] constructors = origClass
0499:                                .getConstructors();
0500:                        if (constructors.length > 0)
0501:                            for (int i = 0; i < constructors.length; i++)
0502:                                addConstructor(constructors[i]);
0503:                        else
0504:                            addEmptyConstructor();
0505:
0506:                        Method[] methods = origClass.getMethods();
0507:                        for (int i = 0; i < methods.length; i++) {
0508:                            int mod = methods[i].getModifiers();
0509:                            if (!(Modifier.isStatic(mod) || Modifier
0510:                                    .isFinal(mod)))
0511:                                addMethod(methods[i]);
0512:                        }
0513:
0514:                        addCommonJunk();
0515:
0516:                        if (Value.DEBUG && false) {
0517:                            try {
0518:                                org.apache.bcel.util.Class2HTML c2html = new org.apache.bcel.util.Class2HTML(
0519:                                        cg.getJavaClass(), "../");
0520:                            } catch (java.io.IOException e) {
0521:                                e.printStackTrace();
0522:                            }
0523:                        }
0524:
0525:                        return loader.makeClass(className, cg.getJavaClass());
0526:                    } catch (LinkageError e) {
0527:                        // this means we hit a bug of the compiler:
0528:                        e.printStackTrace();
0529:                        return null;
0530:                    }
0531:                }
0532:            }
0533:
0534:            private void addCommonJunk() {
0535:                // add the __interfaceVersionUID:
0536:                {
0537:                    FieldGen fg = new FieldGen(Constants.ACC_PUBLIC
0538:                            | Constants.ACC_FINAL | Constants.ACC_STATIC,
0539:                            org.apache.bcel.generic.Type.LONG,
0540:                            "__interfaceVersionUID", cp);
0541:                    cg.addField(fg.getField());
0542:                }
0543:
0544:                // add <clinit> to initialize static finals
0545:                {
0546:                    CompilerInstructionList il = new CompilerInstructionList();
0547:
0548:                    il.append(new PUSH(cp,
0549:                            computeInterfaceVersionUID(origClass)));
0550:                    il.append(new PUTSTATIC(cp.addFieldref(className,
0551:                            "__interfaceVersionUID", "J")));
0552:
0553:                    for (Iterator itr = symbolTable.entrySet().iterator(); itr
0554:                            .hasNext();) {
0555:                        Entry e = (Entry) (itr.next());
0556:                        String name = (String) (e.getKey());
0557:                        Integer iidx = (Integer) (e.getValue());
0558:                        il.append(new PUSH(cp, name));
0559:                        il.append(new INVOKESTATIC(cp.addMethodref(
0560:                                "oscript.data.Symbol", "getSymbol",
0561:                                "(Ljava/lang/String;)Loscript/data/Symbol;")));
0562:                        il.append(new INVOKEVIRTUAL(cp.addMethodref(
0563:                                "oscript.data.Symbol", "getId", "()I")));
0564:                        il.append(new PUTSTATIC(iidx.intValue()));
0565:                    }
0566:
0567:                    il.append(InstructionConstants.RETURN);
0568:
0569:                    MethodGen mg = new MethodGen(Constants.ACC_STATIC
0570:                            | Constants.ACC_PUBLIC | Constants.ACC_FINAL,
0571:                            org.apache.bcel.generic.Type.VOID,
0572:                            new org.apache.bcel.generic.Type[] {},
0573:                            new String[] {}, "<clinit>", className, il, cp);
0574:
0575:                    mg.setMaxStack();
0576:                    cg.addMethod(mg.getMethod());
0577:                }
0578:
0579:                // add the __scriptObject field:
0580:                {
0581:                    FieldGen fg = new FieldGen(Constants.ACC_PRIVATE,
0582:                            SCOPE_TYPE, "__scriptObject", cp);
0583:
0584:                    cg.addField(fg.getField());
0585:                }
0586:
0587:                // add the __setScriptObject method:
0588:                {
0589:                    CompilerInstructionList il = new CompilerInstructionList();
0590:                    il.append(InstructionConstants.ALOAD_0);
0591:                    il.append(InstructionConstants.ALOAD_1);
0592:                    //       il.append( new CHECKCAST( cp.addClass("oscript.data.Value") ) ); // XXX do we need this?
0593:                    il.append(new PUTFIELD(cp.addFieldref(className,
0594:                            "__scriptObject", "Loscript/data/Scope;")));
0595:                    il.append(InstructionConstants.RETURN);
0596:                    MethodGen mg = new MethodGen(Constants.ACC_PUBLIC
0597:                            | Constants.ACC_FINAL,
0598:                            org.apache.bcel.generic.Type.VOID,
0599:                            new org.apache.bcel.generic.Type[] { SCOPE_TYPE },
0600:                            new String[] { "val" }, "__setScriptObject",
0601:                            className, il, cp);
0602:
0603:                    mg.setMaxStack();
0604:                    cg.addMethod(mg.getMethod());
0605:                }
0606:
0607:                // add the __getScriptObject method:
0608:                {
0609:                    CompilerInstructionList il = new CompilerInstructionList();
0610:                    il.append(InstructionConstants.ALOAD_0);
0611:                    il.append(new GETFIELD(cp.addFieldref(className,
0612:                            "__scriptObject", "Loscript/data/Scope;")));
0613:                    il.append(InstructionConstants.ARETURN);
0614:                    MethodGen mg = new MethodGen(Constants.ACC_PUBLIC
0615:                            | Constants.ACC_FINAL, SCOPE_TYPE,
0616:                            new org.apache.bcel.generic.Type[] {},
0617:                            new String[] {}, "__getScriptObject", className,
0618:                            il, cp);
0619:
0620:                    mg.setMaxStack();
0621:                    cg.addMethod(mg.getMethod());
0622:                }
0623:            }
0624:
0625:            private void addConstructor(Constructor constructor) {
0626:                Class[] paramTypes = constructor.getParameterTypes();
0627:
0628:                // now generate code:
0629:                CompilerInstructionList il = new CompilerInstructionList();
0630:                insertReturnCallSuper(il, "<init>", Void.TYPE, paramTypes);
0631:
0632:                MethodGen mg = new MethodGen(getAccessFlags(constructor
0633:                        .getModifiers()), org.apache.bcel.generic.Type.VOID,
0634:                        getParamTypes(paramTypes), getParamNames(paramTypes),
0635:                        "<init>", className, il, cp);
0636:
0637:                Class[] exceptionTypes = constructor.getExceptionTypes();
0638:                for (int i = 0; i < exceptionTypes.length; i++) {
0639:                    mg.addException(exceptionTypes[i].getName());
0640:                }
0641:
0642:                mg.setMaxStack();
0643:                cg.addMethod(mg.getMethod());
0644:            }
0645:
0646:            private void addEmptyConstructor() {
0647:                Class[] paramTypes = new Class[0];
0648:
0649:                // now generate code:
0650:                CompilerInstructionList il = new CompilerInstructionList();
0651:
0652:                insertReturnCallSuper(il, "<init>", Void.TYPE, paramTypes);
0653:
0654:                MethodGen mg = new MethodGen(Constants.ACC_PUBLIC,
0655:                        org.apache.bcel.generic.Type.VOID,
0656:                        getParamTypes(paramTypes), getParamNames(paramTypes),
0657:                        "<init>", className, il, cp);
0658:
0659:                mg.setMaxStack();
0660:                cg.addMethod(mg.getMethod());
0661:            }
0662:
0663:            private Hashtable methodTable = new Hashtable(); // XXX quick hack to avoid generating duplicate methods!
0664:
0665:            private void addMethod(Method method) {
0666:                Class[] paramTypes = method.getParameterTypes();
0667:                Class retType = method.getReturnType();
0668:                boolean isAbstract = origClass.isInterface()
0669:                        || Modifier.isAbstract(method.getModifiers()); // XXX is an interface method always abstract?
0670:
0671:                /* This is sort of a hack, to work around what (I think) is a bug that I've seen
0672:                 * under JDK v1.4.1 for windoze (but not JDK v1.3.x on other platforms).  The
0673:                 * problem is this, given:
0674:                 * 
0675:                 *    interface I1
0676:                 *    interface I2 extends I1
0677:                 *    abstract class AC1 implements I1
0678:                 *    abstract class AC2 extends A1 implements I2
0679:                 * 
0680:                 * methods declared in I1 are showing up twice, resulting in us trying to generate
0681:                 * a class with duplcate methods, which results in a LinkageError when we try to
0682:                 * load the class.
0683:                 */
0684:                {
0685:                    String methodSig = method.getName() + "#"
0686:                            + makeMethodSignature(retType, paramTypes);
0687:                    if (methodTable.get(methodSig) != null)
0688:                        return;
0689:                    methodTable.put(methodSig, method);
0690:                }
0691:
0692:                // generate wrapper method:
0693:                {
0694:                    CompilerInstructionList il = new CompilerInstructionList();
0695:
0696:                    il.append(InstructionConstants.ALOAD_0);
0697:                    il.append(new GETFIELD(cp.addFieldref(className,
0698:                            "__scriptObject", "Loscript/data/Scope;")));
0699:
0700:                    il.append(InstructionConstants.DUP);
0701:                    IFNULL ifnull1 = new IFNULL(null);
0702:                    il.append(ifnull1);
0703:
0704:                    pushSymbol(il, method.getName());
0705:                    il.append(new INVOKEVIRTUAL(cp.addMethodref(
0706:                            "oscript.data.Scope", "__getInstanceMember",
0707:                            "(I)Loscript/data/Value;")));
0708:
0709:                    il.append(InstructionConstants.DUP);
0710:                    IFNULL ifnull2 = new IFNULL(null);
0711:                    il.append(ifnull2);
0712:
0713:                    // if calling getMember() didn't throw a NoSuchMember exception, then
0714:                    // build up the argument array:
0715:                    il.append(new PUSH(cp, paramTypes.length));
0716:                    il.append(new ANEWARRAY(cp.addClass("oscript.data.Value")));
0717:
0718:                    for (int i = 0, idx = 1; i < paramTypes.length; i++) {
0719:                        il.append(InstructionConstants.DUP);
0720:                        il.append(new PUSH(cp, i));
0721:
0722:                        idx += insertLoad(il, paramTypes[i], idx);
0723:
0724:                        insertConvertToScriptValue(il, paramTypes[i]);
0725:
0726:                        il.append(InstructionConstants.AASTORE);
0727:                    }
0728:
0729:                    il.append(new INVOKEVIRTUAL(cp.addMethodref(
0730:                            "oscript.data.Value", "callAsFunction",
0731:                            "([Loscript/data/Value;)Loscript/data/Value;")));
0732:
0733:                    // handle return-type conversion:      
0734:                    if (retType.isPrimitive()) {
0735:                        if (retType == Void.TYPE) {
0736:                            il.append(InstructionConstants.RETURN);
0737:                        } else if (retType == Double.TYPE) {
0738:                            il.append(new INVOKEVIRTUAL(cp.addMethodref(
0739:                                    "oscript.data.Value",
0740:                                    "castToInexactNumber", "()D")));
0741:                            il.append(InstructionConstants.DRETURN);
0742:                        } else if (retType == Float.TYPE) {
0743:                            il.append(new INVOKEVIRTUAL(cp.addMethodref(
0744:                                    "oscript.data.Value",
0745:                                    "castToInexactNumber", "()D")));
0746:                            il.append(InstructionConstants.D2F);
0747:                            il.append(InstructionConstants.FRETURN);
0748:                        } else if (retType == Boolean.TYPE) {
0749:                            il.append(new INVOKEVIRTUAL(cp.addMethodref(
0750:                                    "oscript.data.Value", "castToBoolean",
0751:                                    "()Z")));
0752:                            il.append(InstructionConstants.IRETURN);
0753:                        } else if (retType == Long.TYPE) {
0754:                            il.append(new INVOKEVIRTUAL(cp.addMethodref(
0755:                                    "oscript.data.Value", "castToExactNumber",
0756:                                    "()J")));
0757:                            il.append(InstructionConstants.LRETURN);
0758:                        } else {
0759:                            il.append(new INVOKEVIRTUAL(cp.addMethodref(
0760:                                    "oscript.data.Value", "castToExactNumber",
0761:                                    "()J")));
0762:                            il.append(InstructionConstants.L2I);
0763:                            il.append(InstructionConstants.IRETURN);
0764:                        }
0765:                    } else if (retType == Value.class) // XXX or subclass ???
0766:                    {
0767:                        il.append(InstructionConstants.ARETURN);
0768:                    } else {
0769:                        il.append(new PUSH(cp, retType.getName()));
0770:                        il
0771:                                .append(new INVOKESTATIC(
0772:                                        cp
0773:                                                .addMethodref(
0774:                                                        "oscript.data.JavaBridge",
0775:                                                        "convertToJavaObject",
0776:                                                        "(Loscript/data/Value;Ljava/lang/String;)Ljava/lang/Object;")));
0777:                        il
0778:                                .append(new CHECKCAST(cp.addClass(retType
0779:                                        .getName())));
0780:                        il.append(InstructionConstants.ARETURN);
0781:                    }
0782:
0783:                    InstructionHandle target = il
0784:                            .append(InstructionConstants.POP);
0785:                    ifnull2.setTarget(target);
0786:                    ifnull1.setTarget(target);
0787:
0788:                    if (!isAbstract) {
0789:                        insertReturnCallSuper(il, method.getName(), retType,
0790:                                paramTypes);
0791:                    } else {
0792:                        il
0793:                                .append(new NEW(
0794:                                        cp
0795:                                                .addClass("oscript.data.ONoSuchMemberException")));
0796:                        il.append(InstructionConstants.DUP);
0797:                        il.append(new PUSH(cp, "[class " + origClass.getName()
0798:                                + "]: " + method.getName()));
0799:                        il.append(new INVOKESPECIAL(cp.addMethodref(
0800:                                "oscript.data.ONoSuchMemberException",
0801:                                "<init>", "(Ljava/lang/String;)V")));
0802:                        il
0803:                                .append(new INVOKESTATIC(
0804:                                        cp
0805:                                                .addMethodref(
0806:                                                        "oscript.exceptions.PackagedScriptObjectException",
0807:                                                        "makeExceptionWrapper",
0808:                                                        "(Loscript/data/Value;)Loscript/exceptions/PackagedScriptObjectException;")));
0809:                        il.append(InstructionConstants.ATHROW);
0810:                    }
0811:
0812:                    MethodGen mg = new MethodGen(getAccessFlags(method
0813:                            .getModifiers()), getParamType(retType),
0814:                            getParamTypes(paramTypes),
0815:                            getParamNames(paramTypes), method.getName(),
0816:                            className, il, cp);
0817:
0818:                    Class[] exceptionTypes = method.getExceptionTypes();
0819:                    for (int i = 0; i < exceptionTypes.length; i++) {
0820:                        mg.addException(exceptionTypes[i].getName());
0821:                    }
0822:
0823:                    mg.setMaxStack();
0824:                    cg.addMethod(mg.getMethod());
0825:                }
0826:
0827:                // generate "orig" method:
0828:                if (!isAbstract) {
0829:                    CompilerInstructionList il = new CompilerInstructionList();
0830:                    insertReturnCallSuper(il, method.getName(), retType,
0831:                            paramTypes);
0832:
0833:                    MethodGen mg = new MethodGen(getAccessFlags(method
0834:                            .getModifiers()), getParamType(retType),
0835:                            getParamTypes(paramTypes),
0836:                            getParamNames(paramTypes), getOrigMethodName(method
0837:                                    .getName()), className, il, cp);
0838:
0839:                    Class[] exceptionTypes = method.getExceptionTypes();
0840:                    for (int i = 0; i < exceptionTypes.length; i++)
0841:                        mg.addException(exceptionTypes[i].getName());
0842:
0843:                    mg.setMaxStack();
0844:                    cg.addMethod(mg.getMethod());
0845:                }
0846:            }
0847:
0848:            private int identifierCnt = 0;
0849:
0850:            private void pushSymbol(CompilerInstructionList il, String name) {
0851:                Integer iidx = (Integer) (symbolTable.get(name));
0852:                if (iidx == null) {
0853:                    String fieldName = "_sym_" + (identifierCnt++) + name;
0854:                    FieldGen fg = new FieldGen(Constants.ACC_PRIVATE
0855:                            | Constants.ACC_STATIC,
0856:                            org.apache.bcel.generic.Type.INT, fieldName, cp);
0857:                    cg.addField(fg.getField());
0858:                    iidx = new Integer(cp.addFieldref(className, fieldName,
0859:                            org.apache.bcel.generic.Type.INT.getSignature()));
0860:                    symbolTable.put(name, iidx);
0861:                }
0862:                il.append(new GETSTATIC(iidx.intValue()));
0863:            }
0864:
0865:            private void insertReturnCallSuper(CompilerInstructionList il,
0866:                    String name, Class retType, Class[] paramTypes) {
0867:                String className;
0868:
0869:                if (origClass.isInterface())
0870:                    className = "java.lang.Object";
0871:                else
0872:                    className = origClassName;
0873:
0874:                il.append(InstructionConstants.ALOAD_0); // this
0875:
0876:                for (int i = 0, idx = 1; i < paramTypes.length; i++)
0877:                    idx += insertLoad(il, paramTypes[i], idx);
0878:
0879:                il.append(new INVOKESPECIAL(cp.addMethodref(className, name,
0880:                        makeMethodSignature(retType, paramTypes))));
0881:
0882:                if (retType.isPrimitive()) {
0883:                    if (retType == Void.TYPE)
0884:                        il.append(InstructionConstants.RETURN);
0885:                    else if (retType == Double.TYPE)
0886:                        il.append(InstructionConstants.DRETURN);
0887:                    else if (retType == Float.TYPE)
0888:                        il.append(InstructionConstants.FRETURN);
0889:                    else if (retType == Long.TYPE)
0890:                        il.append(InstructionConstants.LRETURN);
0891:                    else
0892:                        il.append(InstructionConstants.IRETURN);
0893:                } else {
0894:                    il.append(InstructionConstants.ARETURN);
0895:                }
0896:            }
0897:
0898:            private int insertLoad(CompilerInstructionList il, Class paramType,
0899:                    int idx) {
0900:                if (paramType.isPrimitive()) {
0901:                    if (paramType == Double.TYPE) {
0902:                        il.append(new DLOAD(idx));
0903:                        return 2;
0904:                    } else if (paramType == Float.TYPE) {
0905:                        il.append(new FLOAD(idx));
0906:                        return 1;
0907:                    } else if (paramType == Long.TYPE) {
0908:                        il.append(new LLOAD(idx));
0909:                        return 2;
0910:                    } else {
0911:                        il.append(new ILOAD(idx));
0912:                        return 1;
0913:                    }
0914:                } else {
0915:                    il.append(new ALOAD(idx));
0916:                    return 1;
0917:                }
0918:            }
0919:
0920:            private void insertConvertToScriptValue(CompilerInstructionList il,
0921:                    Class paramType) {
0922:                String signature;
0923:
0924:                // XXX note this has to be kept in sync with JavaBridge... uhhg!
0925:                if (paramType.isPrimitive()) {
0926:                    if (paramType == Double.TYPE) {
0927:                        signature = "(D)Loscript/data/Value;";
0928:                    } else if (paramType == Float.TYPE) {
0929:                        il.append(InstructionConstants.F2D);
0930:                        signature = "(D)Loscript/data/Value;";
0931:                    } else if (paramType == Long.TYPE) {
0932:                        signature = "(J)Loscript/data/Value;";
0933:                    } else if (paramType == Integer.TYPE) {
0934:                        il.append(InstructionConstants.I2L);
0935:                        signature = "(J)Loscript/data/Value;";
0936:                    } else if (paramType == Short.TYPE) {
0937:                        il.append(InstructionConstants.I2L);
0938:                        signature = "(J)Loscript/data/Value;";
0939:                    } else if (paramType == Byte.TYPE) {
0940:                        il.append(InstructionConstants.I2L);
0941:                        signature = "(J)Loscript/data/Value;";
0942:                    } else if (paramType == Boolean.TYPE) {
0943:                        signature = "(Z)Loscript/data/Value;";
0944:                    } else if (paramType == Character.TYPE) {
0945:                        il.append(new INVOKESTATIC(cp.addMethodref(
0946:                                "java.lang.String", "valueOf",
0947:                                "(C)Ljava/lang/String;")));
0948:                        signature = "(Ljava/lang/String;)Loscript/data/Value;";
0949:                    } else {
0950:                        throw new ProgrammingErrorException(
0951:                                "unknown primitive type: " + paramType);
0952:                    }
0953:                } else if (paramType == String.class) {
0954:                    signature = "(Ljava/lang/String;)Loscript/data/Value;";
0955:                } else {
0956:                    signature = "(Ljava/lang/Object;)Loscript/data/Value;";
0957:                }
0958:
0959:                il.append(new INVOKESTATIC(cp.addMethodref(
0960:                        "oscript.data.JavaBridge", "convertToScriptObject",
0961:                        signature)));
0962:            }
0963:
0964:            private int getAccessFlags(int mod) {
0965:                int acc = 0;
0966:
0967:                if (Modifier.isPublic(mod)) {
0968:                    acc |= Constants.ACC_PUBLIC;
0969:                }
0970:
0971:                // XXX
0972:
0973:                return acc;
0974:            }
0975:
0976:            private org.apache.bcel.generic.Type[] getParamTypes(
0977:                    Class[] paramTypes) {
0978:                org.apache.bcel.generic.Type[] types = new org.apache.bcel.generic.Type[paramTypes.length];
0979:
0980:                for (int i = 0; i < types.length; i++) {
0981:                    types[i] = getParamType(paramTypes[i]);
0982:                }
0983:
0984:                return types;
0985:            }
0986:
0987:            private org.apache.bcel.generic.Type getParamType(Class paramType) {
0988:                if (paramType.isPrimitive()) {
0989:                    if (paramType == Boolean.TYPE)
0990:                        return org.apache.bcel.generic.Type.BOOLEAN;
0991:                    else if (paramType == Character.TYPE)
0992:                        return org.apache.bcel.generic.Type.CHAR;
0993:                    else if (paramType == Double.TYPE)
0994:                        return org.apache.bcel.generic.Type.DOUBLE;
0995:                    else if (paramType == Float.TYPE)
0996:                        return org.apache.bcel.generic.Type.FLOAT;
0997:                    else if (paramType == Integer.TYPE)
0998:                        return org.apache.bcel.generic.Type.INT;
0999:                    else if (paramType == Long.TYPE)
1000:                        return org.apache.bcel.generic.Type.LONG;
1001:                    else if (paramType == Short.TYPE)
1002:                        return org.apache.bcel.generic.Type.SHORT;
1003:                    else if (paramType == Byte.TYPE)
1004:                        return org.apache.bcel.generic.Type.BYTE;
1005:                    else if (paramType == Void.TYPE)
1006:                        return org.apache.bcel.generic.Type.VOID;
1007:                    else
1008:                        throw new ProgrammingErrorException(
1009:                                "unknown primitive: " + paramType);
1010:                } else if (paramType.isArray()) {
1011:                    return new ArrayType(getParamType(paramType
1012:                            .getComponentType()), 1);
1013:                } else {
1014:                    return new ObjectType(paramType.getName());
1015:                }
1016:            }
1017:
1018:            private String[] getParamNames(Class[] paramTypes) {
1019:                String[] names = new String[paramTypes.length];
1020:
1021:                for (int i = 0; i < names.length; i++) {
1022:                    names[i] = "arg" + i;
1023:                }
1024:
1025:                return names;
1026:            }
1027:
1028:            private String makeMethodSignature(Class retType, Class[] paramTypes) {
1029:                String signature = org.apache.bcel.generic.Type
1030:                        .getMethodSignature(getParamType(retType),
1031:                                getParamTypes(paramTypes));
1032:
1033:                return signature;
1034:            }
1035:
1036:        }
1037:
1038:        /*
1039:         *   Local Variables:
1040:         *   tab-width: 2
1041:         *   indent-tabs-mode: nil
1042:         *   mode: java
1043:         *   c-indentation-style: java
1044:         *   c-basic-offset: 2
1045:         *   eval: (c-set-offset 'substatement-open '0)
1046:         *   eval: (c-set-offset 'case-label '+)
1047:         *   eval: (c-set-offset 'inclass '+)
1048:         *   eval: (c-set-offset 'inline-open '0)
1049:         *   End:
1050:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.