Source Code Cross Referenced for JavaInvoke.java in  » Scripting » jacl » tcl » lang » 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 » jacl » tcl.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * JavaInvoke.java --
0003:         *
0004:         *	This class implements the common routines used by the java::*
0005:         *	commands to access the Java Reflection API.
0006:         *
0007:         * Copyright (c) 1997 Sun Microsystems, Inc.
0008:         *
0009:         * See the file "license.terms" for information on usage and
0010:         * redistribution of this file, and for a DISCLAIMER OF ALL
0011:         * WARRANTIES.
0012:         *
0013:         * RCS: @(#) $Id: JavaInvoke.java,v 1.25 2006/06/13 06:52:47 mdejong Exp $
0014:         *
0015:         */
0016:
0017:        package tcl.lang;
0018:
0019:        import tcl.lang.reflect.*;
0020:        import java.lang.reflect.*;
0021:        import java.util.*;
0022:        import java.beans.*;
0023:
0024:        /**
0025:         * This class implements the common routines used by the java::*
0026:         * commands to create Java objects, call Java methods and access fields
0027:         * and properties. It also has auxiliary routines for converting between
0028:         * TclObject's and Java Object's.
0029:         */
0030:
0031:        class JavaInvoke {
0032:
0033:            // We need to use empty array Object[0] a lot. We keep a static copy
0034:            // and re-use it to avoid garbage collection.
0035:
0036:            static private Object EMPTY_ARGS[] = new Object[0];
0037:
0038:            /*
0039:             *-----------------------------------------------------------------------------
0040:             *
0041:             * newInstance --
0042:             *
0043:             *	Call the specified constructor.
0044:             *
0045:             * Results:
0046:             *	When successful, the object created by the constructor.
0047:             *
0048:             * Side effects:
0049:             *	The constructor can cause arbitrary side effects.
0050:             *
0051:             *-----------------------------------------------------------------------------
0052:             */
0053:
0054:            static TclObject newInstance(Interp interp, // Current interpreter.
0055:                    TclObject signature, // Constructor signature.
0056:                    TclObject[] argv, // Arguments.
0057:                    int startIdx, // Index of the first argument in argv to
0058:                    // pass to the constructor.
0059:                    int count) // Number of arguments to pass to the
0060:                    // constructor.
0061:                    throws TclException // Standard Tcl exception.
0062:            {
0063:                // Some built-in types have wrapper classes that behave in
0064:                // unexpected ways. For example, the Boolean constructor
0065:                // is overloaded to accept either a boolean primitive or
0066:                // a String value. The FuncSig module prefers method signatures
0067:                // that accept a String, but the version that accepts a String
0068:                // does not match Tcl's number parsing semantics. Fix this problem
0069:                // by explicitly invoking the wrapper constructor that accepts
0070:                // a primitive type so that the type conversion logic in this
0071:                // module is used to pass a Tcl value to a Java primitive argument.
0072:
0073:                if (count == 1) {
0074:                    final String sig = signature.toString();
0075:                    if (sig.equals("Boolean")
0076:                            || sig.equals("java.lang.Boolean")) {
0077:                        signature = TclString
0078:                                .newInstance("java.lang.Boolean boolean");
0079:                    } else if (sig.equals("Integer")
0080:                            || sig.equals("java.lang.Integer")) {
0081:                        signature = TclString
0082:                                .newInstance("java.lang.Integer int");
0083:                    } else if (sig.equals("Byte")
0084:                            || sig.equals("java.lang.Byte")) {
0085:                        signature = TclString
0086:                                .newInstance("java.lang.Byte byte");
0087:                    } else if (sig.equals("Short")
0088:                            || sig.equals("java.lang.Short")) {
0089:                        signature = TclString
0090:                                .newInstance("java.lang.Short short");
0091:                    } else if (sig.equals("Character")
0092:                            || sig.equals("java.lang.Character")) {
0093:                        signature = TclString
0094:                                .newInstance("java.lang.Character char");
0095:                    } else if (sig.equals("Long")
0096:                            || sig.equals("java.lang.Long")) {
0097:                        signature = TclString
0098:                                .newInstance("java.lang.Long long");
0099:                    } else if (sig.equals("Float")
0100:                            || sig.equals("java.lang.Float")) {
0101:                        signature = TclString
0102:                                .newInstance("java.lang.Float float");
0103:                    } else if (sig.equals("Double")
0104:                            || sig.equals("java.lang.Double")) {
0105:                        signature = TclString
0106:                                .newInstance("java.lang.Double double");
0107:                    }
0108:                }
0109:
0110:                FuncSig sig = FuncSig.get(interp, null, signature, argv,
0111:                        startIdx, count, false);
0112:
0113:                Object javaObj = call(interp, sig.pkgInvoker, signature,
0114:                        sig.func, null, argv, startIdx, count);
0115:
0116:                return ReflectObject
0117:                        .newInstance(interp, sig.targetCls, javaObj);
0118:            }
0119:
0120:            /*
0121:             *-----------------------------------------------------------------------------
0122:             *
0123:             * callMethod --
0124:             *
0125:             *	Call the specified instance or static method of the given object.
0126:             *
0127:             * Results:
0128:             *      When successful, this method returns the Java object that the
0129:             *      Java method would have returned. If the Java method has a void
0130:             *      return type then null is returned.
0131:             *
0132:             * Side effects:
0133:             *	The method can cause arbitrary side effects.
0134:             *
0135:             *-----------------------------------------------------------------------------
0136:             */
0137:
0138:            static TclObject callMethod(Interp interp, // Current interpreter.
0139:                    TclObject reflectObj, // The object whose method to invoke.
0140:                    TclObject signature, // Method signature.
0141:                    TclObject argv[], // Arguments.
0142:                    int startIdx, // Index of the first argument in argv[] to
0143:                    // pass to the method.
0144:                    int count, // Number of arguments to pass to the
0145:                    // method.
0146:                    boolean convert) // Whether the value should be converted
0147:                    // into Tcl objects of the closest types.
0148:                    throws TclException {
0149:                Object javaObj = ReflectObject.get(interp, reflectObj);
0150:                Class javaCl = ReflectObject.getClass(interp, reflectObj);
0151:                FuncSig sig = FuncSig.get(interp, javaCl, signature, argv,
0152:                        startIdx, count, false);
0153:                Method method = (Method) sig.func;
0154:                Class rtype = method.getReturnType();
0155:
0156:                if (!PkgInvoker.isAccessible(rtype)) {
0157:                    throw new TclException(interp, "Return type \""
0158:                            + JavaInfoCmd.getNameFromClass(rtype)
0159:                            + "\" is not accessible");
0160:                }
0161:
0162:                Object result = call(interp, sig.pkgInvoker, signature, method,
0163:                        javaObj, argv, startIdx, count);
0164:
0165:                if (rtype == Void.TYPE) {
0166:                    return null;
0167:                } else {
0168:                    return wrap(interp, rtype, result, convert);
0169:                }
0170:            }
0171:
0172:            /*
0173:             *-----------------------------------------------------------------------------
0174:             *
0175:             * callStaticMethod --
0176:             *
0177:             *	Call the specified static method of the given object.
0178:             *
0179:             * Results:
0180:             *      When successful, this method returns the Java object that the
0181:             *      Java method would have returned. If the Java method has a void
0182:             *      return type then null is returned.
0183:             *
0184:             * Side effects:
0185:             *	The method can cause arbitrary side effects.
0186:             *
0187:             *-----------------------------------------------------------------------------
0188:             */
0189:
0190:            static TclObject callStaticMethod(Interp interp, // Current interpreter.	
0191:                    TclObject classObj, // Class whose static method to invoke.
0192:                    TclObject signature, // Method signature.
0193:                    TclObject argv[], // Arguments.
0194:                    int startIdx, // Index of the first argument in argv[] to
0195:                    // pass to the method.
0196:                    int count, // Number of arguments to pass to the
0197:                    // method.
0198:                    boolean convert) // Whether the value should be converted
0199:                    // into Tcl objects of the closest types.
0200:                    throws TclException {
0201:                Class cls = ClassRep.get(interp, classObj);
0202:                FuncSig sig = FuncSig.get(interp, cls, signature, argv,
0203:                        startIdx, count, true);
0204:
0205:                Method method = (Method) sig.func;
0206:                Class rtype = method.getReturnType();
0207:
0208:                if (!PkgInvoker.isAccessible(rtype)) {
0209:                    throw new TclException(interp, "Return type \""
0210:                            + JavaInfoCmd.getNameFromClass(rtype)
0211:                            + "\" is not accessible");
0212:                }
0213:
0214:                Object result = call(interp, sig.pkgInvoker, signature, method,
0215:                        null, argv, startIdx, count);
0216:
0217:                if (rtype == Void.TYPE) {
0218:                    return null;
0219:                } else {
0220:                    return wrap(interp, method.getReturnType(), result, convert);
0221:                }
0222:            }
0223:
0224:            /*
0225:             *-----------------------------------------------------------------------------
0226:             *
0227:             * call --
0228:             *
0229:             *	Call the constructor, instance method, or static method with
0230:             *	the given parameters. Check the parameter types and perform
0231:             *	TclObject to JavaObject conversion.
0232:             *
0233:             * Results:
0234:             *	The object created by the constructor, or the return value
0235:             *	of the method call.
0236:             *
0237:             * Side effects:
0238:             *	The constructor/method call may have arbitrary side effects.
0239:             *
0240:             *-----------------------------------------------------------------------------
0241:             */
0242:
0243:            static Object call(Interp interp, PkgInvoker invoker, // The PkgInvoked used to invoke the
0244:                    // method or constructor.
0245:                    TclObject signature, // For formatting error message.
0246:                    Object func, // The Constructor or Method to call.
0247:                    Object obj, // The object associated with an instace
0248:                    // method call. Should be null for
0249:                    // constructor calls and static method
0250:                    // calls.
0251:                    TclObject argv[], // Argument list.
0252:                    int startIdx, // Index of the first argument in argv[] to
0253:                    // pass to the method or constructor.
0254:                    int count) // Number of arguments to pass to the
0255:                    // method or constructor.
0256:                    throws TclException // Standard Tcl exception.
0257:            {
0258:                Class paramTypes[];
0259:                Constructor cons = null;
0260:                Method method = null;
0261:                int i;
0262:                boolean isConstructor = (func instanceof  Constructor);
0263:
0264:                if (isConstructor) {
0265:                    cons = (Constructor) func;
0266:                    paramTypes = cons.getParameterTypes();
0267:                } else {
0268:                    method = (Method) func;
0269:                    paramTypes = method.getParameterTypes();
0270:                }
0271:
0272:                if (count != paramTypes.length) {
0273:                    throw new TclException(interp, "wrong # args for calling "
0274:                            + (isConstructor ? "constructor" : "method")
0275:                            + " \"" + signature + "\"");
0276:                }
0277:
0278:                Object args[];
0279:
0280:                if (count == 0) {
0281:                    args = EMPTY_ARGS;
0282:                } else {
0283:                    args = new Object[count];
0284:                    for (i = 0; i < count; i++) {
0285:                        args[i] = convertTclObject(interp, paramTypes[i],
0286:                                argv[i + startIdx]);
0287:                    }
0288:                }
0289:
0290:                try {
0291:                    final boolean debug = false;
0292:                    Object result;
0293:
0294:                    if (isConstructor) {
0295:                        result = invoker.invokeConstructor(cons, args);
0296:                    } else {
0297:                        result = invoker.invokeMethod(method, obj, args);
0298:                    }
0299:
0300:                    if (debug) {
0301:                        System.out
0302:                                .println("result object from invocation is \""
0303:                                        + result + "\"");
0304:                    }
0305:
0306:                    return result;
0307:                } catch (InstantiationException e) {
0308:                    throw new TclRuntimeError("unexpected abstract class: "
0309:                            + e.getMessage());
0310:                } catch (IllegalAccessException e) {
0311:                    throw new TclRuntimeError(
0312:                            "unexpected inaccessible ctor or method: "
0313:                                    + e.getMessage());
0314:                } catch (IllegalArgumentException e) {
0315:                    throw new TclRuntimeError(
0316:                            "unexpected IllegalArgumentException: "
0317:                                    + e.getMessage());
0318:                } catch (InvocationTargetException e) {
0319:                    Throwable te = e.getTargetException();
0320:                    if (te instanceof  TclException) {
0321:                        interp.setResult(te.getMessage());
0322:                        throw (TclException) te;
0323:                    } else {
0324:                        throw new ReflectException(interp, te);
0325:                    }
0326:                }
0327:            }
0328:
0329:            /*
0330:             *-----------------------------------------------------------------------------
0331:             *
0332:             * getField --
0333:             *
0334:             *	Returns the value of a field in the given object.
0335:             *
0336:             * Results:
0337:             *	When successful, returns an array: Object result[2]. result[0]
0338:             *	is the value of the field; result[1] is the type of the field.
0339:             *
0340:             * Side effects:
0341:             *	None.
0342:             *
0343:             *-----------------------------------------------------------------------------
0344:             */
0345:
0346:            static final TclObject getField(Interp interp, // Current interpreter.
0347:                    TclObject classOrObj, // Class or object whose field to get.
0348:                    TclObject signature, // Signature of the field.
0349:                    boolean convert) // Whether the value should be converted
0350:                    // into Tcl objects of the closest types.
0351:                    throws TclException // Standard Tcl exception.
0352:            {
0353:                return getsetField(interp, classOrObj, signature, null,
0354:                        convert, true);
0355:            }
0356:
0357:            /*
0358:             *-----------------------------------------------------------------------------
0359:             *
0360:             * setField --
0361:             *
0362:             *	Sets the value of a field in the given object.
0363:             *
0364:             * Results:
0365:             *	None.
0366:             *
0367:             * Side effects:
0368:             *	When successful, the field is set to the given value.
0369:             *
0370:             *-----------------------------------------------------------------------------
0371:             */
0372:
0373:            static final void setField(Interp interp, // Current interpreter.
0374:                    TclObject classOrObj, // Class or object whose field to get.
0375:                    TclObject signature, // Signature of the field.
0376:                    TclObject value) // New value for the field.
0377:                    throws TclException // Standard Tcl exception.
0378:            {
0379:                getsetField(interp, classOrObj, signature, value, false, false);
0380:            }
0381:
0382:            /*
0383:             *-----------------------------------------------------------------------------
0384:             *
0385:             * getsetField --
0386:             *
0387:             *	Gets or sets the field in the given object.
0388:             *
0389:             * Results:
0390:             *	None.
0391:             *
0392:             * Side effects:
0393:             *	When successful, the field is set to the given value if isget
0394:             *	is false.
0395:             *
0396:             *-----------------------------------------------------------------------------
0397:             */
0398:
0399:            static TclObject getsetField(Interp interp, // Current interpreter.
0400:                    TclObject classOrObj, // Class or object whose field to get.
0401:                    TclObject signature, // Signature of the field.
0402:                    TclObject value, // New value for the field.
0403:                    boolean convert, // Whether the value should be converted
0404:                    // into Tcl objects of the closest types.
0405:                    boolean isget) throws TclException // Standard Tcl exception.
0406:            {
0407:                Class cls = null;
0408:                Object obj = null;
0409:                boolean isStatic = false;
0410:
0411:                try {
0412:                    obj = ReflectObject.get(interp, classOrObj);
0413:                } catch (TclException e) {
0414:                    try {
0415:                        cls = ClassRep.get(interp, classOrObj);
0416:                    } catch (TclException e1) {
0417:                        throw new TclException(interp,
0418:                                "unknown class or object \"" + classOrObj
0419:                                        + "\"");
0420:                    }
0421:                    isStatic = true;
0422:
0423:                    if (!PkgInvoker.isAccessible(cls)) {
0424:                        JavaInvoke.notAccessibleError(interp, cls);
0425:                    }
0426:                }
0427:
0428:                if (!isStatic) {
0429:                    if (obj == null) {
0430:                        throw new TclException(interp,
0431:                                "can't access fields in a null object reference");
0432:                    }
0433:                    cls = ReflectObject.getClass(interp, classOrObj);
0434:                }
0435:
0436:                // Check for the special case where the field is named "class"
0437:                // which has a special meaning and is enforced by the javac compiler.
0438:                // If found, return the java.lang.Class object for the named class.
0439:
0440:                if (isStatic && isget && signature.toString().equals("class")) {
0441:                    return wrap(interp, Class.class, cls, false);
0442:                }
0443:
0444:                FieldSig sig = FieldSig.get(interp, signature, cls);
0445:                Field field = sig.field;
0446:                if (isStatic && (!(Modifier.isStatic(field.getModifiers())))) {
0447:                    throw new TclException(interp,
0448:                            "can't access an instance field without an object");
0449:                }
0450:                Class ftype = field.getType();
0451:
0452:                if (!PkgInvoker.isAccessible(field.getType())) {
0453:                    throw new TclException(interp, "Field type \""
0454:                            + JavaInfoCmd.getNameFromClass(ftype)
0455:                            + "\" is not accessible");
0456:                }
0457:
0458:                if (!isget && Modifier.isFinal(field.getModifiers())) {
0459:                    throw new TclException(interp, "can't set final field \""
0460:                            + signature + "\"");
0461:                }
0462:
0463:                try {
0464:                    if (isget) {
0465:                        return wrap(interp, ftype, sig.pkgInvoker.getField(
0466:                                field, obj), convert);
0467:                    } else {
0468:                        Object javaValue = convertTclObject(interp, ftype,
0469:                                value);
0470:                        sig.pkgInvoker.setField(field, obj, javaValue);
0471:                        return null;
0472:                    }
0473:                } catch (IllegalArgumentException e) {
0474:                    throw new TclRuntimeError(
0475:                            "unexpected IllegalArgumentException: "
0476:                                    + e.getMessage());
0477:                } catch (IllegalAccessException e) {
0478:                    throw new TclRuntimeError(
0479:                            "unexpected IllegalAccessException: "
0480:                                    + e.getMessage());
0481:                }
0482:            }
0483:
0484:            /*
0485:             *-----------------------------------------------------------------------------
0486:             *
0487:             * getProperty --
0488:             *
0489:             *	Returns the value of a property in the given object.
0490:             *
0491:             * Results:
0492:             *	When successful, returns a the value of the property inside
0493:             *	a TclObject
0494:             *
0495:             * Side effects:
0496:             *	None.
0497:             *
0498:             *-----------------------------------------------------------------------------
0499:             */
0500:
0501:            static TclObject getProperty(Interp interp, // Current interpreter.
0502:                    TclObject reflectObj, // The object whose property to query.
0503:                    TclObject propName, // The name of the property to query.
0504:                    boolean convert) // Whether the value should be converted
0505:                    // into Tcl objects of the closest types.
0506:                    throws TclException // A standard Tcl exception.
0507:            {
0508:                Object javaObj = ReflectObject.get(interp, reflectObj);
0509:                if (javaObj == null) {
0510:                    throw new TclException(interp,
0511:                            "can't get property from null object");
0512:                }
0513:
0514:                Class javaClass = ReflectObject.getClass(interp, reflectObj);
0515:                PropertySig sig = PropertySig.get(interp, javaClass, propName);
0516:
0517:                Method readMethod = sig.desc.getReadMethod();
0518:
0519:                if (readMethod == null) {
0520:                    throw new TclException(interp,
0521:                            "can't get write-only property \"" + propName
0522:                                    + "\"");
0523:                }
0524:
0525:                try {
0526:                    return wrap(interp, readMethod.getReturnType(),
0527:                            sig.pkgInvoker.invokeMethod(readMethod, javaObj,
0528:                                    EMPTY_ARGS), convert);
0529:                } catch (IllegalAccessException e) {
0530:                    throw new TclRuntimeError(
0531:                            "unexpected inaccessible readMethod: "
0532:                                    + e.getMessage());
0533:                } catch (IllegalArgumentException e) {
0534:                    throw new TclRuntimeError(
0535:                            "unexpected IllegalArgumentException: "
0536:                                    + e.getMessage());
0537:                } catch (InvocationTargetException e) {
0538:                    throw new ReflectException(interp, e);
0539:                }
0540:
0541:            }
0542:
0543:            /*
0544:             *-----------------------------------------------------------------------------
0545:             *
0546:             * setProperty --
0547:             *
0548:             *	Returns the value of a property in the given object.
0549:             *
0550:             * Results:
0551:             *	None.
0552:             *
0553:             * Side effects:
0554:             *	When successful, the property will have the new value.
0555:             *
0556:             *-----------------------------------------------------------------------------
0557:             */
0558:
0559:            static void setProperty(Interp interp, // Current interpreter.
0560:                    TclObject reflectObj, // The object whose property to query.
0561:                    TclObject propName, // The name of the property to query.
0562:                    TclObject value) // Whether the value should be converted
0563:                    // into Tcl objects of the closest types.
0564:                    throws TclException // A standard Tcl exception.
0565:            {
0566:                Object javaObj = ReflectObject.get(interp, reflectObj);
0567:                if (javaObj == null) {
0568:                    throw new TclException(interp,
0569:                            "can't set property in null object");
0570:                }
0571:
0572:                Class javaClass = ReflectObject.getClass(interp, reflectObj);
0573:                PropertySig sig = PropertySig.get(interp, javaClass, propName);
0574:
0575:                Method writeMethod = sig.desc.getWriteMethod();
0576:                Class type = sig.desc.getPropertyType();
0577:
0578:                if (writeMethod == null) {
0579:                    throw new TclException(interp,
0580:                            "can't set read-only property \"" + propName + "\"");
0581:                }
0582:
0583:                Object args[] = new Object[1];
0584:                args[0] = convertTclObject(interp, type, value);
0585:
0586:                try {
0587:                    sig.pkgInvoker.invokeMethod(writeMethod, javaObj, args);
0588:                } catch (IllegalAccessException e) {
0589:                    throw new TclRuntimeError(
0590:                            "unexpected inaccessible writeMethod: "
0591:                                    + e.getMessage());
0592:                } catch (IllegalArgumentException e) {
0593:                    throw new TclRuntimeError(
0594:                            "unexpected IllegalArgumentException: "
0595:                                    + e.getMessage());
0596:                } catch (InvocationTargetException e) {
0597:                    throw new ReflectException(interp, e);
0598:                }
0599:            }
0600:
0601:            /*
0602:             *-----------------------------------------------------------------------------
0603:             *
0604:             * getClassByName --
0605:             *
0606:             *	Returns Class object identified by the string name. We allow
0607:             *	abbreviation of the java.lang.* class if there is no ambiguity:
0608:             *	e.g., if there is no class whose fully qualified name is "String",
0609:             *	then "String" means java.lang.String. Inner classes are supported
0610:             *	both with fully qualified names and imported class names.
0611:             *
0612:             * Results:
0613:             *	If successful, The Class object identified by the string name.
0614:             *
0615:             * Side effects:
0616:             *	None.
0617:             *
0618:             *-----------------------------------------------------------------------------
0619:             */
0620:
0621:            static Class getClassByName(Interp interp, // Interp used by TclClassLoader
0622:                    String clsName) // String name of the class.
0623:                    throws TclException // If the class cannot be found or loaded.
0624:
0625:            {
0626:                Class result = null;
0627:                int dimension;
0628:
0629:                final boolean debug = false;
0630:                if (debug) {
0631:                    System.out.println("JavaInvoke.getClassByName(\"" + clsName
0632:                            + "\")");
0633:                }
0634:
0635:                // If the string is of the form className[][]..., strip out the trailing
0636:                // []s and record the dimension of the array.
0637:
0638:                StringBuffer prefix_buf = new StringBuffer(64);
0639:                StringBuffer suffix_buf = new StringBuffer(64);
0640:                StringBuffer clsName_buf = new StringBuffer(clsName);
0641:
0642:                String lname;
0643:
0644:                int clsName_len;
0645:                for (dimension = 0; true; dimension++) {
0646:                    clsName_len = clsName_buf.length();
0647:
0648:                    if ((clsName_len > 2)
0649:                            && (clsName_buf.charAt(clsName_len - 2) == '[')
0650:                            && (clsName_buf.charAt(clsName_len - 1) == ']')) {
0651:
0652:                        clsName_buf.setLength(clsName_len - 2);
0653:                        prefix_buf.append('[');
0654:                    } else {
0655:                        break;
0656:                    }
0657:                }
0658:
0659:                boolean package_name_exception = false;
0660:
0661:                if (true) {
0662:                    clsName = clsName_buf.toString(); // Use shortened form of name
0663:
0664:                    // Search for the char '.' in the name. If '.' is in
0665:                    // the name then we know it is not a builtin type.
0666:
0667:                    if (clsName.indexOf('.') == -1) {
0668:                        if (dimension > 0) {
0669:                            boolean isPrimitive = true;
0670:
0671:                            if (clsName.equals("int")) {
0672:                                prefix_buf.append('I');
0673:                            } else if (clsName.equals("boolean")) {
0674:                                prefix_buf.append('Z');
0675:                            } else if (clsName.equals("long")) {
0676:                                prefix_buf.append('J');
0677:                            } else if (clsName.equals("float")) {
0678:                                prefix_buf.append('F');
0679:                            } else if (clsName.equals("double")) {
0680:                                prefix_buf.append('D');
0681:                            } else if (clsName.equals("byte")) {
0682:                                prefix_buf.append('B');
0683:                            } else if (clsName.equals("short")) {
0684:                                prefix_buf.append('S');
0685:                            } else if (clsName.equals("char")) {
0686:                                prefix_buf.append('C');
0687:                            } else {
0688:                                isPrimitive = false;
0689:                            }
0690:
0691:                            if (isPrimitive) {
0692:                                try {
0693:                                    return Class.forName(prefix_buf.toString());
0694:                                } catch (ClassNotFoundException e) {
0695:                                    throw new TclRuntimeError(
0696:                                            "unexpected ClassNotFoundException: "
0697:                                                    + e.getMessage());
0698:                                }
0699:                            }
0700:
0701:                            // Otherwise, not a primitive array type
0702:
0703:                            prefix_buf.append('L');
0704:                            suffix_buf.append(';');
0705:                        } else {
0706:                            if (clsName.equals("int")) {
0707:                                return Integer.TYPE;
0708:                            } else if (clsName.equals("boolean")) {
0709:                                return Boolean.TYPE;
0710:                            } else if (clsName.equals("long")) {
0711:                                return Long.TYPE;
0712:                            } else if (clsName.equals("float")) {
0713:                                return Float.TYPE;
0714:                            } else if (clsName.equals("double")) {
0715:                                return Double.TYPE;
0716:                            } else if (clsName.equals("byte")) {
0717:                                return Byte.TYPE;
0718:                            } else if (clsName.equals("short")) {
0719:                                return Short.TYPE;
0720:                            } else if (clsName.equals("char")) {
0721:                                return Character.TYPE;
0722:                            }
0723:                        }
0724:
0725:                        // Use TclClassLoader defined on a per-interp basis.
0726:                        TclClassLoader tclClassLoader = (TclClassLoader) interp
0727:                                .getClassLoader();
0728:
0729:                        try {
0730:                            lname = prefix_buf + clsName + suffix_buf;
0731:
0732:                            if (debug) {
0733:                                System.out.println("attempting load of \""
0734:                                        + lname + "\"");
0735:                            }
0736:
0737:                            result = tclClassLoader.loadClass(lname);
0738:                        } catch (ClassNotFoundException e) {
0739:                            result = null;
0740:                        } catch (PackageNameException e) {
0741:                            // Should not be possible to catch a PackageNameException
0742:                            // here since the class name above should contain no '.' chars.
0743:                            throw new TclRuntimeError(
0744:                                    "unexpected PackageNameException :"
0745:                                            + e.getMessage());
0746:                        }
0747:
0748:                        if (result == null) {
0749:                            // If the class loader can not find the class then check with
0750:                            // the "import" feature to see if the given clsName maps to
0751:                            // a fully qualified class name.
0752:
0753:                            boolean inJavaLang = false;
0754:                            String fullyqualified = JavaImportCmd.getImport(
0755:                                    interp, clsName);
0756:
0757:                            // If we do not find a fully qualified name in the import table
0758:                            // then try to fully qualify the class with the java.lang prefix 
0759:
0760:                            if (fullyqualified == null) {
0761:                                inJavaLang = true;
0762:                                fullyqualified = "java.lang." + clsName;
0763:                            }
0764:
0765:                            // If the class starts with "java." and it can't be
0766:                            // loaded with the system class loader, then a
0767:                            // PackageNameException is raised.
0768:
0769:                            try {
0770:                                lname = prefix_buf + fullyqualified
0771:                                        + suffix_buf;
0772:
0773:                                if (debug) {
0774:                                    System.out.println("attempting load of \""
0775:                                            + lname + "\"");
0776:                                }
0777:
0778:                                result = tclClassLoader.loadClass(lname);
0779:                            } catch (ClassNotFoundException e) {
0780:                                result = null;
0781:                            } catch (PackageNameException e) {
0782:                                // If loading a class from java.lang package fails
0783:                                // and we fully qualified the class name with the
0784:                                // java.lang prefix, then don't emit a special
0785:                                // error message related to the package name.
0786:
0787:                                if (inJavaLang) {
0788:                                    // No-op
0789:                                } else {
0790:                                    package_name_exception = true;
0791:                                }
0792:                                result = null;
0793:                            }
0794:
0795:                            if (debug) {
0796:                                if (result == null) {
0797:                                    System.out.println("load failed");
0798:                                } else {
0799:                                    System.out.println("load worked");
0800:                                }
0801:                            }
0802:                        }
0803:                    } else {
0804:                        // clsName contains a '.' character. It is either a fully
0805:                        // qualified toplevel class name or an inner class name.
0806:                        // Note that use of a '$' to indicate an inner class is
0807:                        // supported only for backwards compatibility and
0808:                        // works only with a fully qualified class name.
0809:
0810:                        TclClassLoader tclClassLoader = (TclClassLoader) interp
0811:                                .getClassLoader();
0812:
0813:                        if (dimension > 0) {
0814:                            prefix_buf.append("L");
0815:                            suffix_buf.append(";");
0816:                        }
0817:
0818:                        try {
0819:                            lname = prefix_buf + clsName + suffix_buf;
0820:
0821:                            if (debug) {
0822:                                System.out.println("attempting load of \""
0823:                                        + lname + "\"");
0824:                            }
0825:
0826:                            result = tclClassLoader.loadClass(lname);
0827:                        } catch (ClassNotFoundException e) {
0828:                            result = null;
0829:                        } catch (PackageNameException e) {
0830:                            package_name_exception = true;
0831:                            result = null;
0832:                        }
0833:
0834:                        if (debug) {
0835:                            if (result == null) {
0836:                                System.out.println("load failed");
0837:                            } else {
0838:                                System.out.println("load worked");
0839:                            }
0840:                        }
0841:
0842:                        if ((result == null) && (clsName.indexOf('$') == -1)) {
0843:                            // Toplevel class with fully qualified name not found.
0844:                            // Search for an inner class with this name. This
0845:                            // search is tricky because inner classes can be
0846:                            // nested inside other inner classes. Find a containing
0847:                            // class that exists, then search for an inner class
0848:                            // relative to the containing class. Old style inner class
0849:                            // names that contain a literal '$' character are not searched.
0850:
0851:                            ArrayList parts = new ArrayList(5);
0852:                            int si = 0;
0853:                            int clsNameLength = clsName.length();
0854:                            for (int i = 0; i <= clsNameLength; i++) {
0855:                                if ((i == clsNameLength)
0856:                                        || (clsName.charAt(i) == '.')) {
0857:                                    parts.add(clsName.substring(si, i));
0858:                                    si = i + 1;
0859:                                }
0860:                            }
0861:                            if (debug) {
0862:                                System.out.println("clsName parts is " + parts);
0863:                            }
0864:
0865:                            // Search for a contanining class, construct inner
0866:                            // class name if a contanining class was found.
0867:
0868:                            String toplevel = null;
0869:                            String inner = null;
0870:                            boolean load_inner = false;
0871:
0872:                            for (int i = parts.size() - 1; i > 0; i--) {
0873:                                StringBuffer sb;
0874:
0875:                                sb = new StringBuffer(64);
0876:                                for (int bi = 0; bi < i; bi++) {
0877:                                    sb.append(parts.get(bi));
0878:                                    sb.append('.');
0879:                                }
0880:                                if ((sb.length() > 0)
0881:                                        && (sb.charAt(sb.length() - 1) == '.')) {
0882:                                    sb.setLength(sb.length() - 1);
0883:                                }
0884:                                toplevel = sb.toString();
0885:
0886:                                sb = new StringBuffer(64);
0887:                                for (int ai = i; ai < parts.size(); ai++) {
0888:                                    sb.append(parts.get(ai));
0889:                                    sb.append('$');
0890:                                }
0891:                                if ((sb.length() > 0)
0892:                                        && (sb.charAt(sb.length() - 1) == '$')) {
0893:                                    sb.setLength(sb.length() - 1);
0894:                                }
0895:                                inner = sb.toString();
0896:
0897:                                if (debug) {
0898:                                    System.out.println("loop " + i + ":");
0899:                                    System.out.println("toplevel is "
0900:                                            + toplevel);
0901:                                    System.out.println("inner is " + inner);
0902:                                }
0903:
0904:                                try {
0905:                                    lname = prefix_buf + toplevel + suffix_buf;
0906:
0907:                                    if (debug) {
0908:                                        System.out
0909:                                                .println("attempting load of \""
0910:                                                        + lname + "\"");
0911:                                    }
0912:
0913:                                    result = tclClassLoader.loadClass(lname);
0914:                                } catch (ClassNotFoundException e) {
0915:                                    // Not an enclosing toplevel class, raise TclException
0916:                                    result = null;
0917:                                } catch (PackageNameException e) {
0918:                                    package_name_exception = true;
0919:                                    result = null;
0920:                                }
0921:
0922:                                if (debug) {
0923:                                    if (result == null) {
0924:                                        System.out.println("load failed");
0925:                                    } else {
0926:                                        System.out.println("load worked");
0927:                                    }
0928:                                }
0929:
0930:                                if (result != null) {
0931:                                    // Containing class was loaded, break out of
0932:                                    // this loop and load the inner class by name.
0933:
0934:                                    load_inner = true;
0935:                                    break;
0936:                                } else if ((toplevel.indexOf('.') == -1)) {
0937:                                    // The toplevel class was not loaded, it could
0938:                                    // be an imported class name. Check the import
0939:                                    // table for this class name. Don't bother
0940:                                    // loading an imported name since the class
0941:                                    // had to exist to be imported in the first place.
0942:
0943:                                    if (debug) {
0944:                                        System.out
0945:                                                .println("checking import table for \""
0946:                                                        + toplevel + "\"");
0947:                                    }
0948:                                    String fullyqualified = JavaImportCmd
0949:                                            .getImport(interp, toplevel);
0950:                                    if (debug) {
0951:                                        if (fullyqualified == null) {
0952:                                            System.out
0953:                                                    .println("was not imported");
0954:                                        } else {
0955:                                            System.out
0956:                                                    .println("was imported as \""
0957:                                                            + fullyqualified
0958:                                                            + "\"");
0959:                                        }
0960:                                    }
0961:
0962:                                    if (fullyqualified != null) {
0963:                                        load_inner = true;
0964:                                        toplevel = fullyqualified;
0965:                                        break;
0966:                                    } else {
0967:                                        // Not an imported toplevel class. Check to
0968:                                        // see if the class is in the java.lang package.
0969:
0970:                                        fullyqualified = "java.lang."
0971:                                                + toplevel;
0972:
0973:                                        try {
0974:                                            lname = prefix_buf + fullyqualified
0975:                                                    + suffix_buf;
0976:
0977:                                            if (debug) {
0978:                                                System.out
0979:                                                        .println("attempting load of \""
0980:                                                                + lname + "\"");
0981:                                            }
0982:
0983:                                            result = tclClassLoader
0984:                                                    .loadClass(lname);
0985:                                        } catch (ClassNotFoundException e) {
0986:                                            result = null;
0987:                                        } catch (PackageNameException e) {
0988:                                            result = null;
0989:                                        }
0990:
0991:                                        if (debug) {
0992:                                            if (result == null) {
0993:                                                System.out
0994:                                                        .println("load failed");
0995:                                            } else {
0996:                                                System.out
0997:                                                        .println("load worked");
0998:                                            }
0999:                                        }
1000:
1001:                                        if (result != null) {
1002:                                            load_inner = true;
1003:                                            toplevel = fullyqualified;
1004:                                            break;
1005:                                        }
1006:                                    }
1007:                                }
1008:                            }
1009:
1010:                            if (load_inner) {
1011:                                // If enclosing class exists, attempt to load inner class.
1012:
1013:                                try {
1014:                                    lname = prefix_buf + toplevel + "$" + inner
1015:                                            + suffix_buf;
1016:
1017:                                    if (debug) {
1018:                                        System.out
1019:                                                .println("attempting load of \""
1020:                                                        + lname + "\"");
1021:                                    }
1022:
1023:                                    result = tclClassLoader.loadClass(lname);
1024:                                } catch (ClassNotFoundException e) {
1025:                                    // Not an inner class, raise TclException
1026:                                    result = null;
1027:                                } catch (PackageNameException e) {
1028:                                    package_name_exception = true;
1029:                                    result = null;
1030:                                }
1031:
1032:                                if (debug) {
1033:                                    if (result == null) {
1034:                                        System.out.println("load failed");
1035:                                    } else {
1036:                                        System.out.println("load worked");
1037:                                    }
1038:                                }
1039:                            } // end if (load_inner)
1040:                        }
1041:                    }
1042:                } // end if (true) block
1043:
1044:                if ((result == null) && package_name_exception) {
1045:                    if (debug) {
1046:                        System.out
1047:                                .println("throwing TclException because of PackageNameException");
1048:                    }
1049:
1050:                    throw new TclException(interp,
1051:                            "cannot load new class into java or tcl package");
1052:                }
1053:
1054:                if (result == null) {
1055:                    if (debug) {
1056:                        System.out
1057:                                .println("throwing unknown class TclException");
1058:                    }
1059:
1060:                    throw new TclException(interp, "unknown class \""
1061:                            + clsName_buf + "\"");
1062:                }
1063:
1064:                return result;
1065:            }
1066:
1067:            /*
1068:             *----------------------------------------------------------------------
1069:             *
1070:             *  convertJavaObject --
1071:             *
1072:             *	Converts the java.lang.Object into a Tcl object and return
1073:             *	TclObject that holds the reult. Primitive data types
1074:             *	are converted into primitive Tcl data types. Otherwise,
1075:             *	a ReflectObject wrapper is created for the object so that it
1076:             *	can be later accessed with the Reflection API.
1077:             *
1078:             * Results:
1079:             *	The TclObject representation of the Java object.
1080:             *
1081:             * Side effects:
1082:             *	None.
1083:             *
1084:             *----------------------------------------------------------------------
1085:             */
1086:
1087:            static TclObject convertJavaObject(Interp interp, // Current interpreter.
1088:                    Class cls, // The class of the Java Object
1089:                    Object javaObj) // The java.lang.Object to convert to a TclObject.
1090:                    throws TclException {
1091:                if (javaObj == null) {
1092:                    if (cls == String.class) {
1093:                        return TclString.newInstance("");
1094:                    } else {
1095:                        return ReflectObject.newInstance(interp, cls, javaObj);
1096:                    }
1097:
1098:                } else if ((cls == Integer.TYPE) || (cls == Integer.class)) {
1099:                    return TclInteger.newInstance(((Integer) javaObj)
1100:                            .intValue());
1101:
1102:                } else if ((cls == Long.TYPE) || (cls == Long.class)) {
1103:                    // A long can not be represented as a TclInteger
1104:                    return TclString.newInstance(javaObj.toString());
1105:
1106:                } else if ((cls == Short.TYPE) || (cls == Short.class)) {
1107:                    return TclInteger.newInstance(((Short) javaObj).intValue());
1108:
1109:                } else if ((cls == Byte.TYPE) || (cls == Byte.class)) {
1110:                    return TclInteger.newInstance(((Byte) javaObj).intValue());
1111:
1112:                } else if ((cls == Double.TYPE) || (cls == Double.class)) {
1113:                    return TclDouble.newInstance(((Double) javaObj)
1114:                            .doubleValue());
1115:
1116:                } else if ((cls == Float.TYPE) || (cls == Float.class)) {
1117:                    return TclDouble.newInstance(((Float) javaObj)
1118:                            .doubleValue());
1119:
1120:                } else if ((cls == Boolean.TYPE) || (cls == Boolean.class)) {
1121:                    return TclBoolean.newInstance(((Boolean) javaObj)
1122:                            .booleanValue());
1123:
1124:                } else if ((cls == Character.TYPE) || (cls == Character.class)) {
1125:                    return TclString.newInstance(((Character) javaObj)
1126:                            .toString());
1127:
1128:                } else if (cls == String.class) {
1129:                    return TclString.newInstance((String) javaObj);
1130:
1131:                } else {
1132:                    return ReflectObject.newInstance(interp, cls, javaObj);
1133:                }
1134:            }
1135:
1136:            /*
1137:             *-----------------------------------------------------------------------------
1138:             *
1139:             * convertTclObject --
1140:             *
1141:             *	Converts a Tcl object to a Java Object of the required type.
1142:             *
1143:             * Results:
1144:             *	An Object of the required type.
1145:             *
1146:             * Side effects:
1147:             *	None.
1148:             *
1149:             *-----------------------------------------------------------------------------
1150:             */
1151:
1152:            static final Object convertTclObject(Interp interp, // Current interpreter.
1153:                    Class type, // Convert to this type.
1154:                    TclObject tclObj) // From this Tcl object.
1155:                    throws TclException // If conversion fails.
1156:            {
1157:                Object javaObj = null;
1158:                Class javaClass = null;
1159:                boolean isReflectObj = false;
1160:
1161:                try {
1162:                    javaObj = ReflectObject.get(interp, tclObj);
1163:                    javaClass = ReflectObject.getClass(interp, tclObj);
1164:                    isReflectObj = true;
1165:                } catch (TclException e) {
1166:                    interp.resetResult();
1167:                }
1168:
1169:                if (!isReflectObj) {
1170:                    // tclObj a Tcl "primitive" value. We try convert it to the 
1171:                    // corresponding primitive value in Java.
1172:                    //
1173:                    // To optimize performance, the following "if" statements are
1174:                    // arranged according to (my guesstimation of) the frequency
1175:                    // that a certain type is used.
1176:
1177:                    if (type == String.class) {
1178:                        return tclObj.toString();
1179:
1180:                    } else if (type == Object.class) {
1181:                        return tclObj.toString();
1182:
1183:                    } else if ((type == Integer.TYPE)
1184:                            || (type == Integer.class)) {
1185:                        // If an object is already a TclInteger type, then pass
1186:                        // the existing value directly. Otherwise, parse the
1187:                        // number as a Java int and see if it can be represented
1188:                        // as a Java int. This logic will raise an exception
1189:                        // when a number can't be represented as a 32bit signed int.
1190:                        // Tcl's weird number parsing rules will wrap the integer
1191:                        // around and calling code can't detect an overflow.
1192:
1193:                        int jint = parseJavaInt(interp, tclObj);
1194:                        return new Integer(jint);
1195:
1196:                    } else if ((type == Boolean.TYPE)
1197:                            || (type == Boolean.class)) {
1198:                        return new Boolean(TclBoolean.get(interp, tclObj));
1199:
1200:                    } else if ((type == Long.TYPE) || (type == Long.class)) {
1201:                        // If an object is already a TclInteger type, then pass
1202:                        // the existing value directly. Otherwise, parse the
1203:                        // number as a Java long. Raise a TclException if the
1204:                        // number is not an integer or is outside the long bounds.
1205:
1206:                        long jlong = parseJavaLong(interp, tclObj);
1207:                        return new Long(jlong);
1208:
1209:                    } else if ((type == Float.TYPE) || (type == Float.class)) {
1210:                        // Tcl stores floating point numbers as doubles,
1211:                        // so we just need to check to see if the value
1212:                        // is outside the float bounds. Invoking a Java
1213:                        // method should not automatically lose precision.
1214:
1215:                        double jdouble = TclDouble.get(interp, tclObj);
1216:                        float jfloat = (float) jdouble;
1217:
1218:                        if ((jdouble == Double.NaN)
1219:                                || (jdouble == Double.NEGATIVE_INFINITY)
1220:                                || (jdouble == Double.POSITIVE_INFINITY)) {
1221:                            // No-op
1222:                        } else if ((jdouble != 0.0)
1223:                                && ((Math.abs(jdouble) > (double) Float.MAX_VALUE) || (Math
1224:                                        .abs(jdouble) < (double) Float.MIN_VALUE))) {
1225:                            throw new TclException(interp,
1226:                                    "double value too large to represent in a float");
1227:                        }
1228:                        return new Float(jfloat);
1229:
1230:                    } else if ((type == Double.TYPE) || (type == Double.class)) {
1231:                        return new Double(TclDouble.get(interp, tclObj));
1232:
1233:                    } else if ((type == Byte.TYPE) || (type == Byte.class)) {
1234:                        // Parse a Java int, then check valid byte range.
1235:
1236:                        int jint = parseJavaInt(interp, tclObj);
1237:                        if ((jint < Byte.MIN_VALUE) || (jint > Byte.MAX_VALUE)) {
1238:                            throw new TclException(interp,
1239:                                    "integer value too large to represent in a byte");
1240:                        }
1241:                        return new Byte((byte) jint);
1242:
1243:                    } else if ((type == Short.TYPE) || (type == Short.class)) {
1244:                        // Parse a Java int, then check valid byte range.
1245:
1246:                        int jint = parseJavaInt(interp, tclObj);
1247:                        if ((jint < Short.MIN_VALUE)
1248:                                || (jint > Short.MAX_VALUE)) {
1249:                            throw new TclException(interp,
1250:                                    "integer value too large to represent in a short");
1251:                        }
1252:                        return new Short((short) jint);
1253:
1254:                    } else if ((type == Character.TYPE)
1255:                            || (type == Character.class)) {
1256:                        String str = tclObj.toString();
1257:                        if (str.length() != 1) {
1258:                            throw new TclException(interp,
1259:                                    "expected character but got \"" + tclObj
1260:                                            + "\"");
1261:                        }
1262:                        return new Character(str.charAt(0));
1263:
1264:                    } else if (type == TclObject.class) {
1265:                        // Pass a non ReflectObject TclObject directly to a Java method.
1266:                        return tclObj;
1267:                    } else {
1268:                        throw new TclException(interp, "\"" + tclObj
1269:                                + "\" is not an object handle of class \""
1270:                                + JavaInfoCmd.getNameFromClass(type) + "\"");
1271:                    }
1272:                } else {
1273:                    // The TclObject is a ReflectObject that contains javaObj. We
1274:                    // check to see if javaObj can be converted to the required
1275:                    // type. If javaObj is a wrapper for a primitive type then
1276:                    // we check to see if the object is an instanceof the type.
1277:
1278:                    if (isAssignable(type, javaClass)) {
1279:                        return javaObj;
1280:                    }
1281:
1282:                    if (type.isPrimitive()) {
1283:                        if (type == Boolean.TYPE) {
1284:                            if (javaObj instanceof  Boolean) {
1285:                                return javaObj;
1286:                            }
1287:                        } else if (type == Character.TYPE) {
1288:                            if (javaObj instanceof  Character) {
1289:                                return javaObj;
1290:                            }
1291:                        } else if (type == Byte.TYPE) {
1292:                            if (javaObj instanceof  Byte) {
1293:                                return javaObj;
1294:                            }
1295:                        } else if (type == Short.TYPE) {
1296:                            if (javaObj instanceof  Short) {
1297:                                return javaObj;
1298:                            }
1299:                        } else if (type == Integer.TYPE) {
1300:                            if (javaObj instanceof  Integer) {
1301:                                return javaObj;
1302:                            }
1303:                        } else if (type == Long.TYPE) {
1304:                            if (javaObj instanceof  Long) {
1305:                                return javaObj;
1306:                            }
1307:                        } else if (type == Float.TYPE) {
1308:                            if (javaObj instanceof  Float) {
1309:                                return javaObj;
1310:                            }
1311:                        } else if (type == Double.TYPE) {
1312:                            if (javaObj instanceof  Double) {
1313:                                return javaObj;
1314:                            }
1315:                        } else if (type == Void.TYPE) {
1316:                            // void is not a valid type for conversions
1317:                        }
1318:                    }
1319:
1320:                    // Pass TclObject that contains the ReflectObject directly.
1321:                    if (type == TclObject.class) {
1322:                        return tclObj;
1323:                    }
1324:
1325:                    throw new TclException(interp, "expected object of type "
1326:                            + JavaInfoCmd.getNameFromClass(type)
1327:                            + " but got \""
1328:                            + tclObj
1329:                            + "\" ("
1330:                            + ((javaClass == null) ? "null" : JavaInfoCmd
1331:                                    .getNameFromClass(javaClass)) + ")");
1332:                }
1333:            }
1334:
1335:            /*
1336:             *-----------------------------------------------------------------------------
1337:             *
1338:             * wrap --
1339:             *
1340:             *	Wraps a Java Object into a TclObject according to whether the
1341:             *	convert flag is set.
1342:             *
1343:             * Results:
1344:             *	The TclObject that wraps the Java Object.
1345:             *
1346:             * Side effects:
1347:             *	None.
1348:             *
1349:             *-----------------------------------------------------------------------------
1350:             */
1351:
1352:            private static final TclObject wrap(Interp interp, // Current interpreter.
1353:                    Class cls, // The class of the Java Object
1354:                    Object javaObj, // The Java Object to wrap.
1355:                    boolean convert) // Whether the value should be converted
1356:                    // into Tcl objects of the closest types. 
1357:                    throws TclException {
1358:                if (convert) {
1359:                    return convertJavaObject(interp, cls, javaObj);
1360:                } else {
1361:                    return ReflectObject.newInstance(interp, cls, javaObj);
1362:                }
1363:            }
1364:
1365:            /*
1366:             *-----------------------------------------------------------------------------
1367:             *
1368:             * isAssignable --
1369:             *
1370:             *	Return true if the argument object can be assigned to
1371:             *	convert flag is set.
1372:             *
1373:             * Results:
1374:             *	The TclObject that wraps the Java Object.
1375:             *
1376:             * Side effects:
1377:             *	None.
1378:             *
1379:             *-----------------------------------------------------------------------------
1380:             */
1381:
1382:            static final boolean isAssignable(Class to_cls, // The class we want to assign to
1383:                    Class from_cls) // The class we want to assign from (can be null)
1384:            {
1385:                // A primitive type can not be assigned the null value, but it
1386:                // can be assigned to any type derived from Object.
1387:
1388:                if (from_cls == null) {
1389:                    if (to_cls.isPrimitive()) {
1390:                        return false;
1391:                    } else {
1392:                        return true;
1393:                    }
1394:                } else {
1395:                    if ((to_cls == from_cls)
1396:                            || to_cls.isAssignableFrom(from_cls)) {
1397:                        return true;
1398:                    } else {
1399:                        return false;
1400:                    }
1401:                }
1402:            }
1403:
1404:            /*
1405:             *-----------------------------------------------------------------------------
1406:             *
1407:             * notAccessibleError --
1408:             *
1409:             *	Raise a specific TclException when a class that is not accessible
1410:             *	is found.
1411:             *
1412:             * Results:
1413:             *	None.
1414:             *
1415:             * Side effects:
1416:             *	None.
1417:             *
1418:             *-----------------------------------------------------------------------------
1419:             */
1420:
1421:            static void notAccessibleError(Interp interp, Class cls)
1422:                    throws TclException {
1423:                throw new TclException(interp, "Class \""
1424:                        + JavaInfoCmd.getNameFromClass(cls)
1425:                        + "\" is not accessible");
1426:            }
1427:
1428:            /*
1429:             *-----------------------------------------------------------------------------
1430:             *
1431:             * isInnerClass --
1432:             *
1433:             *	Return true is a class is either an inner class or an inner interface.
1434:             *	This is true only for classes defined inside other classes.
1435:             *
1436:             * Results:
1437:             *	None.
1438:             *
1439:             * Side effects:
1440:             *	None.
1441:             *
1442:             *-----------------------------------------------------------------------------
1443:             */
1444:
1445:            static boolean isInnerClass(Class cls) throws TclException {
1446:                String cname = cls.getName();
1447:                if (cname.indexOf('$') == -1) {
1448:                    return false;
1449:                } else {
1450:                    return true;
1451:                }
1452:            }
1453:
1454:            /*
1455:             *-----------------------------------------------------------------------------
1456:             *
1457:             * parseJavaInt --
1458:             *
1459:             *	Parse a Java int type from a TclObject. Unlike the rest of Tcl,
1460:             *	this method will raise an error when an integer value is not
1461:             *	in the range Integer.MIN_VALUE to Integer.MAX_VALUE. This is
1462:             *	the range of a 32bit signed number as defined by Java. Tcl parses
1463:             *	integers as 32bit unsigned numbers and wraps values outside the
1464:             *	valid range. This method will catch the case of an integer outside
1465:             *	of the valid range and raise a TclException so that a bogus value
1466:             *	is not passed to Java.
1467:             *
1468:             * Results:
1469:             *	Returns an int value or raises a TclException to indicate that
1470:             *	the number can't be parsed as a Java int.
1471:             *
1472:             * Side effects:
1473:             *	None.
1474:             *
1475:             *-----------------------------------------------------------------------------
1476:             */
1477:
1478:            static int parseJavaInt(Interp interp, TclObject obj)
1479:                    throws TclException {
1480:                // No point in reparsing a "pure" integer.
1481:
1482:                if (obj.hasNoStringRep() && obj.isIntType()) {
1483:                    return TclInteger.get(interp, obj);
1484:                }
1485:
1486:                String srep = obj.toString();
1487:                String s = srep;
1488:                int len = s.length();
1489:                char c;
1490:                int startInd, endInd;
1491:                boolean isNegative = false;
1492:
1493:                // Trim whitespace off front of string
1494:
1495:                int i = 0;
1496:                while (i < len
1497:                        && (((c = s.charAt(i)) == ' ') || Character
1498:                                .isWhitespace(c))) {
1499:                    i++;
1500:                }
1501:                if (i >= len) {
1502:                    throw new TclException(interp,
1503:                            "expected integer but got \"" + s + "\"");
1504:                }
1505:                startInd = i;
1506:
1507:                // Trim whitespace off end of string
1508:
1509:                endInd = len - 1;
1510:                while (endInd > startInd
1511:                        && (((c = s.charAt(endInd)) == ' ') || Character
1512:                                .isWhitespace(c))) {
1513:                    endInd--;
1514:                }
1515:
1516:                // Check for optional '-' sign, needed for hex and octal parse.
1517:
1518:                c = s.charAt(i);
1519:                if (c == '-') {
1520:                    isNegative = true;
1521:                    i++;
1522:                }
1523:                if (i >= (endInd + 1)) {
1524:                    throw new TclException(interp,
1525:                            "expected integer but got \"" + s + "\"");
1526:                }
1527:
1528:                // Check for hex or octal string prefix characters
1529:
1530:                int radix = Character.MIN_RADIX - 1; // An invalid value
1531:
1532:                c = s.charAt(i);
1533:                if (c == '0' && len > 1) {
1534:                    // Either hex or octal
1535:                    i++;
1536:                    c = s.charAt(i);
1537:
1538:                    if (len > 2 && (c == 'x' || c == 'X')) {
1539:                        // Parse as hex
1540:                        radix = 16;
1541:                        i++;
1542:                    } else {
1543:                        // Parse as octal
1544:                        radix = 8;
1545:                    }
1546:
1547:                    // Create string that contains a leading negative sign followed
1548:                    // by the radix letters, leaving out the radix prefix.
1549:                    // For example, "-0xFF" is parsed as "-FF".
1550:
1551:                    if (isNegative) {
1552:                        s = "-" + s.substring(i, endInd + 1);
1553:                    } else {
1554:                        s = s.substring(i, endInd + 1);
1555:                    }
1556:                } else {
1557:                    // Parse as decimal integer
1558:
1559:                    if ((startInd > 0) || (endInd < (len - 1))) {
1560:                        s = s.substring(startInd, endInd + 1);
1561:                    }
1562:
1563:                    radix = 10;
1564:                }
1565:
1566:                if (s.length() == 0) {
1567:                    throw new TclException(interp,
1568:                            "expected integer but got \"" + srep + "\"");
1569:                }
1570:
1571:                int ival;
1572:                try {
1573:                    ival = Integer.parseInt(s, radix);
1574:                } catch (NumberFormatException nfe) {
1575:                    // If one of the letters is not a valid radix character, then
1576:                    // the number is not a valid. Otherwise, the number must be
1577:                    // an integer value that is outside the valid range.
1578:
1579:                    for (i = 0; i < s.length(); i++) {
1580:                        c = s.charAt(i);
1581:                        if (i == 0 && c == '-') {
1582:                            continue; // Skip minus sign
1583:                        }
1584:                        if (Character.digit(c, radix) == -1) {
1585:                            throw new TclException(interp,
1586:                                    "expected integer but got \"" + srep + "\"");
1587:                        }
1588:                    }
1589:
1590:                    throw new TclException(interp,
1591:                            "integer value too large to represent in a int");
1592:                }
1593:
1594:                return ival;
1595:            }
1596:
1597:            /*
1598:             *-----------------------------------------------------------------------------
1599:             *
1600:             * parseJavaLong --
1601:             *
1602:             *	Parse a Java long type from a TclObject. Tcl may not support
1603:             *	64 bit integers (Jacl does not), so this method needs to be used
1604:             *	to determine if a string can be parsed into a long and if the
1605:             *	result is in the range Long.MIN_VALUE to Long.MAX_VALUE.
1606:             *	This method will catch the case of an long outside of
1607:             *	the valid range and raise a TclException so that a bogus value
1608:             *	is not passed to Java.
1609:             *
1610:             * Results:
1611:             *	Returns a long value or raises a TclException to indicate that
1612:             *	the number can't be parsed as a Java long.
1613:             *
1614:             * Side effects:
1615:             *	None.
1616:             *
1617:             *-----------------------------------------------------------------------------
1618:             */
1619:
1620:            static long parseJavaLong(Interp interp, TclObject obj)
1621:                    throws TclException {
1622:                // No point in reparsing a "pure" integer.
1623:
1624:                if (obj.hasNoStringRep() && obj.isIntType()) {
1625:                    return (long) TclInteger.get(interp, obj);
1626:                }
1627:
1628:                String srep = obj.toString();
1629:                String s = srep;
1630:                int len = s.length();
1631:                char c;
1632:                int startInd, endInd;
1633:                boolean isNegative = false;
1634:
1635:                // Trim whitespace off front of string
1636:
1637:                int i = 0;
1638:                while (i < len
1639:                        && (((c = s.charAt(i)) == ' ') || Character
1640:                                .isWhitespace(c))) {
1641:                    i++;
1642:                }
1643:                if (i >= len) {
1644:                    throw new TclException(interp,
1645:                            "expected integer but got \"" + s + "\"");
1646:                }
1647:                startInd = i;
1648:
1649:                // Trim whitespace off end of string
1650:
1651:                endInd = len - 1;
1652:                while (endInd > startInd
1653:                        && (((c = s.charAt(endInd)) == ' ') || Character
1654:                                .isWhitespace(c))) {
1655:                    endInd--;
1656:                }
1657:
1658:                // Check for optional '-' sign, needed for hex and octal parse.
1659:
1660:                c = s.charAt(i);
1661:                if (c == '-') {
1662:                    isNegative = true;
1663:                    i++;
1664:                }
1665:                if (i >= (endInd + 1)) {
1666:                    throw new TclException(interp,
1667:                            "expected integer but got \"" + s + "\"");
1668:                }
1669:
1670:                // Check for hex or octal string prefix characters
1671:
1672:                int radix = Character.MIN_RADIX - 1; // An invalid value
1673:
1674:                c = s.charAt(i);
1675:                if (c == '0' && len > 1) {
1676:                    // Either hex or octal
1677:                    i++;
1678:                    c = s.charAt(i);
1679:
1680:                    if (len > 2 && (c == 'x' || c == 'X')) {
1681:                        // Parse as hex
1682:                        radix = 16;
1683:                        i++;
1684:                    } else {
1685:                        // Parse as octal
1686:                        radix = 8;
1687:                    }
1688:
1689:                    // Create string that contains a leading negative sign followed
1690:                    // by the radix letters, leaving out the radix prefix.
1691:                    // For example, "-0xFF" is parsed as "-FF".
1692:
1693:                    if (isNegative) {
1694:                        s = "-" + s.substring(i, endInd + 1);
1695:                    } else {
1696:                        s = s.substring(i, endInd + 1);
1697:                    }
1698:                } else {
1699:                    // Parse as decimal integer
1700:
1701:                    if ((startInd > 0) || (endInd < (len - 1))) {
1702:                        s = s.substring(startInd, endInd + 1);
1703:                    }
1704:
1705:                    radix = 10;
1706:                }
1707:
1708:                if (s.length() == 0) {
1709:                    throw new TclException(interp,
1710:                            "expected integer but got \"" + srep + "\"");
1711:                }
1712:
1713:                long lval;
1714:                try {
1715:                    lval = Long.parseLong(s, radix);
1716:                } catch (NumberFormatException nfe) {
1717:                    // If one of the letters is not a valid radix character, then
1718:                    // the number is not a valid. Otherwise, the number must be
1719:                    // an integer value that is outside the valid range.
1720:
1721:                    for (i = 0; i < s.length(); i++) {
1722:                        c = s.charAt(i);
1723:                        if (i == 0 && c == '-') {
1724:                            continue; // Skip minus sign
1725:                        }
1726:                        if (Character.digit(c, radix) == -1) {
1727:                            throw new TclException(interp,
1728:                                    "expected integer but got \"" + srep + "\"");
1729:                        }
1730:                    }
1731:
1732:                    throw new TclException(interp,
1733:                            "integer value too large to represent in a long");
1734:                }
1735:
1736:                return lval;
1737:            }
1738:
1739:        } // end JavaInvoke
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.