Source Code Cross Referenced for Name.java in  » Scripting » beanshell » bsh » 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 » beanshell » bsh 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*****************************************************************************
0002:         *                                                                           *
0003:         *  This file is part of the BeanShell Java Scripting distribution.          *
0004:         *  Documentation and updates may be found at http://www.beanshell.org/      *
0005:         *                                                                           *
0006:         *  Sun Public License Notice:                                               *
0007:         *                                                                           *
0008:         *  The contents of this file are subject to the Sun Public License Version  *
0009:         *  1.0 (the "License"); you may not use this file except in compliance with *
0010:         *  the License. A copy of the License is available at http://www.sun.com    * 
0011:         *                                                                           *
0012:         *  The Original Code is BeanShell. The Initial Developer of the Original    *
0013:         *  Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright     *
0014:         *  (C) 2000.  All Rights Reserved.                                          *
0015:         *                                                                           *
0016:         *  GNU Public License Notice:                                               *
0017:         *                                                                           *
0018:         *  Alternatively, the contents of this file may be used under the terms of  *
0019:         *  the GNU Lesser General Public License (the "LGPL"), in which case the    *
0020:         *  provisions of LGPL are applicable instead of those above. If you wish to *
0021:         *  allow use of your version of this file only under the  terms of the LGPL *
0022:         *  and not to allow others to use your version of this file under the SPL,  *
0023:         *  indicate your decision by deleting the provisions above and replace      *
0024:         *  them with the notice and other provisions required by the LGPL.  If you  *
0025:         *  do not delete the provisions above, a recipient may use your version of  *
0026:         *  this file under either the SPL or the LGPL.                              *
0027:         *                                                                           *
0028:         *  Patrick Niemeyer (pat@pat.net)                                           *
0029:         *  Author of Learning Java, O'Reilly & Associates                           *
0030:         *  http://www.pat.net/~pat/                                                 *
0031:         *                                                                           *
0032:         *****************************************************************************/package bsh;
0033:
0034:        import java.lang.reflect.Array;
0035:        import java.util.Hashtable;
0036:        import java.io.*;
0037:        import java.lang.reflect.InvocationTargetException;
0038:        import java.lang.reflect.Method;
0039:
0040:        /**
0041:         What's in a name?  I'll tell you...
0042:         Name() is a somewhat ambiguous thing in the grammar and so is this.
0043:         <p>
0044:        
0045:         This class is a name resolver.  It holds a possibly ambiguous dot 
0046:         separated name and reference to a namespace in which it allegedly lives.  
0047:         It provides methods that attempt to resolve the name to various types of 
0048:         entities: e.g. an Object, a Class, a declared scripted BeanShell method.
0049:         <p>
0050:
0051:         Name objects are created by the factory method NameSpace getNameResolver(), 
0052:         which caches them subject to a class namespace change.  This means that 
0053:         we can cache information about various types of resolution here.
0054:         Currently very little if any information is cached.  However with a future
0055:         "optimize" setting that defeats certain dynamic behavior we might be able
0056:         to cache quite a bit.
0057:         */
0058:        /*
0059:         <strong>Implementation notes</strong>
0060:         <pre>
0061:         Thread safety: all of the work methods in this class must be synchronized
0062:         because they share the internal intermediate evaluation state.
0063:
0064:         Note about invokeMethod():  We could simply use resolveMethod and return
0065:         the MethodInvoker (BshMethod or JavaMethod) however there is no easy way
0066:         for the AST (BSHMehodInvocation) to use this as it doesn't have type
0067:         information about the target to resolve overloaded methods.
0068:         (In Java, overloaded methods are resolved at compile time... here they
0069:         are, of necessity, dynamic).  So it would have to do what we do here
0070:         and cache by signature.  We now do that for the client in Reflect.java.
0071:
0072:         Note on this.caller resolution:
0073:         Although references like these do work:
0074:
0075:         this.caller.caller.caller...   // works
0076:
0077:         the equivalent using successive calls:
0078:
0079:         // does *not* work
0080:         for( caller=this.caller; caller != null; caller = caller.caller );
0081:
0082:         is prohibited by the restriction that you can only call .caller on a 
0083:         literal	this or caller reference.  The effect is that magic caller 
0084:         reference only works through the current 'this' reference.
0085:         The real explanation is that This referernces do not really know anything
0086:         about their depth on the call stack.  It might even be hard to define
0087:         such a thing...
0088:
0089:         For those purposes we provide :
0090:
0091:         this.callstack
0092:
0093:         </pre>
0094:         */
0095:        class Name implements  java.io.Serializable {
0096:            // These do not change during evaluation
0097:            public NameSpace namespace;
0098:            String value = null;
0099:
0100:            // ---------------------------------------------------------
0101:            // The following instance variables mutate during evaluation and should
0102:            // be reset by the reset() method where necessary
0103:
0104:            // For evaluation
0105:            /** Remaining text to evaluate */
0106:            private String evalName;
0107:            /** 
0108:            	The last part of the name evaluated.  This is really only used for
0109:             	this, caller, and super resolution.
0110:             */
0111:            private String lastEvalName;
0112:            private static String FINISHED = null; // null evalname and we're finished
0113:            private Object evalBaseObject; // base object for current eval
0114:
0115:            private int callstackDepth; // number of times eval hit 'this.caller'
0116:
0117:            //  
0118:            //  End mutable instance variables.
0119:            // ---------------------------------------------------------
0120:
0121:            // Begin Cached result structures
0122:            // These are optimizations 
0123:
0124:            // Note: it's ok to cache class resolution here because when the class
0125:            // space changes the namespace will discard cached names.
0126:
0127:            /** 
0128:            	The result is a class 
0129:             */
0130:            Class asClass;
0131:
0132:            /** 
0133:            	The result is a static method call on the following class 
0134:             */
0135:            Class classOfStaticMethod;
0136:
0137:            // End Cached result structures
0138:
0139:            private void reset() {
0140:                evalName = value;
0141:                evalBaseObject = null;
0142:                callstackDepth = 0;
0143:            }
0144:
0145:            /**
0146:            	This constructor should *not* be used in general. 
0147:            	Use NameSpace getNameResolver() which supports caching.
0148:            	@see NameSpace getNameResolver().
0149:             */
0150:            // I wish I could make this "friendly" to only NameSpace
0151:            Name(NameSpace namespace, String s) {
0152:                this .namespace = namespace;
0153:                value = s;
0154:            }
0155:
0156:            /**
0157:            	Resolve possibly complex name to an object value.
0158:
0159:            	Throws EvalError on various failures.
0160:            	A null object value is indicated by a Primitive.NULL.
0161:            	A return type of Primitive.VOID comes from attempting to access
0162:            	an undefined variable.
0163:
0164:            	Some cases:
0165:            		myVariable
0166:            		myVariable.foo
0167:            		myVariable.foo.bar
0168:            		java.awt.GridBagConstraints.BOTH
0169:            		my.package.stuff.MyClass.someField.someField...
0170:
0171:            	Interpreter reference is necessary to allow resolution of 
0172:            	"this.interpreter" magic field.
0173:            	CallStack reference is necessary to allow resolution of 
0174:            	"this.caller" magic field.
0175:            	"this.callstack" magic field.
0176:             */
0177:            public Object toObject(CallStack callstack, Interpreter interpreter)
0178:                    throws UtilEvalError {
0179:                return toObject(callstack, interpreter, false);
0180:            }
0181:
0182:            /**
0183:            	@see toObject()
0184:            	@param forceClass if true then resolution will only produce a class.
0185:            	This is necessary to disambiguate in cases where the grammar knows
0186:            	that we want a class; where in general the var path may be taken.
0187:             */
0188:            synchronized public Object toObject(CallStack callstack,
0189:                    Interpreter interpreter, boolean forceClass)
0190:                    throws UtilEvalError {
0191:                reset();
0192:
0193:                Object obj = null;
0194:                while (evalName != null)
0195:                    obj = consumeNextObjectField(callstack, interpreter,
0196:                            forceClass, false/*autoalloc*/);
0197:
0198:                if (obj == null)
0199:                    throw new InterpreterError("null value in toObject()");
0200:
0201:                return obj;
0202:            }
0203:
0204:            private Object completeRound(String lastEvalName,
0205:                    String nextEvalName, Object returnObject) {
0206:                if (returnObject == null)
0207:                    throw new InterpreterError("lastEvalName = " + lastEvalName);
0208:                this .lastEvalName = lastEvalName;
0209:                this .evalName = nextEvalName;
0210:                this .evalBaseObject = returnObject;
0211:                return returnObject;
0212:            }
0213:
0214:            /**
0215:            	Get the next object by consuming one or more components of evalName.  
0216:            	Often this consumes just one component, but if the name is a classname 
0217:            	it will consume all of the components necessary to make the class 
0218:            	identifier.
0219:             */
0220:            private Object consumeNextObjectField(CallStack callstack,
0221:                    Interpreter interpreter, boolean forceClass,
0222:                    boolean autoAllocateThis) throws UtilEvalError {
0223:                /*
0224:                	Is it a simple variable name?
0225:                	Doing this first gives the correct Java precedence for vars 
0226:                	vs. imported class names (at least in the simple case - see
0227:                	tests/precedence1.bsh).  It should also speed things up a bit.
0228:                 */
0229:                if ((evalBaseObject == null && !isCompound(evalName))
0230:                        && !forceClass) {
0231:                    Object obj = resolveThisFieldReference(callstack,
0232:                            namespace, interpreter, evalName, false);
0233:
0234:                    if (obj != Primitive.VOID)
0235:                        return completeRound(evalName, FINISHED, obj);
0236:                }
0237:
0238:                /*
0239:                	Is it a bsh script variable reference?
0240:                	If we're just starting the eval of name (no base object)
0241:                	or we're evaluating relative to a This type reference check.
0242:                 */
0243:                String varName = prefix(evalName, 1);
0244:                if ((evalBaseObject == null || evalBaseObject instanceof  This)
0245:                        && !forceClass) {
0246:                    if (Interpreter.DEBUG)
0247:                        Interpreter.debug("trying to resolve variable: "
0248:                                + varName);
0249:
0250:                    Object obj;
0251:                    // switch namespace and special var visibility
0252:                    if (evalBaseObject == null) {
0253:                        obj = resolveThisFieldReference(callstack, namespace,
0254:                                interpreter, varName, false);
0255:                    } else {
0256:                        obj = resolveThisFieldReference(callstack,
0257:                                ((This) evalBaseObject).namespace, interpreter,
0258:                                varName, true);
0259:                    }
0260:
0261:                    if (obj != Primitive.VOID) {
0262:                        // Resolved the variable
0263:                        if (Interpreter.DEBUG)
0264:                            Interpreter.debug("resolved variable: " + varName
0265:                                    + " in namespace: " + namespace);
0266:
0267:                        return completeRound(varName, suffix(evalName), obj);
0268:                    }
0269:                }
0270:
0271:                /*
0272:                	Is it a class name?
0273:                	If we're just starting eval of name try to make it, else fail.
0274:                 */
0275:                if (evalBaseObject == null) {
0276:                    if (Interpreter.DEBUG)
0277:                        Interpreter.debug("trying class: " + evalName);
0278:
0279:                    /*
0280:                    	Keep adding parts until we have a class 
0281:                     */
0282:                    Class clas = null;
0283:                    int i = 1;
0284:                    String className = null;
0285:                    for (; i <= countParts(evalName); i++) {
0286:                        className = prefix(evalName, i);
0287:                        if ((clas = namespace.getClass(className)) != null)
0288:                            break;
0289:                    }
0290:
0291:                    if (clas != null) {
0292:                        return completeRound(className, suffix(evalName,
0293:                                countParts(evalName) - i), new ClassIdentifier(
0294:                                clas));
0295:                    }
0296:                    // not a class (or variable per above)
0297:                    if (Interpreter.DEBUG)
0298:                        Interpreter.debug("not a class, trying var prefix "
0299:                                + evalName);
0300:                }
0301:
0302:                // No variable or class found in 'this' type ref.
0303:                // if autoAllocateThis then create one; a child 'this'.
0304:                if ((evalBaseObject == null || evalBaseObject instanceof  This)
0305:                        && !forceClass && autoAllocateThis) {
0306:                    NameSpace targetNameSpace = (evalBaseObject == null) ? namespace
0307:                            : ((This) evalBaseObject).namespace;
0308:                    Object obj = new NameSpace(targetNameSpace, "auto: "
0309:                            + varName).getThis(interpreter);
0310:                    targetNameSpace.setVariable(varName, obj, false);
0311:                    return completeRound(varName, suffix(evalName), obj);
0312:                }
0313:
0314:                /*
0315:                	If we didn't find a class or variable name (or prefix) above
0316:                	there are two possibilities:
0317:
0318:                	- If we are a simple name then we can pass as a void variable 
0319:                	reference.
0320:                	- If we are compound then we must fail at this point.
0321:                 */
0322:                if (evalBaseObject == null) {
0323:                    if (!isCompound(evalName)) {
0324:                        return completeRound(evalName, FINISHED, Primitive.VOID);
0325:                    } else
0326:                        throw new UtilEvalError("Class or variable not found: "
0327:                                + evalName);
0328:                }
0329:
0330:                /*
0331:                	--------------------------------------------------------
0332:                	After this point we're definitely evaluating relative to
0333:                	a base object.
0334:                	--------------------------------------------------------
0335:                 */
0336:
0337:                /*
0338:                	Do some basic validity checks.
0339:                 */
0340:
0341:                if (evalBaseObject == Primitive.NULL) // previous round produced null
0342:                    throw new UtilTargetError(new NullPointerException(
0343:                            "Null Pointer while evaluating: " + value));
0344:
0345:                if (evalBaseObject == Primitive.VOID) // previous round produced void
0346:                    throw new UtilEvalError(
0347:                            "Undefined variable or class name while evaluating: "
0348:                                    + value);
0349:
0350:                if (evalBaseObject instanceof  Primitive)
0351:                    throw new UtilEvalError(
0352:                            "Can't treat primitive like an object. "
0353:                                    + "Error while evaluating: " + value);
0354:
0355:                /* 
0356:                	Resolve relative to a class type
0357:                	static field, inner class, ?
0358:                 */
0359:                if (evalBaseObject instanceof  ClassIdentifier) {
0360:                    Class clas = ((ClassIdentifier) evalBaseObject)
0361:                            .getTargetClass();
0362:                    String field = prefix(evalName, 1);
0363:
0364:                    // Class qualified 'this' reference from inner class.
0365:                    // e.g. 'MyOuterClass.this'
0366:                    if (field.equals("this")) {
0367:                        // find the enclosing class instance space of the class name
0368:                        NameSpace ns = namespace;
0369:                        while (ns != null) {
0370:                            // getClassInstance() throws exception if not there
0371:                            if (ns.classInstance != null
0372:                                    && ns.classInstance.getClass() == clas)
0373:                                return completeRound(field, suffix(evalName),
0374:                                        ns.classInstance);
0375:                            ns = ns.getParent();
0376:                        }
0377:                        throw new UtilEvalError(
0378:                                "Can't find enclosing 'this' instance of class: "
0379:                                        + clas);
0380:                    }
0381:
0382:                    Object obj = null;
0383:                    // static field?
0384:                    try {
0385:                        if (Interpreter.DEBUG)
0386:                            Interpreter
0387:                                    .debug("Name call to getStaticFieldValue, class: "
0388:                                            + clas + ", field:" + field);
0389:                        obj = Reflect.getStaticFieldValue(clas, field);
0390:                    } catch (ReflectError e) {
0391:                        if (Interpreter.DEBUG)
0392:                            Interpreter.debug("field reflect error: " + e);
0393:                    }
0394:
0395:                    // inner class?
0396:                    if (obj == null) {
0397:                        String iclass = clas.getName() + "$" + field;
0398:                        Class c = namespace.getClass(iclass);
0399:                        if (c != null)
0400:                            obj = new ClassIdentifier(c);
0401:                    }
0402:
0403:                    if (obj == null)
0404:                        throw new UtilEvalError(
0405:                                "No static field or inner class: " + field
0406:                                        + " of " + clas);
0407:
0408:                    return completeRound(field, suffix(evalName), obj);
0409:                }
0410:
0411:                /*
0412:                	If we've fallen through here we are no longer resolving to
0413:                	a class type.
0414:                 */
0415:                if (forceClass)
0416:                    throw new UtilEvalError(value
0417:                            + " does not resolve to a class name.");
0418:
0419:                /* 
0420:                	Some kind of field access?
0421:                 */
0422:
0423:                String field = prefix(evalName, 1);
0424:
0425:                // length access on array? 
0426:                if (field.equals("length")
0427:                        && evalBaseObject.getClass().isArray()) {
0428:                    Object obj = new Primitive(Array.getLength(evalBaseObject));
0429:                    return completeRound(field, suffix(evalName), obj);
0430:                }
0431:
0432:                // Check for field on object 
0433:                // Note: could eliminate throwing the exception somehow
0434:                try {
0435:                    Object obj = Reflect.getObjectFieldValue(evalBaseObject,
0436:                            field);
0437:                    return completeRound(field, suffix(evalName), obj);
0438:                } catch (ReflectError e) { /* not a field */
0439:                }
0440:
0441:                // if we get here we have failed
0442:                throw new UtilEvalError("Cannot access field: " + field
0443:                        + ", on object: " + evalBaseObject);
0444:            }
0445:
0446:            /**
0447:            	Resolve a variable relative to a This reference.
0448:
0449:            	This is the general variable resolution method, accomodating special
0450:            	fields from the This context.  Together the namespace and interpreter
0451:            	comprise the This context.  The callstack, if available allows for the
0452:            	this.caller construct.  
0453:            	Optionally interpret special "magic" field names: e.g. interpreter.
0454:            	<p/>
0455:
0456:            	@param callstack may be null, but this is only legitimate in special
0457:            	cases where we are sure resolution will not involve this.caller.
0458:
0459:            	@param namespace the namespace of the this reference (should be the
0460:            	same as the top of the stack?
0461:             */
0462:            Object resolveThisFieldReference(CallStack callstack,
0463:                    NameSpace this NameSpace, Interpreter interpreter,
0464:                    String varName, boolean specialFieldsVisible)
0465:                    throws UtilEvalError {
0466:                if (varName.equals("this")) {
0467:                    /*
0468:                    	Somewhat of a hack.  If the special fields are visible (we're
0469:                    	operating relative to a 'this' type already) dissallow further
0470:                    	.this references to prevent user from skipping to things like
0471:                    	super.this.caller
0472:                     */
0473:                    if (specialFieldsVisible)
0474:                        throw new UtilEvalError(
0475:                                "Redundant to call .this on This type");
0476:
0477:                    // Allow getThis() to work through BlockNameSpace to the method
0478:                    // namespace
0479:                    // XXX re-eval this... do we need it?
0480:                    This ths = this NameSpace.getThis(interpreter);
0481:                    this NameSpace = ths.getNameSpace();
0482:                    Object result = ths;
0483:
0484:                    NameSpace classNameSpace = getClassNameSpace(this NameSpace);
0485:                    if (classNameSpace != null) {
0486:                        if (isCompound(evalName))
0487:                            result = classNameSpace.getThis(interpreter);
0488:                        else
0489:                            result = classNameSpace.getClassInstance();
0490:                    }
0491:
0492:                    return result;
0493:                }
0494:
0495:                /*
0496:                	Some duplication for "super".  See notes for "this" above
0497:                	If we're in an enclsing class instance and have a superclass
0498:                	instance our super is the superclass instance.
0499:                 */
0500:                if (varName.equals("super")) {
0501:                    //if ( specialFieldsVisible )
0502:                    //throw new UtilEvalError("Redundant to call .this on This type");
0503:
0504:                    // Allow getSuper() to through BlockNameSpace to the method's super
0505:                    This ths = this NameSpace.getSuper(interpreter);
0506:                    this NameSpace = ths.getNameSpace();
0507:                    // super is now the closure's super or class instance
0508:
0509:                    // XXXX re-evaluate this
0510:                    // can getSuper work by itself now?
0511:                    // If we're a class instance and the parent is also a class instance
0512:                    // then super means our parent.
0513:                    if (this NameSpace.getParent() != null
0514:                            && this NameSpace.getParent().isClass)
0515:                        ths = this NameSpace.getParent().getThis(interpreter);
0516:
0517:                    return ths;
0518:                }
0519:
0520:                Object obj = null;
0521:
0522:                if (varName.equals("global"))
0523:                    obj = this NameSpace.getGlobal(interpreter);
0524:
0525:                if (obj == null && specialFieldsVisible) {
0526:                    if (varName.equals("namespace"))
0527:                        obj = this NameSpace;
0528:                    else if (varName.equals("variables"))
0529:                        obj = this NameSpace.getVariableNames();
0530:                    else if (varName.equals("methods"))
0531:                        obj = this NameSpace.getMethodNames();
0532:                    else if (varName.equals("interpreter"))
0533:                        if (lastEvalName.equals("this"))
0534:                            obj = interpreter;
0535:                        else
0536:                            throw new UtilEvalError(
0537:                                    "Can only call .interpreter on literal 'this'");
0538:                }
0539:
0540:                if (obj == null && specialFieldsVisible
0541:                        && varName.equals("caller")) {
0542:                    if (lastEvalName.equals("this")
0543:                            || lastEvalName.equals("caller")) {
0544:                        // get the previous context (see notes for this class)
0545:                        if (callstack == null)
0546:                            throw new InterpreterError("no callstack");
0547:                        obj = callstack.get(++callstackDepth).getThis(
0548:                                interpreter);
0549:                    } else
0550:                        throw new UtilEvalError(
0551:                                "Can only call .caller on literal 'this' or literal '.caller'");
0552:
0553:                    // early return
0554:                    return obj;
0555:                }
0556:
0557:                if (obj == null && specialFieldsVisible
0558:                        && varName.equals("callstack")) {
0559:                    if (lastEvalName.equals("this")) {
0560:                        // get the previous context (see notes for this class)
0561:                        if (callstack == null)
0562:                            throw new InterpreterError("no callstack");
0563:                        obj = callstack;
0564:                    } else
0565:                        throw new UtilEvalError(
0566:                                "Can only call .callstack on literal 'this'");
0567:                }
0568:
0569:                if (obj == null)
0570:                    obj = this NameSpace.getVariable(varName);
0571:
0572:                if (obj == null)
0573:                    throw new InterpreterError("null this field ref:" + varName);
0574:
0575:                return obj;
0576:            }
0577:
0578:            /**
0579:            	@return the enclosing class body namespace or null if not in a class.
0580:             */
0581:            static NameSpace getClassNameSpace(NameSpace this NameSpace) {
0582:                // is a class instance
0583:                //if ( thisNameSpace.classInstance != null )
0584:                if (this NameSpace.isClass)
0585:                    return this NameSpace;
0586:
0587:                if (this NameSpace.isMethod && this NameSpace.getParent() != null
0588:                //&& thisNameSpace.getParent().classInstance != null
0589:                        && this NameSpace.getParent().isClass)
0590:                    return this NameSpace.getParent();
0591:
0592:                return null;
0593:            }
0594:
0595:            /**
0596:            	Check the cache, else use toObject() to try to resolve to a class
0597:            	identifier.  
0598:
0599:            	@throws ClassNotFoundException on class not found.
0600:            	@throws ClassPathException (type of EvalError) on special case of 
0601:            	ambiguous unqualified name after super import. 
0602:             */
0603:            synchronized public Class toClass() throws ClassNotFoundException,
0604:                    UtilEvalError {
0605:                if (asClass != null)
0606:                    return asClass;
0607:
0608:                reset();
0609:
0610:                // "var" means untyped, return null class
0611:                if (evalName.equals("var"))
0612:                    return asClass = null;
0613:
0614:                /* Try straightforward class name first */
0615:                Class clas = namespace.getClass(evalName);
0616:
0617:                if (clas == null) {
0618:                    /* 
0619:                    	Try toObject() which knows how to work through inner classes
0620:                    	and see what we end up with 
0621:                     */
0622:                    Object obj = null;
0623:                    try {
0624:                        // Null interpreter and callstack references.
0625:                        // class only resolution should not require them.
0626:                        obj = toObject(null, null, true);
0627:                    } catch (UtilEvalError e) {
0628:                    }
0629:                    ; // couldn't resolve it
0630:
0631:                    if (obj instanceof  ClassIdentifier)
0632:                        clas = ((ClassIdentifier) obj).getTargetClass();
0633:                }
0634:
0635:                if (clas == null)
0636:                    throw new ClassNotFoundException("Class: " + value
0637:                            + " not found in namespace");
0638:
0639:                asClass = clas;
0640:                return asClass;
0641:            }
0642:
0643:            /*
0644:             */
0645:            synchronized public LHS toLHS(CallStack callstack,
0646:                    Interpreter interpreter) throws UtilEvalError {
0647:                // Should clean this up to a single return statement
0648:                reset();
0649:                LHS lhs;
0650:
0651:                // Simple (non-compound) variable assignment e.g. x=5;
0652:                if (!isCompound(evalName)) {
0653:                    if (evalName.equals("this"))
0654:                        throw new UtilEvalError("Can't assign to 'this'.");
0655:
0656:                    // Interpreter.debug("Simple var LHS...");
0657:                    lhs = new LHS(namespace, evalName, false/*bubble up if allowed*/);
0658:                    return lhs;
0659:                }
0660:
0661:                // Field e.g. foo.bar=5;
0662:                Object obj = null;
0663:                try {
0664:                    while (evalName != null && isCompound(evalName)) {
0665:                        obj = consumeNextObjectField(callstack, interpreter,
0666:                                false/*forcclass*/, true/*autoallocthis */);
0667:                    }
0668:                } catch (UtilEvalError e) {
0669:                    throw new UtilEvalError("LHS evaluation: " + e.getMessage());
0670:                }
0671:
0672:                // Finished eval and its a class.
0673:                if (evalName == null && obj instanceof  ClassIdentifier)
0674:                    throw new UtilEvalError("Can't assign to class: " + value);
0675:
0676:                if (obj == null)
0677:                    throw new UtilEvalError("Error in LHS: " + value);
0678:
0679:                // e.g. this.x=5;  or someThisType.x=5;
0680:                if (obj instanceof  This) {
0681:                    // dissallow assignment to magic fields
0682:                    if (evalName.equals("namespace")
0683:                            || evalName.equals("variables")
0684:                            || evalName.equals("methods")
0685:                            || evalName.equals("caller"))
0686:                        throw new UtilEvalError(
0687:                                "Can't assign to special variable: " + evalName);
0688:
0689:                    Interpreter.debug("found This reference evaluating LHS");
0690:                    /*
0691:                    	If this was a literal "super" reference then we allow recursion
0692:                    	in setting the variable to get the normal effect of finding the
0693:                    	nearest definition starting at the super scope.  On any other
0694:                    	resolution qualified by a 'this' type reference we want to set
0695:                    	the variable directly in that scope. e.g. this.x=5;  or 
0696:                    	someThisType.x=5;
0697:                    	
0698:                    	In the old scoping rules super didn't do this.
0699:                     */
0700:                    boolean localVar = !lastEvalName.equals("super");
0701:                    return new LHS(((This) obj).namespace, evalName, localVar);
0702:                }
0703:
0704:                if (evalName != null) {
0705:                    try {
0706:                        if (obj instanceof  ClassIdentifier) {
0707:                            Class clas = ((ClassIdentifier) obj)
0708:                                    .getTargetClass();
0709:                            lhs = Reflect.getLHSStaticField(clas, evalName);
0710:                            return lhs;
0711:                        } else {
0712:                            lhs = Reflect.getLHSObjectField(obj, evalName);
0713:                            return lhs;
0714:                        }
0715:                    } catch (ReflectError e) {
0716:                        throw new UtilEvalError("Field access: " + e);
0717:                    }
0718:                }
0719:
0720:                throw new InterpreterError("Internal error in lhs...");
0721:            }
0722:
0723:            /**
0724:            	Invoke the method identified by this name.
0725:            	Performs caching of method resolution using SignatureKey.
0726:            	<p>
0727:
0728:                Name contains a wholely unqualfied messy name; resolve it to 
0729:            	( object | static prefix ) + method name and invoke.
0730:            	<p>
0731:
0732:                The interpreter is necessary to support 'this.interpreter' references
0733:            	in the called code. (e.g. debug());
0734:            	<p>
0735:
0736:            	<pre>
0737:                Some cases:
0738:
0739:                    // dynamic
0740:                    local();
0741:                    myVariable.foo();
0742:                    myVariable.bar.blah.foo();
0743:                    // static
0744:                    java.lang.Integer.getInteger("foo");
0745:            	</pre>
0746:             */
0747:            public Object invokeMethod(Interpreter interpreter, Object[] args,
0748:                    CallStack callstack, SimpleNode callerInfo)
0749:                    throws UtilEvalError, EvalError, ReflectError,
0750:                    InvocationTargetException {
0751:                String methodName = Name.suffix(value, 1);
0752:                BshClassManager bcm = interpreter.getClassManager();
0753:                NameSpace namespace = callstack.top();
0754:
0755:                // Optimization - If classOfStaticMethod is set then we have already 
0756:                // been here and determined that this is a static method invocation.
0757:                // Note: maybe factor this out with path below... clean up.
0758:                if (classOfStaticMethod != null) {
0759:                    return Reflect.invokeStaticMethod(bcm, classOfStaticMethod,
0760:                            methodName, args);
0761:                }
0762:
0763:                if (!Name.isCompound(value))
0764:                    return invokeLocalMethod(interpreter, args, callstack,
0765:                            callerInfo);
0766:
0767:                // Note: if we want methods declared inside blocks to be accessible via
0768:                // this.methodname() inside the block we could handle it here as a
0769:                // special case.  See also resolveThisFieldReference() special handling
0770:                // for BlockNameSpace case.  They currently work via the direct name
0771:                // e.g. methodName().
0772:
0773:                String prefix = Name.prefix(value);
0774:
0775:                // Superclass method invocation? (e.g. super.foo())
0776:                if (prefix.equals("super") && Name.countParts(value) == 2) {
0777:                    // Allow getThis() to work through block namespaces first
0778:                    This ths = namespace.getThis(interpreter);
0779:                    NameSpace this NameSpace = ths.getNameSpace();
0780:                    NameSpace classNameSpace = getClassNameSpace(this NameSpace);
0781:                    if (classNameSpace != null) {
0782:                        Object instance = classNameSpace.getClassInstance();
0783:                        return ClassGenerator.getClassGenerator()
0784:                                .invokeSuperclassMethod(bcm, instance,
0785:                                        methodName, args);
0786:                    }
0787:                }
0788:
0789:                // Find target object or class identifier
0790:                Name targetName = namespace.getNameResolver(prefix);
0791:                Object obj = targetName.toObject(callstack, interpreter);
0792:
0793:                if (obj == Primitive.VOID)
0794:                    throw new UtilEvalError("Attempt to resolve method: "
0795:                            + methodName
0796:                            + "() on undefined variable or class name: "
0797:                            + targetName);
0798:
0799:                // if we've got an object, resolve the method
0800:                if (!(obj instanceof  ClassIdentifier)) {
0801:
0802:                    if (obj instanceof  Primitive) {
0803:
0804:                        if (obj == Primitive.NULL)
0805:                            throw new UtilTargetError(new NullPointerException(
0806:                                    "Null Pointer in Method Invocation"));
0807:
0808:                        // some other primitive
0809:                        // should avoid calling methods on primitive, as we do
0810:                        // in Name (can't treat primitive like an object message)
0811:                        // but the hole is useful right now.
0812:                        if (Interpreter.DEBUG)
0813:                            interpreter
0814:                                    .debug("Attempt to access method on primitive..."
0815:                                            + " allowing bsh.Primitive to peek through for debugging");
0816:                    }
0817:
0818:                    // found an object and it's not an undefined variable
0819:                    return Reflect.invokeObjectMethod(obj, methodName, args,
0820:                            interpreter, callstack, callerInfo);
0821:                }
0822:
0823:                // It's a class
0824:
0825:                // try static method
0826:                if (Interpreter.DEBUG)
0827:                    Interpreter.debug("invokeMethod: trying static - "
0828:                            + targetName);
0829:
0830:                Class clas = ((ClassIdentifier) obj).getTargetClass();
0831:
0832:                // cache the fact that this is a static method invocation on this class
0833:                classOfStaticMethod = clas;
0834:
0835:                if (clas != null)
0836:                    return Reflect.invokeStaticMethod(bcm, clas, methodName,
0837:                            args);
0838:
0839:                // return null; ???
0840:                throw new UtilEvalError("invokeMethod: unknown target: "
0841:                        + targetName);
0842:            }
0843:
0844:            /**
0845:            	Invoke a locally declared method or a bsh command.
0846:            	If the method is not already declared in the namespace then try
0847:            	to load it as a resource from the imported command path (e.g.
0848:            	/bsh/commands)
0849:             */
0850:            /*
0851:            	Note: the bsh command code should probably not be here...  we need to
0852:            	scope it by the namespace that imported the command... so it probably
0853:            	needs to be integrated into NameSpace.
0854:             */
0855:            private Object invokeLocalMethod(Interpreter interpreter,
0856:                    Object[] args, CallStack callstack, SimpleNode callerInfo)
0857:                    throws EvalError/*, ReflectError, InvocationTargetException*/
0858:            {
0859:                if (Interpreter.DEBUG)
0860:                    Interpreter.debug("invokeLocalMethod: " + value);
0861:                if (interpreter == null)
0862:                    throw new InterpreterError(
0863:                            "invokeLocalMethod: interpreter = null");
0864:
0865:                String commandName = value;
0866:                Class[] argTypes = Types.getTypes(args);
0867:
0868:                // Check for existing method
0869:                BshMethod meth = null;
0870:                try {
0871:                    meth = namespace.getMethod(commandName, argTypes);
0872:                } catch (UtilEvalError e) {
0873:                    throw e.toEvalError("Local method invocation", callerInfo,
0874:                            callstack);
0875:                }
0876:
0877:                // If defined, invoke it
0878:                if (meth != null)
0879:                    return meth
0880:                            .invoke(args, interpreter, callstack, callerInfo);
0881:
0882:                BshClassManager bcm = interpreter.getClassManager();
0883:
0884:                // Look for a BeanShell command
0885:
0886:                Object commandObject;
0887:                try {
0888:                    commandObject = namespace.getCommand(commandName, argTypes,
0889:                            interpreter);
0890:                } catch (UtilEvalError e) {
0891:                    throw e.toEvalError("Error loading command: ", callerInfo,
0892:                            callstack);
0893:                }
0894:
0895:                // should try to print usage here if nothing found
0896:                if (commandObject == null) {
0897:                    // Look for a default invoke() handler method in the namespace
0898:                    // Note: this code duplicates that in This.java... should it?
0899:                    // Call on 'This' can never be a command
0900:                    BshMethod invokeMethod = null;
0901:                    try {
0902:                        invokeMethod = namespace.getMethod("invoke",
0903:                                new Class[] { null, null });
0904:                    } catch (UtilEvalError e) {
0905:                        throw e.toEvalError("Local method invocation",
0906:                                callerInfo, callstack);
0907:                    }
0908:
0909:                    if (invokeMethod != null)
0910:                        return invokeMethod.invoke(new Object[] { commandName,
0911:                                args }, interpreter, callstack, callerInfo);
0912:
0913:                    throw new EvalError("Command not found: "
0914:                            + StringUtil.methodString(commandName, argTypes),
0915:                            callerInfo, callstack);
0916:                }
0917:
0918:                if (commandObject instanceof  BshMethod)
0919:                    return ((BshMethod) commandObject).invoke(args,
0920:                            interpreter, callstack, callerInfo);
0921:
0922:                if (commandObject instanceof  Class)
0923:                    try {
0924:                        return Reflect.invokeCompiledCommand(
0925:                                ((Class) commandObject), args, interpreter,
0926:                                callstack);
0927:                    } catch (UtilEvalError e) {
0928:                        throw e.toEvalError(
0929:                                "Error invoking compiled command: ",
0930:                                callerInfo, callstack);
0931:                    }
0932:
0933:                throw new InterpreterError("invalid command type");
0934:            }
0935:
0936:            /*
0937:             private String getHelp( String name )
0938:             throws UtilEvalError
0939:             {
0940:             try {
0941:             // should check for null namespace here
0942:             return get( "bsh.help."+name, null/interpreter/ );
0943:             } catch ( Exception e ) {
0944:             return "usage: "+name;
0945:             }
0946:             }
0947:
0948:             private String getHelp( Class commandClass )
0949:             throws UtilEvalError
0950:             {
0951:             try {
0952:             return (String)Reflect.invokeStaticMethod(
0953:             null/bcm/, commandClass, "usage", null );
0954:             } catch( Exception e )
0955:             return "usage: "+name;
0956:             }
0957:             }
0958:             */
0959:
0960:            // Static methods that operate on compound ('.' separated) names
0961:            // I guess we could move these to StringUtil someday
0962:            public static boolean isCompound(String value) {
0963:                return value.indexOf('.') != -1;
0964:                //return countParts(value) > 1;
0965:            }
0966:
0967:            static int countParts(String value) {
0968:                if (value == null)
0969:                    return 0;
0970:
0971:                int count = 0;
0972:                int index = -1;
0973:                while ((index = value.indexOf('.', index + 1)) != -1)
0974:                    count++;
0975:                return count + 1;
0976:            }
0977:
0978:            static String prefix(String value) {
0979:                if (!isCompound(value))
0980:                    return null;
0981:
0982:                return prefix(value, countParts(value) - 1);
0983:            }
0984:
0985:            static String prefix(String value, int parts) {
0986:                if (parts < 1)
0987:                    return null;
0988:
0989:                int count = 0;
0990:                int index = -1;
0991:
0992:                while (((index = value.indexOf('.', index + 1)) != -1)
0993:                        && (++count < parts)) {
0994:                    ;
0995:                }
0996:
0997:                return (index == -1) ? value : value.substring(0, index);
0998:            }
0999:
1000:            static String suffix(String name) {
1001:                if (!isCompound(name))
1002:                    return null;
1003:
1004:                return suffix(name, countParts(name) - 1);
1005:            }
1006:
1007:            public static String suffix(String value, int parts) {
1008:                if (parts < 1)
1009:                    return null;
1010:
1011:                int count = 0;
1012:                int index = value.length() + 1;
1013:
1014:                while (((index = value.lastIndexOf('.', index - 1)) != -1)
1015:                        && (++count < parts))
1016:                    ;
1017:
1018:                return (index == -1) ? value : value.substring(index + 1);
1019:            }
1020:
1021:            // end compound name routines
1022:
1023:            public String toString() {
1024:                return value;
1025:            }
1026:
1027:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.