diff --git a/src/helma/scripting/Action.java b/src/helma/scripting/Action.java new file mode 100644 index 00000000..7e106b0d --- /dev/null +++ b/src/helma/scripting/Action.java @@ -0,0 +1,291 @@ +// Action.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + +package helma.scripting; + +import java.util.Vector; +import java.util.Iterator; +import java.io.*; +import helma.framework.*; +import helma.framework.core.*; +import helma.util.Updatable; +import FESI.Data.*; +import FESI.Parser.*; +import FESI.AST.ASTFormalParameterList; +import FESI.AST.ASTStatementList; +import FESI.AST.EcmaScriptTreeConstants; +import FESI.Interpreter.*; +import FESI.Exceptions.*; + + + +/** + * An Action is a JavaScript function that is exposed as a URI. It is + * usually represented by a file with extension .hac (hop action file) + * that contains the pure JavaScript body of the function. + */ + + +public class Action implements Updatable { + + String name; + String functionName; + Prototype prototype; + Application app; + File file; + long lastmod; + + // this is the parsed function which can be easily applied to RequestEvaluator objects + TypeUpdater pfunc; + + + public Action (File file, String name, Prototype proto) { + this.prototype = proto; + this.app = proto.getApplication (); + this.name = name; + this.file = file; + if (file != null) + update (); + } + + /** + * Tell the type manager whether we need an update. this is the case when + * the file has been modified or deleted. + */ + public boolean needsUpdate () { + return lastmod != file.lastModified (); + } + + + public void update () { + + if (!file.exists ()) { + // remove functions declared by this from all object prototypes + remove (); + } else { + try { + FileReader reader = new FileReader (file); + char cbuf[] = new char[(int) file.length ()]; + reader.read (cbuf); + reader.close (); + String content = new String (cbuf); + update (content); + } catch (Exception filex) { + app.logEvent ("*** Error reading action file "+file+": "+filex); + } + + lastmod = file.lastModified (); + } + } + + + public void update (String content) throws Exception { + // app.logEvent ("Reading text template " + name); + + functionName = name+"_action"; + + try { + pfunc = parseFunction (functionName, "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", content); + } catch (Throwable x) { + String message = x.getMessage (); + pfunc = new ErrorFeedback (functionName, message); + } + + Iterator evals = app.typemgr.getRegisteredRequestEvaluators (); + while (evals.hasNext ()) { + try { + RequestEvaluator reval = (RequestEvaluator) evals.next (); + updateRequestEvaluator (reval); + } catch (Exception ignore) {} + } + } + + void remove () { + prototype.actions.remove (name); + prototype.updatables.remove (file.getName()); + + Iterator evals = app.typemgr.getRegisteredRequestEvaluators (); + while (evals.hasNext ()) { + try { + RequestEvaluator reval = (RequestEvaluator) evals.next (); + ObjectPrototype op = reval.getPrototype (prototype.getName()); + functionName = name+"_action"; + ESValue esv = (ESValue) op.getProperty (functionName, functionName.hashCode()); + if (esv instanceof ConstructedFunctionObject || esv instanceof ThrowException) { + op.deleteProperty (functionName, functionName.hashCode()); + } + } catch (Exception ignore) {} + } + } + + public String getName () { + return name; + } + + public String getFunctionName () { + return functionName; + } + + public String toString () { + return prototype.getName()+"/"+file.getName(); + } + + public synchronized void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException { + if (pfunc != null) + pfunc.updateRequestEvaluator (reval); + } + + protected TypeUpdater parseFunction (String funcname, String params, String body) throws EcmaScriptException { + + // ESObject fp = app.eval.evaluator.getFunctionPrototype(); + // ConstructedFunctionObject function = null; + ASTFormalParameterList fpl = null; + ASTStatementList sl = null; + FunctionEvaluationSource fes = null; + + if (body == null || "".equals (body.trim())) + body = ";\r\n"; + else + body = body + "\r\n"; + if (params == null) params = ""; + else params = params.trim (); + + String fulltext = "function "+funcname+" (" + params + ") {\n" + body + "\n}"; + + EcmaScript parser; + StringReader is; + + // Special case for empty parameters + if (params.length()==0) { + fpl = new ASTFormalParameterList(EcmaScriptTreeConstants.JJTFORMALPARAMETERLIST); + } else { + is = new java.io.StringReader(params); + parser = new EcmaScript(is); + try { + fpl = (ASTFormalParameterList) parser.FormalParameterList(); + is.close(); + } catch (ParseException x) { + throw new EcmaScriptParseException (x, new StringEvaluationSource(fulltext, null)); + } + } + // this is very very very strange: without the toString, lots of obscure exceptions + // deep inside the parser... + is = new java.io.StringReader(body.toString ()); + try { + parser = new EcmaScript (is); + sl = (ASTStatementList) parser.StatementList(); + is.close(); + } catch (ParseException x) { + app.logEvent ("Error parsing file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+x); + throw new EcmaScriptParseException (x, new StringEvaluationSource(fulltext, null)); + } catch (Exception x) { + app.logEvent ("Error parsing file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+x); + throw new RuntimeException (x.getMessage ()); + } + + fes = new FunctionEvaluationSource (new StringEvaluationSource(fulltext, null), funcname); + return new ParsedFunction (fpl, sl, fes, fulltext, funcname); + } + + class ParsedFunction implements TypeUpdater { + + ASTFormalParameterList fpl = null; + ASTStatementList sl = null; + FunctionEvaluationSource fes = null; + String fullFunctionText = null; + String functionName; + + public ParsedFunction (ASTFormalParameterList fpl, ASTStatementList sl, FunctionEvaluationSource fes, + String fullFunctionText, String functionName) { + this.fpl = fpl; + this.sl = sl; + this.fes = fes; + this.fullFunctionText = fullFunctionText; + this.functionName = functionName; + } + + public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException { + + ObjectPrototype op = reval.getPrototype (prototype.getName()); + + EcmaScriptVariableVisitor vdvisitor = reval.evaluator.getVarDeclarationVisitor(); + Vector vnames = vdvisitor.processVariableDeclarations(sl, fes); + + FunctionPrototype fp = ConstructedFunctionObject.makeNewConstructedFunction ( + reval.evaluator, functionName, fes, + fullFunctionText, fpl.getArguments(), vnames, sl); + op.putHiddenProperty (functionName, fp); + } + + } + + class ErrorFeedback implements TypeUpdater { + + String functionName, errorMessage; + + public ErrorFeedback (String fname, String msg) { + functionName = fname; + errorMessage = msg; + } + + public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException { + + ObjectPrototype op = reval.getPrototype (prototype.getName ()); + + FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype (); + FunctionPrototype func = new ThrowException (functionName, reval.evaluator, fp, errorMessage); + op.putHiddenProperty (functionName, func); + + } + } + + class ThrowException extends BuiltinFunctionObject { + String message; + ThrowException (String name, Evaluator evaluator, FunctionPrototype fp, String message) { + super (fp, evaluator, name, 1); + this.message = message == null ? "No error message available" : message; + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + throw new EcmaScriptException (message); + } + public ESObject doConstruct (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + throw new EcmaScriptException (message); + } + } + + interface TypeUpdater { + public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException; + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/helma/scripting/FunctionFile.java b/src/helma/scripting/FunctionFile.java new file mode 100644 index 00000000..2b59c0b1 --- /dev/null +++ b/src/helma/scripting/FunctionFile.java @@ -0,0 +1,272 @@ +// FunctionFile.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + +package helma.scripting; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.HashSet; +import java.util.Enumeration; +import java.io.*; +import helma.framework.*; +import helma.framework.core.*; +import helma.util.Updatable; +import FESI.Data.*; +import FESI.Exceptions.EcmaScriptException; +import FESI.Interpreter.*; + + +/** + * This represents a File containing JavaScript functions for a given Object. + */ + + +public class FunctionFile implements Updatable { + + String name; + Prototype prototype; + Application app; + File file; + String content; + long lastmod; + + // a set of funcion names defined by this file. We keep this to be able to + // remove them once the file should get removed + HashSet declaredProps; + long declaredPropsTimestamp; + + public FunctionFile (File file, String name, Prototype proto) { + this.prototype = proto; + this.app = proto.getApplication (); + this.name = name; + this.file = file; + update (); + } + + /** + * Create a function file without a file, passing the code directly. This is used for + * files contained in zipped applications. The whole update mechanism is bypassed + * by immediately parsing the code. + */ + public FunctionFile (String body, String name, Prototype proto) { + this.prototype = proto; + this.app = proto.getApplication (); + this.name = name; + this.file = null; + this.content = body; + + Iterator evals = app.typemgr.getRegisteredRequestEvaluators (); + while (evals.hasNext ()) { + try { + + StringEvaluationSource es = new StringEvaluationSource (body, null); + StringReader reader = new StringReader (body); + + RequestEvaluator reval = (RequestEvaluator) evals.next (); + updateRequestEvaluator (reval, reader, es); + + } catch (Exception ignore) {} + } + + } + + /** + * Tell the type manager whether we need an update. this is the case when + * the file has been modified or deleted. + */ + public boolean needsUpdate () { + return lastmod != file.lastModified (); + } + + + public void update () { + + if (!file.exists ()) { + remove (); + + } else { + + lastmod = file.lastModified (); + // app.typemgr.readFunctionFile (file, prototype.getName ()); + + Iterator evals = app.typemgr.getRegisteredRequestEvaluators (); + while (evals.hasNext ()) { + try { + + RequestEvaluator reval = (RequestEvaluator) evals.next (); + FileReader fr = new FileReader(file); + EvaluationSource es = new FileEvaluationSource(file.getPath(), null); + updateRequestEvaluator (reval, fr, es); + + } catch (Throwable ignore) {} + } + } + + } + + + public synchronized void updateRequestEvaluator (RequestEvaluator reval) { + if (file != null) { + try { + FileReader fr = new FileReader (file); + EvaluationSource es = new FileEvaluationSource (file.getPath (), null); + updateRequestEvaluator (reval, fr, es); + } catch (Exception ignore) {} + } else { + StringReader reader = new StringReader (content); + StringEvaluationSource es = new StringEvaluationSource (content, null); + updateRequestEvaluator (reval, reader, es); + } + } + + public synchronized void updateRequestEvaluator (RequestEvaluator reval, Reader reader, EvaluationSource source) { + + HashMap priorProps = null; + HashSet newProps = null; + + try { + + ObjectPrototype op = reval.getPrototype (prototype.getName()); + + // extract all properties from prototype _before_ evaluation, so we can compare afterwards + // but only do this is declaredProps is not up to date yet + if (declaredPropsTimestamp != lastmod) { + priorProps = new HashMap (); + // remember properties before evaluation, so we can tell what's new afterwards + try { + for (Enumeration en=op.getAllProperties(); en.hasMoreElements(); ) { + String prop = (String) en.nextElement (); + priorProps.put (prop, op.getProperty (prop, prop.hashCode())); + } + } catch (Exception ignore) {} + } + + // do the update, evaluating the file + reval.evaluator.evaluate(reader, op, source, false); + + // check what's new + if (declaredPropsTimestamp != lastmod) try { + newProps = new HashSet (); + for (Enumeration en=op.getAllProperties(); en.hasMoreElements(); ) { + String prop = (String) en.nextElement (); + if (priorProps.get (prop) == null || op.getProperty (prop, prop.hashCode()) != priorProps.get (prop)) + newProps.add (prop); + } + } catch (Exception ignore) {} + + } catch (Exception e) { + // app.logEvent ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e); + app.logEvent ("Error parsing function file "+source+": "+e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException ignore) {} + } + + // now remove the props that were not refreshed, and set declared props to new collection + if (declaredPropsTimestamp != lastmod) { + declaredPropsTimestamp = lastmod; + if (declaredProps != null) { + declaredProps.removeAll (newProps); + removeProperties (declaredProps); + } + declaredProps = newProps; + // System.err.println ("DECLAREDPROPS = "+declaredProps); + } + + } + } + + + void remove () { + prototype.functions.remove (name); + prototype.updatables.remove (file.getName()); + + // if we did not add anything to any evaluator, we're done + if (declaredProps == null || declaredProps.size() == 0) + return; + + removeProperties (declaredProps); + } + + /** + * Remove the properties in the HashMap iff they're still the same as declared by this file. + * This method is called by remove() with the latest props, and by update with the prior props + * after the file has been reevaluated. + */ + void removeProperties (HashSet props) { + // first loop through other function files in this prototype to make a set of properties + // owned by other files. + HashSet otherFiles = new HashSet (); + for (Iterator it=prototype.functions.values ().iterator (); it.hasNext (); ) { + FunctionFile other = (FunctionFile) it.next (); + if (other != this && other.declaredProps != null) + otherFiles.addAll (other.declaredProps); + } + + Iterator evals = app.typemgr.getRegisteredRequestEvaluators (); + while (evals.hasNext ()) { + try { + RequestEvaluator reval = (RequestEvaluator) evals.next (); + ObjectPrototype op = reval.getPrototype (prototype.getName()); + for (Iterator it = props.iterator (); it.hasNext (); ) { + String fname = (String) it.next (); + // check if this property has been declared by some other function file in the meantime + if (otherFiles.contains (fname)) + continue; + op.deleteProperty (fname, fname.hashCode()); + // System.err.println ("REMOVING PROP: "+fname); + } + } catch (Exception ignore) {} + } + } + + public String toString () { + if (file == null) + return "[Zipped script file]"; + else + return prototype.getName()+"/"+file.getName(); + } + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/helma/scripting/ScriptingEnvironment.java b/src/helma/scripting/ScriptingEnvironment.java new file mode 100644 index 00000000..4c75bc93 --- /dev/null +++ b/src/helma/scripting/ScriptingEnvironment.java @@ -0,0 +1,60 @@ +// ScriptingEnvironment.java +// Copyright (c) Hannes Wallnöfer 1998-2001 + +package helma.scripting; + + +import java.util.*; + + +/** + * This is the interface that must be implemented to make a scripting environment + * usable by the Helma application server. + */ +public interface ScriptingEnvironment { + + /** + * Initialize the environment using the given properties + */ + public void init (Properties props) throws ScriptingException; + + + /** + * Invoke a function on some object, using the given arguments and global vars. + */ + public Object invoke (Object thisObject, Object[] args, HashMap globals) throws ScriptingException; + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/helma/scripting/ScriptingException.java b/src/helma/scripting/ScriptingException.java new file mode 100644 index 00000000..d738013b --- /dev/null +++ b/src/helma/scripting/ScriptingException.java @@ -0,0 +1,52 @@ +// ScriptingException.java +// Copyright (c) Hannes Wallnöfer 1998-2001 + +package helma.scripting; + + +/** + * The base class for exceptions thrown by Helma scripting package + */ +public class ScriptingException extends Exception { + + /** + * Construct a ScriptingException given an error message + */ + public ScriptingException (String msg) { + super (msg); + } + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/helma/scripting/Template.java b/src/helma/scripting/Template.java new file mode 100644 index 00000000..6aa4c76e --- /dev/null +++ b/src/helma/scripting/Template.java @@ -0,0 +1,257 @@ +// Template.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + +package helma.scripting; + +import java.io.*; +import java.util.Vector; +import java.util.Iterator; +import java.util.StringTokenizer; +import helma.framework.*; +import helma.framework.core.*; +import FESI.Data.*; +import FESI.Exceptions.*; + + +/** + * This represents a Helma template, i.e. a file with the extension .hsp + * (Helma server page) that contains both parts that are to be evaluated + * as EcmaScript and parts that are to be delivered to the client as-is. + * Internally, templates are regular functions. + * Helma templates are callable via URL, but this is just a leftover from the + * days when there were no .hac (action) files. The recommended way + * now is to have a .hac file with all the logic which in turn calls one or more + * template files to do the formatting. + */ + +public class Template extends Action { + + // this is the *_as_string function, which is in addition to the normal one + TypeUpdater psfunc; + + + public Template (File file, String name, Prototype proto) { + super (file, name, proto); + } + + + public void update (String content) throws Exception { + // IServer.getLogger().log ("Reading text template " + name); + + Vector partBuffer = new Vector (); + int l = content.length (); + char cnt[] = new char[l]; + content.getChars (0, l, cnt, 0); + + // if last charackter is whitespace, swallow it. this is necessary for some inner templates to look ok. + if (Character.isWhitespace (cnt[l-1])) + l -= 1; + + int lastIdx = 0; + for (int i = 0; i < l-1; i++) { + if (cnt[i] == '<' && cnt[i+1] == '%') { + int j = i+2; + while (j < l-1 && (cnt[j] != '%' || cnt[j+1] != '>')) { + j++; + } + if (j > i+2) { + if (i - lastIdx > 0) + partBuffer.addElement (new Part (this, new String (cnt, lastIdx, i - lastIdx), true)); + String script = new String (cnt, i+2, (j-i)-2); + partBuffer.addElement (new Part (this, script, false)); + lastIdx = j+2; + } + i = j+1; + } + } + if (lastIdx < l) + partBuffer.addElement (new Part (this, new String (cnt, lastIdx, l - lastIdx), true)); + + StringBuffer templateBody = new StringBuffer (); + int nparts = partBuffer.size(); + + for (int k = 0; k < nparts; k++) { + Part nextPart = (Part) partBuffer.elementAt (k); + + if (nextPart.isStatic || nextPart.content.trim ().startsWith ("=")) { + // check for <%= ... %> statements + if (!nextPart.isStatic) { + nextPart.content = nextPart.content.trim ().substring (1).trim (); + // cut trailing ";" + while (nextPart.content.endsWith (";")) + nextPart.content = nextPart.content.substring (0, nextPart.content.length()-1); + } + + StringTokenizer st = new StringTokenizer (nextPart.content, "\r\n", true); + String nextLine = st.hasMoreTokens () ? st.nextToken () : null; + + // count newLines we "swallow", see explanation below + int newLineCount = 0; + + templateBody.append ("res.write ("); + if (nextPart.isStatic) { + templateBody.append ("\""); + } + + while (nextLine != null) { + + if ("\n".equals (nextLine)) { + // append a CRLF + newLineCount++; + templateBody.append ("\\r\\n"); + } else if (!"\r".equals (nextLine)){ + StringReader lineReader = new StringReader (nextLine); + int c = lineReader.read (); + while (c > -1) { + if (nextPart.isStatic && ((char)c == '"' || (char)c == '\\')) { + templateBody.append ('\\'); + } + templateBody.append ((char) c); + c = lineReader.read (); + } + } + + nextLine = st.hasMoreTokens () ? st.nextToken () : null; + + } + + if (nextPart.isStatic) { + templateBody.append ("\""); + } + + templateBody.append ("); "); + + // append the number of lines we have "swallowed" into + // one write statement, so error messages will *approximately* + // give correct line numbers. + for (int i=0; i"; + return node.toString (); + } + + public String toDetailString () { + return "ES:[Object: builtin " + this.getClass().getName() + ":" + + ((node == null) ? "null" : node.toString()) + "]"; + } + + protected void setError (Throwable e) { + lastError = e; + } + + + public boolean add (ESValue what[]) { + checkNode (); + for (int i=0; i 2) + return false; + if (!(pval[0] instanceof ESNode)) + return false; + ESNode esn = (ESNode) pval[0]; + INode pn = esn.getNode (); + if (!(pn instanceof helma.objectmodel.db.Node)) + return false; + // check if there is an additional string element - if so, it's the property name by which the node is + // accessed, otherwise it will be accessed as anonymous subnode via its id + String propname = null; + if (pval.length == 2 && pval[1] != null && !(pval[1] instanceof ESNull)) + propname = pval[1].toString (); + helma.objectmodel.db.Node n = (helma.objectmodel.db.Node) node; + n.setParent ((helma.objectmodel.db.Node) pn, propname); + return true; + } + + + public void putProperty(String propertyName, ESValue propertyValue, int hash) throws EcmaScriptException { + checkNode (); + // eval.app.logEvent ("put property called: "+propertyName+", "+propertyValue.getClass()); + if (/* "lastmodified".equalsIgnoreCase (propertyName) || "created".equalsIgnoreCase (propertyName) || */ + "cache".equalsIgnoreCase (propertyName)) + throw new EcmaScriptException ("Can't modify read-only property \""+propertyName+"\"."); + + if ("subnodeRelation".equalsIgnoreCase (propertyName)) { + node.setSubnodeRelation (propertyValue instanceof ESNull ? null : propertyValue.toString ()); + return; + } + + if (propertyValue instanceof ESNull) + node.unset (propertyName); + else if (propertyValue instanceof ESString) + node.setString (propertyName, propertyValue.toString ()); + else if (propertyValue instanceof ESBoolean) + node.setBoolean (propertyName, propertyValue.booleanValue ()); + else if (propertyValue instanceof ESNumber) + node.setFloat (propertyName, propertyValue.doubleValue ()); + else if (propertyValue instanceof DatePrototype) + node.setDate (propertyName, (Date) propertyValue.toJavaObject ()); + else if (propertyValue instanceof ESNode) { + // long now = System.currentTimeMillis (); + ESNode esn = (ESNode) propertyValue; + node.setNode (propertyName, esn.getNode ()); + // eval.app.logEvent ("*** spent "+(System.currentTimeMillis () - now)+" ms to set property "+propertyName); + } else { + // eval.app.logEvent ("got "+propertyValue.getClass ()); + // A persistent node can't store anything other than the types above, so throw an exception + // throw new EcmaScriptException ("Can't set a JavaScript Object or Array as property of "+node); + node.setJavaObject (propertyName, propertyValue.toJavaObject ()); + } + } + + public boolean deleteProperty(String propertyName, int hash) throws EcmaScriptException { + checkNode (); + // eval.app.logEvent ("delete property called: "+propertyName); + if (node.get (propertyName, false) != null) { + node.unset (propertyName); + return true; + } + return super.deleteProperty (propertyName, hash); + } + + public ESValue getProperty (int i) throws EcmaScriptException { + checkNode (); + INode n = node.getSubnodeAt (i); + if (n == null) + return ESNull.theNull; + return eval.getNodeWrapper (n); + } + + public void putProperty(int index, ESValue propertyValue) throws EcmaScriptException { + checkNode (); + if (propertyValue instanceof ESNode) { + ESNode n = (ESNode) propertyValue; + node.addNode (n.getNode (), index); + } else + throw new EcmaScriptException ("Can only add Nodes to Node arrays"); + } + + + public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException { + checkNode (); + // eval.app.logEvent ("get property called: "+propertyName); + ESValue retval = super.getProperty (propertyName, hash); + if (! (retval instanceof ESUndefined)) + return retval; + + // persistent or persistent capable nodes have a cache property that's a transient node. + // it it hasn't requested before, initialize it now + if ("cache".equalsIgnoreCase (propertyName) && node instanceof Node) { + if (cacheWrapper == null) { + cache = node.getCacheNode (); + cacheWrapper = new ESNode (cache, eval); + } + return cacheWrapper; + } + if ("subnodeRelation".equalsIgnoreCase (propertyName)) { + String rel = node.getSubnodeRelation (); + return rel == null ? (ESValue) ESNull.theNull : new ESString (rel); + } + + if ("_id".equals (propertyName)) + return new ESString (node.getID ()); + if ("_parent".equals (propertyName)) { + INode n = node.getParent (); + if (n != null) + return eval.getNodeWrapper (n); + else + return ESNull.theNull; + } + + // this is not very nice, but as a hack we return the id of a node as node.__id__ + if (propertyName.startsWith ("__") && propertyName.endsWith ("__")) + return getInternalProperty (propertyName); + + // this _may_ do a relational query if properties are mapped to a relational type. + IProperty p = node.get (propertyName, false); + if (p != null) { + if (p.getType () == IProperty.STRING) { + String str = p.getStringValue (); + if (str == null) + return ESNull.theNull; + else + return new ESString (str); + } + if (p.getType () == IProperty.BOOLEAN) + return ESBoolean.makeBoolean (p.getBooleanValue ()); + if (p.getType () == IProperty.DATE) + return new DatePrototype (evaluator, p.getDateValue ()); + if (p.getType () == IProperty.INTEGER) + return new ESNumber ((double) p.getIntegerValue ()); + if (p.getType () == IProperty.FLOAT) + return new ESNumber (p.getFloatValue ()); + if (p.getType () == IProperty.NODE) { + INode nd = p.getNodeValue (); + if (nd == null) + return ESNull.theNull; + else + return eval.getNodeWrapper (nd); + } + if (p.getType () == IProperty.JAVAOBJECT) + return ESLoader.normalizeObject (p.getJavaObjectValue (), evaluator); + } + + // these are predefined + // if ("created".equalsIgnoreCase (propertyName)) + // return new DatePrototype (evaluator, node.created ()); + // if ("lastmodified".equalsIgnoreCase (propertyName)) + // return new DatePrototype (evaluator, node.lastModified ()); + + // as last resort, try to get property as anonymous subnode + INode anon = node.getSubnode (propertyName); + if (anon != null) + return eval.getNodeWrapper (anon); + + return ESNull.theNull; + } + + private ESValue getInternalProperty (String propertyName) throws EcmaScriptException { + if ("__id__".equalsIgnoreCase (propertyName)) { + return new ESString (node.getID ()); + } + if ("__prototype__".equalsIgnoreCase (propertyName)) { + String p = node.getPrototype (); + if (p == null) + return ESNull.theNull; + else + return new ESString (node.getPrototype ()); + } + // some more internal properties + if ("__parent__".equals (propertyName)) { + INode n = node.getParent (); + if (n == null) + return ESNull.theNull; + else + return eval.getNodeWrapper (n); + } + if ("__name__".equals (propertyName)) + return new ESString (node.getName ()); + if ("__fullname__".equals (propertyName)) + return new ESString (node.getFullName ()); + if ("__hash__".equals (propertyName)) + return new ESString (""+node.hashCode ()); + if ("__node__".equals (propertyName)) + return new ESWrapper (node, evaluator); + if ("__created__".equalsIgnoreCase (propertyName)) + return new DatePrototype (evaluator, node.created ()); + if ("__lastmodified__".equalsIgnoreCase (propertyName)) + return new DatePrototype (evaluator, node.lastModified ()); + + return ESNull.theNull; + } + + public Enumeration getAllProperties () { + return getProperties (); + } + + public Enumeration getProperties () { + checkNode (); + return node.properties (); + } + + + public String error() { + if (lastError == null) { + return ""; + } else { + String exceptionName = lastError.getClass().getName(); + int l = exceptionName.lastIndexOf("."); + if (l>0) exceptionName = exceptionName.substring(l+1); + return exceptionName +": " + lastError.getMessage(); + } + } + + 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! + */ + public boolean equals (Object what) { + if (what == null) + return false; + if (what == this) + return true; + if (what instanceof ESNode) { + ESNode other = (ESNode) what; + if (handle != null) + return handle.equals (other.handle); + else + return (node == other.node); + } + return false; + } + +} // class ESNode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/helma/scripting/fesi/ESRequestData.java b/src/helma/scripting/fesi/ESRequestData.java new file mode 100644 index 00000000..86bffd04 --- /dev/null +++ b/src/helma/scripting/fesi/ESRequestData.java @@ -0,0 +1,129 @@ +// ESRequestData.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + + +package helma.scripting.fesi; + +import helma.framework.core.*; +import helma.objectmodel.INode; +import FESI.Data.*; +import FESI.Exceptions.*; +import FESI.Interpreter.Evaluator; +import java.util.Hashtable; +import java.util.Enumeration; + + + +/** + * An EcmaScript object that makes stuff in a hashtable accessible as its properties + */ + +public class ESRequestData extends ESWrapper { + + private Hashtable data; + private RequestEvaluator reval; + + public ESRequestData (RequestEvaluator reval) { + super (new Object(), reval.evaluator); + this.reval = reval; + } + + public void setData (Hashtable data) { + this.data = data; + } + + /** + * Overridden to make the object read-only + */ + public void putProperty(String propertyName, ESValue propertyValue, int hash) throws EcmaScriptException { + throw new EcmaScriptException ("Can't set property, object is read-only"); + } + + public boolean deleteProperty(String propertyName, int hash) throws EcmaScriptException { + throw new EcmaScriptException ("Can't delete property, object is read-only"); + } + + public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException { + if (data == null) + return ESNull.theNull; + + Object val = data.get (propertyName); + + if (val == null) + return ESNull.theNull; + + if (val instanceof String) + return new ESString ((String) val); + else if (val instanceof INode) + return reval.getNodeWrapper ((INode) val); + + return ESLoader.normalizeValue(val, evaluator); + } + + + public Enumeration getAllProperties () { + return getProperties (); + } + + public Enumeration getProperties () { + if (data == null) + return new Hashtable().keys(); + return data.keys(); + } + + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/helma/scripting/fesi/ESUser.java b/src/helma/scripting/fesi/ESUser.java new file mode 100644 index 00000000..4cfc9e82 --- /dev/null +++ b/src/helma/scripting/fesi/ESUser.java @@ -0,0 +1,141 @@ +// ESUser.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + +package helma.scripting.fesi; + +import helma.framework.core.*; +import helma.objectmodel.*; +import FESI.Interpreter.*; +import FESI.Exceptions.*; +import FESI.Data.*; + +/** + * The ESUser is a special kind of Node object that represents a user of + * a HOP application. The actual user session data are kept in class User. + * If the user is logged in as a registered member, the wrapped node represents + * the user object in the database, while for anonymous surfers the node object + * is just a transient node.

+ * This means that the wrapped node will be swapped when the user logs in or out. + * To save session state across logins and logouts, the + * cache property of the user object stays the same for the whole time the user + * spends on this site. + */ + +public class ESUser extends ESNode { + + /** if the user is online, this is his/her online session object */ + public User user; + + public ESUser (INode node, RequestEvaluator eval, User user) { + super (eval.esUserPrototype, eval.evaluator, node, eval); + this.user = user; + if (user != null) { + cache = user.getCache (); + cacheWrapper = new ESNode (cache, eval); + } + } + + /** + * Overrides getProperty to return the uid (which is not a regular property) + */ + public ESValue getProperty (String propname, int hash) throws EcmaScriptException { + if ("uid".equals (propname)) { + if (user == null || user.getUID () == null) + return ESNull.theNull; + else + return new ESString (user.getUID ()); + } + if ("sessionID".equals (propname)) { + if (user == null || user.getSessionID () == null) + return ESNull.theNull; + else + return new ESString (user.getSessionID ()); + } + if ("cache".equals (propname)) + return cacheWrapper; + return super.getProperty (propname, hash); + } + + + /** + * The node for a user object changes at login and logout, so we don't use our + * own node, but just reach through to the session user object instead. + */ + public void setNode (INode node) { + user.setNode (node); + if (node != null) { + this.node = node; + } else { + // user.getNode will never return null. If the node is set to null (=user logged out) + // it will user the original transient cache node again. + this.node = user.getNode (); + } + // set node handle to wrapped node + if (node instanceof helma.objectmodel.db.Node) + handle = ((helma.objectmodel.db.Node) node).getHandle (); + else + handle = null; + // we don't take over the transient cache from the node, + // because we always stick to the one from the user object. + } + + public void updateNodeFromUser () { + node = user.getNode (); + // set node handle to wrapped node + if (node instanceof helma.objectmodel.db.Node) + handle = ((helma.objectmodel.db.Node) node).getHandle (); + else + handle = null; + + } + + public String toString () { + return ("UserObject "+node.getName ()); + } + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/helma/scripting/fesi/HopExtension.java b/src/helma/scripting/fesi/HopExtension.java new file mode 100644 index 00000000..ebb1c3e8 --- /dev/null +++ b/src/helma/scripting/fesi/HopExtension.java @@ -0,0 +1,1162 @@ +// HopExtension.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + +package helma.scripting.fesi; + +import helma.framework.core.*; +import helma.objectmodel.*; +import helma.util.*; +import helma.framework.IPathElement; +import FESI.Interpreter.*; +import FESI.Exceptions.*; +import FESI.Extensions.*; +import FESI.Data.*; +import java.io.*; +import java.util.Hashtable; +import java.util.Enumeration; +import java.util.TimeZone; +import java.util.Date; +import java.text.*; +import org.xml.sax.InputSource; + +/** + * This is the basic Extension for FESI interpreters used in HOP. It sets up + * varios constructors, global functions and properties etc. + */ + +public class HopExtension { + + protected Application app; + protected RequestEvaluator reval; + + public HopExtension () { + super(); + } + + + /** + * Called by the evaluator after the extension is loaded. + */ + public void initializeExtension (RequestEvaluator reval) throws EcmaScriptException { + + this.reval = reval; + this.app = reval.app; + Evaluator evaluator = reval.evaluator; + GlobalObject go = evaluator.getGlobalObject(); + FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype(); + + ESObject op = evaluator.getObjectPrototype(); + + ////////// The editor functions for String, Boolean and Number are deprecated! + ESObject sp = evaluator.getStringPrototype (); + sp.putHiddenProperty ("editor", new StringEditor ("editor", evaluator, fp)); + ESObject np = evaluator.getNumberPrototype (); + np.putHiddenProperty ("editor", new NumberEditor ("editor", evaluator, fp)); + np.putHiddenProperty ("format", new NumberPrototypeFormat ("format", evaluator, fp)); + ESObject bp = evaluator.getBooleanPrototype (); + bp.putHiddenProperty ("editor", new BooleanEditor ("editor", evaluator, fp)); + ESObject dp = evaluator.getDatePrototype (); + dp.putHiddenProperty ("format", new DatePrototypeFormat ("format", evaluator, fp)); + + reval.esNodePrototype = new ObjectPrototype(op, evaluator); // the Node prototype + + reval.esUserPrototype = new ObjectPrototype (reval.esNodePrototype, evaluator); // the User prototype + + ESObject node = new NodeConstructor ("Node", fp, reval); // the Node constructor + + // register the default methods of Node objects in the Node prototype + reval.esNodePrototype.putHiddenProperty ("add", new NodeAdd ("add", evaluator, fp)); + reval.esNodePrototype.putHiddenProperty ("addAt", new NodeAddAt ("addAt", evaluator, fp)); + reval.esNodePrototype.putHiddenProperty ("remove", new NodeRemove ("remove", evaluator, fp)); + reval.esNodePrototype.putHiddenProperty ("link", new NodeLink ("link", evaluator, fp)); + reval.esNodePrototype.putHiddenProperty ("list", new NodeList ("list", evaluator, fp)); + reval.esNodePrototype.putHiddenProperty ("set", new NodeSet ("set", evaluator, fp)); + reval.esNodePrototype.putHiddenProperty ("get", new NodeGet ("get", evaluator, fp)); + reval.esNodePrototype.putHiddenProperty ("count", new NodeCount ("count", evaluator, fp)); + reval.esNodePrototype.putHiddenProperty ("contains", new NodeContains ("contains", evaluator, fp)); + reval.esNodePrototype.putHiddenProperty ("size", new NodeCount ("size", evaluator, fp)); + 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 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)); + reval.esNodePrototype.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false)); + reval.esNodePrototype.putHiddenProperty("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true)); + + // methods that give access to properties and global user lists + go.putHiddenProperty("Node", node); // register the constructor for a plain Node object. + go.putHiddenProperty("HopObject", node); // HopObject is the new name for node. + go.putHiddenProperty("getProperty", new GlobalGetProperty ("getProperty", evaluator, fp)); + go.putHiddenProperty("token", new GlobalGetProperty ("token", evaluator, fp)); + go.putHiddenProperty("getUser", new GlobalGetUser ("getUser", evaluator, fp)); + go.putHiddenProperty("getUserBySession", new GlobalGetUserBySession ("getUserBySession", evaluator, fp)); + go.putHiddenProperty("getAllUsers", new GlobalGetAllUsers ("getAllUsers", evaluator, fp)); + go.putHiddenProperty("getActiveUsers", new GlobalGetActiveUsers ("getActiveUsers", evaluator, fp)); + go.putHiddenProperty("countActiveUsers", new GlobalCountActiveUsers ("countActiveUsers", evaluator, fp)); + go.putHiddenProperty("isActive", new GlobalIsActive ("isActive", evaluator, fp)); + go.putHiddenProperty("getAge", new GlobalGetAge ("getAge", evaluator, fp)); + go.putHiddenProperty("getURL", new GlobalGetURL ("getURL", evaluator, fp)); + go.putHiddenProperty("encode", new GlobalEncode ("encode", evaluator, fp)); + go.putHiddenProperty("encodeXml", new GlobalEncodeXml ("encodeXml", evaluator, fp)); + go.putHiddenProperty("encodeForm", new GlobalEncodeForm ("encodeForm", evaluator, fp)); + go.putHiddenProperty("format", new GlobalFormat ("format", evaluator, fp)); + go.putHiddenProperty("stripTags", new GlobalStripTags ("stripTags", evaluator, fp)); + go.putHiddenProperty("getXmlDocument", new GlobalGetXmlDocument ("getXmlDocument", evaluator, fp)); + go.putHiddenProperty("getHtmlDocument", new GlobalGetHtmlDocument ("getHtmlDocument", evaluator, fp)); + go.putHiddenProperty("jdomize", new GlobalJDOM ("jdomize", evaluator, fp)); + go.putHiddenProperty("getSkin", new GlobalCreateSkin ("getSkin", evaluator, fp)); + go.putHiddenProperty("createSkin", new GlobalCreateSkin ("createSkin", evaluator, fp)); + go.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, true, false)); + go.putHiddenProperty("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, true, true)); + go.putHiddenProperty("authenticate", new GlobalAuthenticate ("authenticate", evaluator, fp)); + go.deleteProperty("exit", "exit".hashCode()); + + // and some methods for session management from JS... + reval.esUserPrototype.putHiddenProperty("logon", new UserLogin ("logon", evaluator, fp)); + reval.esUserPrototype.putHiddenProperty("login", new UserLogin ("login", evaluator, fp)); + reval.esUserPrototype.putHiddenProperty("register", new UserRegister ("register", evaluator, fp)); + reval.esUserPrototype.putHiddenProperty("logout", new UserLogout ("logout", evaluator, fp)); + reval.esUserPrototype.putHiddenProperty("onSince", new UserOnSince ("onSince", evaluator, fp)); + reval.esUserPrototype.putHiddenProperty("lastActive", new UserLastActive ("lastActive", evaluator, fp)); + reval.esUserPrototype.putHiddenProperty("touch", new UserTouch ("touch", evaluator, fp)); + + } + + class NodeAdd extends BuiltinFunctionObject { + NodeAdd (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode node = (ESNode) thisObject; + return ESBoolean.makeBoolean (node.add (arguments)); + } + } + + class NodeAddAt extends BuiltinFunctionObject { + NodeAddAt (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode node = (ESNode) thisObject; + return ESBoolean.makeBoolean (node.addAt (arguments)); + } + } + + class NodeRemove extends BuiltinFunctionObject { + NodeRemove (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode node = (ESNode) thisObject; + return ESBoolean.makeBoolean (node.remove (arguments)); + } + } + + + class NodeLink extends BuiltinFunctionObject { + NodeLink (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode node = (ESNode) thisObject; + return ESBoolean.makeBoolean (node.link (arguments)); + } + } + + class NodeList extends BuiltinFunctionObject { + NodeList (String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 0); + } + public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode node = (ESNode) thisObject; + return node.list (); + } + } + + class NodeGet extends BuiltinFunctionObject { + NodeGet (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESValue esv = null; + if (arguments[0].isNumberValue ()) { + int i = arguments[0].toInt32 (); + esv = thisObject.getProperty (i); + } else { + String name = arguments[0].toString (); + esv = thisObject.getProperty (name, name.hashCode ()); + } + return (esv); + } + } + + class NodeSet extends BuiltinFunctionObject { + NodeSet (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode esn = (ESNode) thisObject; + if (arguments[0].isNumberValue ()) { + return ESBoolean.makeBoolean (esn.addAt (arguments)); + } else { + String propname = arguments[0].toString (); + esn.putProperty (propname, arguments[1], propname.hashCode ()); + } + return ESBoolean.makeBoolean (true); + } + } + + class NodeCount extends BuiltinFunctionObject { + NodeCount (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + INode node = ((ESNode) thisObject).getNode (); + return new ESNumber ((double) node.numberOfNodes ()); + } + } + + class NodeContains extends BuiltinFunctionObject { + NodeContains (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode node = (ESNode) thisObject; + return new ESNumber (node.contains (arguments)); + } + } + + + class NodeInvalidate extends BuiltinFunctionObject { + NodeInvalidate (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 0); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode esn = (ESNode) thisObject; + INode node = esn.getNode (); + if (node instanceof helma.objectmodel.db.Node) { + ((helma.objectmodel.db.Node) node).invalidate (); + esn.checkNode (); + } + return ESBoolean.makeBoolean (true); + } + } + + + class NodeEditor extends BuiltinFunctionObject { + + NodeEditor (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 1) + throw new EcmaScriptException ("Missing argument for Node.editor(): Name of property to be edited."); + String propName = arguments[0].toString (); + ESValue propValue = thisObject.getProperty (propName, propName.hashCode ()); + if (propValue.isBooleanValue ()) + return (booleanEditor (thisObject, propName, propValue, arguments)); + if (propValue.isNumberValue ()) + return (numberEditor (thisObject, propName, propValue, arguments)); + if (propValue instanceof DatePrototype) + return (dateEditor (thisObject, propName, propValue, arguments)); + return (stringEditor (thisObject, propName, propValue, arguments)); + } + + public ESValue stringEditor (ESObject thisObject, String propName, ESValue propValue, ESValue[] arguments) + throws EcmaScriptException { + String value = null; + if (propValue == null || ESNull.theNull == propValue || ESUndefined.theUndefined == propValue) + value = ""; + else + value = HtmlEncoder.encodeFormValue (propValue.toString ()); + if (arguments.length == 2 && arguments[1].isNumberValue ()) + return new ESString (""); + else if (arguments.length == 3 && arguments[1].isNumberValue () && arguments[2].isNumberValue ()) + return new ESString (""); + return new ESString (""); + } + + public ESValue dateEditor (ESObject thisObject, String propName, ESValue propValue, ESValue[] arguments) + throws EcmaScriptException { + Date date = (Date) propValue.toJavaObject (); + DateFormat fmt = arguments.length > 1 ? new SimpleDateFormat (arguments[1].toString ()) : new SimpleDateFormat (); + return new ESString (""); + } + + public ESValue numberEditor (ESObject thisObject, String propName, ESValue propValue, ESValue[] arguments) + throws EcmaScriptException { + ESNumber esn = (ESNumber) propValue.toESNumber (); + double value = esn.doubleValue (); + if (arguments.length == 3 && arguments[1].isNumberValue () && arguments[2].isNumberValue ()) + return new ESString (getNumberChoice (propName, arguments[1].toInt32 (), arguments[2].toInt32 (), 1, value)); + else if (arguments.length == 4 && arguments[1].isNumberValue () && arguments[2].isNumberValue () && arguments[3].isNumberValue ()) + return new ESString (getNumberChoice (propName, arguments[1].doubleValue (), arguments[2].doubleValue (), arguments[3].doubleValue (), value)); + DecimalFormat fmt = new DecimalFormat (); + if (arguments.length == 2 && arguments[1].isNumberValue ()) + return new ESString (""); + else + return new ESString (""); + } + + public ESValue booleanEditor (ESObject thisObject, String propName, ESValue propValue, ESValue[] arguments) + throws EcmaScriptException { + ESBoolean esb = (ESBoolean) propValue.toESBoolean (); + String value = esb.toString (); + if (arguments.length < 2) { + String retval = ""); + return new ESString (retval.toString ()); + } + } + + + class StringEditor extends BuiltinFunctionObject { + StringEditor (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + throw (new EcmaScriptException ("String.editor() wird nicht mehr unterstuetzt. Statt node.strvar.editor(...) kann node.editor(\"strvar\", ...) verwendet werden.")); + } + } + + class NumberEditor extends BuiltinFunctionObject { + NumberEditor (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + throw (new EcmaScriptException ("Number.editor() wird nicht mehr unterstuetzt. Statt node.nvar.editor(...) kann node.editor(\"nvar\", ...) verwendet werden.")); + } + } + + class BooleanEditor extends BuiltinFunctionObject { + BooleanEditor (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + throw (new EcmaScriptException ("Boolean.editor() wird nicht mehr unterstuetzt. Statt node.boolvar.editor(...) kann node.editor(\"boolvar\", ...) verwendet werden.")); + } + } + + // previously in FESI.Data.DateObject + class DatePrototypeFormat extends BuiltinFunctionObject { + DatePrototypeFormat(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 0); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + DatePrototype aDate = (DatePrototype) thisObject; + + DateFormat df = arguments.length > 0 ? + new SimpleDateFormat (arguments[0].toString ()) : + new SimpleDateFormat (); + df.setTimeZone(TimeZone.getDefault()); + return (aDate.toJavaObject() == null) ? + new ESString(""): + new ESString(df.format((Date) aDate.toJavaObject())); + } + } + + // previously in FESI.Data.NumberObject + private Hashtable formatTable = new Hashtable (); + class NumberPrototypeFormat extends BuiltinFunctionObject { + NumberPrototypeFormat(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 0); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESObject aNumber = (ESObject) thisObject; + String fstr = "#,##0.00"; + if (arguments.length >= 1) + fstr = arguments[0].toString (); + DecimalFormat df = (DecimalFormat) formatTable.get (fstr); + if (df == null) { + df = new DecimalFormat (fstr); + formatTable.put (fstr, df); + } + return new ESString(df.format(aNumber.doubleValue ())); + } + } + + class NodeChooser extends BuiltinFunctionObject { + NodeChooser (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode esn = (ESNode) thisObject; + if (arguments.length < 1) { + return ESBoolean.makeBoolean(false); + } + String nodename = arguments[0].toString (); + INode target = esn.getNode ().getNode (nodename, false); + ESNode collection = arguments.length > 1 ? (ESNode) arguments[1] : esn; + if (arguments.length > 2) + return new ESString (getNodeChooserDD (nodename, collection.getNode (), target, arguments[2].toString ())); + else + return new ESString (getNodeChooserRB (nodename, collection.getNode (), target)); + } + } + + class MultiNodeChooser extends BuiltinFunctionObject { + MultiNodeChooser (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode esn = (ESNode) thisObject; + if (arguments.length < 1) { + return ESBoolean.makeBoolean(false); + } + String nodename = arguments[0].toString (); + INode thisNode = esn.getNode (); + INode target = thisNode.getNode (nodename, false); + if (target == null) { + target = thisNode.createNode (nodename); + } + ESNode collection = arguments.length > 1 ? (ESNode) arguments[1] : esn; + return new ESString (getNodeChooserCB (nodename, collection.getNode (), target)); + } + } + + class UserLogin extends BuiltinFunctionObject { + UserLogin (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 2) + return ESBoolean.makeBoolean(false); + ESUser u = (ESUser) thisObject; + if (u.user == null) + throw new EcmaScriptException ("login() can only be called for user objects that are online at the moment!"); + boolean success = app.loginUser (arguments[0].toString (), arguments[1].toString (), u); + try { + u.doIndirectCall (this.evaluator, u, "onLogin", new ESValue[0]); + } catch (Exception nosuch) {} + return ESBoolean.makeBoolean (success); + } + } + + class UserRegister extends BuiltinFunctionObject { + UserRegister (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 2); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 2) + return ESBoolean.makeBoolean(false); + INode unode = app.registerUser (arguments[0].toString (), arguments[1].toString ()); + if (unode == null) + return ESNull.theNull; + else + return reval.getNodeWrapper (unode); + } + } + + class UserLogout extends BuiltinFunctionObject { + UserLogout (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESUser u = (ESUser) thisObject; + if (u.user == null) + return ESBoolean.makeBoolean (true); + try { + u.doIndirectCall (this.evaluator, u, "onLogout", new ESValue[0]); + } catch (Exception nosuch) {} + return ESBoolean.makeBoolean (app.logoutUser (u)); + } + } + + class UserOnSince extends BuiltinFunctionObject { + UserOnSince (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESUser u = (ESUser) thisObject; + if (u.user == null) + throw new EcmaScriptException ("onSince() can only be called for users that are online at the moment!"); + DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.onSince ())); + return date; + } + } + + class UserLastActive extends BuiltinFunctionObject { + UserLastActive (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESUser u = (ESUser) thisObject; + if (u.user == null) + throw new EcmaScriptException ("lastActive() can only be called for users that are online at the moment!"); + DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.lastTouched ())); + return date; + } + } + + class UserTouch extends BuiltinFunctionObject { + UserTouch (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESUser u = (ESUser) thisObject; + if (u.user != null) + u.user.touch (); + return ESNull.theNull; + } + } + + class GlobalGetProperty extends BuiltinFunctionObject { + GlobalGetProperty (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length == 0) + return new ESString (""); + String defval = (arguments.length > 1) ? arguments[1].toString () : ""; + return new ESString (app.getProperty (arguments[0].toString (), defval)); + + } + } + + class GlobalAuthenticate extends BuiltinFunctionObject { + GlobalAuthenticate (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length != 2) + return ESBoolean.makeBoolean (false); + return ESBoolean.makeBoolean (app.authenticate (arguments[0].toString (), arguments[1].toString ())); + + } + } + + /** + * Get a parsed Skin from an app-managed skin text + */ + class GlobalCreateSkin extends BuiltinFunctionObject { + GlobalCreateSkin (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length != 1 || ESNull.theNull.equals (arguments[0])) + throw new EcmaScriptException ("createSkin must be called with one String argument"); + String str = arguments[0].toString (); + Skin skin = new Skin (str, app); + return new ESWrapper (skin, evaluator); + } + } + + /** + * Render a skin + */ + class RenderSkin extends BuiltinFunctionObject { + boolean global; + boolean asString; + RenderSkin (String name, Evaluator evaluator, FunctionPrototype fp, boolean global, boolean asString) { + super (fp, evaluator, name, 1); + this.global = global; + this.asString = asString; + } + 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; + ESObject thisObject = global ? null : thisObj; + ESObject paramObject = null; + if (arguments.length > 1 && arguments[1] instanceof ESObject) + paramObject = (ESObject) arguments[1]; + + // first, see if the first argument already is a skin object. If not, it's the name of the skin to be called + if (arguments[0] instanceof ESWrapper) { + Object obj = ((ESWrapper) arguments[0]).toJavaObject (); + if (obj instanceof Skin) + skin = (Skin) obj; + } + + if (skin == null) + skin = reval.getSkin (thisObject, arguments[0].toString ()); + if (asString) + reval.res.pushStringBuffer (); + if (skin != null) + skin.render (reval, thisObject, paramObject); + else + reval.res.write ("[Skin not found: "+arguments[0]+"]"); + if (asString) + return new ESString (reval.res.popStringBuffer ()); + } catch (Exception x) { + x.printStackTrace (); + throw new EcmaScriptException ("renderSkin: "+x); + } + return ESNull.theNull; + } + } + + + + class GlobalGetUser extends BuiltinFunctionObject { + GlobalGetUser (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + INode user = null; + if (arguments.length > 0) { + String uname = arguments[0].toString ().trim (); + user = app.getUserNode (uname); + } + if (user == null) + return ESNull.theNull; + return reval.getNodeWrapper (user); + } + } + + class GlobalGetUserBySession extends BuiltinFunctionObject { + GlobalGetUserBySession (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + User user = null; + if (arguments.length > 0) { + String sid = arguments[0].toString ().trim (); + user = app.getUser (sid); + } + if (user == null || user.getUID() == null) + return ESNull.theNull; + user.touch (); + return reval.getNodeWrapper (user.getNode ()); + } + } + + + class GlobalGetAllUsers extends BuiltinFunctionObject { + GlobalGetAllUsers (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + INode users = app.getUserRoot (); + ESObject ap = this.evaluator.getArrayPrototype(); + ArrayPrototype theArray = new ArrayPrototype(ap, this.evaluator); + int i=0; + for (Enumeration e=users.properties (); e.hasMoreElements (); ) { + String propname = (String) e.nextElement (); + theArray.putProperty (i++, new ESString (propname)); + } + return theArray; + } + } + + class GlobalGetActiveUsers extends BuiltinFunctionObject { + GlobalGetActiveUsers (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + Hashtable sessions = (Hashtable) app.sessions.clone (); + ESObject ap = this.evaluator.getArrayPrototype(); + ArrayPrototype theArray = new ArrayPrototype (ap, this.evaluator); + theArray.setSize (sessions.size ()); + int i=0; + // Hashtable visited = new Hashtable (); + for (Enumeration e=sessions.elements(); e.hasMoreElements(); ) { + User u = (User) e.nextElement (); + // Note: we previously sorted out duplicate users - now we simply enumerate all active sessions. + // if (u.uid == null || !visited.containsKey (u.uid)) { + theArray.setElementAt (reval.getNodeWrapper (u), i++); + // if (u.uid != null) visited.put (u.uid, u); + // } + } + return theArray; + } + } + + class GlobalCountActiveUsers extends BuiltinFunctionObject { + GlobalCountActiveUsers (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + return new ESNumber (app.sessions.size ()); + } + } + + class GlobalIsActive extends BuiltinFunctionObject { + GlobalIsActive (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 1) + return ESBoolean.makeBoolean (false); + String username = null; + boolean active = false; + if (arguments[0] instanceof ESUser) { + ESUser esu = (ESUser) arguments[0]; + active = (esu.user != null); + } else { + active = app.activeUsers.contains (arguments[0].toString ()); + } + return ESBoolean.makeBoolean (active); + } + } + + class GlobalGetAge extends BuiltinFunctionObject { + GlobalGetAge (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length != 1 || !(arguments[0] instanceof DatePrototype)) + throw new EcmaScriptException ("Invalid arguments for function getAge(Date)"); + + Date d = (Date) arguments[0].toJavaObject (); + try { + long then = d.getTime () / 60000l; + long now = System.currentTimeMillis () / 60000l; + StringBuffer age = new StringBuffer (); + String divider = "vor "; + long diff = now - then; + long days = diff / 1440; + if (days > 0) { + age.append (days > 1 ? divider+days+ " Tagen" : divider+"1 Tag"); + divider = ", "; + } + long hours = (diff % 1440) / 60; + if (hours > 0) { + age.append (hours > 1 ? divider+hours+ " Stunden" : divider+"1 Stunde"); + divider = ", "; + } + long minutes = diff % 60; + if (minutes > 0) + age.append (minutes > 1 ? divider+minutes+ " Minuten" : divider+"1 Minute"); + return new ESString (age.toString ()); + + } catch (Exception e) { + app.logEvent ("Error formatting date: "+e); + e.printStackTrace (); + return new ESString (""); + } + } + } + + class GlobalGetURL extends BuiltinFunctionObject { + GlobalGetURL (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 1) + return ESNull.theNull; + try { + StringBuffer urltext = new StringBuffer (); + java.net.URL url = new java.net.URL (arguments[0].toString ()); + BufferedReader in = new BufferedReader (new InputStreamReader (url.openConnection ().getInputStream ())); + char[] c = new char[1024]; + int read = -1; + while ((read = in.read (c)) > -1) + urltext.append (c, 0, read); + in.close (); + return new ESString (urltext.toString ()); + } catch (Exception ignore) {} + return ESNull.theNull; + } + } + + class GlobalEncode extends BuiltinFunctionObject { + GlobalEncode (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 1) + return ESNull.theNull; + return new ESString (HtmlEncoder.encodeAll (arguments[0].toString ())); + } + } + + class GlobalEncodeXml extends BuiltinFunctionObject { + GlobalEncodeXml (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 1) + return ESNull.theNull; + return new ESString (HtmlEncoder.encodeXml (arguments[0].toString ())); + } + } + + class GlobalEncodeForm extends BuiltinFunctionObject { + GlobalEncodeForm (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 1) + return ESNull.theNull; + return new ESString (HtmlEncoder.encodeFormValue (arguments[0].toString ())); + } + } + + // strip tags from XML/HTML text + class GlobalStripTags extends BuiltinFunctionObject { + GlobalStripTags (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 1) + return ESNull.theNull; + StringBuffer b = new StringBuffer (); + char[] c = arguments[0].toString ().toCharArray (); + boolean inTag = false; + for (int i=0; i') inTag = false; + } + return new ESString (b.toString ()); + } + } + + class GlobalFormat extends BuiltinFunctionObject { + GlobalFormat (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + if (arguments.length < 1) + return ESNull.theNull; + return new ESString (HtmlEncoder.encode (arguments[0].toString ())); + } + } + + class GlobalGetXmlDocument extends BuiltinFunctionObject { + GlobalGetXmlDocument (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + try { + // Class.forName ("org.apache.xerces.parsers.DOMParser"); + // org.apache.xerces.parsers.DOMParser parser = new org.apache.xerces.parsers.DOMParser(); + Class.forName ("org.openxml.parser.XMLParser"); + org.openxml.parser.XMLParser parser = new org.openxml.parser.XMLParser(); + Object p = arguments[0].toJavaObject (); + if (p instanceof String) try { + // first try to interpret string as URL + java.net.URL u = new java.net.URL (p.toString ()); + parser.parse (p.toString()); + } catch (java.net.MalformedURLException nourl) { + // if not a URL, maybe it is the XML itself + parser.parse (new InputSource (new StringReader (p.toString()))); + } + else if (p instanceof InputStream) + parser.parse (new InputSource ((InputStream) p)); + else if (p instanceof Reader) + parser.parse (new InputSource ((Reader) p)); + return ESLoader.normalizeObject (parser.getDocument(), evaluator); + } catch (Exception noluck) { + app.logEvent ("Error creating XML document: "+noluck); + } + return ESNull.theNull; + } + } + + class GlobalGetHtmlDocument extends BuiltinFunctionObject { + GlobalGetHtmlDocument (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + try { + Class.forName ("org.openxml.parser.HTMLParser"); + org.openxml.parser.HTMLParser parser = new org.openxml.parser.HTMLParser(); + Object p = arguments[0].toJavaObject (); + if (p instanceof String) try { + // first try to interpret string as URL + java.net.URL u = new java.net.URL (p.toString ()); + parser.parse (p.toString()); + } catch (java.net.MalformedURLException nourl) { + // if not a URL, maybe it is the HTML itself + parser.parse (new InputSource (new StringReader (p.toString()))); + } + else if (p instanceof InputStream) + parser.parse (new InputSource ((InputStream) p)); + else if (p instanceof Reader) + parser.parse (new InputSource ((Reader) p)); + return ESLoader.normalizeObject (parser.getDocument(), evaluator); + } catch (Exception noluck) { + app.logEvent ("Error creating HTML document: "+noluck); + } + return ESNull.theNull; + } + } + + class GlobalJDOM extends BuiltinFunctionObject { + GlobalJDOM (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + try { + Class.forName ("org.w3c.dom.Document"); + org.w3c.dom.Document doc = (org.w3c.dom.Document) arguments[0].toJavaObject (); + Class.forName ("org.jdom.input.DOMBuilder"); + org.jdom.input.DOMBuilder builder = new org.jdom.input.DOMBuilder (); + return ESLoader.normalizeObject (builder.build (doc), evaluator); + } catch (Exception noluck) { + app.logEvent ("Error wrapping JDOM document: "+noluck); + } + return ESNull.theNull; + } + } + + + /* class NodePath extends BuiltinFunctionObject { + NodePath (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + INode n = ((ESNode) thisObject).getNode (); + String tmpname = arguments[0].toString (); + return new ESString (app.getNodePath (n, tmpname)); + } + } */ + + class NodeSetParent extends BuiltinFunctionObject { + NodeSetParent (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 2); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode node = (ESNode) thisObject; + return ESBoolean.makeBoolean (node.setParent (arguments)); + } + } + + + class NodeHref extends BuiltinFunctionObject { + NodeHref (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + IPathElement elem = (IPathElement) thisObject.toJavaObject (); + String tmpname = arguments.length == 0 ? "" : arguments[0].toString (); + String basicHref =app.getNodeHref (elem, tmpname); + String hrefSkin = app.getProperty ("hrefSkin", null); + // 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. + IPathElement skinElem = elem; + Skin skin = null; + while (skin == null && skinElem != null) { + Prototype proto = app.getPrototype (skinElem); + if (proto != null) + skin = proto.getSkin (hrefSkin); + if (skin == null) + skinElem = skinElem.getParentElement (); + } + + if (skin != null) { + ESObject eso = reval.getElementWrapper (skinElem); + return renderSkin (skin, basicHref, eso); + } + } + return new ESString (basicHref); + } + 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 ()); + skin.render (reval, obj, param); + return new ESString (reval.res.popStringBuffer ().trim ()); + } + } + + + private String getNumberChoice (String name, double from, double to, double step, double value) { + double l = 0.000001; + StringBuffer b = new StringBuffer (""); + return b.toString (); + } + + private String getNodeChooserDD (String name, INode collection, INode target, String teaser) { + StringBuffer buffer = new StringBuffer (""); + return buffer.toString (); + } + + private String getNodeChooserRB (String name, INode collection, INode target) { + StringBuffer buffer = new StringBuffer (); + if (collection != null) { + int l = collection.numberOfNodes (); + for (int i=0; i"); + String cname = next.getString ("name", false); + if (cname == null) cname = next.getName (); + buffer.append (HtmlEncoder.encodeAll (cname)); + buffer.append ("
"); + } + } + return buffer.toString (); + } + + private String getNodeChooserCB (String name, INode collection, INode target) { + StringBuffer buffer = new StringBuffer (); + if (collection != null) { + int l = collection.numberOfNodes (); + for (int i=0; i"); + buffer.append (HtmlEncoder.encodeAll (next.getName ())); + buffer.append ("
"); + } + } + return buffer.toString (); + } + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/helma/scripting/fesi/NodeConstructor.java b/src/helma/scripting/fesi/NodeConstructor.java new file mode 100644 index 00000000..c0104b2e --- /dev/null +++ b/src/helma/scripting/fesi/NodeConstructor.java @@ -0,0 +1,86 @@ +// NodeConstructor.java +// Copyright (c) Hannes Wallnöfer 2000 + +package helma.scripting.fesi; + +import helma.objectmodel.db.Node; +import helma.framework.core.*; +import FESI.Data.*; +import FESI.Exceptions.*; +import FESI.Interpreter.*; + +/** + * A constructor for user defined data types. This first constructs a node, sets its prototype + * and invokes the scripted constructor function on it. + */ + +public class NodeConstructor extends BuiltinFunctionObject { + + RequestEvaluator reval; + String typename; + + public NodeConstructor (String name, FunctionPrototype fp, RequestEvaluator reval) { + super(fp, reval.evaluator, name, 1); + typename = name; + this.reval = reval; + } + + public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + return doConstruct(thisObject, arguments); + } + + public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESNode node = null; + if ("Node".equals (typename) || "hopobject".equalsIgnoreCase (typename)) { + if (arguments.length == 0) { + Node n = new Node ((String) null, (String) null, reval.app.getWrappedNodeManager ()); + node = new ESNode (reval.esNodePrototype, this.evaluator, n, reval); + reval.objectcache.put (node.getNode (), node); + } else { + Node n = new Node (arguments[0].toString(), (String) null, reval.app.getWrappedNodeManager ()); + node = new ESNode (reval.esNodePrototype, this.evaluator, n, reval); + reval.objectcache.put (node.getNode (), node); + } + } else { + // Typed nodes are instantiated as helma.objectmodel.db.Node from the beginning + // even if we don't know yet if they are going to be stored in a database. The reason + // is that we want to be able to use the specail features like subnode relations even for + // transient nodes. + ObjectPrototype op = reval.getPrototype (typename); + Node n = new Node (typename, typename, reval.app.getWrappedNodeManager ()); + node = new ESNode (op, reval.evaluator, n, reval); + node.setPrototype (typename); + node.getNode ().setDbMapping (reval.app.getDbMapping (typename)); + try { + // first try calling "constructor", if that doesn't work, try calling a function + // with the name of the type. + // HACK: There is an incompatibility problem here, because the property + // constructor is defined as the constructor of the object by EcmaScript. + if (op.getProperty("constructor", "constructor".hashCode()) instanceof ConstructedFunctionObject) + node.doIndirectCall (reval.evaluator, node, "constructor", arguments); + else + node.doIndirectCall (reval.evaluator, node, typename, arguments); + } catch (Exception ignore) {} + } + return node; + } + + public ESValue getPropertyInScope(String propertyName, ScopeChain previousScope, int hash) throws EcmaScriptException { + return super.getPropertyInScope (propertyName, previousScope, hash); + } + + public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException { + if ("prototype".equals (propertyName)) + return reval.getPrototype (typename); + return super.getProperty(propertyName, hash); + } + + public String[] getSpecialPropertyNames() { + String ns[] = {}; + return ns; + } + + } // class NodeConstructor + + + diff --git a/src/helma/scripting/fesi/extensions/Database.java b/src/helma/scripting/fesi/extensions/Database.java new file mode 100644 index 00000000..b30f2077 --- /dev/null +++ b/src/helma/scripting/fesi/extensions/Database.java @@ -0,0 +1,1076 @@ +// Database.java +// FESI Copyright (c) Jean-Marc Lugrin, 1999 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +// Modified to use Helma database connections, Hannes Wallnöfer 2000 + +package helma.scripting.fesi.extensions; + +import helma.framework.core.Application; +import helma.objectmodel.db.DbSource; +import FESI.Parser.*; +import FESI.AST.*; +import FESI.Interpreter.*; +import FESI.Exceptions.*; +import FESI.Extensions.*; +import FESI.Data.*; + +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; +import java.sql.*; + + +/** + * A Database object, representing a connection to a JDBC Driver + */ +class ESDatabase extends ESObject { + + private transient Connection connection = null; // Null if not connected + private transient DatabaseMetaData databaseMetaData = null; + private transient String driverName = null; + private transient ClassLoader driverLoader = null; + private transient Exception lastError = null; + private transient ESObject esRowSetPrototype = null; + private transient boolean driverOK = false; + + /** + * Create a new database object based on a hop data source. + * + * @param prototype The prototype object for all database object + * @param evaluator The current evaluator + * @param esRowSetPrototype The prototype to use to create row set + * @param dbsource The name of the DB source + */ + + ESDatabase(ESObject prototype, + Evaluator evaluator, + ESObject esRowSetPrototype, + DbSource dbsource, int flag) { + super(prototype, evaluator); + this.esRowSetPrototype = esRowSetPrototype; // specific to an evaluator + try { + connection = dbsource.getConnection (); + driverName = dbsource.getDriverName (); + } catch (Exception e) { + // System.err.println("##Cannot find driver class: " + e); + // e.printStackTrace(); + lastError = e; + } + driverOK = true; + } + + /** + * Create a new database object based on a driver name, with driver on the classpath + * + * @param prototype The prototype object for all database object + * @param evaluator The current evaluator + * @param esRowSetPrototype The prototype to use to create row set + * @param driverName The class name of the JDBC driver + */ + + ESDatabase(ESObject prototype, + Evaluator evaluator, + ESObject esRowSetPrototype, + String driverName) { + super(prototype, evaluator); + this.driverName = driverName; + this.esRowSetPrototype = esRowSetPrototype; // specific to an evaluator + try { + Class driverClass = Class.forName(driverName); + if (!Driver.class.isAssignableFrom(driverClass)) { + + // System.err.println("##Bad class " + driverClass); + lastError = new EcmaScriptException("Class " + driverClass + " is not a JDBC driver"); + } + driverClass.newInstance(); // may be needed by some drivers, harmless for others + } catch (ClassNotFoundException e) { + // System.err.println("##Cannot find driver class: " + e); + // e.printStackTrace(); + lastError = e; + } catch (InstantiationException e) { + + // System.err.println("##Cannot instantiate driver class: " + e); + // e.printStackTrace(); + lastError = e; + } catch (IllegalAccessException e) { + // ignore as this may happen depending on driver, it may not be severe + // for example because the instance was created at class initialization time + } + driverOK = true; + } + + /** + * Create a new database object based on a driver name and its classpath + * + * @param prototype The prototype object for all database object + * @param evaluator The current evaluator + * @param esRowSetPrototype The prototype to use to create row set + * @param driverName The class name of the JDBC driver + * @param pathName The path to the classes of the JDBC driver + */ + ESDatabase(ESObject prototype, + Evaluator evaluator, + ESObject esRowSetPrototype, + String driverName, + String pathName) { + super(prototype, evaluator); + this.driverName = driverName; + this.esRowSetPrototype = esRowSetPrototype; + try { + this.driverLoader = LocalClassLoader.makeLocalClassLoader(pathName); + } catch (EcmaScriptException e) { + // System.err.println("##Cannot find driver class: " + e); + // e.printStackTrace(); + lastError = e; + return; + } + try { + Class driverClass = driverLoader.loadClass(driverName); + if (!Driver.class.isAssignableFrom(driverClass)) { + // System.err.println("##Bad class " + driverClass); + // e.printStackTrace(); + lastError = new EcmaScriptException("Class " + driverClass + " is not a JDBC driver"); + return; + } + driverClass.newInstance(); + } catch (ClassNotFoundException e) { + // System.err.println("##Cannot find driver class: " + e); + // e.printStackTrace(); + lastError = e; + } catch (InstantiationException e) { + // System.err.println("##Cannot instantiate driver class: " + e); + // e.printStackTrace(); + lastError = e; + } catch (IllegalAccessException e) { + // System.err.println("##Cannot access driver class: " + e); + // e.printStackTrace(); + lastError = e; + } + driverOK = true; + } + + /** + * Create the database prototype object which cannot be connected + * + * @param prototype The prototype object for the database prototype object + * @param evaluator The current evaluator + */ + + ESDatabase(ESObject prototype, + Evaluator evaluator) { + super(prototype, evaluator); + this.driverName = null; + this.esRowSetPrototype = null; + driverOK = false; // Avoid usage of this object + } + + public String getESClassName() { + return "Database"; + } + + public String toString() { + if (driverName==null) return "[database protoype]"; + return "[Database: '" + driverName + + (driverOK ? + (connection==null ? "' - disconnected] " : " - connected]") + : " - in error]"); + } + + public String toDetailString() { + return "ES:[Object: builtin " + this.getClass().getName() + ":" + + this.toString() + "]"; + } + + ESValue getLastError() throws EcmaScriptException { + if (lastError == null) { + return ESNull.theNull; + } else { + return ESLoader.normalizeValue(lastError, evaluator); + } + } + + + /** + * Connect to the database, using the specific url, optional user name and password + * + * @param arguments The argument list + * @return true if successful, false otherwise + */ + ESValue connect(ESValue arguments[]) throws EcmaScriptException { + if (!driverOK) { + throw new EcmaScriptException("Driver not initialized properly - cannot connect"); + } + lastError = null; + String url = (arguments.length>0) ? arguments[0].toString() : null; + String userName = (arguments.length>1) ? arguments[1].toString() : null; + String password = (arguments.length>2) ? arguments[2].toString() : null; + try { + if (userName == null) { + connection = DriverManager.getConnection(url); + } else { + connection = DriverManager.getConnection(url,userName,password); + } + } catch(Exception e) { + // System.err.println("##Cannot connect: " + e); + // e.printStackTrace(); + lastError = e; + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + + + /** + * Disconnect from the database, nop if not conected + * + * @return true if successful, false if error during idsconnect + */ + ESValue disconnect() throws EcmaScriptException { + if (!driverOK) { + throw new EcmaScriptException("Driver not initialized properly - cannot disconnect"); + } + lastError = null; + if (connection != null) { + try { + connection.close(); + connection = null; + lastError = null; + } catch (SQLException e) { + // System.err.println("##Cannot disonnect: " + e); + // e.printStackTrace(); + lastError = e; + return ESBoolean.makeBoolean(false); + } + } + return ESBoolean.makeBoolean(true); + } + + ESValue release() { + if (driverOK) { + try { + disconnect(); + } catch (EcmaScriptException e) { + // ignored + } + } + return ESUndefined.theUndefined; + } + + ESValue executeRetrieval(ESValue arguments[]) throws EcmaScriptException { + String sql = (arguments.length>0) ? arguments[0].toString() : null; + + if (connection==null) { + throw new EcmaScriptException("JDBC driver not connected"); + } + Statement statement = null; + ResultSet resultSet = null; + + try { + statement = connection.createStatement(); + resultSet = statement.executeQuery(sql); // will return true if first result is a result set + } catch(SQLException e) { + // System.err.println("##Cannot retrieve: " + e); + // e.printStackTrace(); + lastError = e; + try { + if (statement!=null) statement.close(); + } catch (Exception ignored) { + } + statement = null; + return ESBoolean.makeBoolean(false); + } + ESRowSet rowSet = new ESRowSet(esRowSetPrototype, evaluator, sql, this, statement, resultSet); + return rowSet; + //return ESBoolean.makeBoolean(true); + } + + ESValue executeCommand(ESValue arguments[]) throws EcmaScriptException { + String sql = (arguments.length>0) ? arguments[0].toString() : null; + int count = 0; + + if (connection==null) { + throw new EcmaScriptException("JDBC driver not connected"); + } + + Statement statement = null; + try { + + statement = connection.createStatement(); + count = statement.executeUpdate(sql); // will return true if first result is a result set + } catch(SQLException e) { + // System.err.println("##Cannot retrieve: " + e); + // e.printStackTrace(); + lastError = e; + try { + if (statement != null) statement.close(); + } catch (Exception ignored) { + } + statement = null; + return ESBoolean.makeBoolean(false); + } + if (statement!=null) try { + statement.close(); + } catch (SQLException e) { + // ignored + } + return new ESNumber(count); + //return ESBoolean.makeBoolean(true); + } + + public Object getMetaData() + { + if (databaseMetaData == null) + try { + databaseMetaData = connection.getMetaData(); + } catch (SQLException e) { + // ignored + } + return databaseMetaData; + } +} + + +/** + * A RowSet object + */ +class ESRowSet extends ESObject { + + private transient ESDatabase database = null; + private transient String sql = null; + private transient Statement statement = null; + private transient ResultSet resultSet = null; + private transient ResultSetMetaData resultSetMetaData = null; + private transient Vector colNames = null; + private transient boolean lastRowSeen = false; + private transient boolean firstRowSeen = false; + private transient Exception lastError = null; + + ESRowSet(ESObject prototype, + Evaluator evaluator, + String sql, + ESDatabase database, + Statement statement, + ResultSet resultSet) throws EcmaScriptException { + super(prototype, evaluator); + this.sql = sql; + this.database = database; + this.statement = statement; + this.resultSet = resultSet; + + if (sql==null) throw new NullPointerException(); + if (resultSet==null) throw new NullPointerException(); + if (statement==null) throw new NullPointerException(); + if (database==null) throw new NullPointerException(); + + try { + + this.resultSetMetaData = resultSet.getMetaData(); + int numcols = resultSetMetaData.getColumnCount(); + //IServer.getLogger().log("$$NEXT : " + numcols); + colNames = new Vector(numcols); + for (int i=0; i0 && idx <=colNames.size()) { + return (String) colNames.elementAt(idx-1); // to base 0 + } else { + throw new EcmaScriptException("Column index (base 1) " + idx + + " out of range, max: " +colNames.size()); + } + } + + + public int getColumnDatatypeNumber(int idx) throws EcmaScriptException { + if (resultSet == null) { + throw new EcmaScriptException("Attempt to access a released result set"); + } + if (idx>0 && idx <=colNames.size()) { + try { + return resultSetMetaData.getColumnType(idx); + } catch (SQLException e) { + lastError = e; + return -1; + } + } else { + throw new EcmaScriptException("Column index (base 1) " + idx + + " out of range, max: " +colNames.size()); + } + } + + + public String getColumnDatatypeName(int idx) throws EcmaScriptException { + if (resultSet == null) { + throw new EcmaScriptException("Attempt to access a released result set"); + } + if (idx>0 && idx <=colNames.size()) { + try { + return resultSetMetaData.getColumnTypeName(idx); + } catch (SQLException e) { + lastError = e; + return null; + } + } else { + throw new EcmaScriptException("Column index (base 1) " + idx + + " out of range, max: " +colNames.size()); + } + } + + + public ESValue getColumnItem(String propertyName) throws EcmaScriptException { + if (resultSet == null) { + throw new EcmaScriptException("Attempt to access a released result set"); + } + if (!firstRowSeen) { + throw new EcmaScriptException("Attempt to access data before the first row is read"); + } + int hash = propertyName.hashCode(); + try { + int index = -1; // indicates not a valid index value + try { + char c = propertyName.charAt(0); + if ('0' <= c && c <= '9') { + index = Integer.parseInt(propertyName); + } + } catch (NumberFormatException e) { + } catch (StringIndexOutOfBoundsException e) { // for charAt + } + if (index>=0) { + return getProperty(index); + } + Object o = resultSet.getObject(propertyName); + ESValue value = ESLoader.normalizeValue(o, evaluator); + // IServer.getLogger().log("&& @VALUE : " + value); + lastError = null; + return value; + } catch (SQLException e) { + //System.err.println("##Cannot get property '" + propertyName + "' " + e); + //e.printStackTrace(); + lastError = e; + } + return ESUndefined.theUndefined; + } + + public ESValue getProperty(String propertyName, int hash) + throws EcmaScriptException { + //System.err.println(" &&& Getting property '" + propertyName + "'"); + + // Length property is firsy checked + + // First return system or or prototype properties + if (propertyName.equals("length")) { + return new ESNumber((double) colNames.size()); + } else if (super.hasProperty(propertyName, hash)) { + return super.getProperty(propertyName, hash); + } else { + if (resultSet == null) { + throw new EcmaScriptException("Attempt to access a released result set"); + } + if (!firstRowSeen) { + throw new EcmaScriptException("Attempt to access data before the first row is read"); + } + try { + int index = -1; // indicates not a valid index value + try { + char c = propertyName.charAt(0); + if ('0' <= c && c <= '9') { + index = Integer.parseInt(propertyName); + } + } catch (NumberFormatException e) { + } catch (StringIndexOutOfBoundsException e) { // for charAt + } + if (index>=0) { + return getProperty(index); + } + Object o = resultSet.getObject(propertyName); + ESValue value = ESLoader.normalizeValue(o, evaluator); + // IServer.getLogger().log("&& @VALUE : " + value); + lastError = null; + return value; + } catch (SQLException e) { + // System.err.println("##Cannot get property '" + propertyName + "' " + e); + // e.printStackTrace(); + lastError = e; + } + } + return ESUndefined.theUndefined; + } + + public ESValue getProperty(int index) + throws EcmaScriptException { + if (!firstRowSeen) { + throw new EcmaScriptException("Attempt to access data before the first row is read"); + } + if (resultSet == null) { + throw new EcmaScriptException("Attempt to access a released result set"); + } + + try { + Object o = resultSet.getObject(index); + ESValue value = ESLoader.normalizeValue(o, evaluator); + lastError = null; + return value; + } catch (SQLException e) { + // System.err.println("##Cannot get property: " + e); + // e.printStackTrace(); + lastError = e; + } + return ESUndefined.theUndefined; + } + + /* + * Returns an enumerator for the key elements of this object. + * + * @return the enumerator - may have 0 length of coulmn names where not found + */ + public Enumeration getProperties() { + if (resultSet == null) { + return (new Vector()).elements(); + } + return colNames.elements(); + } + + /** + * Get all properties (including hidden ones), for the command + * @listall of the interpreter. Include the visible properties of the + * prototype (that is the one added by the user) but not the + * hidden ones of the prototype (otherwise this would list + * all functions for any object). + * + * @return An enumeration of all properties (visible and hidden). + */ + public Enumeration getAllProperties() { + return new Enumeration() { + String [] specialProperties = getSpecialPropertyNames(); + int specialEnumerator = 0; + Enumeration props = getProperties(); // all of object properties + String currentKey = null; + int currentHash = 0; + boolean inside = false; // true when examing prototypes properties + public boolean hasMoreElements() { + // OK if we already checked for a property and one exists + if (currentKey != null) return true; + // Loop on special properties first + if (specialEnumerator < specialProperties.length) { + currentKey = specialProperties[specialEnumerator]; + currentHash = currentKey.hashCode(); + specialEnumerator++; + return true; + } + // loop on standard or prototype properties + while (props.hasMoreElements()) { + currentKey = (String) props.nextElement(); + currentHash = currentKey.hashCode(); + if (inside) { + try { + if (hasProperty(currentKey, currentHash)) continue; + } catch (EcmaScriptException ignore) { + } + // SHOULD CHECK IF NOT IN SPECIAL + } + return true; + } + // If prototype properties have not yet been examined, look for them + if (!inside && getPrototype() != null) { + inside = true; + props = getPrototype().getProperties(); + while (props.hasMoreElements()) { + currentKey = (String) props.nextElement(); + currentHash = currentKey.hashCode(); + try { + if (hasProperty(currentKey, currentHash)) continue; + } catch (EcmaScriptException ignore) { + } + return true; + } + } + return false; + } + public Object nextElement() { + if (hasMoreElements()) { + String key = currentKey; + currentKey = null; + return key; + } else { + throw new java.util.NoSuchElementException(); + } + } + }; + } + + public String[] getSpecialPropertyNames() { + String [] ns = {"length"}; + return ns; + } + + + ESValue next() throws EcmaScriptException { + boolean status = false; + if (lastRowSeen) { + throw new EcmaScriptException("Attempt to access a next row after last row has been returned"); + } + if (resultSet == null) { + throw new EcmaScriptException("Attempt to access a released result set"); + } + try { + status = resultSet.next(); + lastError = null; + } catch (SQLException e) { + // System.err.println("##Cannot do next:" + e); + // e.printStackTrace(); + lastError = e; + } + if (status) firstRowSeen = true; + else lastRowSeen = true; + return ESBoolean.makeBoolean(status); + } + + public String toString() { + return "[RowSet: '"+sql+"'" + + (resultSet==null ? " - released]" : + (lastRowSeen ? " - at end]" : + (firstRowSeen ? "]" : " - at start]"))); + } + +} + + + + +public class Database extends Extension { + + + private transient Evaluator evaluator = null; + private ESObject esDatabasePrototype = null; + private ESObject esRowSetPrototype = null; + Application app; + + public Database () { + super(); + } + + + public void setApplication (Application app) { + this.app = app; + } + + ////////////////// Added by Hannes Wallnoefer + class GlobalGetDBConnection extends BuiltinFunctionObject { + GlobalGetDBConnection(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, ESValue[] arguments) + throws EcmaScriptException { + if (arguments.length != 1) + throw new EcmaScriptException ("Wrong number of arguments in getDBConnection(dbsource)"); + String srcname = arguments[0].toString (); + DbSource dbsrc = app.getDbSource (srcname.toLowerCase ()); + if (dbsrc == null) + throw new EcmaScriptException ("DbSource "+srcname+" does not exist"); + ESDatabase db = new ESDatabase (esDatabasePrototype, this.evaluator, + esRowSetPrototype, dbsrc, 0); + return db; + } + } + + + class GlobalObjectDatabase extends BuiltinFunctionObject { + GlobalObjectDatabase(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + return doConstruct(thisObject, arguments); + } + + public ESObject doConstruct(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESDatabase database = null; + //IServer.getLogger().log("esDatabasePrototype="+esDatabasePrototype); + if (arguments.length==0) { + throw new EcmaScriptException("Database requires 1 or 2 arguments"); + } else if (arguments.length==1) { + database = new ESDatabase(esDatabasePrototype, + this.evaluator, + esRowSetPrototype, + arguments[0].toString()); + } else if (arguments.length>1) { + database = new ESDatabase(esDatabasePrototype, + this.evaluator, + esRowSetPrototype, + arguments[0].toString(), + arguments[1].toString()); + } + return database; + } + + + } + + + class DatabaseGetLastError extends BuiltinFunctionObject { + DatabaseGetLastError(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESDatabase database = (ESDatabase) thisObject; + return database.getLastError(); + } + } + + class DatabaseRelease extends BuiltinFunctionObject { + DatabaseRelease(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESDatabase database = (ESDatabase) thisObject; + return database.release(); + } + } + + + class DatabaseConnect extends BuiltinFunctionObject { + DatabaseConnect(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESDatabase database = (ESDatabase) thisObject; + return database.connect(arguments); + } + } + + + class DatabaseDisconnect extends BuiltinFunctionObject { + DatabaseDisconnect(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESDatabase database = (ESDatabase) thisObject; + return database.disconnect(); + } + } + + class DatabaseExecuteRetrieval extends BuiltinFunctionObject { + DatabaseExecuteRetrieval(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESDatabase database = (ESDatabase) thisObject; + return database.executeRetrieval(arguments); + } + } + + + class DatabaseExecuteCommand extends BuiltinFunctionObject { + DatabaseExecuteCommand(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESDatabase database = (ESDatabase) thisObject; + return database.executeCommand(arguments); + } + } + + + class DatabaseGetMetaData extends BuiltinFunctionObject { + DatabaseGetMetaData(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESDatabase database = (ESDatabase) thisObject; + return new ESWrapper(database.getMetaData(), this.evaluator); + } + } + + + + + + class RowSetRelease extends BuiltinFunctionObject { + RowSetRelease(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESRowSet rowSet = (ESRowSet) thisObject; + return rowSet.release(); + } + } + + class RowSetNext extends BuiltinFunctionObject { + RowSetNext(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESRowSet rowSet = (ESRowSet) thisObject; + return rowSet.next(); + } + } + + class RowSetGetColumnCount extends BuiltinFunctionObject { + RowSetGetColumnCount(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESRowSet rowSet = (ESRowSet) thisObject; + return new ESNumber((double) rowSet.getColumnCount()); + } + } + + class RowSetGetColumnName extends BuiltinFunctionObject { + RowSetGetColumnName(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESRowSet rowSet = (ESRowSet) thisObject; + if (arguments.length<1) { + throw new EcmaScriptException("Missing parameter in function " + this); + } + int idx = arguments[0].toUInt32(); + String name = rowSet.getColumnName(idx); // base 1 + if (name==null) { + return ESUndefined.theUndefined; + } else { + return new ESString(name); + } + } + } + + + class RowSetGetColumnItem extends BuiltinFunctionObject { + RowSetGetColumnItem(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESRowSet rowSet = (ESRowSet) thisObject; + if (arguments.length<1) { + throw new EcmaScriptException("Missing parameter in function " + this); + } + String name = arguments[0].toString(); + return rowSet.getColumnItem(name); + } + } + + + + class RowSetGetColumnDatatypeNumber extends BuiltinFunctionObject { + RowSetGetColumnDatatypeNumber(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESRowSet rowSet = (ESRowSet) thisObject; + if (arguments.length<1) { + throw new EcmaScriptException("Missing parameter in function " + this); + } + int idx = arguments[0].toUInt32(); + return new ESNumber((double)rowSet.getColumnDatatypeNumber(idx)); + } + } + + + class RowSetGetColumnDatatypeName extends BuiltinFunctionObject { + RowSetGetColumnDatatypeName(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESRowSet rowSet = (ESRowSet) thisObject; + if (arguments.length<1) { + throw new EcmaScriptException("Missing parameter in function " + this); + } + int idx = arguments[0].toUInt32(); + String name = rowSet.getColumnDatatypeName(idx); + //IServer.getLogger().log("Datat type name for col " + idx + " is " +name); + if (name==null) { + return ESUndefined.theUndefined; + } else { + return new ESString(name); + } + } + } + + + class RowSetHasMoreRows extends BuiltinFunctionObject { + RowSetHasMoreRows(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESRowSet rowSet = (ESRowSet) thisObject; + return ESBoolean.makeBoolean(rowSet.hasMoreRows()); + } + } + + + class RowSetGetMetaData extends BuiltinFunctionObject { + RowSetGetMetaData(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESRowSet rowSet = (ESRowSet) thisObject; + return new ESWrapper(rowSet.getMetaData(), this.evaluator); + } + } + + + public void initializeExtension(Evaluator evaluator) throws EcmaScriptException { + + this.evaluator = evaluator; + GlobalObject go = evaluator.getGlobalObject(); + ObjectPrototype op = (ObjectPrototype) evaluator.getObjectPrototype(); + FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype(); + + esRowSetPrototype = new ObjectPrototype(op, evaluator); + esDatabasePrototype = new ESDatabase(op, evaluator); // No driver + + ESObject globalDatabaseObject = new GlobalObjectDatabase("Database", evaluator, fp); + globalDatabaseObject.putHiddenProperty("prototype",esDatabasePrototype); + globalDatabaseObject.putHiddenProperty("length",new ESNumber(2)); + + + esDatabasePrototype.putHiddenProperty("constructor",globalDatabaseObject); + esDatabasePrototype.putHiddenProperty("getLastError", + new DatabaseGetLastError("getLastError", evaluator, fp)); + esDatabasePrototype.putHiddenProperty("release", + new DatabaseRelease("release", evaluator, fp)); + esDatabasePrototype.putHiddenProperty("connect", + new DatabaseConnect("connect", evaluator, fp)); + esDatabasePrototype.putHiddenProperty("disconnect", + new DatabaseDisconnect("disconnect", evaluator, fp)); + esDatabasePrototype.putHiddenProperty("executeRetrieval", + new DatabaseExecuteRetrieval("executeRetrieval", evaluator, fp)); + esDatabasePrototype.putHiddenProperty("executeCommand", + new DatabaseExecuteCommand("executeCommand", evaluator, fp)); + esDatabasePrototype.putHiddenProperty("getMetaData", + new DatabaseGetMetaData("getMetaData", evaluator, fp)); + + esRowSetPrototype.putHiddenProperty("release", + new RowSetRelease("release", evaluator, fp)); + esRowSetPrototype.putHiddenProperty("next", + new RowSetNext("next", evaluator, fp)); + esRowSetPrototype.putHiddenProperty("getColumnCount", + new RowSetGetColumnCount("getColumnCount", evaluator, fp)); + esRowSetPrototype.putHiddenProperty("getColumnName", + new RowSetGetColumnName("getColumnName", evaluator, fp)); + esRowSetPrototype.putHiddenProperty("getColumnItem", + new RowSetGetColumnItem("getColumnItem", evaluator, fp)); + esRowSetPrototype.putHiddenProperty("getColumnDatatypeNumber", + new RowSetGetColumnDatatypeNumber("getColumnDatatypeNumber", evaluator, fp)); + esRowSetPrototype.putHiddenProperty("getColumnDatatypeName", + new RowSetGetColumnDatatypeName("getColumnDatatypeName", evaluator, fp)); + esRowSetPrototype.putHiddenProperty("hasMoreRows", + new RowSetHasMoreRows("hasMoreRows", evaluator, fp)); + esRowSetPrototype.putHiddenProperty("getMetaData", + new RowSetGetMetaData("getMetaData", evaluator, fp)); + + go.putHiddenProperty("Database", globalDatabaseObject); + // added by Hannes Wallnoefer + go.putHiddenProperty ("getDBConnection", new GlobalGetDBConnection ("getDBConnection", evaluator, fp)); + } + } diff --git a/src/helma/scripting/fesi/extensions/ESMail.java b/src/helma/scripting/fesi/extensions/ESMail.java new file mode 100644 index 00000000..90ddba71 --- /dev/null +++ b/src/helma/scripting/fesi/extensions/ESMail.java @@ -0,0 +1,196 @@ +// ESMail.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + + +package helma.scripting.fesi.extensions; + +import javax.mail.*; +import javax.mail.internet.*; +import javax.activation.*; +import java.io.*; +import java.util.*; +import helma.main.Server; +import helma.framework.core.*; +import helma.util.*; +import FESI.Data.*; +import FESI.Interpreter.*; +import FESI.Exceptions.*; + +/** + * A JavaScript wrapper around a JavaMail message class to send + * mail via SMTP from Helma + */ + +public class ESMail extends ESObject implements Serializable { + + MailExtension mailx; + Properties mprops; + MimeMessage message; + Multipart multipart; + StringBuffer buffer; + + int status; + public static final int OK=0; + public static final int SUBJECT=10; + public static final int TEXT=11; + public static final int MIMEPART=12; + public static final int TO=20; + public static final int CC=21; + public static final int BCC=22; + public static final int FROM=23; + public static final int REPLYTO=24; + public static final int SEND=30; + + + public ESMail (MailExtension mailx) { + + super (mailx.esMailPrototype, mailx.evaluator); + this.status = OK; + this.mailx = mailx; + this.mprops = mailx.mprops; + + // create some properties and get the default Session + try { + Properties props = new Properties(); + props.put ("mail.smtp.host", mprops.getProperty ("smtp", "mail")); + + Session session = Session.getDefaultInstance(props, null); + message = new MimeMessage (session); + } catch (Throwable t) { + Server.getLogger().log ("caught in mail constructor: "+t); + } + } + + public void setStatus (int status) { + // Only register the first error that occurrs + if (this.status == 0) + this.status = status; + } + + public int getStatus () { + return status; + } + + public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException { + if ("status".equalsIgnoreCase (propertyName)) + return new ESNumber (status); + return super.getProperty (propertyName, hash); + } + + /** + * + */ + + public void setText (ESValue val) throws Exception { + if (buffer == null) + buffer = new StringBuffer (); + if (val != null) + buffer.append (val.toString ()); + } + + public void addPart (ESValue val[]) throws Exception { + if (val == null || val.length == 0) return; + if (multipart == null) { + multipart = new MimeMultipart (); + } + for (int i=0; i 1) + address = new InternetAddress (addstring, MimeUtility.encodeWord (add[1].toString (), "iso-8859-1", null)); + else + address = new InternetAddress (addstring); + message.setFrom (address); + } + + public void addTo (ESValue add[]) throws Exception { + String addstring = add[0].toString (); + if (addstring.indexOf ("@") < 0) + throw new AddressException (); + Address address = null; + if (add.length > 1) + address = new InternetAddress (addstring, MimeUtility.encodeWord (add[1].toString (), "iso-8859-1", null)); + else + address = new InternetAddress (addstring); + message.addRecipient (Message.RecipientType.TO, address); + } + + public void addCC (ESValue add[]) throws Exception { + String addstring = add[0].toString (); + if (addstring.indexOf ("@") < 0) + throw new AddressException (); + Address address = null; + if (add.length > 1) + address = new InternetAddress (addstring, MimeUtility.encodeWord (add[1].toString (), "iso-8859-1", null)); + else + address = new InternetAddress (addstring); + message.addRecipient (Message.RecipientType.CC, address); + } + + public void addBCC (ESValue add[]) throws Exception { + String addstring = add[0].toString (); + if (addstring.indexOf ("@") < 0) + throw new AddressException (); + Address address = null; + if (add.length > 1) + address = new InternetAddress (addstring, MimeUtility.encodeWord (add[1].toString (), "iso-8859-1", null)); + else + address = new InternetAddress (addstring); + message.addRecipient (Message.RecipientType.BCC, address); + } + + public void send () throws Exception { + if (buffer != null) + message.setText (buffer.toString ()); + else if (multipart != null) + message.setContent (multipart); + else + message.setText (""); + Transport.send (message); + } + + +} + + + + + + + + + + + + diff --git a/src/helma/scripting/fesi/extensions/FtpExtension.java b/src/helma/scripting/fesi/extensions/FtpExtension.java new file mode 100644 index 00000000..fce14850 --- /dev/null +++ b/src/helma/scripting/fesi/extensions/FtpExtension.java @@ -0,0 +1,419 @@ +// FtpExtension.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + +package helma.scripting.fesi.extensions; + +import helma.objectmodel.*; +import FESI.Parser.*; +import FESI.AST.*; +import FESI.Interpreter.*; +import FESI.Exceptions.*; +import FESI.Extensions.*; +import FESI.Data.*; +import java.io.*; + +import com.oroinc.net.ftp.*; + + +/** + * A FTP-client object that allows to do some FTP from HOP applications. + * FTP support is far from complete but can easily be extended if more + * functionality is needed. + * This uses the NetComponent classes from savarese.org (ex oroinc.com). + */ + +class ESFtpClient extends ESObject { + + private FTPClient ftpclient; + private String server; + private Exception lastError = null; + private File localDir = null; + + + /** + * Create a new FTP Client + * + * @param prototype The prototype object for the FTP object + * @param evaluator The current evaluator + */ + ESFtpClient(ESObject prototype, Evaluator evaluator, ESValue srvstr) { + super(prototype, evaluator); + this.server = srvstr.toString (); + } + + ESFtpClient(ESObject prototype, Evaluator evaluator) { + super(prototype, evaluator); + } + + + public String getESClassName() { + return "FtpClient"; + } + + public String toString() { + return "[FtpClient]"; + } + + public String toDetailString() { + return "ES:[Object: builtin " + this.getClass().getName() + ":" + + this.toString() + "]"; + } + + ESValue getLastError() throws EcmaScriptException { + if (lastError == null) { + return ESNull.theNull; + } else { + return ESLoader.normalizeValue(lastError, evaluator); + } + } + + + /** + * Login to the FTP server + * + * @param arguments The argument list + * @return true if successful, false otherwise + */ + ESValue login(ESValue arguments[]) throws EcmaScriptException { + if (server == null) + return ESBoolean.makeBoolean(false); + try { + ftpclient = new FTPClient (); + ftpclient.connect (server); + ftpclient.login (arguments[0].toString(), arguments[1].toString()); + return ESBoolean.makeBoolean (true); + } catch (Exception x) { + return ESBoolean.makeBoolean (false); + } catch (NoClassDefFoundError x) { + return ESBoolean.makeBoolean (false); + } + } + + ESValue cd (ESValue arguments[]) throws EcmaScriptException { + if (ftpclient == null) + return ESBoolean.makeBoolean(false); + try { + ftpclient.changeWorkingDirectory (arguments[0].toString ()); + return ESBoolean.makeBoolean(true); + } catch (Exception wrong) {} + return ESBoolean.makeBoolean(false); + } + + + ESValue mkdir (ESValue arguments[]) throws EcmaScriptException { + if (ftpclient == null) + return ESBoolean.makeBoolean(false); + try { + return ESBoolean.makeBoolean(ftpclient.makeDirectory (arguments[0].toString ())); + } catch (Exception wrong) {} + return ESBoolean.makeBoolean(false); + } + + ESValue lcd (ESValue arguments[]) throws EcmaScriptException { + try { + localDir = new File (arguments[0].toString()); + if (!localDir.exists()) + localDir.mkdirs(); + return ESBoolean.makeBoolean(true); + } catch (Exception wrong) {} + return ESBoolean.makeBoolean(false); + } + + ESValue putFile(ESValue arguments[]) throws EcmaScriptException { + if (ftpclient == null) + return ESBoolean.makeBoolean(false); + try { + String fn = arguments[0].toString(); + File f = localDir == null ? new File (fn) : new File (localDir, fn); + InputStream fin = new BufferedInputStream (new FileInputStream (f)); + ftpclient.storeFile (arguments[1].toString (), fin); + fin.close (); + return ESBoolean.makeBoolean(true); + } catch (Exception wrong) {} + return ESBoolean.makeBoolean(false); + } + + ESValue putString(ESValue arguments[]) throws EcmaScriptException { + if (ftpclient == null) + return ESBoolean.makeBoolean(false); + try { + byte[] bytes = null; + // check if this already is a byte array + if (arguments[0] instanceof ESArrayWrapper) { + Object o = ((ESArrayWrapper) arguments[0]).toJavaObject (); + if (o instanceof byte[]) + bytes = (byte[]) o; + } + if (bytes == null) + bytes = arguments[0].toString().getBytes(); + ByteArrayInputStream bin = new ByteArrayInputStream (bytes); + ftpclient.storeFile (arguments[1].toString (), bin); + return ESBoolean.makeBoolean(true); + } catch (Exception wrong) {} + return ESBoolean.makeBoolean(false); + } + + + ESValue getFile(ESValue arguments[]) throws EcmaScriptException { + if (ftpclient == null ) + return ESBoolean.makeBoolean(false); + try { + String fn = arguments[0].toString(); + File f = localDir == null ? new File (fn) : new File (localDir, fn); + OutputStream out = new BufferedOutputStream (new FileOutputStream(f)); + ftpclient.retrieveFile (arguments[0].toString (), out); + out.close (); + return ESBoolean.makeBoolean(true); + } catch (Exception wrong) {} + return ESBoolean.makeBoolean(false); + } + + ESValue getString(ESValue arguments[]) throws EcmaScriptException { + if (ftpclient == null ) + return ESNull.theNull; + try { + ByteArrayOutputStream bout = new ByteArrayOutputStream (); + ftpclient.retrieveFile (arguments[0].toString (), bout); + return new ESString (bout.toString ()); + } catch (Exception wrong) {} + return ESNull.theNull; + } + + /** + * Disconnect from FTP server + * + * @param arguments The argument list + * @return true if successful, false otherwise + */ + ESValue logout (ESValue arguments[]) throws EcmaScriptException { + if (ftpclient != null) { + try { + ftpclient.logout (); + } catch (IOException ignore) {} + try { + ftpclient.disconnect (); + } catch (IOException ignore) {} + } + return ESBoolean.makeBoolean (true); + } + + ESValue binary (ESValue arguments[]) throws EcmaScriptException { + if (ftpclient != null) { + try { + ftpclient.setFileType (FTP.BINARY_FILE_TYPE); + return ESBoolean.makeBoolean (true); + } catch (IOException ignore) {} + } + return ESBoolean.makeBoolean (false); + } + + ESValue ascii (ESValue arguments[]) throws EcmaScriptException { + if (ftpclient != null) { + try { + ftpclient.setFileType (FTP.ASCII_FILE_TYPE); + return ESBoolean.makeBoolean (true); + } catch (IOException ignore) {} + } + return ESBoolean.makeBoolean (false); + } + + +} + + +public class FtpExtension extends Extension { + + private transient Evaluator evaluator = null; + private ESObject esFtpPrototype = null; + + public FtpExtension () { + super(); + } + + class GlobalObjectFtpClient extends BuiltinFunctionObject { + GlobalObjectFtpClient(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + + public ESValue callFunction(ESObject thisObject, ESValue[] arguments) + throws EcmaScriptException { + return doConstruct(thisObject, arguments); + } + + public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = null; + if (arguments.length != 1) + throw new EcmaScriptException("FtpClient requires 1 argument"); + ftp = new ESFtpClient (esFtpPrototype, + this.evaluator, + arguments[0]); + return ftp; + } + + } + + + class FtpClientLogin extends BuiltinFunctionObject { + FtpClientLogin(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.login (arguments); + } + } + + class FtpClientCD extends BuiltinFunctionObject { + FtpClientCD(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.cd (arguments); + } + } + + class FtpClientMKDIR extends BuiltinFunctionObject { + FtpClientMKDIR(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.mkdir (arguments); + } + } + + class FtpClientLCD extends BuiltinFunctionObject { + FtpClientLCD(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.lcd (arguments); + } + } + + class FtpClientPutFile extends BuiltinFunctionObject { + FtpClientPutFile (String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.putFile (arguments); + } + } + + class FtpClientPutString extends BuiltinFunctionObject { + FtpClientPutString (String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.putString (arguments); + } + } + + class FtpClientGetFile extends BuiltinFunctionObject { + FtpClientGetFile (String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.getFile (arguments); + } + } + + class FtpClientGetString extends BuiltinFunctionObject { + FtpClientGetString (String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.getString (arguments); + } + } + + class FtpClientLogout extends BuiltinFunctionObject { + FtpClientLogout(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.logout (arguments); + } + } + + class FtpClientBinary extends BuiltinFunctionObject { + FtpClientBinary(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.binary (arguments); + } + } + + class FtpClientAscii extends BuiltinFunctionObject { + FtpClientAscii(String name, Evaluator evaluator, FunctionPrototype fp) { + super(fp, evaluator, name, 1); + } + public ESValue callFunction(ESObject thisObject, + ESValue[] arguments) + throws EcmaScriptException { + ESFtpClient ftp = (ESFtpClient) thisObject; + return ftp.ascii (arguments); + } + } + + + public void initializeExtension(Evaluator evaluator) throws EcmaScriptException { + + this.evaluator = evaluator; + GlobalObject go = evaluator.getGlobalObject(); + ObjectPrototype op = (ObjectPrototype) evaluator.getObjectPrototype(); + FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype(); + + esFtpPrototype = new ESFtpClient (op, evaluator); + + ESObject globalFtpObject = new GlobalObjectFtpClient("FtpClient", evaluator, fp); + globalFtpObject.putHiddenProperty("prototype",esFtpPrototype); + globalFtpObject.putHiddenProperty("length",new ESNumber(1)); + + + esFtpPrototype.putHiddenProperty("login", new FtpClientLogin("login", evaluator, fp)); + esFtpPrototype.putHiddenProperty("cd", new FtpClientCD("cd", evaluator, fp)); + esFtpPrototype.putHiddenProperty("mkdir", new FtpClientMKDIR("mkdir", evaluator, fp)); + esFtpPrototype.putHiddenProperty("lcd", new FtpClientLCD("lcd", evaluator, fp)); + esFtpPrototype.putHiddenProperty("putFile", new FtpClientPutFile("putFile", evaluator, fp)); + esFtpPrototype.putHiddenProperty("putString", new FtpClientPutString("putString", evaluator, fp)); + esFtpPrototype.putHiddenProperty("getFile", new FtpClientGetFile("getFile", evaluator, fp)); + esFtpPrototype.putHiddenProperty("getString", new FtpClientGetString("getString", evaluator, fp)); + esFtpPrototype.putHiddenProperty("logout", new FtpClientLogout("logout", evaluator, fp)); + esFtpPrototype.putHiddenProperty("binary", new FtpClientBinary("binary", evaluator, fp)); + esFtpPrototype.putHiddenProperty("ascii", new FtpClientAscii("ascii", evaluator, fp)); + + go.putHiddenProperty("FtpClient", globalFtpObject); + + } + } diff --git a/src/helma/scripting/fesi/extensions/ImageExtension.java b/src/helma/scripting/fesi/extensions/ImageExtension.java new file mode 100644 index 00000000..a7cfc7d2 --- /dev/null +++ b/src/helma/scripting/fesi/extensions/ImageExtension.java @@ -0,0 +1,133 @@ +// ImageExtension.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + +package helma.scripting.fesi.extensions; + +import helma.objectmodel.*; +import helma.util.*; +import helma.image.*; + +import FESI.Interpreter.*; +import FESI.Exceptions.*; +import FESI.Extensions.*; +import FESI.Data.*; + +import java.io.*; +import java.awt.image.*; +import java.util.*; +import java.rmi.Naming; + + +/** + * Extension to do Image manipulation from HOP. + */ + +public class ImageExtension extends Extension { + + protected Evaluator evaluator = null; + + static boolean remote = false; + + + public ImageExtension () { + super(); + } + + + class GlobalObjectImage extends BuiltinFunctionObject { + + ImageExtension imagex; + ImageGenerator imggen; + + GlobalObjectImage (String name, Evaluator evaluator, FunctionPrototype fp, ImageExtension imagex) { + super(fp, evaluator, name, 1); + this.imagex = imagex; + } + + public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + return doConstruct(thisObject, arguments); + } + + public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + Object img = null; + IRemoteGenerator rgen = null; + + try { + if (imggen == null && !remote) { + try { + imggen = new ImageGenerator (); + } catch (UnsatisfiedLinkError noawt) { + remote = true; + } + } + + if (remote) + rgen = (IRemoteGenerator) Naming.lookup ("//localhost:3033/server"); + + if (arguments.length == 1) { + if (arguments[0] instanceof ESArrayWrapper) { + Object obj = ((ESArrayWrapper) arguments[0]).toJavaObject (); + if (obj instanceof byte[]) { + img = remote ? + (Object) rgen.createImage ((byte[]) obj) : + (Object) imggen.createImage ((byte[]) obj); + } + } else if (arguments[0] instanceof ESString) { + String imgurl = arguments[0].toString (); + img = remote ? + (Object) rgen.createPaintableImage (imgurl) : + (Object) imggen.createPaintableImage (imgurl); + } + } else if (arguments.length == 2) { + if (arguments[0] instanceof ESWrapper && arguments[1] instanceof ESWrapper) { + // create a new image from an existing one and an image filter + Object image = arguments[0].toJavaObject (); + Object filter = arguments[1].toJavaObject (); + img = imggen.createPaintableImage ((ImageWrapper) image, (ImageFilter) filter); + } else if (arguments[0].isNumberValue () && arguments[1].isNumberValue ()) { + img = remote ? + (Object) rgen.createPaintableImage (arguments[0].toInt32(), arguments[1].toInt32()) : + (Object) imggen.createPaintableImage (arguments[0].toInt32(), arguments[1].toInt32()); + } + } + } catch (Exception error) { + System.err.println ("Error creating Image: "+error); + } + + if (img == null) + throw new EcmaScriptException ("Error creating image: Bad parameters or setup problem."); + + return new ESWrapper (img, this.evaluator); + } + } + + + /** + * Called by the evaluator after the extension is loaded. + */ + public void initializeExtension(Evaluator evaluator) throws EcmaScriptException { + + this.evaluator = evaluator; + GlobalObject go = evaluator.getGlobalObject(); + FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype(); + + ESObject image = new GlobalObjectImage ("Image", evaluator, fp, this); // the Image constructor + + go.putHiddenProperty("Image", image); // register the constructor for a Image object. + + } + + + } + + + + + + + + + + + + diff --git a/src/helma/scripting/fesi/extensions/MailExtension.java b/src/helma/scripting/fesi/extensions/MailExtension.java new file mode 100644 index 00000000..da4c5a30 --- /dev/null +++ b/src/helma/scripting/fesi/extensions/MailExtension.java @@ -0,0 +1,255 @@ +// MailExtension.java +// Copyright (c) Hannes Wallnöfer 1998-2000 + +package helma.scripting.fesi.extensions; + +import helma.main.Server; +import helma.util.*; + +import FESI.Interpreter.*; +import FESI.Exceptions.*; +import FESI.Extensions.*; +import FESI.Data.*; + +import java.io.*; +import java.util.*; + + +/** + * Extension to create and send mail messages via SMTP from HOP applications + */ + +public class MailExtension extends Extension { + + + protected Evaluator evaluator = null; + protected ObjectPrototype esMailPrototype = null; + protected Properties mprops; + + + public MailExtension () { + super(); + } + + public void setProperties (Properties props) { + this.mprops = props; + } + + /** + * Called by the evaluator after the extension is loaded. + */ + public void initializeExtension(Evaluator evaluator) throws EcmaScriptException { + + this.evaluator = evaluator; + GlobalObject go = evaluator.getGlobalObject(); + FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype(); + + ESObject op = evaluator.getObjectPrototype(); + esMailPrototype = new ObjectPrototype(op, evaluator); // the Node prototype + + ESObject mail = new GlobalObjectMail ("Mail", evaluator, fp, this); // the Mail constructor + + go.putHiddenProperty("Mail", mail); // register the constructor for a Mail object. + + + // methods for sending mail from JS... + ESObject p = new MailSetText ("setText", evaluator, fp); + esMailPrototype.putHiddenProperty("setText", p); + esMailPrototype.putHiddenProperty("addText", p); + + esMailPrototype.putHiddenProperty("addPart", new MailAddPart ("addPart", evaluator, fp)); + esMailPrototype.putHiddenProperty("setSubject", new MailSetSubject ("setSubject", evaluator, fp)); + esMailPrototype.putHiddenProperty("setReplyTo", new MailSetReplyTo ("setReplyTo", evaluator, fp)); + esMailPrototype.putHiddenProperty("setFrom", new MailSetFrom ("setFrom", evaluator, fp)); + + p = new MailAddTo ("addTo", evaluator, fp); + esMailPrototype.putHiddenProperty("addTo", p); + esMailPrototype.putHiddenProperty("setTo", p); + + p = new MailAddCC ("addCC", evaluator, fp); + esMailPrototype.putHiddenProperty("addCC", p); + esMailPrototype.putHiddenProperty("setCC", p); + + p = new MailAddBCC ("addBCC", evaluator, fp); + esMailPrototype.putHiddenProperty("addBCC", p); + esMailPrototype.putHiddenProperty("setBCC", p); + + esMailPrototype.putHiddenProperty("send", new MailSend ("send", evaluator, fp)); + + } + + + class GlobalObjectMail extends BuiltinFunctionObject { + + MailExtension mailx; + + GlobalObjectMail (String name, Evaluator evaluator, FunctionPrototype fp, MailExtension mailx) { + super(fp, evaluator, name, 1); + this.mailx = mailx; + } + + public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + return doConstruct(thisObject, arguments); + } + + public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = null; + + if (arguments.length == 0) { + mail = new ESMail (mailx); + } else { + mail = new ESMail (mailx); + // should/could do something with extra arguments... + } + return mail; + } + } + + + class MailSetText extends BuiltinFunctionObject { + MailSetText (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = (ESMail) thisObject; + if (arguments.length == 1) try { + mail.setText (arguments[0]); + } catch (Exception x) { + mail.setStatus (ESMail.TEXT); + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + } + + class MailAddPart extends BuiltinFunctionObject { + MailAddPart (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = (ESMail) thisObject; + try { + mail.addPart (arguments); + } catch (Exception x) { + mail.setStatus (ESMail.MIMEPART); + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + } + + class MailSetSubject extends BuiltinFunctionObject { + MailSetSubject (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = (ESMail) thisObject; + if (arguments.length == 1) try { + mail.setSubject (arguments[0]); + } catch (Exception x) { + mail.setStatus (ESMail.SUBJECT); + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + } + + class MailSetReplyTo extends BuiltinFunctionObject { + MailSetReplyTo (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = (ESMail) thisObject; + if (arguments.length == 1) try { + mail.setReplyTo (arguments[0]); + } catch (Exception x) { + mail.setStatus (ESMail.REPLYTO); + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + } + + class MailSetFrom extends BuiltinFunctionObject { + MailSetFrom (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = (ESMail) thisObject; + try { + mail.setFrom (arguments); + } catch (Exception x) { + mail.setStatus (ESMail.FROM); + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + } + + class MailAddTo extends BuiltinFunctionObject { + MailAddTo (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = (ESMail) thisObject; + try { + mail.addTo (arguments); + } catch (Exception x) { + mail.setStatus (ESMail.TO); + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + } + + class MailAddCC extends BuiltinFunctionObject { + MailAddCC (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = (ESMail) thisObject; + try { + mail.addCC (arguments); + } catch (Exception x) { + mail.setStatus (ESMail.CC); + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + } + + class MailAddBCC extends BuiltinFunctionObject { + MailAddBCC (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = (ESMail) thisObject; + try { + mail.addBCC (arguments); + } catch (Exception x) { + mail.setStatus (ESMail.BCC); + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + } + + class MailSend extends BuiltinFunctionObject { + MailSend (String name, Evaluator evaluator, FunctionPrototype fp) { + super (fp, evaluator, name, 1); + } + public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { + ESMail mail = (ESMail) thisObject; + try { + mail.send (); + } catch (Exception x) { + Server.getLogger().log ("Error sending mail: "+x); + mail.setStatus (ESMail.SEND); + return ESBoolean.makeBoolean(false); + } + return ESBoolean.makeBoolean(true); + } + } + +} +