Source Code Cross Referenced for RequestEvaluator.java in  » Web-Framework » helma » helma » framework » core » 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 » Web Framework » helma » helma.framework.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Helma License Notice
0003:         *
0004:         * The contents of this file are subject to the Helma License
0005:         * Version 2.0 (the "License"). You may not use this file except in
0006:         * compliance with the License. A copy of the License is available at
0007:         * http://adele.helma.org/download/helma/license.txt
0008:         *
0009:         * Copyright 1998-2003 Helma Software. All Rights Reserved.
0010:         *
0011:         * $RCSfile$
0012:         * $Author: hannes $
0013:         * $Revision: 8700 $
0014:         * $Date: 2007-12-11 11:03:48 +0100 (Die, 11 Dez 2007) $
0015:         */
0016:
0017:        package helma.framework.core;
0018:
0019:        import helma.framework.*;
0020:        import helma.objectmodel.*;
0021:        import helma.objectmodel.db.*;
0022:        import helma.scripting.*;
0023:        import java.lang.reflect.*;
0024:        import java.util.*;
0025:
0026:        import org.apache.xmlrpc.XmlRpcRequestProcessor;
0027:        import org.apache.xmlrpc.XmlRpcServerRequest;
0028:
0029:        /**
0030:         * This class does the work for incoming requests. It holds a transactor thread
0031:         * and an EcmaScript evaluator to get the work done. Incoming threads are
0032:         * blocked until the request has been serviced by the evaluator, or the timeout
0033:         * specified by the application has passed. In the latter case, the evaluator thread
0034:         * is killed and an error message is returned.
0035:         */
0036:        public final class RequestEvaluator implements  Runnable {
0037:            static final int NONE = 0; // no request
0038:            static final int HTTP = 1; // via HTTP gateway
0039:            static final int XMLRPC = 2; // via XML-RPC
0040:            static final int INTERNAL = 3; // generic function call, e.g. by scheduler
0041:            static final int EXTERNAL = 4; // function from script etc
0042:
0043:            public static final Object[] EMPTY_ARGS = new Object[0];
0044:
0045:            public final Application app;
0046:
0047:            protected ScriptingEngine scriptingEngine;
0048:
0049:            // skin depth counter, used to avoid recursive skin rendering
0050:            protected int skinDepth;
0051:
0052:            private volatile RequestTrans req;
0053:            private volatile ResponseTrans res;
0054:
0055:            // the one and only transactor thread
0056:            private volatile Transactor rtx;
0057:
0058:            // the type of request to be serviced,
0059:            // used to coordinate worker and waiter threads
0060:            private volatile int reqtype;
0061:
0062:            // the object on which to invoke a function, if specified
0063:            private volatile Object this Object;
0064:
0065:            // the method to be executed
0066:            private volatile Object function;
0067:
0068:            // the session object associated with the current request
0069:            private volatile Session session;
0070:
0071:            // arguments passed to the function
0072:            private volatile Object[] args;
0073:
0074:            // the result of the operation
0075:            private volatile Object result;
0076:
0077:            // the exception thrown by the evaluator, if any.
0078:            private volatile Exception exception;
0079:
0080:            /**
0081:             *  Create a new RequestEvaluator for this application.
0082:             *  @param app the application
0083:             */
0084:            public RequestEvaluator(Application app) {
0085:                this .app = app;
0086:            }
0087:
0088:            protected synchronized void initScriptingEngine() {
0089:                if (scriptingEngine == null) {
0090:                    String engineClassName = app.getProperty("scriptingEngine",
0091:                            "helma.scripting.rhino.RhinoEngine");
0092:                    try {
0093:                        app.setCurrentRequestEvaluator(this );
0094:                        Class clazz = app.getClassLoader().loadClass(
0095:                                engineClassName);
0096:
0097:                        scriptingEngine = (ScriptingEngine) clazz.newInstance();
0098:                        scriptingEngine.init(app, this );
0099:                    } catch (Exception x) {
0100:                        Throwable t = x;
0101:
0102:                        if (x instanceof  InvocationTargetException) {
0103:                            t = ((InvocationTargetException) x)
0104:                                    .getTargetException();
0105:                        }
0106:
0107:                        app
0108:                                .logEvent("******************************************");
0109:                        app.logEvent("*** Error creating scripting engine: ");
0110:                        app.logEvent("*** " + t.toString());
0111:                        app
0112:                                .logEvent("******************************************");
0113:                        app.logError("Error creating scripting engine", t);
0114:
0115:                        // null out invalid scriptingEngine
0116:                        scriptingEngine = null;
0117:                        // rethrow exception
0118:                        if (t instanceof  RuntimeException) {
0119:                            throw ((RuntimeException) t);
0120:                        } else {
0121:                            throw new RuntimeException(t.toString(), t);
0122:                        }
0123:                    } finally {
0124:                        app.setCurrentRequestEvaluator(null);
0125:                    }
0126:                }
0127:            }
0128:
0129:            /**
0130:             *
0131:             */
0132:            public void run() {
0133:                // first, set a local variable to the current transactor thread so we know
0134:                // when it's time to quit because another thread took over.
0135:                Transactor localrtx = (Transactor) Thread.currentThread();
0136:
0137:                // spans whole execution loop - close connections in finally clause
0138:                try {
0139:
0140:                    // while this thread is serving requests
0141:                    while (localrtx == rtx) {
0142:
0143:                        // object reference to ressolve request path
0144:                        Object currentElement;
0145:
0146:                        // Get req and res into local variables to avoid memory caching problems
0147:                        // in unsynchronized method.
0148:                        RequestTrans req = getRequest();
0149:                        ResponseTrans res = getResponse();
0150:
0151:                        // request path object
0152:                        RequestPath requestPath = new RequestPath(app);
0153:
0154:                        int tries = 0;
0155:                        boolean done = false;
0156:                        String error = null;
0157:                        String functionName = function instanceof  String ? (String) function
0158:                                : null;
0159:
0160:                        while (!done && localrtx == rtx) {
0161:                            // catch errors in path resolution and script execution
0162:                            try {
0163:
0164:                                // initialize scripting engine
0165:                                initScriptingEngine();
0166:                                app.setCurrentRequestEvaluator(this );
0167:                                // update scripting prototypes
0168:                                scriptingEngine.updatePrototypes();
0169:
0170:                                // avoid going into transaction if called function doesn't exist.
0171:                                // this only works for the (common) case that method is a plain
0172:                                // method name, not an obj.method path
0173:                                if (reqtype == INTERNAL) {
0174:                                    // if object is an instance of NodeHandle, get the node object itself.
0175:                                    if (this Object instanceof  NodeHandle) {
0176:                                        this Object = ((NodeHandle) this Object)
0177:                                                .getNode(app.nmgr.safe);
0178:                                        // If no valid node object return immediately
0179:                                        if (this Object == null) {
0180:                                            done = true;
0181:                                            reqtype = NONE;
0182:                                            break;
0183:                                        }
0184:                                    }
0185:                                    // If function doesn't exist, return immediately
0186:                                    if (functionName != null
0187:                                            && !scriptingEngine.hasFunction(
0188:                                                    this Object, functionName,
0189:                                                    true)) {
0190:                                        app.logEvent(missingFunctionMessage(
0191:                                                this Object, functionName));
0192:                                        done = true;
0193:                                        reqtype = NONE;
0194:                                        break;
0195:                                    }
0196:                                } else if (function != null
0197:                                        && functionName == null) {
0198:                                    // only internal requests may pass a function instead of a function name
0199:                                    throw new IllegalStateException(
0200:                                            "No function name in non-internal request ");
0201:                                }
0202:
0203:                                // Transaction name is used for logging etc.
0204:                                StringBuffer txname = new StringBuffer(app
0205:                                        .getName());
0206:                                txname.append(":").append(
0207:                                        req.getMethod().toLowerCase()).append(
0208:                                        ":");
0209:                                txname.append((error == null) ? req.getPath()
0210:                                        : "error");
0211:
0212:                                // begin transaction
0213:                                localrtx.begin(txname.toString());
0214:
0215:                                Object root = app.getDataRoot();
0216:                                initGlobals(root, requestPath);
0217:
0218:                                String action = null;
0219:
0220:                                if (error != null) {
0221:                                    res.setError(error);
0222:                                }
0223:
0224:                                switch (reqtype) {
0225:                                case HTTP:
0226:
0227:                                    // bring over the message from a redirect
0228:                                    session.recoverResponseMessages(res);
0229:
0230:                                    // catch redirect in path resolution or script execution
0231:                                    try {
0232:                                        // catch object not found in path resolution
0233:                                        try {
0234:                                            if (error != null) {
0235:                                                // there was an error in the previous loop, call error handler
0236:                                                currentElement = root;
0237:                                                res.setStatus(500);
0238:
0239:                                                // do not reset the requestPath so error handler can use the original one
0240:                                                // get error handler action
0241:                                                String errorAction = app.props
0242:                                                        .getProperty("error",
0243:                                                                "error");
0244:
0245:                                                action = getAction(
0246:                                                        currentElement,
0247:                                                        errorAction, req);
0248:
0249:                                                if (action == null) {
0250:                                                    throw new RuntimeException(
0251:                                                            error);
0252:                                                }
0253:                                            } else if ((req.getPath() == null)
0254:                                                    || "".equals(req.getPath()
0255:                                                            .trim())) {
0256:                                                currentElement = root;
0257:                                                requestPath.add(null,
0258:                                                        currentElement);
0259:
0260:                                                action = getAction(
0261:                                                        currentElement, null,
0262:                                                        req);
0263:
0264:                                                if (action == null) {
0265:                                                    throw new NotFoundException(
0266:                                                            "Action not found");
0267:                                                }
0268:                                            } else {
0269:                                                // march down request path...
0270:                                                StringTokenizer st = new StringTokenizer(
0271:                                                        req.getPath(), "/");
0272:                                                int ntokens = st.countTokens();
0273:
0274:                                                // limit path to < 50 tokens
0275:                                                if (ntokens > 50) {
0276:                                                    throw new RuntimeException(
0277:                                                            "Path too long");
0278:                                                }
0279:
0280:                                                String[] pathItems = new String[ntokens];
0281:
0282:                                                for (int i = 0; i < ntokens; i++)
0283:                                                    pathItems[i] = st
0284:                                                            .nextToken();
0285:
0286:                                                currentElement = root;
0287:                                                requestPath.add(null,
0288:                                                        currentElement);
0289:
0290:                                                for (int i = 0; i < ntokens; i++) {
0291:                                                    if (currentElement == null) {
0292:                                                        throw new NotFoundException(
0293:                                                                "Object not found.");
0294:                                                    }
0295:
0296:                                                    if (pathItems[i].length() == 0) {
0297:                                                        continue;
0298:                                                    }
0299:
0300:                                                    // if we're at the last element of the path,
0301:                                                    // try to interpret it as action name.
0302:                                                    if (i == (ntokens - 1)
0303:                                                            && !req
0304:                                                                    .getPath()
0305:                                                                    .endsWith(
0306:                                                                            "/")) {
0307:                                                        action = getAction(
0308:                                                                currentElement,
0309:                                                                pathItems[i],
0310:                                                                req);
0311:                                                    }
0312:
0313:                                                    if (action == null) {
0314:                                                        currentElement = getChildElement(
0315:                                                                currentElement,
0316:                                                                pathItems[i]);
0317:
0318:                                                        // add object to request path if suitable
0319:                                                        if (currentElement != null) {
0320:                                                            // add to requestPath array
0321:                                                            requestPath
0322:                                                                    .add(
0323:                                                                            pathItems[i],
0324:                                                                            currentElement);
0325:                                                        }
0326:                                                    }
0327:                                                }
0328:
0329:                                                if (currentElement == null) {
0330:                                                    throw new NotFoundException(
0331:                                                            "Object not found.");
0332:                                                }
0333:
0334:                                                if (action == null) {
0335:                                                    action = getAction(
0336:                                                            currentElement,
0337:                                                            null, req);
0338:                                                }
0339:
0340:                                                if (action == null) {
0341:                                                    throw new NotFoundException(
0342:                                                            "Action not found");
0343:                                                }
0344:                                            }
0345:                                        } catch (NotFoundException notfound) {
0346:                                            if (error != null) {
0347:
0348:                                                // we already have an error and the error template wasn't found,
0349:                                                // display it instead of notfound message
0350:                                                throw new RuntimeException();
0351:                                            }
0352:
0353:                                            // The path could not be resolved. Check if there is a "not found" action
0354:                                            // specified in the property file.
0355:                                            res.setStatus(404);
0356:
0357:                                            String notFoundAction = app.props
0358:                                                    .getProperty("notfound",
0359:                                                            "notfound");
0360:
0361:                                            currentElement = root;
0362:                                            action = getAction(currentElement,
0363:                                                    notFoundAction, req);
0364:
0365:                                            if (action == null) {
0366:                                                throw new NotFoundException(
0367:                                                        notfound.getMessage());
0368:                                            }
0369:                                        }
0370:
0371:                                        // register path objects with their prototype names in
0372:                                        // res.handlers
0373:                                        Map macroHandlers = res
0374:                                                .getMacroHandlers();
0375:                                        int l = requestPath.size();
0376:                                        Prototype[] protos = new Prototype[l];
0377:
0378:                                        for (int i = 0; i < l; i++) {
0379:
0380:                                            Object obj = requestPath.get(i);
0381:
0382:                                            protos[i] = app.getPrototype(obj);
0383:
0384:                                            // immediately register objects with their direct prototype name
0385:                                            if (protos[i] != null) {
0386:                                                macroHandlers.put(protos[i]
0387:                                                        .getName(), obj);
0388:                                                macroHandlers.put(protos[i]
0389:                                                        .getLowerCaseName(),
0390:                                                        obj);
0391:                                            }
0392:                                        }
0393:
0394:                                        // in a second pass, we register path objects with their indirect
0395:                                        // (i.e. parent prototype) names, starting at the end and only
0396:                                        // if the name isn't occupied yet.
0397:                                        for (int i = l - 1; i >= 0; i--) {
0398:                                            if (protos[i] != null) {
0399:                                                protos[i].registerParents(
0400:                                                        macroHandlers,
0401:                                                        requestPath.get(i));
0402:                                            }
0403:                                        }
0404:
0405:                                        /////////////////////////////////////////////////////////////////////////////
0406:                                        // end of path resolution section
0407:                                        /////////////////////////////////////////////////////////////////////////////
0408:                                        // beginning of execution section
0409:
0410:                                        // set the req.action property, cutting off the _action suffix
0411:                                        req.setAction(action);
0412:
0413:                                        // reset skin recursion detection counter
0414:                                        skinDepth = 0;
0415:
0416:                                        // try calling onRequest() function on object before
0417:                                        // calling the actual action
0418:                                        scriptingEngine
0419:                                                .invoke(
0420:                                                        currentElement,
0421:                                                        "onRequest",
0422:                                                        EMPTY_ARGS,
0423:                                                        ScriptingEngine.ARGS_WRAP_DEFAULT,
0424:                                                        false);
0425:
0426:                                        // reset skin recursion detection counter
0427:                                        skinDepth = 0;
0428:
0429:                                        // do the actual action invocation
0430:                                        if (req.isXmlRpc()) {
0431:                                            XmlRpcRequestProcessor xreqproc = new XmlRpcRequestProcessor();
0432:                                            XmlRpcServerRequest xreq = xreqproc
0433:                                                    .decodeRequest(req
0434:                                                            .getServletRequest()
0435:                                                            .getInputStream());
0436:                                            Vector args = xreq.getParameters();
0437:                                            args.add(0, xreq.getMethodName());
0438:                                            result = scriptingEngine
0439:                                                    .invoke(
0440:                                                            currentElement,
0441:                                                            action,
0442:                                                            args.toArray(),
0443:                                                            ScriptingEngine.ARGS_WRAP_XMLRPC,
0444:                                                            false);
0445:                                            res.writeXmlRpcResponse(result);
0446:                                        } else {
0447:                                            scriptingEngine
0448:                                                    .invoke(
0449:                                                            currentElement,
0450:                                                            action,
0451:                                                            EMPTY_ARGS,
0452:                                                            ScriptingEngine.ARGS_WRAP_DEFAULT,
0453:                                                            false);
0454:                                        }
0455:
0456:                                        // try calling onResponse() function on object before
0457:                                        // calling the actual action
0458:                                        scriptingEngine
0459:                                                .invoke(
0460:                                                        currentElement,
0461:                                                        "onResponse",
0462:                                                        EMPTY_ARGS,
0463:                                                        ScriptingEngine.ARGS_WRAP_DEFAULT,
0464:                                                        false);
0465:
0466:                                    } catch (RedirectException redirect) {
0467:                                        // if there is a message set, save it on the user object for the next request
0468:                                        if (res.getRedirect() != null)
0469:                                            session.storeResponseMessages(res);
0470:                                    }
0471:
0472:                                    // check if request is still valid, or if the requesting thread has stopped waiting already
0473:                                    if (localrtx != rtx) {
0474:                                        return;
0475:                                    }
0476:                                    commitTransaction();
0477:                                    done = true;
0478:
0479:                                    break;
0480:
0481:                                case XMLRPC:
0482:                                case EXTERNAL:
0483:
0484:                                    try {
0485:                                        currentElement = root;
0486:
0487:                                        if (functionName.indexOf('.') > -1) {
0488:                                            StringTokenizer st = new StringTokenizer(
0489:                                                    functionName, ".");
0490:                                            int cnt = st.countTokens();
0491:
0492:                                            for (int i = 1; i < cnt; i++) {
0493:                                                String next = st.nextToken();
0494:                                                currentElement = getChildElement(
0495:                                                        currentElement, next);
0496:                                            }
0497:
0498:                                            if (currentElement == null) {
0499:                                                throw new NotFoundException(
0500:                                                        "Method name \""
0501:                                                                + function
0502:                                                                + "\" could not be resolved.");
0503:                                            }
0504:
0505:                                            functionName = st.nextToken();
0506:                                        }
0507:
0508:                                        if (reqtype == XMLRPC) {
0509:                                            // check XML-RPC access permissions
0510:                                            String proto = app
0511:                                                    .getPrototypeName(currentElement);
0512:                                            app.checkXmlRpcAccess(proto,
0513:                                                    functionName);
0514:                                        }
0515:
0516:                                        // reset skin recursion detection counter
0517:                                        skinDepth = 0;
0518:                                        if (!scriptingEngine.hasFunction(
0519:                                                currentElement, functionName,
0520:                                                false)) {
0521:                                            throw new NotFoundException(
0522:                                                    missingFunctionMessage(
0523:                                                            currentElement,
0524:                                                            functionName));
0525:                                        }
0526:                                        result = scriptingEngine
0527:                                                .invoke(
0528:                                                        currentElement,
0529:                                                        functionName,
0530:                                                        args,
0531:                                                        ScriptingEngine.ARGS_WRAP_XMLRPC,
0532:                                                        false);
0533:                                        // check if request is still valid, or if the requesting thread has stopped waiting already
0534:                                        if (localrtx != rtx) {
0535:                                            return;
0536:                                        }
0537:                                        commitTransaction();
0538:                                    } catch (Exception x) {
0539:                                        // check if request is still valid, or if the requesting thread has stopped waiting already
0540:                                        if (localrtx != rtx) {
0541:                                            return;
0542:                                        }
0543:                                        abortTransaction();
0544:                                        app.logError(txname + ": " + error, x);
0545:
0546:                                        // If the transactor thread has been killed by the invoker thread we don't have to
0547:                                        // bother for the error message, just quit.
0548:                                        if (localrtx != rtx) {
0549:                                            return;
0550:                                        }
0551:
0552:                                        this .exception = x;
0553:                                    }
0554:
0555:                                    done = true;
0556:                                    break;
0557:
0558:                                case INTERNAL:
0559:
0560:                                    try {
0561:                                        // reset skin recursion detection counter
0562:                                        skinDepth = 0;
0563:
0564:                                        result = scriptingEngine
0565:                                                .invoke(
0566:                                                        this Object,
0567:                                                        function,
0568:                                                        args,
0569:                                                        ScriptingEngine.ARGS_WRAP_DEFAULT,
0570:                                                        true);
0571:                                        // check if request is still valid, or if the requesting thread has stopped waiting already
0572:                                        if (localrtx != rtx) {
0573:                                            return;
0574:                                        }
0575:                                        commitTransaction();
0576:                                    } catch (Exception x) {
0577:                                        // check if request is still valid, or if the requesting thread has stopped waiting already
0578:                                        if (localrtx != rtx) {
0579:                                            return;
0580:                                        }
0581:                                        abortTransaction();
0582:                                        app.logError(txname + ": " + error, x);
0583:
0584:                                        // If the transactor thread has been killed by the invoker thread we don't have to
0585:                                        // bother for the error message, just quit.
0586:                                        if (localrtx != rtx) {
0587:                                            return;
0588:                                        }
0589:
0590:                                        this .exception = x;
0591:                                    }
0592:
0593:                                    done = true;
0594:                                    break;
0595:
0596:                                } // switch (reqtype)
0597:                            } catch (AbortException x) {
0598:                                // res.abort() just aborts the transaction and
0599:                                // leaves the response untouched
0600:                                // check if request is still valid, or if the requesting thread has stopped waiting already
0601:                                if (localrtx != rtx) {
0602:                                    return;
0603:                                }
0604:                                abortTransaction();
0605:                                done = true;
0606:                            } catch (ConcurrencyException x) {
0607:                                res.reset();
0608:
0609:                                if (++tries < 8) {
0610:                                    // try again after waiting some period
0611:                                    // check if request is still valid, or if the requesting thread has stopped waiting already
0612:                                    if (localrtx != rtx) {
0613:                                        return;
0614:                                    }
0615:                                    abortTransaction();
0616:
0617:                                    try {
0618:                                        // wait a bit longer with each try
0619:                                        int base = 800 * tries;
0620:                                        Thread.sleep((long) (base + (Math
0621:                                                .random()
0622:                                                * base * 2)));
0623:                                    } catch (InterruptedException interrupt) {
0624:                                        // we got interrrupted, create minimal error message 
0625:                                        res.reportError(app.getName(), error);
0626:                                        done = true;
0627:                                        // and release resources and thread
0628:                                        rtx = null;
0629:                                    }
0630:                                } else {
0631:                                    // check if request is still valid, or if the requesting thread has stopped waiting already
0632:                                    if (localrtx != rtx) {
0633:                                        return;
0634:                                    }
0635:                                    abortTransaction();
0636:
0637:                                    if (error == null)
0638:                                        error = "Application too busy, please try again later";
0639:
0640:                                    // error in error action. use traditional minimal error message
0641:                                    res.reportError(app.getName(), error);
0642:                                    done = true;
0643:                                }
0644:                            } catch (Throwable x) {
0645:                                String txname = localrtx.getTransactionName();
0646:                                // check if request is still valid, or if the requesting thread has stopped waiting already
0647:                                if (localrtx != rtx) {
0648:                                    return;
0649:                                }
0650:                                abortTransaction();
0651:
0652:                                // If the transactor thread has been killed by the invoker thread we don't have to
0653:                                // bother for the error message, just quit.
0654:                                if (localrtx != rtx) {
0655:                                    return;
0656:                                }
0657:
0658:                                res.reset();
0659:
0660:                                // check if we tried to process the error already,
0661:                                // or if this is an XML-RPC request
0662:                                if (error == null) {
0663:                                    if (!(x instanceof  NotFoundException)) {
0664:                                        app.errorCount += 1;
0665:                                    }
0666:
0667:                                    // set done to false so that the error will be processed
0668:                                    done = false;
0669:                                    error = x.getMessage();
0670:
0671:                                    if ((error == null)
0672:                                            || (error.length() == 0)) {
0673:                                        error = x.toString();
0674:                                    }
0675:
0676:                                    if (error == null) {
0677:                                        error = "Unspecified error";
0678:                                    }
0679:
0680:                                    app.logError(txname + ": " + error, x);
0681:
0682:                                    if (req.isXmlRpc()) {
0683:                                        // if it's an XML-RPC exception immediately generate error response
0684:                                        if (!(x instanceof  Exception)) {
0685:                                            // we need an exception to pass to XML-RPC responder
0686:                                            x = new Exception(x.toString(), x);
0687:                                        }
0688:                                        res.writeXmlRpcError((Exception) x);
0689:                                        done = true;
0690:                                    }
0691:                                } else {
0692:                                    // error in error action. use traditional minimal error message
0693:                                    res.reportError(app.getName(), error);
0694:                                    done = true;
0695:                                }
0696:                            } finally {
0697:                                app.setCurrentRequestEvaluator(null);
0698:                            }
0699:                        }
0700:
0701:                        // exit execution context
0702:                        if (scriptingEngine != null)
0703:                            scriptingEngine.exitContext();
0704:
0705:                        notifyAndWait();
0706:
0707:                    }
0708:                } finally {
0709:                    localrtx.closeConnections();
0710:                }
0711:            }
0712:
0713:            /**
0714:             * Called by the transactor thread when it has successfully fulfilled a request.
0715:             * @throws Exception transaction couldn't be committed
0716:             */
0717:            synchronized void commitTransaction() throws Exception {
0718:                Transactor localrtx = (Transactor) Thread.currentThread();
0719:
0720:                if (localrtx == rtx) {
0721:                    localrtx.commit();
0722:                } else {
0723:                    throw new TimeoutException();
0724:                }
0725:            }
0726:
0727:            /**
0728:             * Called by the transactor thread when the request didn't terminate successfully.
0729:             */
0730:            synchronized void abortTransaction() {
0731:                Transactor localrtx = (Transactor) Thread.currentThread();
0732:                localrtx.abort();
0733:            }
0734:
0735:            /**
0736:             * Initialize and start the transactor thread.
0737:             */
0738:            private synchronized void startTransactor() {
0739:                if (!app.isRunning()) {
0740:                    throw new ApplicationStoppedException();
0741:                }
0742:
0743:                if ((rtx == null) || !rtx.isAlive()) {
0744:                    // app.logEvent ("Starting Thread");
0745:                    rtx = new Transactor(this , app.threadgroup, app.nmgr);
0746:                    rtx.setContextClassLoader(app.getClassLoader());
0747:                    rtx.start();
0748:                } else {
0749:                    notifyAll();
0750:                }
0751:            }
0752:
0753:            /**
0754:             * Tell waiting thread that we're done, then wait for next request
0755:             */
0756:            synchronized void notifyAndWait() {
0757:                Transactor localrtx = (Transactor) Thread.currentThread();
0758:
0759:                // make sure there is only one thread running per instance of this class
0760:                // if localrtx != rtx, the current thread has been aborted and there's no need to notify
0761:                if (localrtx != rtx) {
0762:                    // A new request came in while we were finishing the last one.
0763:                    // Return to run() to get the work done.
0764:                    localrtx.closeConnections();
0765:                    return;
0766:                }
0767:
0768:                reqtype = NONE;
0769:                notifyAll();
0770:
0771:                try {
0772:                    // wait for request, max 10 min
0773:                    wait(1000 * 60 * 10);
0774:                } catch (InterruptedException ix) {
0775:                    // we got interrrupted, releases resources and thread
0776:                    rtx = null;
0777:                }
0778:
0779:                //  if no request arrived, release ressources and thread
0780:                if ((reqtype == NONE) && (rtx == localrtx)) {
0781:                    // comment this in to release not just the thread, but also the scripting engine.
0782:                    // currently we don't do this because of the risk of memory leaks (objects from
0783:                    // framework referencing into the scripting engine)
0784:                    // scriptingEngine = null;
0785:                    rtx = null;
0786:                }
0787:            }
0788:
0789:            /**
0790:             * Stop this request evaluator's current thread. This is called by the
0791:             * waiting thread when it times out and stops waiting, or from an outside
0792:             * thread. If currently active kill the request, otherwise just notify.
0793:             */
0794:            synchronized boolean stopTransactor() {
0795:                Transactor t = rtx;
0796:                rtx = null;
0797:                boolean stopped = false;
0798:                if (t != null && t.isActive()) {
0799:                    // let the scripting engine know that the
0800:                    // current transaction is being aborted.
0801:                    if (scriptingEngine != null) {
0802:                        scriptingEngine.abort();
0803:                    }
0804:
0805:                    app.logEvent("Request timeout for thread " + t);
0806:
0807:                    reqtype = NONE;
0808:
0809:                    t.kill();
0810:                    t.abort();
0811:                    t.closeConnections();
0812:                    stopped = true;
0813:                }
0814:                notifyAll();
0815:                return stopped;
0816:            }
0817:
0818:            /**
0819:             * Invoke an action function for a HTTP request. The function is dispatched
0820:             * in a new thread and waits for it to finish.
0821:             *
0822:             * @param req the incoming HTTP request
0823:             * @param session the client's session
0824:             * @return the result returned by the invocation
0825:             * @throws Exception any exception thrown by the invocation
0826:             */
0827:            public synchronized ResponseTrans invokeHttp(RequestTrans req,
0828:                    Session session) throws Exception {
0829:                initObjects(req, session);
0830:
0831:                app.activeRequests.put(req, this );
0832:
0833:                startTransactor();
0834:                wait(app.requestTimeout);
0835:
0836:                if (reqtype != NONE && stopTransactor()) {
0837:                    res.reset();
0838:                    res.reportError(app.getName(), "Request timed out");
0839:                }
0840:
0841:                session.commit(this );
0842:                return res;
0843:            }
0844:
0845:            /**
0846:             * This checks if the Evaluator is already executing an equal request.
0847:             * If so, attach to it and wait for it to complete. Otherwise return null,
0848:             * so the application knows it has to run the request.
0849:             */
0850:            public synchronized ResponseTrans attachHttpRequest(RequestTrans req)
0851:                    throws Exception {
0852:                // Get a reference to the res object at the time we enter
0853:                ResponseTrans localRes = res;
0854:
0855:                if ((localRes == null) || !req.equals(this .req)) {
0856:                    return null;
0857:                }
0858:
0859:                if (reqtype != NONE) {
0860:                    wait(app.requestTimeout);
0861:                }
0862:
0863:                return localRes;
0864:            }
0865:
0866:            /*
0867:             * TODO invokeXmlRpc(), invokeExternal() and invokeInternal() are basically the same
0868:             * and should be unified
0869:             */
0870:
0871:            /**
0872:             * Invoke a function for an XML-RPC request. The function is dispatched in a new thread
0873:             * and waits for it to finish.
0874:             *
0875:             * @param functionName the name of the function to invoke
0876:             * @param args the arguments
0877:             * @return the result returned by the invocation
0878:             * @throws Exception any exception thrown by the invocation
0879:             */
0880:            public synchronized Object invokeXmlRpc(String functionName,
0881:                    Object[] args) throws Exception {
0882:                initObjects(functionName, XMLRPC, RequestTrans.XMLRPC);
0883:                this .function = functionName;
0884:                this .args = args;
0885:
0886:                startTransactor();
0887:                wait(app.requestTimeout);
0888:
0889:                if (reqtype != NONE && stopTransactor()) {
0890:                    exception = new RuntimeException("Request timed out");
0891:                }
0892:
0893:                // reset res for garbage collection (res.data may hold reference to evaluator)
0894:                res = null;
0895:
0896:                if (exception != null) {
0897:                    throw (exception);
0898:                }
0899:
0900:                return result;
0901:            }
0902:
0903:            /**
0904:             * Invoke a function for an external request. The function is dispatched
0905:             * in a new thread and waits for it to finish.
0906:             *
0907:             * @param functionName the name of the function to invoke
0908:             * @param args the arguments
0909:             * @return the result returned by the invocation
0910:             * @throws Exception any exception thrown by the invocation
0911:             */
0912:            public synchronized Object invokeExternal(String functionName,
0913:                    Object[] args) throws Exception {
0914:                initObjects(functionName, EXTERNAL, RequestTrans.EXTERNAL);
0915:                this .function = functionName;
0916:                this .args = args;
0917:
0918:                startTransactor();
0919:                wait();
0920:
0921:                if (reqtype != NONE && stopTransactor()) {
0922:                    exception = new RuntimeException("Request timed out");
0923:                }
0924:
0925:                // reset res for garbage collection (res.data may hold reference to evaluator)
0926:                res = null;
0927:
0928:                if (exception != null) {
0929:                    throw (exception);
0930:                }
0931:
0932:                return result;
0933:            }
0934:
0935:            /**
0936:             * Invoke a function internally and directly, using the thread we're running on.
0937:             *
0938:             * @param obj the object to invoke the function on
0939:             * @param function the function or name of the function to invoke
0940:             * @param args the arguments
0941:             * @return the result returned by the invocation
0942:             * @throws Exception any exception thrown by the invocation
0943:             */
0944:            public Object invokeDirectFunction(Object obj, Object function,
0945:                    Object[] args) throws Exception {
0946:                return scriptingEngine.invoke(obj, function, args,
0947:                        ScriptingEngine.ARGS_WRAP_DEFAULT, true);
0948:            }
0949:
0950:            /**
0951:             * Invoke a function internally. The function is dispatched in a new thread
0952:             * and waits for it to finish.
0953:             *
0954:             * @param object the object to invoke the function on
0955:             * @param function the function or name of the function to invoke
0956:             * @param args the arguments
0957:             * @return the result returned by the invocation
0958:             * @throws Exception any exception thrown by the invocation
0959:             */
0960:            public synchronized Object invokeInternal(Object object,
0961:                    Object function, Object[] args) throws Exception {
0962:                // give internal call more time (15 minutes) to complete
0963:                return invokeInternal(object, function, args, 60000L * 15);
0964:            }
0965:
0966:            /**
0967:             * Invoke a function internally. The function is dispatched in a new thread
0968:             * and waits for it to finish.
0969:             *
0970:             * @param object the object to invoke the function on
0971:             * @param function the function or name of the function to invoke
0972:             * @param args the arguments
0973:             * @param timeout the time in milliseconds to wait for the function to return, or
0974:             * -1 to wait indefinitely
0975:             * @return the result returned by the invocation
0976:             * @throws Exception any exception thrown by the invocation
0977:             */
0978:            public synchronized Object invokeInternal(Object object,
0979:                    Object function, Object[] args, long timeout)
0980:                    throws Exception {
0981:                initObjects(function, INTERNAL, RequestTrans.INTERNAL);
0982:                this Object = object;
0983:                this .function = function;
0984:                this .args = args;
0985:
0986:                startTransactor();
0987:                if (timeout < 0)
0988:                    wait();
0989:                else
0990:                    wait(timeout);
0991:
0992:                if (reqtype != NONE && stopTransactor()) {
0993:                    exception = new RuntimeException("Request timed out");
0994:                }
0995:
0996:                // reset res for garbage collection (res.data may hold reference to evaluator)
0997:                res = null;
0998:
0999:                if (exception != null) {
1000:                    throw (exception);
1001:                }
1002:
1003:                return result;
1004:            }
1005:
1006:            /**
1007:             * Init this evaluator's objects from a RequestTrans for a HTTP request
1008:             *
1009:             * @param req
1010:             * @param session
1011:             */
1012:            private synchronized void initObjects(RequestTrans req,
1013:                    Session session) {
1014:                this .req = req;
1015:                this .reqtype = HTTP;
1016:                this .session = session;
1017:                res = new ResponseTrans(app, req);
1018:                result = null;
1019:                exception = null;
1020:            }
1021:
1022:            /**
1023:             * Init this evaluator's objects for an internal, external or XML-RPC type
1024:             * request.
1025:             *
1026:             * @param function the function name or object
1027:             * @param reqtype the request type
1028:             * @param reqtypeName the request type name
1029:             */
1030:            private synchronized void initObjects(Object function, int reqtype,
1031:                    String reqtypeName) {
1032:                this .reqtype = reqtype;
1033:                String functionName = function instanceof  String ? (String) function
1034:                        : "<function>";
1035:                req = new RequestTrans(reqtypeName, functionName);
1036:                session = new Session(functionName, app);
1037:                res = new ResponseTrans(app, req);
1038:                result = null;
1039:                exception = null;
1040:            }
1041:
1042:            /**
1043:             * Initialize the globals in the scripting engine for the current request.
1044:             *
1045:             * @param root
1046:             * @throws ScriptingException
1047:             */
1048:            private synchronized void initGlobals(Object root,
1049:                    Object requestPath) throws ScriptingException {
1050:                HashMap globals = new HashMap();
1051:
1052:                globals.put("root", root);
1053:                globals.put("session", new SessionBean(session));
1054:                globals.put("req", new RequestBean(req));
1055:                globals.put("res", new ResponseBean(res));
1056:                globals.put("app", new ApplicationBean(app));
1057:                globals.put("path", requestPath);
1058:
1059:                // enter execution context
1060:                scriptingEngine.enterContext(globals);
1061:            }
1062:
1063:            /**
1064:             * Get the child element with the given name from the given object.
1065:             *
1066:             * @param obj
1067:             * @param name
1068:             * @return
1069:             * @throws ScriptingException
1070:             */
1071:            private Object getChildElement(Object obj, String name)
1072:                    throws ScriptingException {
1073:                if (scriptingEngine.hasFunction(obj, "getChildElement", false)) {
1074:                    return scriptingEngine.invoke(obj, "getChildElement",
1075:                            new Object[] { name },
1076:                            ScriptingEngine.ARGS_WRAP_DEFAULT, false);
1077:                }
1078:
1079:                if (obj instanceof  IPathElement) {
1080:                    return ((IPathElement) obj).getChildElement(name);
1081:                }
1082:
1083:                return null;
1084:            }
1085:
1086:            /**
1087:             *  Null out some fields, mostly for the sake of garbage collection.
1088:             */
1089:            synchronized void recycle() {
1090:                res = null;
1091:                req = null;
1092:                session = null;
1093:                function = null;
1094:                args = null;
1095:                result = null;
1096:                exception = null;
1097:            }
1098:
1099:            /**
1100:             * Check if an action with a given name is defined for a scripted object. If it is,
1101:             * return the action's function name. Otherwise, return null.
1102:             */
1103:            public String getAction(Object obj, String action, RequestTrans req) {
1104:                if (obj == null)
1105:                    return null;
1106:
1107:                if (action == null)
1108:                    action = "main";
1109:
1110:                StringBuffer buffer = new StringBuffer(action)
1111:                        .append("_action");
1112:                // record length so we can check without method
1113:                // afterwards for GET, POST, HEAD requests
1114:                int length = buffer.length();
1115:
1116:                if (req.checkXmlRpc()) {
1117:                    // append _methodname
1118:                    buffer.append("_xmlrpc");
1119:                    if (scriptingEngine.hasFunction(obj, buffer.toString(),
1120:                            false)) {
1121:                        // handle as XML-RPC request
1122:                        req.setMethod(RequestTrans.XMLRPC);
1123:                        return buffer.toString();
1124:                    }
1125:                    // cut off method in case it has been appended
1126:                    buffer.setLength(length);
1127:                }
1128:
1129:                String method = req.getMethod();
1130:                // append HTTP method to action name
1131:                if (method != null) {
1132:                    // append _methodname
1133:                    buffer.append('_').append(method.toLowerCase());
1134:                    if (scriptingEngine.hasFunction(obj, buffer.toString(),
1135:                            false))
1136:                        return buffer.toString();
1137:
1138:                    // cut off method in case it has been appended
1139:                    buffer.setLength(length);
1140:                }
1141:
1142:                // if no method specified or "ordinary" request try action without method
1143:                if (method == null || "GET".equalsIgnoreCase(method)
1144:                        || "POST".equalsIgnoreCase(method)
1145:                        || "HEAD".equalsIgnoreCase(method)) {
1146:                    if (scriptingEngine.hasFunction(obj, buffer.toString(),
1147:                            false))
1148:                        return buffer.toString();
1149:                }
1150:
1151:                return null;
1152:            }
1153:
1154:            /**
1155:             * Returns this evaluator's scripting engine
1156:             */
1157:            public ScriptingEngine getScriptingEngine() {
1158:                if (scriptingEngine == null) {
1159:                    initScriptingEngine();
1160:                }
1161:                return scriptingEngine;
1162:            }
1163:
1164:            /**
1165:             * Get the request object for the current request.
1166:             *
1167:             * @return the request object
1168:             */
1169:            public synchronized RequestTrans getRequest() {
1170:                return req;
1171:            }
1172:
1173:            /**
1174:             * Get the response object for the current request.
1175:             *
1176:             * @return the response object
1177:             */
1178:            public synchronized ResponseTrans getResponse() {
1179:                return res;
1180:            }
1181:
1182:            /**
1183:             * Get the current transactor thread
1184:             *
1185:             * @return the current transactor thread
1186:             */
1187:            public synchronized Transactor getThread() {
1188:                return rtx;
1189:            }
1190:
1191:            /**
1192:             * Return the current session
1193:             *
1194:             * @return the session for the current request
1195:             */
1196:            public synchronized Session getSession() {
1197:                return session;
1198:            }
1199:
1200:            private String missingFunctionMessage(Object obj, String funcName) {
1201:                if (obj == null)
1202:                    return "Function " + funcName
1203:                            + " not defined in global scope";
1204:                else
1205:                    return "Function " + funcName + " not defined for " + obj;
1206:            }
1207:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.