diff --git a/src/helma/framework/core/Application.java b/src/helma/framework/core/Application.java
index a7793514..9602d0bd 100644
--- a/src/helma/framework/core/Application.java
+++ b/src/helma/framework/core/Application.java
@@ -75,6 +75,11 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
private DbMapping rootMapping, userRootMapping, userMapping;
+ // the root of the website, if a custom root object is defined.
+ // otherwise this is managed by the NodeManager and not cached here.
+ IPathElement rootObject = null;
+ String rootObjectClass;
+
boolean checkSubnodes;
String charset;
@@ -131,6 +136,9 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
debug = "true".equalsIgnoreCase (props.getProperty ("debug"));
checkSubnodes = !"false".equalsIgnoreCase (props.getProperty ("subnodeChecking"));
+ // get class name of root object if defined. Otherwise native Helma objectmodel will be used.
+ rootObjectClass = props.getProperty ("rootObject");
+
try {
requestTimeout = Long.parseLong (props.getProperty ("requestTimeout", "60"))*1000l;
} catch (Exception ignore) { }
@@ -333,7 +341,20 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
// do nothing
}
- public INode getDataRoot () {
+ public IPathElement getDataRoot () {
+ if (rootObjectClass != null) {
+ // create custom root element.
+ // NOTE: This is but a very rough first sketch of an implementation
+ // and needs much more care.
+ if (rootObject == null) try {
+ Class c = Class.forName (rootObjectClass);
+ rootObject = (IPathElement) c.newInstance ();
+ } catch (Throwable x) {
+ System.err.println ("ERROR CREATING ROOT OBJECT: "+x);
+ }
+ return rootObject;
+ }
+ // no custom root object is defined - use standard helma objectmodel
INode root = nmgr.safe.getNode ("0", rootMapping);
root.setDbMapping (rootMapping);
return root;
@@ -365,7 +386,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
* Return a prototype for a given node. If the node doesn't specify a prototype,
* return the generic hopobject prototype.
*/
- public Prototype getPrototype (INode n) {
+ public Prototype getPrototype (IPathElement n) {
String protoname = n.getPrototype ();
if (protoname == null)
return typemgr.getPrototype ("hopobject");
@@ -444,7 +465,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
if (pw != null && pw.equals (password)) {
// give the user her piece of persistence
u.setNode (unode);
- activeUsers.put (unode.getNameOrID (), u.user);
+ activeUsers.put (unode.getName (), u.user);
return true;
}
@@ -477,29 +498,69 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IRep
return pwfile.authenticate (uname, password);
}
- public String getNodePath (INode n, String tmpname) {
- INode root = getDataRoot ();
+ /* public String getNodePath (INode n, String tmpname) {
+ // FIXME: will fail for non-node roots
+ INode root = (INode) getDataRoot ();
INode users = getUserRoot ();
String siteroot = props.getProperty ("rootPrototype");
String href = n.getUrl (root, users, tmpname, siteroot);
return href;
- }
+ } */
- public String getNodeHref (INode n, String tmpname) {
- INode root = getDataRoot ();
+ /**
+ * Return a path to be used in a URL pointing to the given element and action
+ */
+ public String getNodeHref (IPathElement elem, String actionName) {
+ // FIXME: will fail for non-node roots
+ IPathElement root = getDataRoot ();
INode users = getUserRoot ();
// check base uri and optional root prototype from app.properties
String base = props.getProperty ("baseURI");
- String siteroot = props.getProperty ("rootPrototype");
+ String rootproto = props.getProperty ("rootPrototype");
if (base != null || baseURI == null)
setBaseURI (base);
- String href = n.getUrl (root, users, tmpname, siteroot);
+
+ // String href = n.getUrl (root, users, tmpname, siteroot);
+
+ String divider = "/";
+ StringBuffer b = new StringBuffer ();
+ IPathElement p = elem;
+ int loopWatch = 0;
+
+ while (p != null && p.getParentElement () != null && p != root) {
+
+ if (rootproto != null && rootproto.equals (p.getPrototype ()))
+ break;
+
+ b.insert (0, divider);
+
+ // users always have a canonical URL like /users/username
+ if ("user".equals (p.getPrototype ())) {
+ b.insert (0, UrlEncoder.encode (p.getElementName ()));
+ p = users;
+ break;
+ }
+
+ b.insert (0, UrlEncoder.encode (p.getElementName ()));
+
+ p = p.getParentElement ();
+
+ if (loopWatch++ > 20)
+ break;
+ }
+
+ if (p == users) {
+ b.insert (0, divider);
+ b.insert (0, "users");
+ }
+ String href = b.toString()+UrlEncoder.encode (actionName);
return baseURI + href;
}
-
+
+
public void setBaseURI (String uri) {
if (uri == null)
this.baseURI = "/";
diff --git a/src/helma/framework/core/ESAppNode.java b/src/helma/framework/core/ESAppNode.java
index a22d26d9..aa25c049 100644
--- a/src/helma/framework/core/ESAppNode.java
+++ b/src/helma/framework/core/ESAppNode.java
@@ -130,7 +130,7 @@ public class ESAppNode extends ESNode {
public String toString () {
- return ("AppNode "+node.getNameOrID ());
+ return ("AppNode "+node.getElementName ());
}
}
diff --git a/src/helma/framework/core/ESNode.java b/src/helma/framework/core/ESNode.java
index 3bf44edf..fb1ef031 100644
--- a/src/helma/framework/core/ESNode.java
+++ b/src/helma/framework/core/ESNode.java
@@ -412,7 +412,11 @@ public class ESNode extends ObjectPrototype {
public void clearError() {
lastError = null;
}
-
+
+ public Object toJavaObject () {
+ return getNode ();
+ }
+
/**
* An ESNode equals another object if it is an ESNode that wraps the same INode
* or the wrapped INode itself. FIXME: doesen't check dbmapping/type!
diff --git a/src/helma/framework/core/HopExtension.java b/src/helma/framework/core/HopExtension.java
index a957b1ad..20d3848a 100644
--- a/src/helma/framework/core/HopExtension.java
+++ b/src/helma/framework/core/HopExtension.java
@@ -5,6 +5,7 @@ package helma.framework.core;
import helma.objectmodel.*;
import helma.util.*;
+import helma.framework.IPathElement;
import FESI.Interpreter.*;
import FESI.Exceptions.*;
import FESI.Extensions.*;
@@ -76,7 +77,7 @@ public class HopExtension {
reval.esNodePrototype.putHiddenProperty ("editor", new NodeEditor ("editor", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("chooser", new NodeChooser ("chooser", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("multiChooser", new MultiNodeChooser ("multiChooser", evaluator, fp));
- reval.esNodePrototype.putHiddenProperty ("path", new NodePath ("path", evaluator, fp));
+ reval.esNodePrototype.putHiddenProperty ("path", new NodeHref ("path", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp));
@@ -574,12 +575,12 @@ public class HopExtension {
this.global = global;
this.asString = asString;
}
- public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
+ public ESValue callFunction (ESObject thisObj, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length < 1 || arguments.length > 2 || arguments[0] ==null || arguments[0] == ESNull.theNull)
throw new EcmaScriptException ("renderSkin must be called with one Skin argument and an optional parameter argument");
try {
- Skin skin = null;
- ESNode handlerNode = global ? null : (ESNode) thisObject;
+ Skin skin = null;
+ ESObject thisObject = global ? null : thisObj;
ESObject paramObject = null;
if (arguments.length > 1 && arguments[1] instanceof ESObject)
paramObject = (ESObject) arguments[1];
@@ -592,11 +593,11 @@ public class HopExtension {
}
if (skin == null)
- skin = reval.getSkin (handlerNode, arguments[0].toString ());
+ skin = reval.getSkin (thisObject, arguments[0].toString ());
if (asString)
reval.res.pushStringBuffer ();
if (skin != null)
- skin.render (reval, handlerNode, paramObject);
+ skin.render (reval, thisObject, paramObject);
else
reval.res.write ("[Skin not found: "+arguments[0]+"]");
if (asString)
@@ -916,7 +917,7 @@ public class HopExtension {
}
- class NodePath extends BuiltinFunctionObject {
+ /* class NodePath extends BuiltinFunctionObject {
NodePath (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
}
@@ -925,7 +926,7 @@ public class HopExtension {
String tmpname = arguments[0].toString ();
return new ESString (app.getNodePath (n, tmpname));
}
- }
+ } */
class NodeSetParent extends BuiltinFunctionObject {
NodeSetParent (String name, Evaluator evaluator, FunctionPrototype fp) {
@@ -943,33 +944,33 @@ public class HopExtension {
super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- INode n = ((ESNode) thisObject).getNode ();
+ IPathElement elem = (IPathElement) thisObject.toJavaObject ();
String tmpname = arguments.length == 0 ? "" : arguments[0].toString ();
- String basicHref =app.getNodeHref (n, tmpname);
+ String basicHref =app.getNodeHref (elem, tmpname);
String hrefSkin = app.props.getProperty ("hrefSkin");
// FIXME: we should actually walk down the path from the object we called href() on
// instead we move down the URL path.
if (hrefSkin != null) {
// we need to post-process the href with a skin for this application
// first, look in the object href was called on.
- INode sn = n;
+ IPathElement skinElem = elem;
Skin skin = null;
- while (skin == null && sn != null) {
- Prototype proto = app.getPrototype (sn);
+ while (skin == null && skinElem != null) {
+ Prototype proto = app.getPrototype (skinElem);
if (proto != null)
skin = proto.getSkin (hrefSkin);
if (skin == null)
- sn = sn.getParent ();
+ skinElem = skinElem.getParentElement ();
}
if (skin != null) {
- ESNode esn = reval.getNodeWrapper (sn);
- return renderSkin (skin, basicHref, esn);
+ ESObject eso = reval.getElementWrapper (skinElem);
+ return renderSkin (skin, basicHref, eso);
}
}
return new ESString (basicHref);
}
- private ESString renderSkin (Skin skin, String path, ESNode obj) throws EcmaScriptException {
+ private ESString renderSkin (Skin skin, String path, ESObject obj) throws EcmaScriptException {
reval.res.pushStringBuffer ();
ESObject param = new ObjectPrototype (null, reval.evaluator);
param.putProperty ("path", new ESString (path), "path".hashCode ());
@@ -1040,7 +1041,7 @@ public class HopExtension {
buffer.append ("");
@@ -1062,7 +1063,7 @@ public class HopExtension {
buffer.append ("");
diff --git a/src/helma/framework/core/RequestEvaluator.java b/src/helma/framework/core/RequestEvaluator.java
index df070d39..a3573d4d 100644
--- a/src/helma/framework/core/RequestEvaluator.java
+++ b/src/helma/framework/core/RequestEvaluator.java
@@ -77,7 +77,7 @@ public class RequestEvaluator implements Runnable {
static final int XMLRPC = 2; // via XML-RPC
static final int INTERNAL = 3; // generic function call, e.g. by scheduler
- INode root, userroot, currentNode;
+ // INode root, currentNode;
INode[] skinmanagers;
/**
@@ -99,6 +99,7 @@ public class RequestEvaluator implements Runnable {
private void initEvaluator () {
try {
evaluator = new Evaluator();
+ evaluator.reval = this;
global = evaluator.getGlobalObject();
for (int i=0; i -1) {
StringTokenizer st = new StringTokenizer (method, ".");
int cnt = st.countTokens ();
@@ -491,7 +494,7 @@ public class RequestEvaluator implements Runnable {
root = app.getDataRoot ();
- global.putHiddenProperty ("root", getNodeWrapper (root));
+ global.putHiddenProperty ("root", getElementWrapper (root));
global.deleteProperty("user", "user".hashCode());
global.deleteProperty ("req", "req".hashCode());
global.putHiddenProperty ("res", ESLoader.normalizeValue(res, evaluator));
@@ -642,13 +645,13 @@ public class RequestEvaluator implements Runnable {
return result;
}
- public synchronized ESValue invokeFunction (INode node, String functionName, ESValue[] args)
+ public synchronized ESValue invokeFunction (IPathElement node, String functionName, ESValue[] args)
throws Exception {
ESObject obj = null;
if (node == null)
obj = global;
else
- obj = getNodeWrapper (node);
+ obj = getElementWrapper (node);
return invokeFunction (obj, functionName, args);
}
@@ -741,8 +744,14 @@ public class RequestEvaluator implements Runnable {
Prototype proto = null;
if (thisObject == null)
proto = app.typemgr.getPrototype ("global");
- else
- proto = app.getPrototype (((ESNode) thisObject).getNode ());
+ else {
+ try {
+ IPathElement elem = (IPathElement) thisObject.toJavaObject ();
+ proto = app.getPrototype (elem);
+ } catch (ClassCastException wrongClass) {
+ throw new RuntimeException ("Can't render a skin on something that is not a path element: "+wrongClass);
+ }
+ }
return getSkin (proto, skinname);
}
@@ -829,6 +838,21 @@ public class RequestEvaluator implements Runnable {
return (ESNode) objectcache.get (n);
}
+
+ public ESObject getElementWrapper (IPathElement e) {
+ if (e instanceof INode)
+ return getNodeWrapper ((INode) e);
+
+ String protoname = e.getPrototype ();
+
+ ObjectPrototype op = (ObjectPrototype) prototypes.get (protoname);
+
+ return new ESGenericObject (op, evaluator, e);
+ }
+
+ /**
+ * Get a script wrapper for an implemntation of helma.objectmodel.INode
+ */
public ESNode getNodeWrapper (INode n) {
if (n == null)
diff --git a/src/helma/framework/core/Skin.java b/src/helma/framework/core/Skin.java
index abdc84f5..45288de5 100644
--- a/src/helma/framework/core/Skin.java
+++ b/src/helma/framework/core/Skin.java
@@ -72,12 +72,24 @@ public class Skin {
return source;
}
- public void render (RequestEvaluator reval, ESNode thisNode, ESObject paramObject) throws RedirectException {
+ public void render (RequestEvaluator reval, ESObject thisObject, ESObject paramObject) throws RedirectException {
+
if (parts == null)
return;
+
+ IPathElement elem = null;
+
+ if (thisObject != null) {
+ try {
+ elem = (IPathElement) thisObject.toJavaObject ();
+ } catch (ClassCastException wrongClass) {
+ throw new RuntimeException ("Can't render a skin on something that is not a path element: "+wrongClass);
+ }
+ }
+
for (int i=0; i=0; i--) {
- if (handler.equalsIgnoreCase (((ESNode) reval.reqPath.getProperty(i)).getPrototypeName())) {
+ IPathElement pathelem = (IPathElement) reval.reqPath.getProperty (i).toJavaObject ();
+ if (handler.equalsIgnoreCase (pathelem.getPrototype ())) {
handlerObject = (ESNode) reval.reqPath.getProperty(i);
break;
}
diff --git a/src/helma/framework/core/User.java b/src/helma/framework/core/User.java
index e8299e2c..44bdffa0 100644
--- a/src/helma/framework/core/User.java
+++ b/src/helma/framework/core/User.java
@@ -52,7 +52,7 @@ public class User implements Serializable {
nhandle = null;
uid = null;
} else {
- uid = n.getNameOrID ();
+ uid = n.getElementName ();
nhandle = ((helma.objectmodel.db.Node) n).getHandle ();
}
}