diff --git a/src/helma/framework/core/Application.java b/src/helma/framework/core/Application.java index 8c961338..d5dd0a0d 100644 --- a/src/helma/framework/core/Application.java +++ b/src/helma/framework/core/Application.java @@ -115,6 +115,10 @@ public final class Application implements IPathElement, Runnable { // the URL-prefix to use for links into this application private String baseURI; + // the name of the root prototype + private String rootPrototype; + + // Db mappings for some standard prototypes private DbMapping rootMapping; private DbMapping userRootMapping; private DbMapping userMapping; @@ -1019,13 +1023,9 @@ public final class Application implements IPathElement, Runnable { * Return a path to be used in a URL pointing to the given element and action */ public String getNodeHref(Object elem, String actionName) { - // Object root = getDataRoot (); - // check optional root prototype from app.properties - String rootProto = props.getProperty("rootPrototype"); - StringBuffer b = new StringBuffer(baseURI); - composeHref(elem, b, rootProto, 0); + composeHref(elem, b, 0); if (actionName != null) { b.append(UrlEncoded.encode(actionName)); @@ -1034,13 +1034,12 @@ public final class Application implements IPathElement, Runnable { return b.toString(); } - private final void composeHref(Object elem, StringBuffer b, String rootProto, - int pathCount) { + private final void composeHref(Object elem, StringBuffer b, int pathCount) { if ((elem == null) || (pathCount > 20)) { return; } - if ((rootProto != null) && rootProto.equals(getPrototypeName(elem))) { + if ((rootPrototype != null) && rootPrototype.equals(getPrototypeName(elem))) { return; } @@ -1050,11 +1049,19 @@ public final class Application implements IPathElement, Runnable { return; } - composeHref(getParentElement(elem), b, rootProto, pathCount++); + composeHref(getParentElement(elem), b, pathCount++); b.append(UrlEncoded.encode(getElementName(elem))); b.append("/"); } + /** + * Returns the baseURI for Hrefs in this application. + */ + public String getBaseURI() { + return baseURI; + } + + /** * This method sets the base URL of this application which will be prepended to * the actual object path. @@ -1077,6 +1084,13 @@ public final class Application implements IPathElement, Runnable { return props.containsKey("baseuri"); } + /** + * Returns the prototype name that Hrefs in this application should start with. + */ + public String getRootPrototype() { + return rootPrototype; + } + /** * Tell other classes whether they should output logging information for this application. */ @@ -1574,8 +1588,9 @@ public final class Application implements IPathElement, Runnable { // debug flag debug = "true".equalsIgnoreCase(props.getProperty("debug")); + String reqTimeout = props.getProperty("requesttimeout", "60"); try { - requestTimeout = Long.parseLong(props.getProperty("requestTimeout", "60")) * 1000L; + requestTimeout = Long.parseLong(reqTimeout) * 1000L; } catch (Exception ignore) { // go with default value requestTimeout = 60000L; @@ -1590,6 +1605,8 @@ public final class Application implements IPathElement, Runnable { baseURI = "/"; } + rootPrototype = props.getProperty("rootprototype"); + // update the XML-RPC access list, containting prototype.method // entries of functions that may be called via XML-RPC String xmlrpcAccessProp = props.getProperty("xmlrpcaccess"); diff --git a/src/helma/framework/core/Prototype.java b/src/helma/framework/core/Prototype.java index 2d6fa701..5fcab75d 100644 --- a/src/helma/framework/core/Prototype.java +++ b/src/helma/framework/core/Prototype.java @@ -186,9 +186,7 @@ public final class Prototype { Prototype p = parent; while ((p != null) && !"hopobject".equalsIgnoreCase(p.getName())) { - if (!handlers.containsKey(p.name)) { - handlers.put(p.name, obj); - } + handlers.put(p.name, obj); p = p.parent; } @@ -267,15 +265,6 @@ public final class Prototype { lastUpdate = System.currentTimeMillis(); } - /** - * Get the time at which this prototype's scripts were checked - * for changes for the last time. - */ - - /* public long getLastCheck () { - return lastCheck; - } */ - /** * Signal that the prototype's scripts have been checked for * changes. diff --git a/src/helma/framework/core/RequestEvaluator.java b/src/helma/framework/core/RequestEvaluator.java index c9186684..fab68f17 100644 --- a/src/helma/framework/core/RequestEvaluator.java +++ b/src/helma/framework/core/RequestEvaluator.java @@ -55,7 +55,7 @@ public final class RequestEvaluator implements Runnable { Object[] args; // the object path of the request we're evaluating - List requestPath; + RequestPath requestPath; // the result of the operation Object result; @@ -122,7 +122,7 @@ public final class RequestEvaluator implements Runnable { // object refs to ressolve request path Object currentElement; - requestPath = new ArrayList(); + requestPath = new RequestPath(app); switch (reqtype) { case HTTP: @@ -158,6 +158,9 @@ public final class RequestEvaluator implements Runnable { globals.put("path", requestPath); req.startTime = System.currentTimeMillis(); + // enter execution context + scriptingEngine.enterContext(globals); + if (error != null) { res.error = error; } @@ -186,7 +189,7 @@ public final class RequestEvaluator implements Runnable { } else if ((req.path == null) || "".equals(req.path.trim())) { currentElement = root; - requestPath.add(currentElement); + requestPath.add(null, currentElement); action = getAction(currentElement, null); @@ -210,7 +213,7 @@ public final class RequestEvaluator implements Runnable { pathItems[i] = st.nextToken(); currentElement = root; - requestPath.add(currentElement); + requestPath.add(null, currentElement); for (int i = 0; i < ntokens; i++) { @@ -222,9 +225,6 @@ public final class RequestEvaluator implements Runnable { 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)) { @@ -233,13 +233,13 @@ public final class RequestEvaluator implements Runnable { } if (action == null) { - currentElement = app.getChildElement(currentElement, - pathItems[i]); + currentElement = getChildElement(currentElement, + pathItems[i]); // add object to request path if suitable if (currentElement != null) { // add to requestPath array - requestPath.add(currentElement); + requestPath.add(pathItems[i], currentElement); } } } @@ -311,13 +311,10 @@ public final class RequestEvaluator implements Runnable { ///////////////////////////////////////////////////////////////////////////// // 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 + // set the application checksum in response to make ETag // generation sensitive to changes in the app res.setApplicationChecksum(app.getChecksum()); @@ -411,7 +408,7 @@ public final class RequestEvaluator implements Runnable { if (app.debug && !(x instanceof ScriptingException)) { x.printStackTrace (); } - + // set done to false so that the error will be processed done = false; error = x.getMessage(); @@ -459,8 +456,8 @@ public final class RequestEvaluator implements Runnable { for (int i = 1; i < cnt; i++) { String next = st.nextToken(); - currentElement = app.getChildElement(currentElement, - next); + currentElement = getChildElement(currentElement, + next); } if (currentElement == null) { @@ -841,6 +838,18 @@ public final class RequestEvaluator implements Runnable { return result; } + private Object getChildElement(Object obj, String name) throws ScriptingException { + if (scriptingEngine.hasFunction(obj, "getChildElement")) { + return scriptingEngine.invoke(obj, "getChildElement", new Object[] {name}, false); + } + + if (obj instanceof IPathElement) { + return ((IPathElement) obj).getChildElement(name); + } + + return null; + } + /** * Stop this request evaluator's current thread. If currently active kill the request, otherwise just * notify. diff --git a/src/helma/framework/core/RequestPath.java b/src/helma/framework/core/RequestPath.java new file mode 100644 index 00000000..c4e99b7e --- /dev/null +++ b/src/helma/framework/core/RequestPath.java @@ -0,0 +1,134 @@ +/* + * Helma License Notice + * + * The contents of this file are subject to the Helma License + * Version 2.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://adele.helma.org/download/helma/license.txt + * + * Copyright 1998-2003 Helma Software. All Rights Reserved. + * + * $RCSfile$ + * $Author$ + * $Revision$ + * $Date$ + */ + +package helma.framework.core; + +import java.util.*; +import helma.util.UrlEncoded; + +/** + * Represents a URI request path that has been resolved to an object path. + * Offers methods to access objects in the path by index and prototype names, + * and to render the path as URI again. + */ +public class RequestPath { + + Application app; + + List objects; + List ids; + + Map primaryProtos; + Map secondaryProtos; + + /** + * Creates a new RequestPath object. + * + * @param app the application we're running in + */ + public RequestPath(Application app) { + this.app = app; + objects = new ArrayList(); + ids = new ArrayList(); + primaryProtos = new HashMap(); + secondaryProtos = new HashMap(); + } + + /** + * Adds an item to the end of the path. + * + * @param id the item id representing the path in the URL + * @param obj the object to which the id resolves + */ + public void add(String id, Object obj) { + ids.add(id); + objects.add(obj); + + Prototype proto = app.getPrototype(obj); + + if (proto != null) { + primaryProtos.put(proto.getName(), obj); + proto.registerParents(secondaryProtos, obj); + } + } + + /** + * Returns the number of objects in the request path. + */ + public int size() { + return objects.size(); + } + + /** + * Gets an object in the path by index. + * + * @param idx the index of the object in the request path + */ + public Object get(int idx) { + if (idx < 0 || idx >= objects.size()) { + return null; + } + + return objects.get(idx); + } + + /** + * Gets an object in the path by prototype name. + * + * @param typeName the prototype name of the object in the request path + */ + public Object getByPrototypeName(String typeName) { + // search primary prototypes first + Object obj = primaryProtos.get(typeName); + + if (obj != null) { + return obj; + } + + // if that fails, consult secondary prototype map + return secondaryProtos.get(typeName); + } + + /** + * Returns the string representation of this path usable for links. + */ + public String href(String action) { + StringBuffer buffer = new StringBuffer(app.getBaseURI()); + + int start = 1; + String rootPrototype = app.getRootPrototype(); + + if (rootPrototype != null) { + Object rootObject = getByPrototypeName(rootPrototype); + + if (rootObject != null) { + start = objects.indexOf(rootObject) + 1; + } + } + + for (int i=start; i= 0 && index < path.size(); + } + + /** + * Returns a list of array indices 0..length-1. + */ + public Object[] getIds() { + Object[] ids = new Object[path.size()]; + + for (int i=0; i