} }    Map macroHandlers = res.getMacroHandlers(); int l = requestPath.size(); Prototype[] protos = new Prototype[l];  for (int i=0; i<l; i++) {  Object obj = requestPath.get(i);  protos[i] = app.getPrototype(obj);   if (protos[i] != null) { macroHandlers.put(protos[i].getName(), obj); } }     for (int i=l-1; i>=0; i--) { if (protos[i] != null) { protos[i].registerParents(macroHandlers, requestPath.get(i));
    public void run() {        // 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;                // System.err.println ("Type check overhead: "+(System.currentTimeMillis ()-startCheck)+" millis");                // object refs to ressolve request path                Object 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                                StringBuffer txname = new StringBuffer(app.getName());                                txname.append("/");                                txname.append((error == null) ? req.path : "error");                                // begin transaction                                localrtx.begin(txname.toString());                                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;                                }                                Map macroHandlers = res.getMacroHandlers();                                try {                                    if (error != null) {                                        // there was an error in the previous loop, call error handler                                        currentElement = root;                                        // do not reset the requestPath so error handler can use the original one                                        // get error handler action                                        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);                                        macroHandlers.put("root", root);                                        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);                                        macroHandlers.put("root", root);                                        for (int i = 0; i < ntokens; i++) {                                            if (currentElement == null) {                                                throw new FrameworkException("Object not found.");                                            }                                            if (pathItems[i].length() == 0) {                                                continue;                                            }                                            // 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) {                                                currentElement = app.getChildElement(currentElement,                                                                                     pathItems[i]);                                                // add object to request path if suitable                                                if (currentElement != null) {                                                    // add to requestPath array                                                    requestPath.add(currentElement);                                                    Prototype proto = app.getPrototype(currentElement);                                                    if (proto != null) {                                                        proto.addToHandlerMap(macroHandlers,                                                                              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);                                    // set the application checksum in response to make ETag                                     // generation sensitive to changes in the app                                    res.setApplicationChecksum(app.getChecksum());                                    // reset skin recursion detection counter                                    skinDepth = 0;                                    // try calling onRequest() function on object before                                    // calling the actual action                                    try {                                        if (scriptingEngine.hasFunction(currentElement,                                                                            "onRequest")) {                                            scriptingEngine.invoke(currentElement,                                                                   "onRequest",                                                                   new Object[0], false);                                        }                                    } catch (RedirectException redir) {                                        throw redir;                                    }                                    // 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.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 instanceof ScriptingException)) {                                        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 x) {                            abortTransaction(false);                            app.logEvent("Exception in " + Thread.currentThread() + ": " +                                         x);                            // 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 = x;                        }                        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 x) {                                abortTransaction(false);                                app.logEvent("Exception in " + Thread.currentThread() +                                             ": " + x);                                // 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 = x;                            }                        }                        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();        }    }