String txname = app.getName()+"/"+req.path;
StringBuffer txname = new StringBuffer(app.getName()); txname.append ("/"); txname.append (error == null ? req.path : "error");
    public void run () {        int txcount = 0;        // first, set a local variable to the current transactor thread so we know        // when it's time to quit because another thread took over.        Transactor localrtx = (Transactor) Thread.currentThread ();        try {	do {	    // long startCheck = System.currentTimeMillis ();	    app.typemgr.checkPrototypes ();	    initScriptingEngine ();	    scriptingEngine.updatePrototypes ();	    // System.err.println ("Type check overhead: "+(System.currentTimeMillis ()-startCheck)+" millis");	    // object refs to ressolve request path	    Object root, currentElement;	    requestPath = new ArrayList ();	    switch (reqtype) {	    case HTTP:	        int tries = 0;	        boolean done = false;	        String error = null;	        while (!done) {	            currentElement = null;	            try {	                // used for logging	                String txname = app.getName()+"/"+req.path;	                // begin transaction	                localrtx.begin (txname);	                String action = null;	                root = app.getDataRoot ();	                HashMap globals = new HashMap ();	                globals.put ("root", root);	                globals.put ("session", new SessionBean (session));	                globals.put ("req", new RequestBean (req));	                globals.put ("res", new ResponseBean (res));	                globals.put ("app", new ApplicationBean (app));	                globals.put ("path", requestPath);	                req.startTime = System.currentTimeMillis ();	                if (error != null)	                    res.error = error;	                if (session.message != null) {	                    // bring over the message from a redirect	                    res.message = session.message;	                    session.message = null;	                }	                try {	                    if (error != null) {	                        // there was an error in the previous loop, call error handler	                        currentElement = root;	                        requestPath.add (currentElement);	                        String errorAction = app.props.getProperty ("error", "error");	                        action = getAction (currentElement, errorAction);	                        if (action == null)	                            throw new RuntimeException (error);	                    } else if (req.path == null || "".equals (req.path.trim ())) {	                        currentElement = root;	                        requestPath.add (currentElement);	                        action = getAction (currentElement, null);	                        if (action == null)	                            throw new FrameworkException ("Action not found");	                    } else {	                        // march down request path...	                        StringTokenizer st = new StringTokenizer (req.path, "/");	                        int ntokens = st.countTokens ();	                        // limit path to < 50 tokens	                        if (ntokens > 50)	                            throw new RuntimeException ("Path too long");	                        String[] pathItems = new String [ntokens];	                        for (int i=0; i<ntokens; i++)	                              pathItems[i] = st.nextToken ();	                        currentElement = root;	                        requestPath.add (currentElement);	                        for (int i=0; i<ntokens; i++) {	                            if (currentElement == null)	                                throw new FrameworkException ("Object not found.");	                            // we used to do special processing for /user and /users	                            // here but with the framework cleanup, this stuff has to be	                            // mounted manually.	                            // if we're at the last element of the path,	                            // try to interpret it as action name.	                            if (i == ntokens-1) {	                                action = getAction (currentElement, pathItems[i]);	                            }	                            if (action == null) {	                                if (pathItems[i].length () == 0)	                                    continue;	                                currentElement = app.getChildElement (currentElement, pathItems[i]);	                                // add object to request path if suitable	                                if (currentElement != null) {	                                    // add to requestPath array	                                    requestPath.add (currentElement);	                                }	                            }	                        }	                        if (currentElement == null)	                            throw new FrameworkException ("Object not found.");	                        if (action == null)	                            action = getAction (currentElement, null);	                        if (action == null)	                            throw new FrameworkException ("Action not found");	                    }	                } catch (FrameworkException notfound) {	                    if (error != null)	                        // we already have an error and the error template wasn't found,	                        // display it instead of notfound message	                        throw new RuntimeException ();	                    // The path could not be resolved. Check if there is a "not found" action	                    // specified in the property file.	                    res.status = 404;	                    String notFoundAction = app.props.getProperty ("notFound", "notfound");	                    currentElement = root;	                    action = getAction (currentElement, notFoundAction);	                    if (action == null)	                        throw new FrameworkException (notfound.getMessage ());	                }	                /////////////////////////////////////////////////////////////////////////////	                // end of path resolution section	                /////////////////////////////////////////////////////////////////////////////	                // beginning of execution section	                try {	                    // enter execution context	                    scriptingEngine.enterContext (globals);	                    // set the req.action property, cutting off the _action suffix	                    req.action = action.substring (0, action.length()-7);	                    // reset skin recursion detection counter	                    skinDepth = 0;	                    // try calling onRequest() function on object before	                    // calling the actual action	                    try {	                        scriptingEngine.invoke (currentElement, "onRequest", new Object[0], false);	                    } catch (RedirectException redir) {	                        throw redir;	                    } catch (Exception ignore) {	                        // function is not defined or caused an exception, ignore	                    }	                    // reset skin recursion detection counter	                    skinDepth = 0;	                    // do the actual action invocation	                    scriptingEngine.invoke (currentElement, action, new Object[0], false);	                } catch (RedirectException redirect) {	                    // res.redirect = redirect.getMessage ();	                    // if there is a message set, save it on the user object for the next request	                    if (res.message != null)	                        session.message = res.message;	                    done = true;	                }	                // check if we're still the one and only or if the waiting thread has given up on us already	                commitTransaction ();	                done = true;	            } catch (ConcurrencyException x) {	                res.reset ();	                if (++tries < 8) {	                    // try again after waiting some period	                    abortTransaction (true);	                    try {	                        // wait a bit longer with each try	                        int base = 800 * tries;	                        Thread.currentThread ().sleep ((long) (base + Math.random ()*base*2));	                    } catch (Exception ignore) {}	                    continue;	                } else {	                    abortTransaction (false);	                    if (error == null) {	                        app.errorCount += 1;	                        // set done to false so that the error will be processed	                        done = false;	                        error = "Couldn't complete transaction due to heavy object traffic (tried "+tries+" times)";	                    } else {	                        // error in error action. use traditional minimal error message	                        res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>"+error+"</pre>");	                        done = true;	                    }	                }	            } catch (Exception x) {	                abortTransaction (false);	                // If the transactor thread has been killed by the invoker thread we don't have to	                // bother for the error message, just quit.	                if (localrtx != rtx) {	                    break;	                }	                res.reset ();	                // check if we tried to process the error already	                if (error == null) {	                    app.errorCount += 1;	                    app.logEvent ("Exception in "+Thread.currentThread()+": "+x);	                    // Dump the profiling data to System.err	                    if (app.debug) {	                        x.printStackTrace ();	                    }	                    // set done to false so that the error will be processed	                    done = false;	                    error = x.getMessage ();	                    if (error == null || error.length() == 0)	                        error = x.toString ();	                    if (error == null)	                        error = "Unspecified error";	                } else {	                    // error in error action. use traditional minimal error message	                    res.write ("<b>Error in application '"+app.getName()+"':</b> <br><br><pre>"+error+"</pre>");	                    done = true;	                }	            }	        }	        break;	    case XMLRPC:	        try {	            localrtx.begin (app.getName()+":xmlrpc/"+method);	            root = app.getDataRoot ();	            HashMap globals = new HashMap ();	            globals.put ("root", root);	            globals.put ("res", new ResponseBean (res));	            globals.put ("app", new ApplicationBean (app));	            scriptingEngine.enterContext (globals);	            currentElement = root;	            if (method.indexOf (".") > -1) {	                StringTokenizer st = new StringTokenizer (method, ".");	                int cnt = st.countTokens ();	                for (int i=1; i<cnt; i++) {	                    String next = st.nextToken ();	                    currentElement = app.getChildElement (currentElement, next);	                }	                if (currentElement == null)	                    throw new FrameworkException ("Method name \""+method+"\" could not be resolved.");	                method = st.nextToken ();	            }	            // check XML-RPC access permissions	            String proto = app.getPrototypeName (currentElement);	            app.checkXmlRpcAccess (proto, method);	            // reset skin recursion detection counter	            skinDepth = 0;	            result = scriptingEngine.invoke (currentElement, method, args, true);	            commitTransaction ();	        } catch (Exception wrong) {	            abortTransaction (false);	            // If the transactor thread has been killed by the invoker thread we don't have to	            // bother for the error message, just quit.	            if (localrtx != rtx) {	                return;	            }	            this.exception = wrong;	        }	        break;	    case INTERNAL:	        // Just a human readable descriptor of this invocation	        String funcdesc = app.getName()+":internal/"+method;	        // if thisObject is an instance of NodeHandle, get the node object itself.	        if (thisObject != null && thisObject instanceof NodeHandle) {	            thisObject = ((NodeHandle) thisObject).getNode (app.nmgr.safe);	            // see if a valid node was returned	            if (thisObject == null) {	                reqtype = NONE;	                break;	            }	        }	        // avoid going into transaction if called function doesn't exist	        boolean functionexists = true;	        functionexists = scriptingEngine.hasFunction (thisObject, method);	        if (!functionexists) {	            // function doesn't exist, nothing to do here.	            reqtype = NONE;	        } else try {	            localrtx.begin (funcdesc);	            root = app.getDataRoot ();	            HashMap globals = new HashMap ();	            globals.put ("root", root);	            globals.put ("res", new ResponseBean (res));	            globals.put ("app", new ApplicationBean (app));	            scriptingEngine.enterContext (globals);	            // reset skin recursion detection counter	            skinDepth = 0;	            result = scriptingEngine.invoke (thisObject, method, args, false);	            commitTransaction ();	        } catch (Exception wrong) {	            abortTransaction (false);	            // If the transactor thread has been killed by the invoker thread we don't have to	            // bother for the error message, just quit.	            if (localrtx != rtx) {	                return;	            }	            this.exception = wrong;	        }	        break;	    }	    // exit execution context	    scriptingEngine.exitContext ();	    // make sure there is only one thread running per instance of this class	    // if localrtx != rtx, the current thread has been aborted and there's no need to notify	    if (localrtx != rtx) {	        localrtx.closeConnections ();	        return;	    }	    notifyAndWait ();            }  while (localrtx == rtx);        } finally {            localrtx.closeConnections ();        }    }