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


0001:        /*=============================================================================
0002:         *     Copyright Texas Instruments 2000-2004.  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.data;
0022:
0023:        import java.lang.reflect.*;
0024:        import java.util.*;
0025:
0026:        import oscript.exceptions.*;
0027:        import oscript.util.*;
0028:        import oscript.classwrap.ClassWrapGen;
0029:
0030:        /**
0031:         * A wrapper for a java class.  Types should be intern'd.
0032:         * 
0033:         * @author Rob Clark (rob@ti.com)
0034:         */
0035:        public class JavaClassWrapper extends Type {
0036:            protected Class javaClass;
0037:            private int id = -1;
0038:
0039:            transient protected JavaClassWrapperImpl impl;
0040:            transient protected JavaClassWrapperImpl wrapperImpl;
0041:
0042:            /**
0043:             * Table of all java-class-wrappers.  A <code>JavaClassWrapper</code>
0044:             * instance is intern'd, so there shouldn't be two instances representing
0045:             * the same java class.
0046:             */
0047:            private static Hashtable classWrapperCache = new Hashtable();
0048:
0049:            /**
0050:             * The type object for an script java type.
0051:             */
0052:            public final static Value TYPE = BuiltinType
0053:                    .makeBuiltinType("oscript.data.JavaClassWrapper");
0054:            public final static String PARENT_TYPE_NAME = "oscript.data.OObject";
0055:            public final static String TYPE_NAME = "JavaClass";
0056:            public final static String[] MEMBER_NAMES = new String[] { "isA",
0057:                    "castToString", "castToJavaObject", "callAsConstructor",
0058:                    "callAsExtends", "getMember", "getClassLoader", "getName" };
0059:
0060:            /*=======================================================================*/
0061:            /**
0062:             * The class wrapper instances need to be intern'd, so the types work out
0063:             * right... otherwise you might have multiple wrappers per java class (ie
0064:             * type), which would confuse type checking...
0065:             * 
0066:             * @param javaClass    the java class this object is a wrapper for
0067:             */
0068:            public static synchronized JavaClassWrapper getClassWrapper(
0069:                    Class javaClass) {
0070:                javaClass = ClassWrapGen.getNonWrapperClass(javaClass);
0071:
0072:                JavaClassWrapper jcw = (JavaClassWrapper) (classWrapperCache
0073:                        .get(javaClass));
0074:
0075:                if (jcw == null) {
0076:                    jcw = new JavaClassWrapper(javaClass);
0077:                    classWrapperCache.put(javaClass, jcw);
0078:                }
0079:
0080:                return jcw;
0081:            }
0082:
0083:            public static JavaClassWrapper getClassWrapper(String className)
0084:                    throws ClassNotFoundException {
0085:                return getClassWrapper(forName(className));
0086:            }
0087:
0088:            public static synchronized Class forName(String className)
0089:                    throws ClassNotFoundException {
0090:                return oscript.compiler.CompilerClassLoader.forName(className,
0091:                        true, null);
0092:            }
0093:
0094:            private static ClassNotFoundException CLASS_NOT_FOUND_EXCEPTION = new ClassNotFoundException();
0095:
0096:            /*=======================================================================*/
0097:            /**
0098:             * Class Constructor.
0099:             * 
0100:             * @param javaClass    the java class this object is a wrapper for
0101:             */
0102:            protected JavaClassWrapper(Class javaClass) {
0103:                super ();
0104:
0105:                this .javaClass = javaClass;
0106:            }
0107:
0108:            /**
0109:             * Initialize this object.  Initialization is done on demand because
0110:             * <code>impl</code> and <code>wrapperImpl</code> are transient, and
0111:             * might not exist if this object gets unserialized...
0112:             */
0113:            protected synchronized void init() {
0114:                if (impl == null) {
0115:                    this .id = Symbol.getSymbol(javaClass.getName()).getId();
0116:
0117:                    // note order is important... we want to initialize "impl" last,
0118:                    // since other places in the code use it to decide whether init()
0119:                    // should be called
0120:
0121:                    if (ClassWrapGen.canMakeWrapperClass(javaClass))
0122:                        wrapperImpl = new JavaClassWrapperImpl(javaClass, true);
0123:
0124:                    impl = new JavaClassWrapperImpl(javaClass, false);
0125:                }
0126:            }
0127:
0128:            /*=======================================================================*/
0129:            /**
0130:             * Get the type of this object.  The returned type doesn't have to take
0131:             * into account the possibility of a script type extending a built-in
0132:             * type, since that is handled by {@link #getType}.
0133:             * 
0134:             * @return the object's type
0135:             */
0136:            protected Value getTypeImpl() {
0137:                return TYPE;
0138:            }
0139:
0140:            /*=======================================================================*/
0141:            /**
0142:             * Convert this object to a native java <code>String</code> value.
0143:             * 
0144:             * @return a String value
0145:             * @throws PackagedScriptObjectException(NoSuchMethodException)
0146:             */
0147:            public String getName() {
0148:                return javaClass.getName();
0149:            }
0150:
0151:            /*=======================================================================*/
0152:            /**
0153:             * If this object is a type, determine if an instance of this type is
0154:             * an instance of the specified type, ie. if this is <code>type</code>,
0155:             * or a subclass.
0156:             * 
0157:             * @param type         the type to compare this type to
0158:             * @return <code>true</code> or <code>false</code>
0159:             * @throws PackagedScriptObjectException(NoSuchMemberException)
0160:             */
0161:            public boolean isA(Value type) {
0162:                type = type.unhand();
0163:
0164:                Class c;
0165:                if (super .isA(type))
0166:                    return true;
0167:
0168:                if (((c = javaClass.getSuperclass()) != null)
0169:                        && getClassWrapper(c).isA(type))
0170:                    return true;
0171:
0172:                Class[] interfaces = javaClass.getInterfaces();
0173:
0174:                for (int i = 0; i < interfaces.length; i++)
0175:                    if (getClassWrapper(interfaces[i]).isA(type))
0176:                        return true;
0177:
0178:                return false;
0179:            }
0180:
0181:            /*=======================================================================*/
0182:            /**
0183:             * Convert this object to a native java <code>String</code> value.
0184:             * 
0185:             * @return a String value
0186:             * @throws PackagedScriptObjectException(NoSuchMethodException)
0187:             */
0188:            public String castToString() throws PackagedScriptObjectException {
0189:                return getName();
0190:            }
0191:
0192:            /*=======================================================================*/
0193:            /**
0194:             * Convert this object to a native java <code>Object</code> value.
0195:             * 
0196:             * @return a java object
0197:             * @throws PackagedScriptObjectException(NoSuchMethodException)
0198:             */
0199:            public Object castToJavaObject()
0200:                    throws PackagedScriptObjectException {
0201:                return javaClass;
0202:            }
0203:
0204:            /*=======================================================================*/
0205:            /**
0206:             * Call this object as a constructor.
0207:             * 
0208:             * @param sf           the current stack frame
0209:             * @param args         the arguments to the function, or <code>null</code> if none
0210:             * @return the newly constructed object
0211:             * @throws PackagedScriptObjectException
0212:             * @see Function
0213:             */
0214:            public Value callAsConstructor(StackFrame sf, MemberTable args)
0215:                    throws PackagedScriptObjectException {
0216:                return JavaBridge.convertToScriptObject(doConstruct(sf, args,
0217:                        false));
0218:            }
0219:
0220:            /*=======================================================================*/
0221:            /**
0222:             * Call this object as a parent class constructor.
0223:             * 
0224:             * @param sf           the current stack frame
0225:             * @param scope        the object
0226:             * @param args         the arguments to the function, or <code>null</code> if none
0227:             * @return the value returned by the function
0228:             * @throws PackagedScriptObjectException
0229:             * @see Function
0230:             */
0231:            public Value callAsExtends(StackFrame sf, Scope scope,
0232:                    MemberTable args) throws PackagedScriptObjectException {
0233:                if (impl == null)
0234:                    init();
0235:
0236:                if (wrapperImpl == null)
0237:                    throw PackagedScriptObjectException
0238:                            .makeExceptionWrapper(new OUnsupportedOperationException(
0239:                                    "java class is final; can't call as constructor"));
0240:
0241:                /* XXX this is kinda a hack.  We need what we link to to be the ScriptObject,
0242:                 *     and not the ForkScope
0243:                 */
0244:                Scope scriptObject = scope;
0245:                while (scriptObject instanceof  ForkScope)
0246:                    scriptObject = scriptObject.getPreviousScope();
0247:
0248:                ClassWrapGen.linkObjects(doConstruct(sf, args, true),
0249:                        scriptObject);
0250:
0251:                return scope;
0252:            }
0253:
0254:            // we have to leave this here, because it gets overloaded... 
0255:            protected Object doConstruct(StackFrame sf, MemberTable args,
0256:                    boolean isWrapper) {
0257:                if (impl == null)
0258:                    init();
0259:
0260:                if (isWrapper)
0261:                    return wrapperImpl.doConstruct(this , sf, args);
0262:                else
0263:                    return impl.doConstruct(this , sf, args);
0264:            }
0265:
0266:            /*=======================================================================*/
0267:            /**
0268:             * Get a member of this object.
0269:             * 
0270:             * @param id           the id of the symbol that maps to the member
0271:             * @param exception    whether an exception should be thrown if the
0272:             *   member object is not resolved
0273:             * @return a reference to the member
0274:             * @throws PackagedScriptObjectException(NoSuchMethodException)
0275:             * @throws PackagedScriptObjectException(NoSuchMemberException)
0276:             */
0277:            public Value getMember(int id, boolean exception)
0278:                    throws PackagedScriptObjectException {
0279:                if (impl == null)
0280:                    init();
0281:
0282:                Value val = impl.getMemberImpl(id);
0283:
0284:                // this should handle looking for inner-classes... 
0285:                if (val == null) {
0286:                    try {
0287:                        val = JavaClassWrapper
0288:                                .getClassWrapper(forName(getInnerClassName(
0289:                                        javaClass, id)));
0290:                    } catch (ClassNotFoundException e) {
0291:                    }
0292:                }
0293:
0294:                if (val != null)
0295:                    return val;
0296:                else
0297:                    return super .getMember(id, exception);
0298:            }
0299:
0300:            /*=======================================================================*/
0301:            /**
0302:             * Get a member of this type.  This is used to interface to the java
0303:             * method of having members be attributes of a type.  Regular object-
0304:             * script object's members are attributes of the object, but in the
0305:             * case of java types (including built-in types), the members are
0306:             * attributes of the type.
0307:             * 
0308:             * @param obj          an object of this type
0309:             * @param id           the id of the symbol that maps to the member
0310:             * @return a reference to the member, or null
0311:             */
0312:            protected Value getTypeMember(Value obj, int id) {
0313:                if (impl == null)
0314:                    init();
0315:
0316:                obj = obj.unhand();
0317:
0318:                Object javaObj;
0319:
0320:                /* XXX hack:  (needed because ExactNumber, InexactNumber, etc. cast to 
0321:                 * Long, Double, etc)
0322:                 */
0323:                if ((this  instanceof  BuiltinType)
0324:                        && !(obj instanceof  ScriptObject))
0325:                    javaObj = obj;
0326:                else
0327:                    javaObj = obj.castToJavaObject();
0328:
0329:                Value val = getTypeMemberImpl(javaObj, id);
0330:
0331:                /* XXX hack: (kinda) if we don't find the method, perhaps it is provided
0332:                 * by Value... this is sorta like multiple inheritance, but we need to
0333:                 * ensure that even java objects implement certain basic methods... if
0334:                 * an object is a ScriptObject, this is handled by the ScriptObject
0335:                 * class... except getMember() won't return the method... so it will work 
0336:                 * for stuff like (foo instanceof Foo), but not foo.bopInstanceOf(Foo)
0337:                 */
0338:                if (val == null) {
0339:                    if (obj instanceof  ScriptObject)
0340:                        val = ScriptObject.TYPE.getTypeMemberImpl(obj, Symbol
0341:                                .getSymbol(
0342:                                        "_"
0343:                                                + Symbol.getSymbol(id)
0344:                                                        .castToString())
0345:                                .getId());
0346:                    else
0347:                        val = Value.TYPE.getTypeMemberImpl(obj, id);
0348:                }
0349:
0350:                /* If we still haven't found it, check if it is a static
0351:                 * member of the class:
0352:                 */
0353:                if (val == null)
0354:                    val = impl.getMemberImpl(id);
0355:
0356:                return val;
0357:            }
0358:
0359:            protected Value getTypeMemberImpl(Object javaObj, int id) {
0360:                if (impl == null)
0361:                    init();
0362:
0363:                CacheEntry ce = null;
0364:                if (ClassWrapGen.isWrapperInstance(javaObj))
0365:                    ce = wrapperImpl.getTypeMemberCacheEntry(id);
0366:
0367:                // XXX will this work to resolve fields??
0368:                if (ce == null)
0369:                    ce = impl.getTypeMemberCacheEntry(id);
0370:
0371:                if (ce == null)
0372:                    return null;
0373:
0374:                return ce.getMember(id, javaObj);
0375:            }
0376:
0377:            /*=======================================================================*/
0378:            /**
0379:             * Get the {@link ClassLoader} object for the java class this class is
0380:             * a wrapper for.
0381:             * 
0382:             * @return the {@link ClassLoader} of the java class
0383:             */
0384:            public ClassLoader getClassLoader() {
0385:                return javaClass.getClassLoader();
0386:            }
0387:
0388:            /*=======================================================================*/
0389:            /**
0390:             * Implements the reflection stuff... this is broken out into it's own
0391:             * class because a <code>JavaClassWrapper</code> might have two of these
0392:             * (which get initialized at different times), one for the regular class
0393:             * and one for the wrapper class.  The wrapper class is only used when
0394:             * script code extends a java type.  Also, since we need to create a
0395:             * new instance of <code>JavaInnerClassWrapper</code> for each access,
0396:             * we cache the impl's for inner classes, to avoid having to go thru
0397:             * the expensive init() process multiple times for the same java class.
0398:             */
0399:            protected static class JavaClassWrapperImpl {
0400:                Class javaClass;
0401:
0402:                private Constructor[] constructors;
0403:
0404:                /**
0405:                 * Cache of static fields, maps name (OString) -> Field or Method[]
0406:                 */
0407:                private SymbolMap classMemberCache;
0408:
0409:                /**
0410:                 * Cache of instance field, maps name (OString) -> Field or Method[]
0411:                 */
0412:                private SymbolMap instanceMemberCache;
0413:
0414:                private boolean isWrapper;
0415:                private boolean initialized = false;
0416:
0417:                /**
0418:                 * Class Constructor
0419:                 */
0420:                JavaClassWrapperImpl(Class javaClass, boolean isWrapper) {
0421:                    this .javaClass = javaClass;
0422:                    this .isWrapper = isWrapper;
0423:                }
0424:
0425:                synchronized void init() {
0426:                    /* Yes, we check this twice... the reasoning is that by checking it
0427:                     * before we call init(), we can avoid a method call (to a synchronized
0428:                     * method, no less).  There is a slight race condition there, so we
0429:                     * have to check it a second time within the protection of the held
0430:                     * monitor.
0431:                     */
0432:                    if (!initialized) {
0433:                        if (isWrapper)
0434:                            javaClass = ClassWrapGen
0435:                                    .makeWrapperClass(javaClass);
0436:
0437:                        constructors = javaClass.getDeclaredConstructors();
0438:
0439:                        /* the handling of unaccessible classes could be a little more optimized,
0440:                         * but this will do for now...
0441:                         */
0442:                        boolean isNotPublic = !Modifier.isPublic(javaClass
0443:                                .getModifiers());
0444:
0445:                        instanceMemberCache = new SymbolMap();
0446:                        classMemberCache = new SymbolMap();
0447:
0448:                        if (isWrapper) {
0449:                            Method[] methods = javaClass.getMethods();
0450:                            SymbolMap methodMap = new SymbolMap();
0451:
0452:                            // build up the method table
0453:                            for (int i = 0; i < methods.length; i++) {
0454:                                if (!Modifier.isStatic(methods[i]
0455:                                        .getModifiers())) {
0456:                                    addMethodToCache(methodMap, Symbol
0457:                                            .getSymbol(methods[i].getName())
0458:                                            .getId(), methods[i]);
0459:                                }
0460:                            }
0461:
0462:                            for (Iterator itr = methodMap.keys(); itr.hasNext();) {
0463:                                int id = ((Integer) (itr.next())).intValue();
0464:
0465:                                Object obj = methodMap.get(Symbol.getSymbol(
0466:                                        ClassWrapGen.getOrigMethodName(Symbol
0467:                                                .getSymbol(id).castToString()))
0468:                                        .getId());
0469:
0470:                                // if there is an entry with the corresponding __orig_ name, use
0471:                                // that... if we use the regular version of the method instead,
0472:                                // it will lookup and resolve to itself, and we'll endup in an
0473:                                // infinite loop!
0474:                                if (obj != null)
0475:                                    instanceMemberCache.put(id, obj);
0476:                            }
0477:                        } else {
0478:                            Method[] methods = javaClass.getMethods();
0479:                            Field[] fields = javaClass.getFields(); //getDeclaredFields();
0480:
0481:                            for (int i = 0; i < fields.length; i++) {
0482:                                int id = Symbol.getSymbol(fields[i].getName())
0483:                                        .getId();
0484:
0485:                                if (Modifier.isStatic(fields[i].getModifiers()))
0486:                                    addFieldToCache(classMemberCache, id,
0487:                                            fields[i]);
0488:                                else
0489:                                    addFieldToCache(instanceMemberCache, id,
0490:                                            fields[i]);
0491:                            }
0492:
0493:                            for (int i = 0; i < methods.length; i++) {
0494:                                Method method = methods[i];
0495:                                String methodName = method.getName();
0496:
0497:                                int id = Symbol.getSymbol(methodName).getId();
0498:
0499:                                if (isNotPublic)
0500:                                    method = searchForAccessibleMethod(
0501:                                            methodName, javaClass, method
0502:                                                    .getParameterTypes());
0503:
0504:                                if (method != null) {
0505:                                    if (Modifier
0506:                                            .isStatic(method.getModifiers()))
0507:                                        addMethodToCache(classMemberCache, id,
0508:                                                method);
0509:                                    else
0510:                                        addMethodToCache(instanceMemberCache,
0511:                                                id, method);
0512:                                }
0513:                            }
0514:                        }
0515:
0516:                        initialized = true;
0517:                    }
0518:                }
0519:
0520:                /**
0521:                 * basically we decide on the constructor with the closest matching args, 
0522:                 * and call it to create a new instance.
0523:                 */
0524:                Object doConstruct(JavaClassWrapper jcw, StackFrame sf,
0525:                        MemberTable args) {
0526:                    if (!initialized)
0527:                        init();
0528:
0529:                    return JavaBridge.call(constructorAccessor, jcw.id, null,
0530:                            constructors, sf, args);
0531:                }
0532:
0533:                // returns <code>null</code> if not found.  Does not throw exception
0534:                // probably should be updated to return a CacheEntry for consistency
0535:                Value getMemberImpl(int id) {
0536:                    if (!initialized)
0537:                        init();
0538:
0539:                    CacheEntry ce = (CacheEntry) (classMemberCache.get(id));
0540:
0541:                    if (ce == null)
0542:                        return null;
0543:
0544:                    return ce.getMember(id, null);
0545:                }
0546:
0547:                CacheEntry getTypeMemberCacheEntry(int id) {
0548:                    if (!initialized)
0549:                        init();
0550:
0551:                    Object ce = instanceMemberCache.get(id);
0552:
0553:                    if (ce == null) {
0554:                        ce = getInnerClass(id);
0555:
0556:                        if (ce == null)
0557:                            ce = getBeanAccessor(id);
0558:
0559:                        if (ce == null)
0560:                            ce = Boolean.FALSE;
0561:
0562:                        instanceMemberCache.put(id, ce);
0563:                    }
0564:
0565:                    if (ce == Boolean.FALSE)
0566:                        ce = null;
0567:
0568:                    return (CacheEntry) ce;
0569:                }
0570:
0571:                private CacheEntry getInnerClass(int id) {
0572:                    try {
0573:                        final Class innerClass = forName(getInnerClassName(
0574:                                javaClass, id));
0575:
0576:                        return new CacheEntry() {
0577:
0578:                            private JavaClassWrapperImpl[] impls;
0579:
0580:                            public Value getMember(int id, Object javaObj) {
0581:                                Value obj = JavaBridge
0582:                                        .convertToScriptObject(javaObj);
0583:
0584:                                /* not synchronized on innerClassImplCache, to avoid deadlock when 
0585:                                 * calling forName() triggers loading a class that does something 
0586:                                 * that causes methods of this object to be called again
0587:                                 */
0588:                                synchronized (javaClass) // XXX is this ok to sync on?
0589:                                {
0590:                                    JavaInnerClassWrapper jicw = null;
0591:
0592:                                    if (impls == null) {
0593:                                        jicw = new JavaInnerClassWrapper(obj,
0594:                                                innerClass);
0595:                                        jicw.init();
0596:
0597:                                        impls = new JavaClassWrapperImpl[2];
0598:                                        impls[0] = jicw.impl;
0599:                                        impls[1] = jicw.wrapperImpl;
0600:                                    }
0601:
0602:                                    if (jicw == null) {
0603:                                        jicw = new JavaInnerClassWrapper(obj,
0604:                                                impls[0].javaClass);
0605:
0606:                                        jicw.impl = impls[0];
0607:                                        jicw.wrapperImpl = impls[1];
0608:                                    }
0609:
0610:                                    return jicw;
0611:                                }
0612:                            }
0613:
0614:                        };
0615:                    } catch (ClassNotFoundException e) {
0616:                        return null;
0617:                    }
0618:                }
0619:
0620:                /**
0621:                 * Check for "getter" and "setter" methods corresponding to <code>id</code>,
0622:                 * and if present return a bean-accessor, to allow access to properties of
0623:                 * java beans.
0624:                 */
0625:                private CacheEntry getBeanAccessor(int id) {
0626:                    String name = Symbol.getSymbol(id).castToString();
0627:                    char l = name.charAt(0);
0628:                    if (!Character.isLowerCase(l))
0629:                        return null;
0630:
0631:                    final String cname = name.substring(0, 1).toUpperCase()
0632:                            + ((name.length() > 1) ? name.substring(1) : "");
0633:
0634:                    Object obj = instanceMemberCache.get(Symbol.getSymbol(
0635:                            "get" + cname).getId());
0636:                    final CacheEntry getterCE = (obj == Boolean.FALSE) ? null
0637:                            : (CacheEntry) obj;
0638:
0639:                    if (getterCE == null)
0640:                        return null;
0641:
0642:                    return new CacheEntry() {
0643:
0644:                        public Value getMember(final int id,
0645:                                final Object javaObj) {
0646:                            /* work-around to deal with the case of this getting called while a
0647:                             * script class that extends a java class is being constructed (but
0648:                             * is not yet linked to the java object).  Since no script types 
0649:                             * have bean properties to access, this is the easy work-around:
0650:                             * <p>
0651:                             * XXX Note work-around for work-around... I need to clean this up!!
0652:                             */
0653:                            if ((javaObj instanceof  Value)
0654:                                    && !(javaObj instanceof  RegExpResult))
0655:                                return null;
0656:
0657:                            return new AbstractReference() {
0658:
0659:                                private Value setter;
0660:                                private Value getter;
0661:
0662:                                public void opAssign(Value val)
0663:                                        throws PackagedScriptObjectException {
0664:                                    if (setter == null) {
0665:                                        String setterName = "set" + cname;
0666:                                        Object obj = instanceMemberCache
0667:                                                .get(Symbol.getSymbol(
0668:                                                        setterName).getId());
0669:                                        CacheEntry setterCE = (obj == Boolean.FALSE) ? null
0670:                                                : (CacheEntry) obj;
0671:
0672:                                        if (setterCE != null)
0673:                                            setter = setterCE.getMember(id,
0674:                                                    javaObj);
0675:
0676:                                        if (setter == null)
0677:                                            throw noSuchMember(setterName);
0678:                                    }
0679:
0680:                                    setter.callAsFunction(new Value[] { val });
0681:                                }
0682:
0683:                                protected Value get() {
0684:                                    if (getter == null)
0685:                                        getter = getterCE
0686:                                                .getMember(id, javaObj);
0687:
0688:                                    return getter.callAsFunction(new Value[0]);
0689:                                }
0690:
0691:                            };
0692:                        }
0693:                    };
0694:                }
0695:
0696:                void populateTypeMemberSet(Set s) {
0697:                    for (Iterator itr = instanceMemberCache.keys(); itr
0698:                            .hasNext();) {
0699:                        int id = ((Integer) (itr.next())).intValue();
0700:                        if (instanceMemberCache.get(id) != Boolean.FALSE)
0701:                            s.add(Symbol.getSymbol(id));
0702:                    }
0703:                }
0704:
0705:                void populateMemberSet(Set s) {
0706:                    for (Iterator itr = classMemberCache.keys(); itr.hasNext();)
0707:                        s.add(Symbol.getSymbol(((Integer) (itr.next()))
0708:                                .intValue()));
0709:                }
0710:            }
0711:
0712:            private static final JavaBridge.JavaCallableAccessor constructorAccessor = new JavaBridge.JavaCallableAccessor() {
0713:
0714:                public Class[] getParameterTypes(Object javaCallable) {
0715:                    return ((Constructor) javaCallable).getParameterTypes();
0716:                }
0717:
0718:                public Object call(Object javaCallable, Object javaObject,
0719:                        Object[] args) throws InvocationTargetException,
0720:                        InstantiationException, IllegalAccessException {
0721:                    return ((Constructor) javaCallable).newInstance(args);
0722:                }
0723:            };
0724:
0725:            private static String getInnerClassName(Class javaClass, int id) {
0726:                return javaClass.getName() + "$"
0727:                        + Symbol.getSymbol(id).castToString();
0728:            }
0729:
0730:            // XXX not a good place for this, but...
0731:            private static final String _arrayToString(Object[] objs) {
0732:                String str = "[";
0733:                for (int i = 0; i < objs.length; i++)
0734:                    str += objs[i] + ",";
0735:                return str + "]";
0736:            }
0737:
0738:            /**
0739:             */
0740:            private interface CacheEntry {
0741:                Value getMember(int id, Object obj);
0742:            }
0743:
0744:            /**
0745:             * member-cache entry for fields
0746:             */
0747:            private static class FieldCacheEntry implements  CacheEntry {
0748:                private Field field;
0749:
0750:                FieldCacheEntry() {
0751:                    this .field = field;
0752:                }
0753:
0754:                void add(Field field) {
0755:                    // unlike methods, we only keep track of one method.. but we need to pick
0756:                    // the one that isn't eclipsed by a field in a derived classe
0757:                    if ((this .field == null)
0758:                            || this .field.getDeclaringClass().isAssignableFrom(
0759:                                    field.getDeclaringClass()))
0760:                        this .field = field;
0761:                }
0762:
0763:                public Value getMember(int id, final Object obj) {
0764:                    return new AbstractReference() {
0765:
0766:                        public void opAssign(Value val)
0767:                                throws PackagedScriptObjectException {
0768:                            try {
0769:                                field.set(obj, val.castToJavaObject());
0770:                            } catch (IllegalAccessException e) {
0771:                                throw OJavaException
0772:                                        .makeJavaExceptionWrapper(e);
0773:                            }
0774:                        }
0775:
0776:                        protected Value get() {
0777:                            try {
0778:                                return JavaBridge.convertToScriptObject(field
0779:                                        .get(obj));
0780:                            } catch (IllegalAccessException e) {
0781:                                throw OJavaException
0782:                                        .makeJavaExceptionWrapper(e);
0783:                            }
0784:                        }
0785:
0786:                    };
0787:                }
0788:            }
0789:
0790:            /**
0791:             * member-cache entry for methods
0792:             */
0793:            private static class MethodCacheEntry implements  CacheEntry {
0794:                private Vector v;
0795:                private Method[] methods;
0796:
0797:                public void add(Method method) {
0798:                    if (v == null) {
0799:                        v = new Vector();
0800:                    }
0801:
0802:                    if (methods != null) {
0803:                        for (int i = 0; i < methods.length; i++)
0804:                            v.add(methods[i]);
0805:                        methods = null;
0806:                    }
0807:
0808:                    /* I'm not sure if we are supposed to be seeing duplicate methods, or not,
0809:                     * but I am (at least under JDK v1.3.1 macosx... I haven't tested others),
0810:                     * so try to deal with this in as sane a mannar as possibly by ignoring
0811:                     * overriden methods:
0812:                     */
0813:                    Class[] parameterTypes = method.getParameterTypes();
0814:                    for (int i = 0; i < v.size(); i++) {
0815:                        if (parameterTypesMatch(((Method) (v.elementAt(i)))
0816:                                .getParameterTypes(), parameterTypes)) {
0817:                            if (((Method) (v.elementAt(i))).getDeclaringClass()
0818:                                    .isAssignableFrom(
0819:                                            method.getDeclaringClass()))
0820:                                v.set(i, method);
0821:                            return;
0822:                        }
0823:                    }
0824:
0825:                    v.add(method);
0826:                }
0827:
0828:                public synchronized Value getMember(int id, Object obj) {
0829:                    if (methods == null) {
0830:                        methods = new Method[v.size()];
0831:                        v.copyInto(methods);
0832:                        v = null;
0833:                    }
0834:                    return new JavaMethodWrapper(id, obj, methods);
0835:                }
0836:            }
0837:
0838:            /**
0839:             * get a member from the specified cache
0840:             */
0841:            /*
0842:             private static final Value getMemberFromCache( SymbolMap memberCache, int id, Object obj )
0843:             {
0844:             CacheEntry ce = (CacheEntry)(memberCache.get(id));
0845:            
0846:             if( ce != null )
0847:             return ce.getMember( id, obj );
0848:            
0849:             return null;
0850:             }
0851:             */
0852:
0853:            /**
0854:             * add a field member to the specified cache
0855:             */
0856:            private static final void addFieldToCache(SymbolMap memberCache,
0857:                    int id, Field field) {
0858:                FieldCacheEntry fce = (FieldCacheEntry) (memberCache.get(id));
0859:                if (fce == null)
0860:                    memberCache.put(id, fce = new FieldCacheEntry());
0861:                fce.add(field);
0862:            }
0863:
0864:            /**
0865:             * add a method member to the specified cache, or if a member already exists
0866:             * for a method with the same name, append this method to the existing member
0867:             */
0868:            private static final void addMethodToCache(SymbolMap memberCache,
0869:                    int id, Method method) {
0870:                Object obj = memberCache.get(id);
0871:
0872:                if ((obj == null) || !(obj instanceof  MethodCacheEntry))
0873:                    memberCache.put(id, obj = new MethodCacheEntry());
0874:
0875:                MethodCacheEntry mce = (MethodCacheEntry) obj;
0876:
0877:                mce.add(method);
0878:            }
0879:
0880:            private static final boolean parameterTypesMatch(Class[] p1,
0881:                    Class[] p2) {
0882:                if (p1.length == p2.length) {
0883:                    for (int i = 0; i < p1.length; i++)
0884:                        if (!p1[i].equals(p2[i]))
0885:                            return false;
0886:
0887:                    return true;
0888:                }
0889:
0890:                return false;
0891:            }
0892:
0893:            /*=======================================================================*/
0894:            /**
0895:             * Utility to search for accessible methods with the specified name and 
0896:             * parameters.
0897:             */
0898:            static final Method searchForAccessibleMethod(String name,
0899:                    Class javaClass, Class[] paramTypes) {
0900:                if (Modifier.isPublic(javaClass.getModifiers())) {
0901:                    try {
0902:                        Method method = javaClass.getDeclaredMethod(name,
0903:                                paramTypes);
0904:                        return method;
0905:                    } catch (NoSuchMethodException e) {
0906:                        // ignore
0907:                    }
0908:                }
0909:
0910:                // we got here, so what we are looking for isn't in this class... so
0911:                // recursively check parent classes and interfaces:
0912:
0913:                //    check interfaces:
0914:                Class[] interfaceClasses = javaClass.getInterfaces();
0915:                for (int i = 0; i < interfaceClasses.length; i++) {
0916:                    Method method = searchForAccessibleMethod(name,
0917:                            interfaceClasses[i], paramTypes);
0918:
0919:                    if (method != null)
0920:                        return method;
0921:                }
0922:
0923:                //    if not an interface, there are superclasses to check:
0924:                Class super Class = javaClass.getSuperclass();
0925:                if (super Class != null)
0926:                    return searchForAccessibleMethod(name, super Class,
0927:                            paramTypes);
0928:
0929:                // if we get here, no match was found:
0930:                return null;
0931:            }
0932:
0933:            /*=======================================================================*/
0934:            /**
0935:             * maintains unique-ness of a JavaClassWrapper when stuff gets serialized or
0936:             * un-serialized
0937:             */
0938:            Object readResolve() throws java.io.ObjectStreamException {
0939:                Object obj;
0940:
0941:                synchronized (JavaClassWrapper.class) {
0942:                    obj = classWrapperCache.get(javaClass);
0943:
0944:                    if (obj == null) {
0945:                        obj = this ;
0946:                        classWrapperCache.put(javaClass, obj);
0947:                    }
0948:                }
0949:
0950:                return obj;
0951:            }
0952:
0953:            /*=======================================================================*/
0954:            /**
0955:             * Derived classes that implement {@link #getMember} should also
0956:             * implement this.
0957:             * 
0958:             * @param s   the set to populate
0959:             * @param debugger  <code>true</code> if being used by debugger, in
0960:             *   which case both public and private/protected field names should 
0961:             *   be returned
0962:             * @see #getMember
0963:             */
0964:            protected void populateMemberSet(Set s, boolean debugger) {
0965:                if (impl == null)
0966:                    init();
0967:                impl.populateMemberSet(s);
0968:            }
0969:
0970:            /*=======================================================================*/
0971:            /**
0972:             * Derived classes that implement {@link #getTypeMember} should also
0973:             * implement this.
0974:             * 
0975:             * @param s   the set to populate
0976:             * @param debugger  <code>true</code> if being used by debugger, in
0977:             *   which case both public and private/protected field names should 
0978:             *   be returned
0979:             * @see #getTypeMember
0980:             */
0981:            protected void populateTypeMemberSet(Set s, boolean debugger) {
0982:                if (impl == null)
0983:                    init();
0984:                impl.populateTypeMemberSet(s);
0985:            }
0986:
0987:            /*=======================================================================*/
0988:            /**
0989:             * used by Debugger#getMemberAccessor, allows access to non-public members
0990:             */
0991:            Debugger.MemberAccessor _getTypeMemberAccessor(Value obj, Value name) {
0992:                if (impl == null)
0993:                    init();
0994:
0995:                Value val = getTypeMember(obj, name);
0996:
0997:                if (val != null)
0998:                    return new JavaClassWrapperMemberAccessor(val);
0999:                else
1000:                    return null;
1001:            }
1002:
1003:            private static class JavaClassWrapperMemberAccessor implements 
1004:                    Debugger.MemberAccessor {
1005:                private Value val;
1006:
1007:                /**
1008:                 * It is safe to use val instead of name, because we never replace an
1009:                 * entry in the member table.
1010:                 */
1011:                JavaClassWrapperMemberAccessor(Value val) {
1012:                    this .val = val;
1013:                }
1014:
1015:                public int getAttr() {
1016:                    return Reference.ATTR_PUBLIC;
1017:                }
1018:
1019:                public Value getValue() {
1020:                    return val;
1021:                }
1022:            }
1023:
1024:            /*=======================================================================*/
1025:            /**
1026:             * For use by test suite...
1027:             */
1028:            public static class Base {
1029:                public static final int ID = 1;
1030:
1031:                public int[] getFoo() {
1032:                    System.err.println("getFoo");
1033:                    return new int[] { 1, 2, 3 };
1034:                }
1035:            }
1036:
1037:            public static class Derived extends Base {
1038:                public static final int ID = 2;
1039:            }
1040:        }
1041:
1042:        /*
1043:         *   Local Variables:
1044:         *   tab-width: 2
1045:         *   indent-tabs-mode: nil
1046:         *   mode: java
1047:         *   c-indentation-style: java
1048:         *   c-basic-offset: 2
1049:         *   eval: (c-set-offset 'substatement-open '0)
1050:         *   eval: (c-set-offset 'case-label '+)
1051:         *   eval: (c-set-offset 'inclass '+)
1052:         *   eval: (c-set-offset 'inline-open '0)
1053:         *   End:
1054:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.