diff --git a/src/Acme/Serve/FileServlet.java b/src/Acme/Serve/FileServlet.java
index 3a8c59a3..427a1fda 100644
--- a/src/Acme/Serve/FileServlet.java
+++ b/src/Acme/Serve/FileServlet.java
@@ -179,7 +179,7 @@ public class FileServlet extends HttpServlet
protected void serveFile( HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, String filename, File file ) throws IOException
{
- // log( "getting " + path );
+ log( "getting " + path );
if ( ! file.canRead() )
{
res.sendError( HttpServletResponse.SC_FORBIDDEN );
diff --git a/src/Acme/Serve/Serve.java b/src/Acme/Serve/Serve.java
index a7c8390b..49214072 100644
--- a/src/Acme/Serve/Serve.java
+++ b/src/Acme/Serve/Serve.java
@@ -147,8 +147,6 @@ public class Serve implements ServletContext, Runnable
private int port;
private PrintStream logStream;
Acme.WildcardDictionary registry;
- // the servlet to use if no other matches the request
- Servlet defaultServlet;
Properties props;
/// Constructor.
@@ -270,10 +268,6 @@ public class Serve implements ServletContext, Runnable
registry.remove (urlPat);
}
- public void setDefaultServlet (Servlet servlet) {
- defaultServlet = servlet;
- }
-
/// Register a standard set of Servlets. These will return
// files or directory listings, and run CGI programs, much like a
// standard HTTP server.
@@ -457,7 +451,8 @@ public class Serve implements ServletContext, Runnable
// Same as the CGI variable SERVER_SOFTWARE.
public String getServerInfo()
{
- return ServeUtils.serverName + " " + helma.main.Server.version + " (" + ServeUtils.serverUrl + ")";
+ return ServeUtils.serverName + " " + ServeUtils.serverVersion +
+ " (" + ServeUtils.serverUrl + ")";
}
/// Returns the value of the named attribute of the network service, or
@@ -658,11 +653,6 @@ class ServeConnection implements Runnable, HttpServletRequest, HttpServletRespon
if (reqQuery != null)
reqQuery = decode (reqQuery);
Servlet servlet = (Servlet) serve.registry.get( reqUriPath );
- // maybe the application name without slash? try with slash appended
- if (servlet == null)
- servlet = (Servlet) serve.registry.get (reqUriPath+"//");
- if (servlet == null)
- servlet = serve.defaultServlet;
if ( servlet != null )
runServlet( (HttpServlet) servlet );
else if ( "/".equals( reqUriPath ))
@@ -687,7 +677,7 @@ class ServeConnection implements Runnable, HttpServletRequest, HttpServletRespon
setStatus( SC_OK );
setDateHeader( "Date", System.currentTimeMillis() );
setHeader(
- "Server", ServeUtils.serverName + "/" + helma.main.Server.version );
+ "Server", ServeUtils.serverName + "/" + ServeUtils.serverVersion );
setHeader( "Connection", "close" );
try
{
diff --git a/src/Acme/Serve/ServeUtils.java b/src/Acme/Serve/ServeUtils.java
index d1c73264..b580ae63 100644
--- a/src/Acme/Serve/ServeUtils.java
+++ b/src/Acme/Serve/ServeUtils.java
@@ -42,9 +42,8 @@ public class ServeUtils
{
// Server identification.
- public static final String serverName = "Helma";
- // we're using the server version from helma.main.Server class.
- // public static final String serverVersion = "1.2 p1";
+ public static final String serverName = "Hop";
+ public static final String serverVersion = "1.1 p1";
public static final String serverUrl = "http://helma.org/";
/// Write a standard-format HTML address for this server.
@@ -53,7 +52,7 @@ public class ServeUtils
PrintStream p = new PrintStream( o );
p.println(
"
" +
- serverName + " " + helma.main.Server.version + " " );
+ serverName + " " + serverVersion + "" );
}
@@ -92,4 +91,3 @@ public class ServeUtils
}
}
-
diff --git a/src/FESI/Data/ESLoader.java b/src/FESI/Data/ESLoader.java
index 7566809a..b6b05d58 100644
--- a/src/FESI/Data/ESLoader.java
+++ b/src/FESI/Data/ESLoader.java
@@ -260,11 +260,8 @@ public abstract class ESLoader extends ESObject {
return (ESArrayWrapper) obj; // An array wrapper received externally
} else if (obj.getClass().isArray()) {
return new ESArrayWrapper(obj, evaluator);
- } // else if (obj instanceof helma.framework.IPathElement) { // Hannes Wallnoefer, 13. Aug 2001
- // return evaluator.reval.getElementWrapper ((helma.framework.IPathElement) obj);
- // }
- // return new ESWrapper(obj, evaluator);
- return evaluator.reval.getObjectWrapper (obj);
+ }
+ return new ESWrapper(obj, evaluator);
}
/**
@@ -338,7 +335,6 @@ public abstract class ESLoader extends ESObject {
* Check that each object in the paremeter array can be converted
* to the type specified by the target array and convert them if needed.
* Even if the parameters are compatible with an EcmaScript value,
-
* some may have to be converted to an intermediate type. For example
* an EcmaScript string of 1 character long is compatible with a Java
* Character, but some conversion is needed. Arrays need a similar
@@ -386,7 +382,6 @@ public abstract class ESLoader extends ESObject {
if (targetClass.isPrimitive()) { // or: Object.class.isAssignableFrom(targetClass)
accepted = false;
debugInfo = " rejected (null cannot be assigned to primitive)";
-
} else {
accepted = true;
debugInfo = " accepted (null to Object)";
diff --git a/src/FESI/Data/ESObject.java b/src/FESI/Data/ESObject.java
index 17899d32..162f7d02 100644
--- a/src/FESI/Data/ESObject.java
+++ b/src/FESI/Data/ESObject.java
@@ -105,16 +105,6 @@ public abstract class ESObject extends ESValue {
}
- /**
- * Allow the prototype to be set, added 2001-04-05 by Hannes Wallnöfer
- *
- * @param prototype The new prototype object
- */
- public void setPrototype(ESObject prototype) {
- this.prototype = prototype;
- }
-
-
/**
* Return the name of the class of objects ([[class]]), as used in the default toString
* method of objects (15.2.4.2)
diff --git a/src/FESI/Data/ESWrapper.java b/src/FESI/Data/ESWrapper.java
index 06e1172b..79413858 100644
--- a/src/FESI/Data/ESWrapper.java
+++ b/src/FESI/Data/ESWrapper.java
@@ -338,10 +338,9 @@ public class ESWrapper extends ESObject {
return noPropertyMarker;
}
int modifiers = fld.getModifiers();
- // ALLOW ACCESS TO STATIC FIELDS. HW, 2001-11-27
- // if ((theObject == null) != Modifier.isStatic(modifiers)) {
- // throw new EcmaScriptException("Field mode (static) not correct for "+ propertyName);
- // }
+ if ((theObject == null) != Modifier.isStatic(modifiers)) {
+ throw new EcmaScriptException("Field mode (static) not correct for "+ propertyName);
+ }
if (!Modifier.isPublic(modifiers)) {
throw new EcmaScriptException("Field "+ propertyName + " not public");
}
diff --git a/src/FESI/FESI.changes b/src/FESI/FESI.changes
index f2cb4905..3332a08b 100644
--- a/src/FESI/FESI.changes
+++ b/src/FESI/FESI.changes
@@ -15,11 +15,3 @@ Changes to standard FESI distribution (1.1.4) for Hop
ESNumber.
- Made EcmaScriptFunctionVisitor recognise thisObj - Functions are now assigned
to the current thisObject.
-- Added setPrototype() method to FESI.Data.ESObject to be able to manipulate
- the prototype after the object was created.
-- Changed FESI.Interpreter.EcmaScriptEvaluateVisitor to use .equals instead of
- == in equal method for helma.framework.core.ESNode objects, since different
- wrappers may wrap the same object.
-- Added RequestEvaluator reval field to FESI.Interpreter.Evaluator in order to
- let ESLoader crate wrappers with correct prototype for path element objects.
-
diff --git a/src/FESI/Interpreter/EcmaScriptEvaluateVisitor.java b/src/FESI/Interpreter/EcmaScriptEvaluateVisitor.java
index 4a0d7959..f9350cb7 100644
--- a/src/FESI/Interpreter/EcmaScriptEvaluateVisitor.java
+++ b/src/FESI/Interpreter/EcmaScriptEvaluateVisitor.java
@@ -248,13 +248,6 @@ public class EcmaScriptEvaluateVisitor
return b1==b2;
}
- // ESNode wrappers must be checked with equals() because
- // it's possible that different wrappers wrap the same node!
- if (v1 instanceof helma.scripting.fesi.ESNode ||
- v1 instanceof helma.scripting.fesi.ESGenericObject) {
- return v1.equals (v2);
- }
-
return v1 == v2;
}
@@ -1363,5 +1356,3 @@ public class EcmaScriptEvaluateVisitor
}
}
-
-
diff --git a/src/FESI/Interpreter/Evaluator.java b/src/FESI/Interpreter/Evaluator.java
index 21f13952..3380641a 100644
--- a/src/FESI/Interpreter/Evaluator.java
+++ b/src/FESI/Interpreter/Evaluator.java
@@ -44,8 +44,6 @@ public class Evaluator {
// used to stop thread, 06.12.99 Hannes Wallnoefer
public volatile Thread thread;
- // used to retrieve wrappers with correct Prototype for path elements in ESLoader
- public helma.scripting.fesi.FesiEvaluator reval;
private static String eol = System.getProperty("line.separator", "\n");
diff --git a/src/helma/doc/DocApplication.java b/src/helma/doc/DocApplication.java
deleted file mode 100644
index 06d6b322..00000000
--- a/src/helma/doc/DocApplication.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package helma.doc;
-
-import helma.framework.IPathElement;
-import helma.main.Server;
-import java.io.*;
-import java.util.*;
-
-public class DocApplication extends DocElement implements IPathElement {
-
- private DocPrototype[] prototypes;
-
- /** read all prototypes
- * @param name application to be documented
- * @param appDir directory of this application */
- public DocApplication(String name, String appDir) throws DocException {
- super( name, appDir, APPLICATION );
- checkCommentFile();
- readPrototypes();
- }
-
- public String getFullName() {
- return ( "Application " + name );
- }
-
- /** return number of prototypes */
- public int countPrototypes() {
- return prototypes.length;
- }
-
- /** return a single prototype */
- public DocPrototype getDocPrototype(String name) {
- for ( int i=0; ie2.getType() )
- return 1;
- else if ( mode==BY_TYPE && e1.getType()=METHOD && type<=SKIN ) return true; else return false; }
- public boolean isAction() { return (type==ACTION)?true:false; }
- public boolean isTemplate() { return (type==TEMPLATE)?true:false; }
- public boolean isFunction() { return (type==FUNCTION)?true:false; }
- public boolean isMacro() { return (type==MACRO)?true:false; }
- public boolean isSkin() { return (type==SKIN)?true:false; }
-
- public int getType() { return type; }
- public String getTypeName() { return typeNames[type]; }
-
- public String getDocFileName() { return (typeNames[type] + "_" + name).toLowerCase() + ".html"; }
-
- /** @return the text of the comment */
- public String getComment() { return (comment!=null)?comment:""; }
-
- public int countTags() { return countTags(-1); }
- public int countTags(int kind) {
- int ct=0;
- for ( int i=0; ibeginLine && ct");
- else
- print("");
- print("");
- print("");
- println("" + title + " ");
- if ( frameset==true )
- print(" ");
- println("");
- }
-
-
- public void printFrameSet() {
- println ("");
- println (" ");
- println (" ");
- println (" sorry, your browser doesn't understand frames! ");
- }
-
- /** print app title for left frame */
- public void printAppIndexTitle(String title) {
- print("");
- print("");
- print("Application " + title + "
" );
- }
-
- /** print prototype list for left frame */
- public void printAppIndexList(DocElement[] pt) {
- print("");
- }
-
- /** navigation on top of the page **/
- public void printNavBar(String name, DocPrototype pt, int page ) {
- String urlPrefix = ( page==METHOD ) ? "../" : "";
- print("");
- print(" ");
- print("");
- print("");
- print(" ");
-
- print("");
- print("");
- if ( page==APPLICATION )
- print("Application ");
- else
- print("Application ");
- if ( page==PROTOTYPE )
- print(" Prototype ");
- else if ( page==METHOD )
- print(" Prototype ");
- else
- print(" Prototype ");
- if ( page==INDEX )
- print("Index ");
- else
- print("Index ");
- print("
");
-
- print(" Application " + name + " ");
- print(" ");
- if ( pt!=null && page!=METHOD ) {
- print("");
- print("ACTIONS | ");
- print("TEMPLATES | ");
- print("FUNCTIONS | ");
- print("MACROS | ");
- print("SKINS ");
- print(" ");
- }
-
- print("
");
- print("");
- }
-
- public void printElementTitle(DocElement docEl) {
- print("" + docEl.getName() + " ");
- print(docEl.getFullName() + " ");
- print(" ");
- }
-
- public void printComment(DocElement docEl) {
- if( docEl.getComment().length()>0 || docEl.countTags()>0 ) {
- print("" + docEl.getComment() + " ");
- print("");
- for ( int i=0; i0 ) {
- print("" + DocTag.kindDesc[i] + " ");
- DocTag[] dt = docEl.listTags(i);
- for ( int j=0; j" + renderTag(dt[j],j) + "");
- }
- }
- }
- print(" ");
- }
- }
-
- private String renderFunctionName(DocFunction func) {
- StringBuffer buf = new StringBuffer ();
- buf.append("");
- if ( DocRun.getOption("-f").equals("true") )
- buf.append("" );
- if ( func.isMacro() ) {
- buf.append( func.getDocPrototype().getName()+"."+func.getName().substring(0,func.getName().length()-6) );
- } else {
- buf.append(func.getName().trim());
- if( func.isTemplate() || func.isFunction() ) {
- buf.append("(");
- int ct = func.countTags(DocTag.ARG);
- for ( int i=0; i
");
- if ( func.isFunction() || func.isMacro() )
- buf.append(" in " + (new File(func.getLocation())).getName() + " " );
- return buf.toString();
- }
-
- private String renderTag(DocTag tag) {
- return renderTag(tag,0);
- }
-
- private String renderTag(DocTag tag, int i) {
- int kind = tag.getKind();
- String text = tag.getText();
- String name = tag.getName();
- switch (kind) {
- case DocTag.ARG:
- return( "Argument " + i + ": " + text );
- case DocTag.PARAM:
- return( "Parameter " + name + " " + text );
- case DocTag.RETURNS:
- case DocTag.AUTHOR:
- case DocTag.VERSION:
- case DocTag.RELEASE:
- return( text );
- case DocTag.SEE:
- if ( text.startsWith("http://") ) {
- StringTokenizer tok = new StringTokenizer (text.trim()," ");
- String url = (tok.countTokens()>1)?tok.nextToken():text;
- return( "" + ((tok.countTokens()>0)?text.substring(url.length(),text.length()):text) + " " );
- } else {
- StringBuffer buf = new StringBuffer();
- StringTokenizer tok = new StringTokenizer (text.trim(),".");
- if ( tok.countTokens()==0 ) return text;
- DocPrototype dp = app.getDocPrototype( tok.nextToken() );
- if ( dp==null ) return text;
- buf.append("0 )
- df = dp.getFunction( tok.nextToken() );
- if ( df==null )
- buf.append( link(dp) + "\">" + dp.getName() );
- else
- buf.append( link(df) + "\">" + dp.getName() + "." + df.getName() );
- return(buf.toString()+" ");
- }
- }
- return text;
- }
-
- public void printListHeader(String title) {
- print(" ");
- print("");
- print("" + title + " ");
- }
-
- public void printPrototypeList(DocPrototype[] dl, String title) {
- if ( dl.length==0 ) return;
- printListHeader(title);
- for ( int i=0; i");
- print(" ");
- print(" " + dl[i].getTypeName() + "
");
- print("" + dl[i].getName() + "
");
- print(" " + dl[i].getComment() + " " );
- print(" ");
- }
- print("
");
- }
-
- public void printFunctionList(DocFunction[] dl, String title) {
- if ( dl.length==0 ) return;
- printListHeader(title);
- for ( int i=0; i");
- print("");
- print(" ");
- print(" " + dl[i].getTypeName() + "
");
- print("" + renderFunctionName(dl[i]) );
- print("");
- printComment(dl[i]);
- print(" ");
- }
- print(" ");
- }
-
- public void printFunctionIndex(DocFunction[] dl) {
- if ( dl.length==0 ) return;
- String curChar = " ";
- print("");
- for ( int i=0; i" + name.substring(0,1).toUpperCase() + " ");
- curChar = name.substring(0,1).toLowerCase();
- }
- print("" + dl[i].getName() + " - " + dl[i].getTypeName() + " in " + dl[i].getDocPrototype().getName() + " " );
- }
- print(" ");
- }
-
- public void printInheritance(DocPrototype pt) {
- if ( pt.getName().equalsIgnoreCase("hopobject") )
- return;
- DocApplication app = pt.getApplication();
- DocPrototype hopobject = (DocPrototype)app.getDocPrototype("hopobject");
- if ( hopobject==null || hopobject.countFunctions()==0 )
- return;
- print("");
- print("");
- print("Methods inherited from Prototype hopobject ");
- print(" ");
- print("");
- DocFunction[] df = hopobject.listFunctions();
-
- int lastType = -1;
- StringBuffer buf1 = new StringBuffer();
- StringBuffer buf2 = new StringBuffer();
-
- for ( int i=0; i0 && buf2.length()>0 ) {
- buf1.append("" + DocElement.typeNames[lastType] + ": " );
- buf1.append( buf2.toString().substring(0, buf2.toString().length()-2) );
- buf1.append("
");
- buf2 = new StringBuffer();
- }
- lastType = df[i].getType();
- buf2.append ( "" + df[i].getName() + " , " );
- }
- if ( buf2.length()>0 ) {
- buf1.append("" + DocElement.typeNames[lastType] + ": " );
- buf1.append( buf2.toString().substring(0, buf2.toString().length()-2) );
- buf1.append("
");
- }
- print ( buf1.toString() );
- print("
");
- }
-
- public void printFunction(DocFunction func) {
- print( "in " + func.getDocPrototype().getName() + "/" + (new File(func.getLocation())).getName() + ": " );
- print( "");
- print( HtmlEncoder.encodeAll(func.getSource()) );
- print( " " );
- }
-
- public void printStyleSheet() {
- println( "/* Javadoc style sheet */");
- println( "/* Define colors, fonts and other style attributes here to override the defaults */");
- println( "* Page background color */");
- println( "body { background-color: #FFFFFF }");
- println( "/* Table colors */");
- println( "#TableHeadingColor { background: #CCCCFF } /* Dark mauve */");
- println( "#TableSubHeadingColor { background: #EEEEFF } /* Light mauve */");
- println( "#TableRowColor { background: #FFFFFF } /* White */");
- println( "/* Font used in left-hand frame lists */");
- println( "#FrameTitleFont { font-size: normal; font-family: normal }");
- println( "#FrameHeadingFont { font-size: normal; font-family: normal }");
- println( "#FrameItemFont { font-size: normal; font-family: normal }");
- println( "/* Example of smaller, sans-serif font in frames */");
- println( "/* #FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */");
- println( "/* Navigation bar fonts and colors */");
- println( "#NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */");
- println( "#NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */");
- println( "#NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;}");
- println( "#NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}");
- println( "#NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}");
- println( "#NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}");
- }
-
- public String link(DocElement docEl) {
- if ( docEl.isPrototype() ) {
- return "prototype_" + docEl.getName() + ".html";
- } else if ( docEl.isMethod() ) {
- DocFunction df = (DocFunction)docEl;
- return "prototype_" + df.getDocPrototype().getName() + ".html#" + df.getName();
- } else {
- return "";
- }
- }
-
-}
-
diff --git a/src/helma/doc/DocPrototype.java b/src/helma/doc/DocPrototype.java
deleted file mode 100644
index 7af3120d..00000000
--- a/src/helma/doc/DocPrototype.java
+++ /dev/null
@@ -1,221 +0,0 @@
-package helma.doc;
-
-import helma.framework.IPathElement;
-import java.io.*;
-import java.util.*;
-import FESI.Parser.*;
-
-
-public class DocPrototype extends DocElement implements IPathElement {
-
- DocFunction[] functions;
- DocApplication app;
-
- public DocPrototype( String name, String location, DocApplication app ) throws DocException {
- super( name, location, PROTOTYPE );
- this.app = app;
- if ( name.equals("hopobject")==false && name.equals("global")==false )
- readPropertiesFile( new File(location,"type.properties").getAbsolutePath());
- checkCommentFile();
- readFunctions();
- }
-
- public String getFullName() { return ( "Prototype " + name ); }
-
- /** return number of functions */
- public int countFunctions() { return functions.length; }
-
- /** return array of functions of a special type */
- public int countFunctions(int type) {
- int ct = 0;
- for ( int i=0; i")) );
- EcmaScriptTokenManager mgr = new EcmaScriptTokenManager(new ASCII_CharStream(str,1,1),0);
- Token tok = mgr.getNextToken();
- func = new DocFunction( fileToFuncName(f), f, DocElement.TEMPLATE, this, getCommentFromToken(tok) );
- } catch ( IndexOutOfBoundsException e ) {
- func = new DocFunction( fileToFuncName(f), f, DocElement.TEMPLATE, this, "" );
- }
- func.setSource(content);
- funcVec.addElement(func);
- }
-
- private void readSkin(String f, Vector funcVec) throws DocException {
- // can't be commented yet
- // simply add them
- DocFunction func = new DocFunction(fileToFuncName(f),f,DocElement.SKIN, this,"");
- func.readSource(f);
- funcVec.addElement(func);
- }
-
-
- /** create token manager for a file */
- private EcmaScriptTokenManager createTokenManager(File f) {
- try {
- ASCII_CharStream is = new ASCII_CharStream(new FileReader(f), 1, 1);
- EcmaScriptTokenManager mgr = new EcmaScriptTokenManager(is,0);
- return mgr;
- } catch ( FileNotFoundException shouldnotappear ) { }
- return null;
- }
-
- /** connect all available specialTokens */
- private String getCommentFromToken(Token tok) {
- StringBuffer buf = new StringBuffer();
- while( tok.specialToken!=null ) {
- buf.append(tok.specialToken.toString() );
- tok = tok.specialToken;
- }
- return ( buf.toString().trim() );
- }
-
- private String fileToFuncName(String f) {
- return fileToFuncName(new File(f));
- }
-
- private String fileToFuncName(File f) {
- String tmp = f.getName();
- return tmp.substring(0,tmp.indexOf("."));
- }
-
- public String toString() {
- return ( "[DocPrototype " + name + "]" );
- }
-
-
- ////////////////////////////////////
- // from helma.framework.IPathElement
- ////////////////////////////////////
-
- public String getElementName() {
- return name;
- }
-
- public IPathElement getChildElement(String name) {
- for ( int i=0; i 0) {
- if (buf.toString().length() == 0) {
- usageError = true;
- } else {
- options.put(name, buf.toString());
- }
- }
- name = args[i];
- buf = new StringBuffer();
- } else {
- buf.append(((buf.toString().length() > 0) ? " " : "") + args[i]);
- }
- }
- options.put(name, buf.toString());
- // include last option
- // now check parameter
- if (options.containsKey("-h")) {
- hopHomeDir = (String) options.get("-h");
- } else {
- hopHomeDir = System.getProperty("user.dir");
- }
- readHopProperties(hopHomeDir);
- String parAppDir = "";
- if (options.containsKey("-a")) {
- parAppDir = (String) options.get("-a");
- } else {
- usageError = true;
- }
- if (usageError == true) {
- help();
- System.exit(0);
- }
- try {
- new DocRun(parAppDir);
- } catch (DocException e) {
- System.out.println("doc error: " + e.getMessage());
- }
- }
-
-
- /**
- * Description of the Method
- */
- public static void help() {
- System.out.println("usage: java helma.doc.DocApplication -a appdir [-f] [-h hopdir] [-d docdir] [-i ignore]");
- System.out.println(" -a appdir Specify source directory");
- System.out.println(" -h hopdir Specify hop home directory");
- System.out.println(" -d docdir Specify destination directory");
- System.out.println(" -f true Link functions to source code");
- System.out.println(" -i ignore Specify prototypes to ignore (like: \"-i CVS mistsack\")");
- System.out.println(" -debug");
- System.out.println("\n");
- }
-
-
- /**
- * Description of the Method
- *
- *@param name Description of Parameter
- *@return Description of the Returned Value
- */
- public static boolean prototypeAllowed(String name) {
- String ig = " " + getOption("-i").toLowerCase() + " ";
- if (ig.equals("")) {
- return true;
- }
- name = name.toLowerCase();
- if (ig.indexOf(" " + name + " ") > -1) {
- return false;
- } else {
- return true;
- }
- }
-
-
- /**
- * reads server.properties, apps.properties and db.properties from
- * hop-home-directory TBD: should be cleaned up to work exactly like the
- * helma server
- *
- *@param hopHomeDir Description of Parameter
- */
- public static void readHopProperties(String hopHomeDir) {
- propfile = new File(hopHomeDir, "server.properties").getAbsolutePath();
- sysProps = new SystemProperties(propfile);
- dbProps = new SystemProperties(new File(hopHomeDir, "db.properties").getAbsolutePath());
- actionExtension = sysProps.getProperty("actionExtension", ".hac");
- scriptExtension = sysProps.getProperty("scriptExtension", ".js");
- templateExtension = sysProps.getProperty("templateExtension", ".hsp");
- }
-
-
- /**
- * Description of the Method
- *
- *@param msg Description of Parameter
- */
- public static void debug(String msg) {
- if (options.containsKey("-debug")) {
- System.out.println(msg);
- }
- }
-
-
- /**
- * Description of the Method
- *
- *@param msg Description of Parameter
- */
- public static void log(String msg) {
- System.out.println(msg);
- }
-
-}
-
-
diff --git a/src/helma/doc/DocTag.java b/src/helma/doc/DocTag.java
deleted file mode 100644
index 63c5ee70..00000000
--- a/src/helma/doc/DocTag.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package helma.doc;
-
-import java.util.*;
-
-public class DocTag {
-
- public static final int ARG = 0;
- public static final int PARAM = 1;
- public static final int RETURNS = 2;
- public static final int AUTHOR = 3;
- public static final int VERSION = 4;
- public static final int RELEASE = 5;
- public static final int SEE = 6;
-
- /** number of different tag-types **/
- public static final int TYPE_COUNT = 7;
-
- /** constants are used as array indices! **/
- public static final String[] kindNames = {"arg","param","return","author","version","release","see"};
- public static final String[] kindDesc = {"Arguments","Parameter","Returns","Author","Version","Release","See also"};
-
- private String name;
- private int kind;
- private String text;
-
- public DocTag( String rawTag ) throws DocException {
- //DocRun.log(rawTag);
- try {
- StringTokenizer tok = new StringTokenizer(rawTag);
- String kindstr = tok.nextToken().toLowerCase();
- for ( int i=0; i
- *
- * Please note that this interface is still work in progress. You should expect it to get some
- * additional methods that allow for looping through child elements, for example, or retrieving the
- * parent element.
- *
- */
-
-public interface IPathElement {
-
- /**
- * Return the name to be used to get this element from its parent
- */
- public String getElementName ();
-
- /**
- * Retrieve a child element of this object by name.
- */
- public IPathElement getChildElement (String name);
-
- /**
- * Return the parent element of this object.
- */
- public IPathElement getParentElement ();
-
-
- /**
- * Get the name of the prototype to be used for this object. This will
- * determine which scripts, actions and skins can be called on it
- * within the Helma scripting and rendering framework.
- */
- public String getPrototype ();
-
-}
-
-
-
-
diff --git a/src/helma/framework/IRemoteApp.java b/src/helma/framework/IRemoteApp.java
index 5bbe2b65..4970e536 100644
--- a/src/helma/framework/IRemoteApp.java
+++ b/src/helma/framework/IRemoteApp.java
@@ -4,7 +4,6 @@
package helma.framework;
import java.rmi.*;
-import java.util.Vector;
/**
* RMI interface for an application. Currently only execute is used and supported.
@@ -14,6 +13,8 @@ public interface IRemoteApp extends Remote {
public ResponseTrans execute (RequestTrans param) throws RemoteException;
+ public ResponseTrans get (String path, String sessionID) throws RemoteException;
+
public void ping () throws RemoteException;
}
diff --git a/src/helma/framework/IReplicatedApp.java b/src/helma/framework/IReplicatedApp.java
deleted file mode 100644
index 8b1bd732..00000000
--- a/src/helma/framework/IReplicatedApp.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// IReplicatedApp.java
-// Copyright (c) Hannes Wallnöfer 2001
-
-package helma.framework;
-
-import java.rmi.*;
-import java.util.Vector;
-
-/**
- * RMI interface for an application that is able to replicate it's node cache.
- */
-
-public interface IReplicatedApp extends Remote {
-
- public void replicateCache (Vector add, Vector delete) throws RemoteException;
-
-}
diff --git a/src/helma/framework/RedirectException.java b/src/helma/framework/RedirectException.java
index 1e43d979..21a54d00 100644
--- a/src/helma/framework/RedirectException.java
+++ b/src/helma/framework/RedirectException.java
@@ -3,13 +3,14 @@
package helma.framework;
+import FESI.Exceptions.EcmaScriptException;
-/**
+/**
* RedirectException is thrown internally when a response is redirected to a
* new URL.
*/
-
-public class RedirectException extends RuntimeException {
+
+public class RedirectException extends EcmaScriptException {
String url;
@@ -17,17 +18,17 @@ public class RedirectException extends RuntimeException {
super ("Redirection Request to "+url);
this.url = url;
}
-
+
public String getMessage () {
- return url;
+ return url;
}
+
+ public void printStackTrace(java.io.PrintStream s) {
- public void printStackTrace(java.io.PrintStream s) {
- // do nothing
}
public void printStackTrace(java.io.PrintWriter w) {
- // do nothing
+
}
}
diff --git a/src/helma/framework/RequestTrans.java b/src/helma/framework/RequestTrans.java
index 16c8a212..b45fcc33 100644
--- a/src/helma/framework/RequestTrans.java
+++ b/src/helma/framework/RequestTrans.java
@@ -6,83 +6,52 @@ package helma.framework;
import java.io.*;
import java.util.*;
import helma.objectmodel.*;
-import helma.xmlrpc.Base64;
/**
* A Transmitter for a request from the servlet client. Objects of this
* class are directly exposed to JavaScript as global property req.
*/
-public class RequestTrans implements Externalizable {
+public class RequestTrans implements Serializable {
- // the uri path of the request
public String path;
- // the request's session id
public String session;
- // the map of form and cookie data
- private Map values;
- // the request method - 0 for GET, 1 for POST
- private byte httpMethod = 0;
+ private Hashtable values;
// this is used to hold the EcmaScript form data object
public transient Object data;
// when was execution started on this request?
public transient long startTime;
- // the name of the action being invoked
- public transient String action;
-
- private transient String httpUsername;
- private transient String httpPassword;
-
- static final long serialVersionUID = 5398880083482000580L;
-
- /**
- * Create a new Request transmitter with an empty data map.
- */
public RequestTrans () {
- httpMethod = 0;
- values = new HashMap ();
+ super ();
+ values = new Hashtable ();
}
- /**
- * Create a new request transmitter with the given data map.
- */
- public RequestTrans (byte method) {
- httpMethod = method;
- values = new HashMap ();
+ public RequestTrans (Hashtable values) {
+ this.values = values;
}
- /**
- * Set a parameter value in this request transmitter.
- */
public void set (String name, Object value) {
values.put (name, value);
}
+ public Enumeration keys () {
+ return values.keys ();
+ }
- /**
- * Get a value from the requests map by key.
- */
public Object get (String name) {
try {
return values.get (name);
} catch (Exception x) {
- return null;
+ return null;
}
}
- /**
- * Get the data map for this request transmitter.
- */
- public Map getRequestData () {
+ public Hashtable getReqData () {
return values;
}
- /**
- * The hash code is computed from the session id if available. This is used to
- * detect multiple identic requests.
- */
public int hashCode () {
return session == null ? super.hashCode () : session.hashCode ();
}
@@ -97,80 +66,10 @@ public class RequestTrans implements Externalizable {
RequestTrans other = (RequestTrans) what;
return (session.equals (other.session) &&
path.equalsIgnoreCase (other.path) &&
- values.equals (other.getRequestData ()));
+ values.equals (other.getReqData ()));
} catch (Exception x) {
return false;
}
}
- /**
- * Return true if this object represents a HTTP GET Request.
- */
- public boolean isGet () {
- return httpMethod == 0;
- }
-
- /**
- * Return true if this object represents a HTTP GET Request.
- */
- public boolean isPost () {
- return httpMethod == 1;
- }
-
- /**
- * Custom externalization code for quicker serialization.
- */
- public void readExternal (ObjectInput s) throws ClassNotFoundException, IOException {
- path = s.readUTF ();
- session = s.readUTF ();
- values = (Map) s.readObject ();
- httpMethod = s.readByte ();
- }
-
- /**
- * Custom externalization code for quicker serialization.
- */
- public void writeExternal (ObjectOutput s) throws IOException {
- s.writeUTF (path);
- s.writeUTF (session);
- s.writeObject (values);
- s.writeByte (httpMethod);
- }
-
- public String getUsername() {
- if ( httpUsername!=null )
- return httpUsername;
- String auth = (String)get("authorization");
- if ( auth==null || "".equals(auth) ) {
- return null;
- }
- decodeHttpAuth(auth);
- return httpUsername;
- }
-
- public String getPassword() {
- if ( httpPassword!=null )
- return httpPassword;
- String auth = (String)get("authorization");
- if ( auth==null || "".equals(auth) ) {
- return null;
- }
- decodeHttpAuth(auth);
- return httpPassword;
- }
-
- private void decodeHttpAuth(String auth) {
- if ( auth==null )
- return;
- StringTokenizer tok;
- if( auth.startsWith("Basic ") )
- tok = new StringTokenizer ( new String( Base64.decode((auth.substring(6)).toCharArray()) ), ":" );
- else
- tok = new StringTokenizer ( new String( Base64.decode(auth.toCharArray()) ), ":" );
- try { httpUsername = tok.nextToken(); }
- catch ( NoSuchElementException e ) { httpUsername = null; }
- try { httpPassword = tok.nextToken(); }
- catch ( NoSuchElementException e ) { httpPassword = null; }
- }
-
}
diff --git a/src/helma/framework/ResponseTrans.java b/src/helma/framework/ResponseTrans.java
index b6867a48..71dede66 100644
--- a/src/helma/framework/ResponseTrans.java
+++ b/src/helma/framework/ResponseTrans.java
@@ -13,112 +13,47 @@ import helma.util.*;
* class are directly exposed to JavaScript as global property res.
*/
-public class ResponseTrans implements Externalizable {
+public class ResponseTrans implements Serializable {
- /**
- * Set the MIME content type of the response.
- */
public String contentType = "text/html";
-
- /**
- * Set the charset of the response.
- */
- public String charset;
-
- /**
- * used to allow or disable client side caching
- */
- public boolean cache = true;
-
- /**
- * Used for HTTP response code, if 0 code 200 OK will be used.
- */
- public int status = 0;
-
- /**
- * Used for HTTP authentication
- */
- public String realm;
-
- // name of the skin to be rendered after completion, if any
- public transient String skin = null;
-
// the actual response
private byte[] response = null;
-
// contains the redirect URL
- private String redir = null;
+ public String redirect = null;
// cookies
- String cookieKeys[];
- String cookieValues[];
- int cookieDays[];
+ public String cookieKeys[];
+ public String cookieValues[];
+ public int cookieDays[];
int nCookies = 0;
+ // used to allow or disable client side caching
+ public boolean cache = true;
+
// the buffer used to build the response
private transient StringBuffer buffer = null;
// these are used to implement the _as_string variants for Hop templates.
private transient Stack buffers;
- // the path used to resolve skin names
- private transient Object skinpath = null;
- // the processed skinpath as array of Nodes or directory names
- private transient Object[] translatedSkinpath = null;
-
- static final long serialVersionUID = -8627370766119740844L;
-
- /**
- * the buffers used to build the single body parts -
- * transient, response must be constructed before this is serialized
- */
+ // the buffers used to build the single body parts -
+ // transient, response must be constructed before this is serialized
public transient String title, head, body, message, error;
- /**
- * JavaScript object to make the values Map accessible to
- * script code as res.data
- */
- public transient Object data;
-
- // the map of form and cookie data
- private transient Map values;
+ // name of the skin to be rendered after completion, if any
+ public transient String mainSkin = null;
public ResponseTrans () {
super ();
- title = head = body = message = error = null;
- values = new HashMap ();
+ title = head = body = message = error = "";
}
-
-
- /**
- * Get a value from the responses map by key.
- */
- public Object get (String name) {
- try {
- return values.get (name);
- } catch (Exception x) {
- return null;
- }
- }
-
- /**
- * Get the data map for this response transmitter.
- */
- public Map getResponseData () {
- return values;
- }
-
- /**
- * Reset the response object to its initial empty state.
- */
+
public void reset () {
if (buffer != null)
buffer.setLength (0);
- response = null;
- redir = null;
- skin = null;
- title = head = body = message = error = null;
- values.clear ();
+ redirect = null;
+ mainSkin = null;
+ title = head = body = message = error = "";
}
@@ -154,26 +89,6 @@ public class ResponseTrans implements Externalizable {
}
}
- /**
- * Utility function that appends a to whatever is written
- */
- public void writeln (Object what) {
- if (buffer == null)
- buffer = new StringBuffer (512);
- if (what != null)
- buffer.append (what.toString ());
- buffer.append (" \r\n");
- }
-
- /**
- * Append a part from a char array to the response buffer.
- */
- public void writeCharArray (char[] c, int start, int length) {
- if (buffer == null)
- buffer = new StringBuffer (512);
- buffer.append (c, start, length);
- }
-
/**
* Replace special characters with entities, including <, > and ", thus allowing
* no HTML tags.
@@ -212,18 +127,6 @@ public class ResponseTrans implements Externalizable {
}
- /**
- * Encode HTML entities, but leave newlines alone. This is for the content of textarea forms.
- */
- public void encodeForm (Object what) {
- if (what != null) {
- if (buffer == null)
- buffer = new StringBuffer (512);
- HtmlEncoder.encodeAll (what.toString (), buffer, false);
- }
- }
-
-
public void append (String what) {
if (what != null) {
if (buffer == null)
@@ -233,51 +136,23 @@ public class ResponseTrans implements Externalizable {
}
public void redirect (String url) throws RedirectException {
- redir = url;
+ redirect = url;
throw new RedirectException (url);
}
- public String getRedirect () {
- return redir;
- }
-
- /**
- * Allow to directly set the byte array for the response. Calling this more than once will
- * overwrite the previous output. We take a generic object as parameter to be able to
- * generate a better error message, but it must be byte[].
- */
- public void writeBinary (byte[] what) {
- response = what;
- }
-
/**
* This has to be called after writing to this response has finished and before it is shipped back to the
* web server. Transforms the string buffer into a char array to minimize size.
*/
- public synchronized void close (String cset) throws UnsupportedEncodingException {
- // only use default charset if not explicitly set for this response.
- if (charset == null)
- charset = cset;
-
- boolean error = false;
- if (response == null) {
- if (buffer != null) {
- try {
- response = buffer.toString ().getBytes (charset);
- } catch (UnsupportedEncodingException uee) {
- error = true;
- response = buffer.toString ().getBytes ();
- }
- buffer = null; // make sure this is done only once, even with more requsts attached
- } else {
- response = new byte[0];
- }
+ public synchronized void close () {
+ if (buffer != null) {
+ response = buffer.toString ().getBytes ();
+ buffer = null; // make sure this is done only once, even with more requsts attached
+ } else {
+ response = new byte[0];
}
notifyAll ();
- // if there was a problem with the encoding, let the app know
- if (error)
- throw new UnsupportedEncodingException (charset);
}
/**
@@ -302,26 +177,7 @@ public class ResponseTrans implements Externalizable {
}
public String getContentType () {
- if (charset != null)
- return contentType+"; charset="+charset;
- return contentType;
- }
-
- public void setSkinpath (Object obj) {
- this.skinpath = obj;
- this.translatedSkinpath = null;
- }
-
- public Object getSkinpath () {
- return skinpath;
- }
-
- public void setTranslatedSkinpath (Object[] arr) {
- this.translatedSkinpath = arr;
- }
-
- public Object[] getTranslatedSkinpath () {
- return translatedSkinpath;
+ return contentType;
}
public synchronized void setCookie (String key, String value) {
@@ -371,31 +227,6 @@ public class ResponseTrans implements Externalizable {
return cookieValues[i];
}
- public void readExternal (ObjectInput s) throws ClassNotFoundException, IOException {
- contentType = (String) s.readObject ();
- response = (byte[]) s.readObject ();
- redir = (String) s.readObject ();
- cookieKeys = (String[]) s.readObject ();
- cookieValues = (String[]) s.readObject ();
- cookieDays = (int[]) s.readObject ();
- nCookies = s.readInt ();
- cache = s.readBoolean ();
- status = s.readInt ();
- realm = (String) s.readObject ();
- }
-
- public void writeExternal (ObjectOutput s) throws IOException {
- s.writeObject (contentType);
- s.writeObject (response);
- s.writeObject (redir);
- s.writeObject (cookieKeys);
- s.writeObject (cookieValues);
- s.writeObject (cookieDays);
- s.writeInt (nCookies);
- s.writeBoolean (cache);
- s.writeInt (status);
- s.writeObject (realm);
- }
}
diff --git a/src/helma/scripting/fesi/FesiActionAdapter.java b/src/helma/framework/core/Action.java
similarity index 63%
rename from src/helma/scripting/fesi/FesiActionAdapter.java
rename to src/helma/framework/core/Action.java
index fb3d8287..0b35e313 100644
--- a/src/helma/scripting/fesi/FesiActionAdapter.java
+++ b/src/helma/framework/core/Action.java
@@ -1,15 +1,12 @@
-// ActionFile.java
+// Action.java
// Copyright (c) Hannes Wallnöfer 1998-2000
-package helma.scripting.fesi;
+package helma.framework.core;
-import helma.scripting.*;
-import java.util.Vector;
-import java.util.Iterator;
+import java.util.*;
import java.io.*;
import helma.framework.*;
-import helma.framework.core.*;
-import helma.util.Updatable;
+import helma.objectmodel.IServer;
import FESI.Data.*;
import FESI.Parser.*;
import FESI.AST.ASTFormalParameterList;
@@ -21,64 +18,90 @@ import FESI.Exceptions.*;
/**
- * An class that updates fesi interpreters with actionfiles and templates.
+ * 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 FesiActionAdapter {
+public class Action {
+ String name;
+ String functionName;
Prototype prototype;
Application app;
- String sourceName;
+ File file;
+ long lastmod;
+
// this is the parsed function which can be easily applied to RequestEvaluator objects
TypeUpdater pfunc;
- public FesiActionAdapter (ActionFile action) {
- prototype = action.getPrototype ();
- app = action.getApplication ();
- String content = action.getContent ();
- String functionName = action.getFunctionName ();
- sourceName = action.toString ();
- 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);
- }
+
+ public Action (File file, String name, Prototype proto) {
+ this.prototype = proto;
+ this.app = proto.app;
+ this.name = name;
+ this.file = file;
+ update (file);
}
- /* protected void update (FesiEvaluator fesi) throws Exception {
- // app.logEvent ("Reading text template " + name);
- FesiScriptingEnvironment scriptEnv = (FesiScriptingEnvironment) app.getScriptingEnvironment ();
- Iterator evals = scriptEnv.getEvaluators().iterator();
- while (evals.hasNext ()) {
- try {
- FesiEvaluator fesi = (FesiEvaluator) evals.next ();
- updateEvaluator (fesi);
- } catch (Exception ignore) {}
+ public void update (File f) {
+
+ this.file = f;
+ long fmod = file.lastModified ();
+ if (lastmod == fmod)
+ return;
+
+ 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) {
+ IServer.getLogger().log ("*** Error reading action file "+file+": "+filex);
}
- } */
+ lastmod = fmod;
+ }
+
+
+
+ public void update (String content) throws Exception {
+ // IServer.getLogger().log ("Reading text template " + name);
+
+ functionName = name+"_hop_action";
+
+ try {
+ pfunc = parseFunction (functionName, "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", content);
+ } catch (Exception x) {
+ String message = x.getMessage ();
+ pfunc = new ErrorFeedback (functionName, message);
+ }
- /* protected void remove () {
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());
- }
+ updateRequestEvaluator (reval);
} catch (Exception ignore) {}
}
- } */
+ }
- public synchronized void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
+ public String getName () {
+ return name;
+ }
+
+ public String getFunctionName () {
+ return functionName;
+ }
+
+
+ public synchronized void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
if (pfunc != null)
- pfunc.updateEvaluator (fesi);
+ pfunc.updateRequestEvaluator (reval);
}
protected TypeUpdater parseFunction (String funcname, String params, String body) throws EcmaScriptException {
@@ -122,10 +145,10 @@ public class FesiActionAdapter {
sl = (ASTStatementList) parser.StatementList();
is.close();
} catch (ParseException x) {
- app.logEvent ("Error parsing file "+app.getName()+":"+sourceName+": "+x);
+ IServer.getLogger().log ("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()+":"+sourceName+": "+x);
+ IServer.getLogger().log ("Error parsing file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+x);
throw new RuntimeException (x.getMessage ());
}
@@ -150,15 +173,15 @@ public class FesiActionAdapter {
this.functionName = functionName;
}
- public void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
+ public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
- ObjectPrototype op = fesi.getPrototype (prototype.getName());
+ ObjectPrototype op = reval.getPrototype (prototype.getName());
- EcmaScriptVariableVisitor vdvisitor = fesi.evaluator.getVarDeclarationVisitor();
+ EcmaScriptVariableVisitor vdvisitor = reval.evaluator.getVarDeclarationVisitor();
Vector vnames = vdvisitor.processVariableDeclarations(sl, fes);
FunctionPrototype fp = ConstructedFunctionObject.makeNewConstructedFunction (
- fesi.evaluator, functionName, fes,
+ reval.evaluator, functionName, fes,
fullFunctionText, fpl.getArguments(), vnames, sl);
op.putHiddenProperty (functionName, fp);
}
@@ -174,12 +197,12 @@ public class FesiActionAdapter {
errorMessage = msg;
}
- public void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
+ public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
- ObjectPrototype op = fesi.getPrototype (prototype.getName ());
+ ObjectPrototype op = reval.getPrototype (prototype.getName ());
- FunctionPrototype fp = (FunctionPrototype) fesi.evaluator.getFunctionPrototype ();
- FunctionPrototype func = new ThrowException (functionName, fesi.evaluator, fp, errorMessage);
+ FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype ();
+ FunctionPrototype func = new ThrowException (functionName, reval.evaluator, fp, errorMessage);
op.putHiddenProperty (functionName, func);
}
@@ -200,8 +223,38 @@ public class FesiActionAdapter {
}
interface TypeUpdater {
- public void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException;
+ public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException;
}
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/framework/core/Application.java b/src/helma/framework/core/Application.java
index a85a7cb0..d0939a74 100644
--- a/src/helma/framework/core/Application.java
+++ b/src/helma/framework/core/Application.java
@@ -3,76 +3,52 @@
package helma.framework.core;
-import helma.doc.DocApplication;
-import helma.doc.DocException;
-import helma.framework.*;
-import helma.main.Server;
-import helma.scripting.*;
-import helma.scripting.fesi.ESUser;
-import helma.objectmodel.*;
-import helma.objectmodel.db.*;
-import helma.xmlrpc.*;
-import helma.util.*;
-import com.sleepycat.db.DbException;
import java.util.*;
import java.io.*;
-import java.net.URLEncoder;
import java.lang.reflect.*;
import java.rmi.*;
import java.rmi.server.*;
+import helma.framework.*;
+import helma.objectmodel.*;
+import helma.objectmodel.db.NodeManager;
+import helma.objectmodel.db.WrappedNodeManager;
+import helma.xmlrpc.*;
+import helma.util.CacheMap;
+import FESI.Data.*;
+import FESI.Interpreter.*;
+import com.sleepycat.db.DbException;
+
/**
- * The central class of a Helma application. This class keeps a pool of so-called
- * request evaluators (threads with JavaScript interpreters), waits for
- * requests from the Web server or XML-RPC port and dispatches them to
+ * The central class of a HOP application. This class keeps a pool of so-called
+ * request evaluators (threads with JavaScript interpreters), waits for
+ * requests from the Web server or XML-RPC port and dispatches them to
* the evaluators.
*/
-public class Application extends UnicastRemoteObject implements IRemoteApp, IPathElement, IReplicatedApp, Runnable {
+public class Application extends UnicastRemoteObject implements IRemoteApp, Runnable {
+ SystemProperties props;
+ File appDir, dbDir;
private String name;
- SystemProperties props, dbProps;
- File home, appDir, dbDir;
protected NodeManager nmgr;
+ protected static WebServer xmlrpc;
+ protected XmlRpcAccess xmlrpcAccess;
- // the class name of the scripting environment implementation
- ScriptingEnvironment scriptingEngine;
+ private String baseURI;
- // the root of the website, if a custom root object is defined.
- // otherwise this is managed by the NodeManager and not cached here.
- Object rootObject = null;
- String rootObjectClass;
+ public boolean debug;
- /**
- * The type manager checks if anything in the application's prototype definitions
- * has been updated prior to each evaluation.
- */
- public TypeManager typemgr;
+ TypeManager typemgr;
- /**
- * The skin manager for this application
- */
- protected SkinManager skinmgr;
-
- /**
- * Each application has one internal request evaluator for calling
- * the scheduler and other internal functions.
- */
RequestEvaluator eval;
-
- /**
- * Collections for evaluator thread pooling
- */
protected Stack freeThreads;
protected Vector allThreads;
boolean stopped = false;
- boolean debug;
- public long starttime;
- public Hashtable sessions;
- public Hashtable activeUsers;
+ Hashtable sessions;
+ Hashtable activeUsers;
Hashtable dbMappings;
- Hashtable dbSources;
Thread worker;
long requestTimeout = 60000; // 60 seconds for request timeout.
@@ -80,10 +56,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
// Map of requesttrans -> active requestevaluators
Hashtable activeRequests;
-
- // Two logs for each application: events and accesses
- Logger eventLog, accessLog;
-
+
protected String templateExtension, scriptExtension, actionExtension, skinExtension;
// A transient node that is shared among all evaluators
@@ -92,123 +65,34 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
protected volatile long xmlrpcCount = 0;
protected volatile long errorCount = 0;
- protected static WebServer xmlrpc;
- protected XmlRpcAccess xmlrpcAccess;
- private String xmlrpcHandlerName;
-
- // the URL-prefix to use for links into this application
- private String baseURI;
-
private DbMapping rootMapping, userRootMapping, userMapping;
- // boolean checkSubnodes;
+ protected CacheMap skincache = new CacheMap (100);
- // name of respone encoding
- String charset;
- // password file to use for authenticate() function
- private CryptFile pwfile;
-
- // Map of java class names to object prototypes
- Properties classMapping;
- // Map of extensions allowed for public skins
- Properties skinExtensions;
-
- // a cache for parsed skin objects
- public CacheMap skincache = new CacheMap (200, 0.80f);
-
- // DocApplication used for introspection
- public DocApplication docApp;
-
- /**
- * Zero argument constructor needed for RMI
- */
public Application () throws RemoteException {
super ();
}
- /**
- * Build an application with the given name in the home directory. Server-wide properties will
- * be created if the files are present, but they don't have to.
- */
- public Application (String name, File home) throws RemoteException, IllegalArgumentException {
- this (name, home,
- new SystemProperties (new File (home, "server.properties").getAbsolutePath ()),
- new SystemProperties (new File (home, "db.properties").getAbsolutePath ()));
- }
-
- /**
- * Build an application with the given name, app and db properties and app base directory. The
- * app directories will be created if they don't exist already.
- */
- public Application (String name, File home, SystemProperties sysProps, SystemProperties sysDbProps)
- throws RemoteException, IllegalArgumentException {
-
- if (name == null || name.trim().length() == 0)
- throw new IllegalArgumentException ("Invalid application name: "+name);
+ public Application (String name, File dbHome, File appHome) throws RemoteException, DbException {
this.name = name;
- this.home = home;
- // give the Helma Thread group a name so the threads can be recognized
threadgroup = new ThreadGroup ("TX-"+name);
- // check the system props to see if custom app directory is set.
- // otherwise use /apps/
- String appHome = null;
- if (sysProps != null)
- appHome = sysProps.getProperty ("appHome");
- if (appHome != null && !"".equals (appHome.trim()))
- appDir = new File (appHome);
- else
- appDir = new File (home, "apps");
- appDir = new File (appDir, name);
+ appDir = new File (appHome, name);
if (!appDir.exists())
appDir.mkdirs ();
-
- // check the system props to see if custom embedded db directory is set.
- // otherwise use /db/
- String dbHome = null;
- if (sysProps != null)
- dbHome = sysProps.getProperty ("dbHome");
- if (dbHome != null && !"".equals (dbHome.trim()))
- dbDir = new File (dbHome);
- else
- dbDir = new File (home, "db");
- dbDir = new File (dbDir, name);
+ dbDir = new File (dbHome, name);
if (!dbDir.exists())
dbDir.mkdirs ();
- // create app-level properties
File propfile = new File (appDir, "app.properties");
- props = new SystemProperties (propfile.getAbsolutePath (), sysProps);
+ props = new SystemProperties (propfile.getAbsolutePath (), IServer.sysProps);
- // create app-level db sources
- File dbpropfile = new File (appDir, "db.properties");
- dbProps = new SystemProperties (dbpropfile.getAbsolutePath (), sysDbProps);
-
- // the passwd file, to be used with the authenticate() function
- File pwf = new File (home, "passwd");
- CryptFile parentpwfile = new CryptFile (pwf, null);
- pwf = new File (appDir, "passwd");
- pwfile = new CryptFile (pwf, parentpwfile);
-
- // the properties that map java class names to prototype names
- classMapping = new SystemProperties (new File (appDir, "class.properties").getAbsolutePath ());
-
- // get class name of root object if defined. Otherwise native Helma objectmodel will be used.
- rootObjectClass = classMapping.getProperty ("root");
-
- // the properties that map allowed public skin extensions to content types
- skinExtensions = new SystemProperties (new File (appDir, "mime.properties").getAbsolutePath ());
-
- // character encoding to be used for responses
- charset = props.getProperty ("charset", "ISO-8859-1");
+ nmgr = new NodeManager (this, dbDir.getAbsolutePath (), props);
debug = "true".equalsIgnoreCase (props.getProperty ("debug"));
- // checkSubnodes = !"false".equalsIgnoreCase (props.getProperty ("subnodeChecking"));
-
-
try {
requestTimeout = Long.parseLong (props.getProperty ("requestTimeout", "60"))*1000l;
} catch (Exception ignore) { }
@@ -221,22 +105,16 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
sessions = new Hashtable ();
activeUsers = new Hashtable ();
dbMappings = new Hashtable ();
- dbSources = new Hashtable ();
- appnode = new TransientNode ("app");
- xmlrpc = helma.main.Server.getXmlRpcServer ();
+ appnode = new Node ("app");
+ xmlrpc = IServer.getXmlRpcServer ();
xmlrpcAccess = new XmlRpcAccess (this);
}
- /**
- * Get the application ready to run, initializing the evaluators and type manager.
- */
- public void init () throws DbException, ScriptingException {
- scriptingEngine = new helma.scripting.fesi.FesiScriptingEnvironment ();
- scriptingEngine.init (this, props);
+ public void start () {
eval = new RequestEvaluator (this);
- logEvent ("Starting evaluators for "+name);
+ IServer.getLogger().log ("Starting evaluators for "+name);
int maxThreads = 12;
try {
maxThreads = Integer.parseInt (props.getProperty ("maxThreads"));
@@ -252,10 +130,8 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
activeRequests = new Hashtable ();
typemgr = new TypeManager (this);
- typemgr.createPrototypes ();
- // logEvent ("Started type manager for "+name);
-
- skinmgr = new SkinManager (this);
+ typemgr.check ();
+ IServer.getLogger().log ("Started type manager for "+name);
rootMapping = getDbMapping ("root");
userMapping = getDbMapping ("user");
@@ -267,29 +143,17 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
userRootMapping = new DbMapping (this, "__userroot__", p);
rewireDbMappings ();
- nmgr = new NodeManager (this, dbDir.getAbsolutePath (), props);
-
- xmlrpcHandlerName = props.getProperty ("xmlrpcHandlerName", this.name);
- if (xmlrpc != null)
- xmlrpc.addHandler (xmlrpcHandlerName, new XmlRpcInvoker (this));
-
- // typemgr.start ();
- }
-
- /**
- * Create request evaluators and start scheduler and cleanup thread
- */
- public void start () {
- starttime = System.currentTimeMillis();
worker = new Thread (this, "Worker-"+name);
worker.setPriority (Thread.NORM_PRIORITY+2);
worker.start ();
- // logEvent ("session cleanup and scheduler thread started");
+ IServer.getLogger().log ("session cleanup and scheduler thread started");
+
+ xmlrpc.addHandler (this.name, new XmlRpcInvoker (this));
+
+ typemgr.start ();
}
- /**
- * This is called to shut down a running application.
- */
+
public void stop () {
stopped = true;
@@ -298,42 +162,25 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
if (worker != null)
worker.interrupt ();
worker = null;
+ typemgr.stop ();
- if (xmlrpc != null && xmlrpcHandlerName != null)
- xmlrpc.removeHandler (xmlrpcHandlerName);
+ xmlrpc.removeHandler (this.name);
- // stop evaluators
if (allThreads != null) {
for (Enumeration e=allThreads.elements (); e.hasMoreElements (); ) {
RequestEvaluator ev = (RequestEvaluator) e.nextElement ();
ev.stopThread ();
}
}
-
- // remove evaluators
allThreads.removeAllElements ();
freeThreads = null;
-
- // shut down node manager and embedded db
try {
nmgr.shutdown ();
} catch (DbException dbx) {
System.err.println ("Error shutting down embedded db: "+dbx);
}
-
- // stop logs if they exist
- if (eventLog != null) {
- eventLog.close ();
- }
- if (accessLog != null) {
- accessLog.close ();
- }
-
}
- /**
- * Returns a free evaluator to handle a request.
- */
protected RequestEvaluator getEvaluator () {
if (stopped)
throw new ApplicationStoppedException ();
@@ -344,19 +191,12 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
}
}
- /**
- * Returns an evaluator back to the pool when the work is done.
- */
protected void releaseEvaluator (RequestEvaluator ev) {
if (ev != null)
freeThreads.push (ev);
}
- /**
- * This can be used to set the maximum number of evaluators which will be allocated.
- * If evaluators are required beyound this number, an error will be thrown.
- */
- public boolean setNumberOfEvaluators (int n) {
+ protected boolean setNumberOfEvaluators (int n) {
if (n < 2 || n > 511)
return false;
int current = allThreads.size();
@@ -374,7 +214,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
try {
RequestEvaluator re = (RequestEvaluator) freeThreads.pop ();
allThreads.removeElement (re);
- // typemgr.unregisterRequestEvaluator (re);
+ typemgr.unregisterRequestEvaluator (re);
re.stopThread ();
} catch (EmptyStackException empty) {
return false;
@@ -385,21 +225,10 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
return true;
}
- /**
- * Return the number of currently active threads
- */
- public int getActiveThreads () {
- return 0;
- }
-
- /**
- * Execute a request coming in from a web client.
- */
public ResponseTrans execute (RequestTrans req) {
requestCount += 1;
-
- // get user for this request's session
+
User u = getUser (req.session);
ResponseTrans res = null;
@@ -432,114 +261,46 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
if (primaryRequest) {
activeRequests.remove (req);
releaseEvaluator (ev);
- // response needs to be closed/encoded before sending it back
- try {
- res.close (charset);
- } catch (UnsupportedEncodingException uee) {
- logEvent ("Unsupported response encoding: "+uee.getMessage());
- }
+ res.close (); // this needs to be done before sending it back
} else {
res.waitForClose ();
}
}
-
+
return res;
}
- /**
- * Update HopObjects in this application's cache. This is used to replicate
- * application caches in a distributed app environment
- */
- public void replicateCache (Vector add, Vector delete) {
- if (!"true".equalsIgnoreCase (props.getProperty ("allowReplication")))
- return;
- nmgr.replicateCache (add, delete);
+ // get raw content from the database, circumventing the scripting framework.
+ // currently not used/supported.
+ public ResponseTrans get (String path, String sessionID) {
+ ResponseTrans res = null;
+ return res;
}
public void ping () {
// do nothing
}
- /**
- * Reset the application's object cache, causing all objects to be refetched from
- * the database.
- */
- public void clearCache () {
- nmgr.clearCache ();
- }
-
- /**
- * Set the application's root element to an arbitrary object. After this is called
- * with a non-null object, the helma node manager will be bypassed. This function
- * can be used to script and publish any Java object structure with Helma.
- */
- public void setDataRoot (Object root) {
- this.rootObject = root;
- }
-
- /**
- * This method returns the root object of this application's object tree.
- */
- public Object getDataRoot () {
- // if rootObject is set, immediately return it.
- if (rootObject != null)
- return rootObject;
- // check if we ought to create a rootObject from its class name
- if (rootObjectClass != null) {
- // create custom root element.
- if (rootObject == null) {
- try {
- if ( classMapping.containsKey("root.factory.class") && classMapping.containsKey("root.factory.method") ) {
- Class c = Class.forName( classMapping.getProperty("root.factory.class") );
- Method m = c.getMethod( classMapping.getProperty("root.factory.method"), null );
- rootObject = m.invoke(c, null);
- } else {
- Class c = Class.forName( classMapping.getProperty("root") );
- rootObject = c.newInstance();
- }
- } catch ( Exception e ) {
- throw new RuntimeException ( "Error creating root object: " + e.toString() );
- }
- }
- return rootObject;
- }
- // no custom root object is defined - use standard helma objectmodel
+ public INode getDataRoot () {
INode root = nmgr.safe.getNode ("0", rootMapping);
root.setDbMapping (rootMapping);
return root;
}
- /**
- * Returns the Object which contains registered users of this application.
- */
public INode getUserRoot () {
INode users = nmgr.safe.getNode ("1", userRootMapping);
users.setDbMapping (userRootMapping);
return users;
}
- /**
- * Returns a wrapper containing the node manager for this application. The node manager is
- * the gateway to the helma.objectmodel packages, which perform the mapping of objects to
- * relational database tables or the embedded database.
- */
public WrappedNodeManager getWrappedNodeManager () {
return nmgr.safe;
}
- /**
- * Return a transient node that is shared by all evaluators of this application ("app node")
- */
- public INode getAppNode () {
- return appnode;
- }
-
-
- /**
- * Returns a Node representing a registered user of this application by his or her user name.
- */
public INode getUserNode (String uid) {
+ if ("prototype".equalsIgnoreCase (uid))
+ return null;
try {
INode users = getUserRoot ();
return users.getNode (uid, false);
@@ -553,56 +314,35 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
* Return a prototype for a given node. If the node doesn't specify a prototype,
* return the generic hopobject prototype.
*/
- public Prototype getPrototype (Object obj) {
- String protoname = getPrototypeName (obj);
+ public Prototype getPrototype (INode n) {
+ String protoname = n.getPrototype ();
if (protoname == null)
return typemgr.getPrototype ("hopobject");
- Prototype p = typemgr.getPrototype (protoname);
- if (p == null)
- p = typemgr.getPrototype ("hopobject");
- return p;
+ return typemgr.getPrototype (protoname);
}
- /**
- * Return a collection containing all prototypes defined for this application
- */
- public Collection getPrototypes () {
- return typemgr.prototypes.values ();
- }
/**
- * Retrurn a skin for a given object. The skin is found by determining the prototype
- * to use for the object, then looking up the skin for the prototype.
- */
- public Skin getSkin (Object object, String skinname, Object[] skinpath) {
- return skinmgr.getSkin (object, skinname, skinpath);
- }
-
- /**
- * Return the user currently associated with a given Hop session ID. This may be
- * a registered or an anonymous user.
+ * Return the user currently associated with a given Hop session ID.
*/
public User getUser (String sessionID) {
- if (sessionID == null)
+ if (sessionID == null)
return null;
- User u = (User) sessions.get (sessionID);
- if (u != null) {
- u.touch ();
+ User u = (User) sessions.get (sessionID);
+ if (u != null) {
+ u.touch ();
} else {
u = new User (sessionID, this);
sessions.put (sessionID, u);
}
- return u;
+ return u;
}
- /**
- * Register a user with the given user name and password.
- */
public INode registerUser (String uname, String password) {
- // Register a user who already has a user object
- // (i.e. who has been surfing around)
+ // Register a user who already has a user object
+ // (i.e. who has been surfing around)
if (uname == null)
return null;
uname = uname.toLowerCase ().trim ();
@@ -616,33 +356,22 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
if (unode != null)
return null;
- unode = users.createNode (uname);
+ unode = new Node (uname);
+ unode.setString ("name", uname);
+ unode.setString ("password", password);
unode.setPrototype ("user");
unode.setDbMapping (userMapping);
- String usernameField = userMapping.getNameField ();
- String usernameProp = null;
- if (usernameField != null)
- usernameProp = userMapping.columnNameToProperty (usernameField);
- if (usernameProp == null)
- usernameProp = "name";
- unode.setName (uname);
- unode.setString (usernameProp, uname);
- unode.setString ("password", password);
- // users.setNode (uname, unode);
- // return users.getNode (uname, false);
- return unode;
+ users.setNode (uname, unode);
+ return users.getNode (uname, false);
} catch (Exception x) {
- logEvent ("Error registering User: "+x);
+ IServer.getLogger().log ("Error registering User: "+x);
return null;
}
}
- /**
- * Log in a user given his or her user name and password.
- */
public boolean loginUser (String uname, String password, ESUser u) {
- // Check the name/password of a user who already has a user object
- // (i.e. who has been surfing around)
+ // Check the name/password of a user who already has a user object
+ // (i.e. who has been surfing around)
if (uname == null)
return false;
uname = uname.toLowerCase ().trim ();
@@ -654,21 +383,19 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
INode unode = users.getNode (uname, false);
String pw = unode.getString ("password", false);
if (pw != null && pw.equals (password)) {
- // give the user his/her persistant node
+ // give the user her piece of persistence
u.setNode (unode);
- activeUsers.put (unode.getName (), u.user);
+ u.user.setNode (unode);
+ activeUsers.put (unode.getNameOrID (), u.user);
return true;
}
-
+
} catch (Exception x) {
return false;
}
return false;
}
- /**
- * Log out a user from this application.
- */
public boolean logoutUser (ESUser u) {
if (u.user != null) {
String uid = u.user.uid;
@@ -676,86 +403,32 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
activeUsers.remove (uid);
// switch back to the non-persistent user node as cache
- u.setNode (null);
+ u.user.setNode (null);
+ u.setNode (u.user.getNode ());
}
return true;
}
- /**
- * In contrast to login, this works outside the Hop user object framework. Instead, the user is
- * authenticated against a passwd file in the application directory. This is to have some sort of
- * authentication available *before* the application is up and running, i.e. for application setup tasks.
- */
- public boolean authenticate (String uname, String password) {
- if (uname == null || password == null)
- return false;
- return pwfile.authenticate (uname, password);
- }
-
- /**
- * Return the href to the root of this application.
- */
- public String getRootHref () {
- return getNodeHref (getDataRoot(), null);
- }
-
- /**
- * Return a path to be used in a URL pointing to the given element and action
- */
- public String getNodeHref (Object elem, String actionName) {
- // FIXME: will fail for non-node roots
- Object root = getDataRoot ();
+ public String getNodePath (INode n, String tmpname) {
+ INode root = getDataRoot ();
INode users = getUserRoot ();
-
- // check base uri and optional root prototype from app.properties
- String base = props.getProperty ("baseURI");
- String rootproto = props.getProperty ("rootPrototype");
-
- if (base != null || baseURI == null)
- setBaseURI (base);
-
- // String href = n.getUrl (root, users, tmpname, siteroot);
-
- String divider = "/";
- StringBuffer b = new StringBuffer ();
- Object p = elem;
- int loopWatch = 0;
-
- while (p != null && getParentElement (p) != null && p != root) {
-
- if (rootproto != null && rootproto.equals (getPrototypeName (p)))
- break;
- b.insert (0, divider);
-
- // users always have a canonical URL like /users/username
- if ("user".equals (getPrototypeName (p))) {
- b.insert (0, URLEncoder.encode (getElementName (p)));
- p = users;
- break;
- }
- b.insert (0, URLEncoder.encode (getElementName (p)));
- p = getParentElement (p);
-
- if (loopWatch++ > 20)
- break;
- }
-
- if (p == users) {
- b.insert (0, divider);
- b.insert (0, "users");
- }
-
- if (actionName != null)
- b.append (URLEncoder.encode (actionName));
-
- return baseURI + b.toString ();
+ String href = n.getUrl (root, users, tmpname);
+ return href;
}
-
- /**
- * This method sets the base URL of this application which will be prepended to
- * the actual object path.
- */
+ public String getNodeHref (INode n, String tmpname) {
+ INode root = getDataRoot ();
+ INode users = getUserRoot ();
+ // check base uri from app.properties
+ String base = props.getProperty ("baseURI");
+ if (base != null)
+ setBaseURI (base);
+ String href = n.getHref (root, users, tmpname, baseURI == null ? "/" : baseURI);
+ // add cache teaser
+ // href = href + "&tease="+((int) (Math.random ()*999));
+ return href;
+ }
+
public void setBaseURI (String uri) {
if (uri == null)
this.baseURI = "/";
@@ -765,193 +438,15 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
this.baseURI = uri;
}
- /**
- * Tell other classes whether they should output logging information for this application.
- */
- public boolean debug () {
- return debug;
- }
-
- private Object invokeFunction (Object obj, String func, Object[] args) {
- Thread thread = Thread.currentThread ();
- RequestEvaluator reval = null;
- int l = allThreads.size();
- for (int i=0; i cleanupSleep) try {
- lastCleanup = now;
- // logEvent ("Cleaning up "+name+": " + sessions.size () + " sessions active");
+ try {
+ worker.sleep (cleanupSleep);
+ } catch (InterruptedException x) {
+ IServer.getLogger().log ("Scheduler for "+name+" interrupted");
+ worker = null;
+ break;
+ }
+ try {
+ IServer.getLogger().log ("Cleaning up "+name+": " + sessions.size () + " sessions active");
+ long now = System.currentTimeMillis ();
Hashtable cloned = (Hashtable) sessions.clone ();
for (Enumeration e = cloned.elements (); e.hasMoreElements (); ) {
User u = (User) e.nextElement ();
- if (now - u.lastTouched () > sessionTimeout * 60000) {
+ if (now - u.touched () > sessionTimeout * 60000) {
if (u.uid != null) {
try {
- eval.invokeFunction (u, "onLogout", new Object[0]);
- } catch (Exception ignore) {}
+ eval.invokeFunction (u, "onLogout", new ESValue[0]);
+ } catch (Exception ignore) {
+ ignore.printStackTrace ();
+ }
activeUsers.remove (u.uid);
}
sessions.remove (u.getSessionID ());
u.setNode (null);
}
}
- // logEvent ("Cleaned up "+name+": " + sessions.size () + " sessions remaining");
+
+ IServer.getLogger().log ("Cleaned up "+name+": " + sessions.size () + " sessions remaining");
} catch (Exception cx) {
- logEvent ("Error cleaning up sessions: "+cx);
+ IServer.getLogger().log ("Error cleaning up sessions: "+cx);
cx.printStackTrace ();
}
- // check if we should call scheduler
+ long now = System.currentTimeMillis ();
if (now - lastScheduler > scheduleSleep) {
lastScheduler = now;
- Object val = null;
+ ESValue val = null;
try {
- val = eval.invokeFunction ((INode) null, "scheduler", new Object[0]);
- } catch (Exception ignore) {}
+ val = eval.invokeFunction ((INode) null, "scheduler", new ESValue[0]);
+ } catch (Exception ignore) {}
try {
- int ret = ((Number) val).intValue ();
+ int ret = val.toInt32 ();
if (ret < 1000)
scheduleSleep = 60000l;
else
scheduleSleep = ret;
} catch (Exception ignore) {}
- // logEvent ("Called scheduler for "+name+", will sleep for "+scheduleSleep+" millis");
+ IServer.getLogger().log ("Called scheduler for "+name+", will sleep for "+scheduleSleep+" millis");
}
-
- // sleep until we have work to do
- try {
- worker.sleep (Math.min (cleanupSleep, scheduleSleep));
- } catch (InterruptedException x) {
- logEvent ("Scheduler for "+name+" interrupted");
- worker = null;
- break;
- }
-
-
}
-
- logEvent ("Scheduler for "+name+" exiting");
+ IServer.getLogger().log ("Scheduler for "+name+" exiting");
}
- /**
- * This method is called after the type.properties files are read on all prototypes, or after one
- * or more of the type properties have been re-read after an update, to let the DbMappings reestablish
- * the relations among them according to their mappings.
- */
public void rewireDbMappings () {
for (Enumeration e=dbMappings.elements(); e.hasMoreElements(); ) {
try {
DbMapping m = (DbMapping) e.nextElement ();
m.rewire ();
- String typename = m.getTypeName ();
- // set prototype hierarchy
- if (!"hopobject".equalsIgnoreCase (typename) && !"global".equalsIgnoreCase (typename)) {
- Prototype proto = (Prototype) typemgr.prototypes.get (typename);
- if (proto != null) {
- String protoname = m.getExtends ();
- // only use hopobject prototype if we're scripting HopObjects, not
- // java objects.
- boolean isjava = isJavaPrototype (typename);
- if (protoname == null && !isjava)
- protoname = "hopobject";
- Prototype parentProto = (Prototype) typemgr.prototypes.get (protoname);
- if (parentProto == null && !isjava)
- parentProto = (Prototype) typemgr.prototypes.get ("hopobject");
- if (parentProto != null)
- proto.setParentPrototype (parentProto);
- }
- }
} catch (Exception x) {
- logEvent ("Error rewiring DbMappings: "+x);
+ IServer.getLogger().log ("Error rewiring DbMappings: "+x);
}
}
}
- /**
- * Check whether a prototype is for scripting a java class, i.e. if there's an entry
- * for it in the class.properties file.
- */
- public boolean isJavaPrototype (String typename) {
- for (Enumeration en = classMapping.elements(); en.hasMoreElements(); ) {
- String value = (String) en.nextElement ();
- if (typename.equals (value))
- return true;
- }
- return false;
- }
-
- /**
- * Return a DbSource object for a given name. A DbSource is a relational database defined
- * in a db.properties file.
- */
- public DbSource getDbSource (String name) {
- String dbSrcName = name.toLowerCase ();
- DbSource dbs = (DbSource) dbSources.get (dbSrcName);
- if (dbs != null)
- return dbs;
- if (dbProps.getProperty (dbSrcName+".url") != null && dbProps.getProperty (dbSrcName+".driver") != null) {
- try {
- dbs = new DbSource (name, dbProps);
- dbSources.put (dbSrcName, dbs);
- } catch (Exception problem) {
- logEvent ("Error creating DbSource "+name);
- logEvent ("Reason: "+problem);
- }
- }
- return dbs;
- }
-
- /**
- * Return the name of this application
- */
public String getName () {
return name;
}
- /**
- * Return the directory of this application
- */
- public File getAppDir() {
- return appDir;
- }
-
- /**
- * Get the DbMapping associated with a prototype name in this application
- */
public DbMapping getDbMapping (String typename) {
return typename == null ? null : (DbMapping) dbMappings.get (typename);
}
- /**
- * Associate a DbMapping object with a prototype name for this application.
- */
public void putDbMapping (String typename, DbMapping dbmap) {
dbMappings.put (typename, dbmap);
}
- /**
- * Proxy method to get a property from the applications properties.
- */
- public String getProperty (String propname) {
- return props.getProperty (propname);
- }
-
- /**
- * Proxy method to get a property from the applications properties.
- */
- public String getProperty (String propname, String defvalue) {
- return props.getProperty (propname, defvalue);
- }
-
- public SystemProperties getProperties() {
- return props;
- }
-
- /**
- *
- */
- public int countThreads () {
- return threadgroup.activeCount() -1;
- }
-
- /**
- *
- */
- public int countEvaluators () {
- return allThreads.size()-1 ;
- }
-
- /**
- *
- */
- public int countFreeEvaluators () {
- return freeThreads.size ();
- }
-
- /**
- *
- */
- public int countActiveEvaluators () {
- return allThreads.size() - freeThreads.size () -1;
- }
-
- /**
- *
- */
- public int countMaxActiveEvaluators () {
- // return typemgr.countRegisteredRequestEvaluators () -1;
- // not available due to framework refactoring
- return -1;
- }
-
- /**
- *
- */
- public long getRequestCount () {
- return requestCount;
- }
-
- /**
- *
- */
- public long getXmlrpcCount () {
- return xmlrpcCount;
- }
-
- /**
- *
- */
- public long getErrorCount () {
- return errorCount;
- }
/**
* Periodically called to log thread stats for this application
*/
public void printThreadStats () {
- logEvent ("Thread Stats for "+name+": "+threadgroup.activeCount()+" active");
- Runtime rt = Runtime.getRuntime ();
+ IServer.getLogger().log ("Thread Stats for "+name+": "+threadgroup.activeCount()+" active");
+ Runtime rt = Runtime.getRuntime ();
long free = rt.freeMemory ();
long total = rt.totalMemory ();
- logEvent ("Free memory: "+(free/1024)+" kB");
- logEvent ("Total memory: "+(total/1024)+" kB");
+ IServer.getLogger().log ("Free memory: "+(free/1024)+" kB");
+ IServer.getLogger().log ("Total memory: "+(total/1024)+" kB");
}
/**
@@ -1210,18 +552,18 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
}
+//////////////////////////////////////////////////////////////
+//// XML-RPC handler class
+
-/**
- * XML-RPC handler class for this application.
- */
class XmlRpcInvoker implements XmlRpcHandler {
-
+
Application app;
public XmlRpcInvoker (Application app) {
- this.app = app;
+ this.app = app;
}
-
+
public Object execute (String method, Vector argvec) throws Exception {
app.xmlrpcCount += 1;
@@ -1230,7 +572,7 @@ class XmlRpcInvoker implements XmlRpcHandler {
RequestEvaluator ev = null;
try {
ev = app.getEvaluator ();
- retval = ev.invokeXmlRpc (method, argvec.toArray());
+ retval = ev.invokeXmlRpc (method, argvec);
} finally {
app.releaseEvaluator (ev);
}
@@ -1239,9 +581,10 @@ class XmlRpcInvoker implements XmlRpcHandler {
}
-/**
- * XML-RPC access permission checker
- */
+//////////////////////////////////////////////////////////////
+//// XML-RPC access permission checker
+
+
class XmlRpcAccess {
Application app;
@@ -1265,11 +608,9 @@ class XmlRpcAccess {
/*
* create internal representation of XML-RPC-Permissions. They're encoded in the app property
- * file like this:
- *
+ * file like this:
* xmlrpcAccess = root.sayHello, story.countMessages, user.login
- *
- * i.e. a prototype.method entry for each function callable via XML-RPC.
+ * i.e. a prototype.method entry for each function callable via XML-RPC.
*/
private void init () {
String newAccessprop = app.props.getProperty ("xmlrpcaccess");
diff --git a/src/helma/scripting/fesi/ESAppNode.java b/src/helma/framework/core/ESAppNode.java
similarity index 54%
rename from src/helma/scripting/fesi/ESAppNode.java
rename to src/helma/framework/core/ESAppNode.java
index 83b3e15f..f80770fc 100644
--- a/src/helma/scripting/fesi/ESAppNode.java
+++ b/src/helma/framework/core/ESAppNode.java
@@ -1,14 +1,12 @@
// ESAppNode.java
// Copyright (c) Hannes Wallnöfer 1998-2000
-package helma.scripting.fesi;
+package helma.framework.core;
-import helma.framework.core.*;
import helma.objectmodel.*;
import FESI.Exceptions.*;
import FESI.Data.*;
import FESI.Interpreter.Evaluator;
-import java.util.Iterator;
/**
* ESApp represents the app node of an application, providing an app-wide transient shared
@@ -20,18 +18,17 @@ public class ESAppNode extends ESNode {
private Application app;
private DatePrototype createtime;
- public ESAppNode (INode node, FesiEvaluator eval) throws EcmaScriptException {
- super (eval.getPrototype("hopobject"), eval.getEvaluator(), node, eval);
- app = eval.getApplication();
- createtime = new DatePrototype (evaluator, node.created());
- FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
+ public ESAppNode (INode node, RequestEvaluator eval) throws EcmaScriptException {
+ super (eval.esNodePrototype, eval.evaluator, node, eval);
+ app = eval.app;
+ createtime = new DatePrototype (eval.evaluator, node.created());
+ FunctionPrototype fp = (FunctionPrototype) eval.evaluator.getFunctionPrototype();
putHiddenProperty("getThreads", new AppCountThreads ("getThreads", evaluator, fp));
putHiddenProperty("getMaxThreads", new AppCountEvaluators ("getMaxThreads", evaluator, fp));
putHiddenProperty("getFreeThreads", new AppCountFreeEvaluators ("getFreeThreads", evaluator, fp));
- putHiddenProperty("getActiveThreads", new AppCountActiveEvaluators ("getActiveThreads", evaluator, fp));
- putHiddenProperty("getMaxActiveThreads", new AppCountMaxActiveEvaluators ("getMaxActiveThreads", evaluator, fp));
+ putHiddenProperty("getActiveThreads", new AppCountBusyEvaluators ("getActiveThreads", evaluator, fp));
+ putHiddenProperty("getMaxActiveThreads", new AppCountMaxBusyEvaluators ("getMaxActiveThreads", evaluator, fp));
putHiddenProperty("setMaxThreads", new AppSetNumberOfEvaluators ("setMaxThreads", evaluator, fp));
- putHiddenProperty("clearCache", new AppClearCache ("clearCache", evaluator, fp));
}
/**
@@ -39,32 +36,17 @@ public class ESAppNode extends ESNode {
*/
public ESValue getProperty (String propname, int hash) throws EcmaScriptException {
if ("requestCount".equals (propname)) {
- return new ESNumber (app.getRequestCount ());
+ return new ESNumber (app.requestCount);
}
if ("xmlrpcCount".equals (propname)) {
- return new ESNumber (app.getXmlrpcCount ());
+ return new ESNumber (app.xmlrpcCount);
}
if ("errorCount".equals (propname)) {
- return new ESNumber (app.getErrorCount ());
+ return new ESNumber (app.errorCount);
}
if ("upSince".equals (propname)) {
return createtime;
}
- if ("skinfiles".equals (propname)) {
- ESObject skinz = new ObjectPrototype (null, evaluator);
- for (Iterator it = app.getPrototypes().iterator(); it.hasNext(); ) {
- Prototype p = (Prototype) it.next ();
- ESObject proto = new ObjectPrototype (null, evaluator);
- for (Iterator it2 = p.skins.values().iterator(); it2.hasNext(); ) {
- SkinFile sf = (SkinFile) it2.next ();
- String name = sf.getName ();
- Skin skin = sf.getSkin ();
- proto.putProperty (name, new ESString (skin.getSource ()), name.hashCode ());
- }
- skinz.putProperty (p.getName (), proto, p.getName ().hashCode ());
- }
- return skinz;
- }
if ("__app__".equals (propname)) {
return new ESWrapper (app, evaluator);
}
@@ -77,7 +59,7 @@ public class ESAppNode extends ESNode {
super (fp, evaluator, name, 0);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- return new ESNumber (app.countEvaluators ());
+ return new ESNumber (app.allThreads.size()-1);
}
}
@@ -86,25 +68,25 @@ public class ESAppNode extends ESNode {
super (fp, evaluator, name, 0);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- return new ESNumber (app.countFreeEvaluators ());
+ return new ESNumber (app.freeThreads.size());
}
}
- class AppCountActiveEvaluators extends BuiltinFunctionObject {
- AppCountActiveEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
+ class AppCountBusyEvaluators extends BuiltinFunctionObject {
+ AppCountBusyEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 0);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- return new ESNumber (app.countActiveEvaluators ());
+ return new ESNumber (app.allThreads.size() - app.freeThreads.size() -1);
}
}
- class AppCountMaxActiveEvaluators extends BuiltinFunctionObject {
- AppCountMaxActiveEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
+ class AppCountMaxBusyEvaluators extends BuiltinFunctionObject {
+ AppCountMaxBusyEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 0);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- return new ESNumber (app.countMaxActiveEvaluators ());
+ return new ESNumber (app.typemgr.countRegisteredRequestEvaluators () -1);
}
}
@@ -113,7 +95,7 @@ public class ESAppNode extends ESNode {
super (fp, evaluator, name, 0);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- return new ESNumber (app.countThreads ());
+ return new ESNumber (app.threadgroup.activeCount() -1);
}
}
@@ -125,25 +107,59 @@ public class ESAppNode extends ESNode {
RequestEvaluator ev = new RequestEvaluator (app);
if (arguments.length != 1)
return ESBoolean.makeBoolean (false);
- // add one to the number to compensate for the internal scheduler.
return ESBoolean.makeBoolean (app.setNumberOfEvaluators (1 + arguments[0].toInt32()));
}
}
- class AppClearCache extends BuiltinFunctionObject {
- AppClearCache (String name, Evaluator evaluator, FunctionPrototype fp) {
- super (fp, evaluator, name, 1);
- }
- public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- app.clearCache ();
- return ESBoolean.makeBoolean (true);
- }
- }
public String toString () {
- return ("AppNode "+node.getElementName ());
+ return ("AppNode "+node.getNameOrID ());
}
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/scripting/fesi/ESNode.java b/src/helma/framework/core/ESNode.java
similarity index 56%
rename from src/helma/scripting/fesi/ESNode.java
rename to src/helma/framework/core/ESNode.java
index 85cef0a7..e6429661 100644
--- a/src/helma/scripting/fesi/ESNode.java
+++ b/src/helma/framework/core/ESNode.java
@@ -2,11 +2,9 @@
// Copyright (c) Hannes Wallnöfer 1998-2000
-package helma.scripting.fesi;
+package helma.framework.core;
import helma.objectmodel.*;
-import helma.objectmodel.db.*;
-import helma.framework.core.*;
import helma.util.*;
import FESI.Interpreter.*;
import FESI.Exceptions.*;
@@ -24,106 +22,158 @@ import java.util.*;
public class ESNode extends ObjectPrototype {
INode node;
-
- // the cache node - persistent nodes have a transient property as a commodity to
- // store temporary stuff.
INode cache;
- // the ecmascript wrapper for the cache.
- ESNode cacheWrapper;
- // The handle of the wrapped Node. Makes ESNodes comparable without accessing the wrapped node.
- NodeHandle handle;
+ // The ID of the wrapped Node. Makes ESNodes comparable without accessing the wrapped node.
+ String nodeID;
DbMapping dbmap;
+ ESObject cacheWrapper;
Throwable lastError = null;
- FesiEvaluator eval;
+ RequestEvaluator eval;
- /**
- * Constructor used to create transient cache nodes
- */
- public ESNode (INode node, FesiEvaluator eval) {
- super (eval.getPrototype("hopobject"), eval.getEvaluator());
- this.eval = eval;
- this.node = node;
- cache = null;
- cacheWrapper = null;
+ // used to create cache nodes
+ protected ESNode (INode node, RequestEvaluator eval) {
+ super (eval.esNodePrototype, eval.evaluator);
+ this.eval = eval;
+ this.node = node;
+ cache = null;
- // this is a transient node, set node handle to null
- handle = null;
+ cacheWrapper = null;
+ nodeID = node.getID ();
+ dbmap = node.getDbMapping ();
}
+
+ public ESNode (ESObject prototype, Evaluator evaluator, Object obj, RequestEvaluator eval) {
+ super (prototype, evaluator);
+ // IServer.getLogger().log ("in ESNode constructor: "+o.getClass ());
+ this.eval = eval;
+ if (obj == null)
+ node = new Node ();
+ else if (obj instanceof ESWrapper)
+ node = (INode) ((ESWrapper) obj).getJavaObject ();
+ else if (obj instanceof INode)
+ node = (INode) obj;
+ else
+ node = new Node (obj.toString ());
+ // set nodeID to id of wrapped node
+ nodeID = node.getID ();
+ dbmap = node.getDbMapping ();
- public ESNode (ESObject prototype, Evaluator evaluator, Object obj, FesiEvaluator eval) {
- super (prototype, evaluator);
- // eval.app.logEvent ("in ESNode constructor: "+o.getClass ());
- this.eval = eval;
- if (obj == null)
- node = new TransientNode (null);
- else if (obj instanceof ESWrapper)
- node = (INode) ((ESWrapper) obj).getJavaObject ();
- else if (obj instanceof INode)
- node = (INode) obj;
- else
- node = new TransientNode (obj.toString ());
- // set node handle to wrapped node
- if (node instanceof Node)
- handle = ((Node) node).getHandle ();
- else
- handle = null;
-
- // cache Node is initialized on demend when it is needed
- cache = null;
- cacheWrapper = null;
+ // get transient cache Node
+ cache = node.getCacheNode ();
+ cacheWrapper = new ESNode (cache, eval);
}
/**
* Check if the node has been invalidated. If so, it has to be re-fetched
* from the db via the app's node manager.
*/
- protected void checkNode () {
+ private void checkNode () {
if (node.getState () == INode.INVALID) try {
- node = handle.getNode (eval.app.getWrappedNodeManager ());
+ setNode (eval.app.nmgr.getNode (node.getID (), node.getDbMapping ()));
} catch (Exception nx) {}
}
- public INode getNode () {
- checkNode ();
- return node;
+ public INode getNode () {
+ checkNode ();
+ return node;
+ }
+
+ public void setNode (INode node) {
+ if (node != null) {
+ this.node = node;
+ nodeID = node.getID ();
+ dbmap = node.getDbMapping ();
+ eval.objectcache.put (node, this);
+ // get transient cache Node
+ cache = node.getCacheNode ();
+ cacheWrapper = new ESNode (cache, eval);
+ }
}
public void setPrototype (String protoName) {
- checkNode ();
- node.setPrototype (protoName);
+ checkNode ();
+ node.setPrototype (protoName);
}
public String getPrototypeName () {
- return node.getPrototype ();
+ return node.getPrototype ();
}
public String getESClassName () {
- return "HopObject";
+ return "HopObject";
}
public String toString () {
- if (node == null)
- return "";
- return node.toString ();
+ if (node == null)
+ return "";
+ return node.toString ();
}
public String toDetailString () {
- return "ES:[Object: builtin " + this.getClass().getName() + ":" +
- ((node == null) ? "null" : node.toString()) + "]";
+ return "ES:[Object: builtin " + this.getClass().getName() + ":" +
+ ((node == null) ? "null" : node.toString()) + "]";
}
protected void setError (Throwable e) {
- lastError = e;
+ lastError = e;
}
+ public boolean setContent (ESValue what[]) {
+ checkNode ();
+ if (what.length > 0) {
+ if (what[0] instanceof ESString) {
+ node.setContent (what[0].toString ());
+ return true;
+ }
+ if (what[0] instanceof ESWrapper) {
+ Object o = ((ESWrapper) what[0]).toJavaObject ();
+ if (o instanceof INode) {
+ try {
+ INode p = (INode) o;
+ node.setContent (p.getContent (), p.getContentType ());
+ return true;
+ } catch (Exception x) {
+ IServer.getLogger().log ("error in ESNode.setContent: "+x);
+ }
+ }
+ }
+ if (what[0] instanceof ESNode) {
+ INode i = ((ESNode) what[0]).getNode ();
+ try {
+ node.setContent (i.getContent (), i.getContentType ());
+ return true;
+ } catch (Exception x) {
+ IServer.getLogger().log ("error in ESNode.setContent: "+x);
+ }
+ }
+ }
+ return false;
+ }
+
+ public Object getContent () {
+ checkNode ();
+ if (node.getContentLength () == 0)
+ return null;
+ String contentType = node.getContentType ();
+ if (contentType != null && contentType.startsWith ("text/")) {
+ return node.getText ();
+ } else {
+ return node.getContent ();
+ }
+ }
+
public boolean add (ESValue what[]) {
checkNode ();
for (int i=0; i "+esn);
+ if (esn != null) {
+ esn.rewrap (newnode.getSubnodeAt (i));
+ }
+ }
+ for (Enumeration e=oldnode.properties (); e.hasMoreElements (); ) {
+ IProperty p = oldnode.get ((String) e.nextElement (), false);
+ if (p != null && p.getType () == IProperty.NODE) {
+ INode next = p.getNodeValue ();
+ ESNode esn = eval.getNodeWrapperFromCache (next);
+ if (esn != null) {
+ esn.rewrap (newnode.getNode (p.getName (), false));
+ }
+ }
+ }
+ }
/**
- * Remove node itself or one or more subnodes.
+ * Remove one or more subnodes.
*/
public boolean remove (ESValue args[]) {
checkNode ();
- // semantics: if called without arguments, remove self.
- // otherwise, remove given subnodes.
- if (args.length == 0) {
- return node.remove ();
- } else {
- for (int i=0; i
+ * 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) {
+ super (eval.esUserPrototype, eval.evaluator, node, eval);
+ user = (User) eval.app.activeUsers.get (node.getNameOrID ());
+ if (user == null)
+ user = (User) eval.app.sessions.get (node.getNameOrID ());
+ if (user != null) {
+ cache = user.cache;
+ 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.uid == null)
+ return ESNull.theNull;
+ else
+ return new ESString (user.uid);
+ }
+ if ("sessionID".equals (propname)) {
+ return new ESString (user.getSessionID ());
+ }
+ return super.getProperty (propname, hash);
+ }
+
+
+ public void setUser (User user) {
+ if (this.user != user) {
+ this.user = user;
+ cache = user.cache;
+ }
+ cacheWrapper = new ESNode (cache, eval);
+ }
+
+ public void setNode (INode node) {
+ if (node != null) {
+ this.node = node;
+ nodeID = node.getID ();
+ dbmap = node.getDbMapping ();
+ eval.objectcache.put (node, this);
+ // we don't take over the transient cache from the node,
+ // because we always use the one from the user object.
+ }
+ }
+
+
+ public String toString () {
+ return ("UserObject "+node.getNameOrID ());
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/framework/core/FunctionFile.java b/src/helma/framework/core/FunctionFile.java
new file mode 100644
index 00000000..32337bb9
--- /dev/null
+++ b/src/helma/framework/core/FunctionFile.java
@@ -0,0 +1,120 @@
+// FunctionFile.java
+// Copyright (c) Hannes Wallnöfer 1998-2000
+
+package helma.framework.core;
+
+import java.util.*;
+import java.io.*;
+import helma.framework.*;
+import helma.objectmodel.IServer;
+import FESI.Data.ObjectPrototype;
+import FESI.Exceptions.EcmaScriptException;
+import FESI.Interpreter.*;
+
+
+/**
+ * This represents a File containing JavaScript functions for a given Object.
+ */
+
+
+public class FunctionFile {
+
+ String name;
+ Prototype prototype;
+ Application app;
+ File file;
+ long lastmod;
+
+ public FunctionFile (File file, String name, Prototype proto) {
+ this.prototype = proto;
+ this.app = proto.app;
+ this.name = name;
+ this.file = file;
+ update (file);
+ }
+
+
+ public void update (File f) {
+
+ this.file = f;
+
+ long fmod = file.lastModified ();
+ if (lastmod == fmod)
+ return;
+
+ lastmod = fmod;
+ // app.typemgr.readFunctionFile (file, prototype.getName ());
+ Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
+ while (evals.hasNext ()) {
+ try {
+ RequestEvaluator reval = (RequestEvaluator) evals.next ();
+ updateRequestEvaluator (reval);
+ } catch (Exception ignore) {}
+ }
+
+ }
+
+ public synchronized void updateRequestEvaluator (RequestEvaluator reval) {
+
+ EvaluationSource es = new FileEvaluationSource(file.getPath(), null);
+ FileReader fr = null;
+
+ try {
+ fr = new FileReader(file);
+ ObjectPrototype op = reval.getPrototype (prototype.getName());
+ reval.evaluator.evaluate(fr, op, es, false);
+ } catch (IOException e) {
+ IServer.getLogger().log ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
+ } catch (EcmaScriptException e) {
+ IServer.getLogger().log ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
+ } finally {
+ if (fr!=null) {
+ try {
+ fr.close();
+ } catch (IOException ignore) {}
+ }
+ }
+
+ }
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/scripting/fesi/HopExtension.java b/src/helma/framework/core/HopExtension.java
similarity index 72%
rename from src/helma/scripting/fesi/HopExtension.java
rename to src/helma/framework/core/HopExtension.java
index be0a8653..b7425f7c 100644
--- a/src/helma/scripting/fesi/HopExtension.java
+++ b/src/helma/framework/core/HopExtension.java
@@ -1,13 +1,10 @@
// HopExtension.java
// Copyright (c) Hannes Wallnöfer 1998-2000
-package helma.scripting.fesi;
+package helma.framework.core;
-import helma.framework.*;
-import helma.framework.core.*;
import helma.objectmodel.*;
import helma.util.*;
-import helma.framework.IPathElement;
import FESI.Interpreter.*;
import FESI.Exceptions.*;
import FESI.Extensions.*;
@@ -17,34 +14,33 @@ import java.util.*;
import java.text.*;
import org.xml.sax.InputSource;
-/**
- * This is the basic Extension for FESI interpreters used in Helma. It sets up
- * varios constructors, global functions and properties on the HopObject prototype
- * (Node objects), the user prototype, the global prototype etc.
+/**
+ * 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 FesiEvaluator fesi;
- public HopExtension (Application app) {
- this.app = app;
+ public HopExtension () {
+ super();
}
/**
* Called by the evaluator after the extension is loaded.
*/
- public void initializeExtension (FesiEvaluator fesi) throws EcmaScriptException {
- this.fesi = fesi;
- Evaluator evaluator = fesi.getEvaluator ();
+ public void initializeExtension (RequestEvaluator reval) throws EcmaScriptException {
+
+ 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!
+ ////////// 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 ();
@@ -55,87 +51,96 @@ public class HopExtension {
ESObject dp = evaluator.getDatePrototype ();
dp.putHiddenProperty ("format", new DatePrototypeFormat ("format", evaluator, fp));
- sp.putHiddenProperty ("trim", new StringTrim ("trim", evaluator, fp));
+ reval.esNodePrototype = new ObjectPrototype(op, evaluator); // the Node prototype
- // generic (Java wrapper) object prototype
- ObjectPrototype esObjectPrototype = new ObjectPrototype (op, evaluator);
- // the Node prototype
- ObjectPrototype esNodePrototype = new ObjectPrototype(op, evaluator);
- // the User prototype
- ObjectPrototype esUserPrototype = new ObjectPrototype (esNodePrototype, evaluator);
- // the Node constructor
- ESObject node = new NodeConstructor ("Node", fp, fesi);
+ 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
- esNodePrototype.putHiddenProperty ("add", new NodeAdd ("add", evaluator, fp));
- esNodePrototype.putHiddenProperty ("addAt", new NodeAddAt ("addAt", evaluator, fp));
- esNodePrototype.putHiddenProperty ("remove", new NodeRemove ("remove", evaluator, fp));
- esNodePrototype.putHiddenProperty ("link", new NodeLink ("link", evaluator, fp));
- esNodePrototype.putHiddenProperty ("list", new NodeList ("list", evaluator, fp));
- esNodePrototype.putHiddenProperty ("set", new NodeSet ("set", evaluator, fp));
- esNodePrototype.putHiddenProperty ("get", new NodeGet ("get", evaluator, fp));
- esNodePrototype.putHiddenProperty ("count", new NodeCount ("count", evaluator, fp));
- esNodePrototype.putHiddenProperty ("contains", new NodeContains ("contains", evaluator, fp));
- esNodePrototype.putHiddenProperty ("size", new NodeCount ("size", evaluator, fp));
- esNodePrototype.putHiddenProperty ("editor", new NodeEditor ("editor", evaluator, fp));
- esNodePrototype.putHiddenProperty ("path", new NodeHref ("path", evaluator, fp));
- esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
- esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp));
- esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp));
- esNodePrototype.putHiddenProperty ("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false));
- esNodePrototype.putHiddenProperty ("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true));
- esNodePrototype.putHiddenProperty ("clearCache", new NodeClearCache ("clearCache", evaluator, fp));
-
- // default methods for generic Java wrapper object prototype.
- // This is a small subset of the methods in esNodePrototype.
- esObjectPrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
- esObjectPrototype.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false));
- esObjectPrototype.putHiddenProperty("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true));
+ 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));
+ 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 ("getContent", new NodeGetContent ("getContent", evaluator, fp));
+ reval.esNodePrototype.putHiddenProperty ("setContent", new NodeSetContent ("setContent", evaluator, fp));
+ reval.esNodePrototype.putHiddenProperty ("path", new NodePath ("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, reval, false, false));
+ reval.esNodePrototype.putHiddenProperty("renderSkin_as_string", new RenderSkin ("renderSkin_as_string", evaluator, fp, reval, 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("getUser", new GlobalGetUser ("getUser", evaluator, fp, reval));
+ go.putHiddenProperty("getUserBySession", new GlobalGetUserBySession ("getUserBySession", evaluator, fp, reval));
+ go.putHiddenProperty("getAllUsers", new GlobalGetAllUsers ("getAllUsers", evaluator, fp, reval));
+ go.putHiddenProperty("getActiveUsers", new GlobalGetActiveUsers ("getActiveUsers", evaluator, fp, reval));
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("getSkin", new GlobalGetSkin ("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.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, reval, true, false));
+ go.putHiddenProperty("renderSkin_as_string", new RenderSkin ("renderSkin_as_string", evaluator, fp, reval, true, true));
go.deleteProperty("exit", "exit".hashCode());
// and some methods for session management from JS...
- esUserPrototype.putHiddenProperty("logon", new UserLogin ("logon", evaluator, fp));
- esUserPrototype.putHiddenProperty("login", new UserLogin ("login", evaluator, fp));
- esUserPrototype.putHiddenProperty("register", new UserRegister ("register", evaluator, fp));
- esUserPrototype.putHiddenProperty("logout", new UserLogout ("logout", evaluator, fp));
- esUserPrototype.putHiddenProperty("onSince", new UserOnSince ("onSince", evaluator, fp));
- esUserPrototype.putHiddenProperty("lastActive", new UserLastActive ("lastActive", evaluator, fp));
- esUserPrototype.putHiddenProperty("touch", new UserTouch ("touch", evaluator, fp));
+ 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));
+ 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));
- // register object prototypes with FesiEvaluator
- fesi.putPrototype ("global", go);
- fesi.putPrototype ("hopobject", esNodePrototype);
- fesi.putPrototype ("__javaobject__", esObjectPrototype);
- fesi.putPrototype ("user", esUserPrototype);
}
+
+ class NodeSetContent extends BuiltinFunctionObject {
+ NodeSetContent (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.setContent (arguments));
+ }
+ }
+
+ class NodeGetContent extends BuiltinFunctionObject {
+ NodeGetContent (String name, Evaluator evaluator, FunctionPrototype fp) {
+ super (fp, evaluator, name, 1);
+ }
+ public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
+ ESNode node = (ESNode) thisObject;
+ Object content = node.getContent ();
+ if (content == null)
+ return ESNull.theNull;
+ else
+ return ESLoader.normalizeValue (content, this.evaluator);
+ }
+ }
+
class NodeAdd extends BuiltinFunctionObject {
NodeAdd (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
@@ -178,8 +183,10 @@ public class HopExtension {
}
class NodeList extends BuiltinFunctionObject {
- NodeList (String name, Evaluator evaluator, FunctionPrototype fp) {
+ RequestEvaluator reval;
+ NodeList (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
super(fp, evaluator, name, 0);
+ this.reval = reval;
}
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
ESNode node = (ESNode) thisObject;
@@ -198,10 +205,7 @@ public class HopExtension {
esv = thisObject.getProperty (i);
} else {
String name = arguments[0].toString ();
- // call esNodeProperty() method special to ESNode because we want to avoid
- // retrieving prototype functions when calling hopobject.get().
- ESNode esn = (ESNode) thisObject;
- esv = esn.getNodeProperty (name);
+ esv = thisObject.getProperty (name, name.hashCode ());
}
return (esv);
}
@@ -253,7 +257,10 @@ public class HopExtension {
INode node = esn.getNode ();
if (node instanceof helma.objectmodel.db.Node) {
((helma.objectmodel.db.Node) node).invalidate ();
- esn.checkNode ();
+ try {
+ node = app.nmgr.getNode (node.getID (), node.getDbMapping ());
+ esn.setNode (node);
+ } catch (Exception x) {}
}
return ESBoolean.makeBoolean (true);
}
@@ -406,21 +413,51 @@ public class HopExtension {
}
}
- class StringTrim extends BuiltinFunctionObject {
- StringTrim (String name, Evaluator evaluator, FunctionPrototype fp) {
- super (fp, evaluator, name, 1);
- }
- public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- return new ESString ( thisObject.toString().trim() );
- }
- }
+ 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)
+ if (arguments.length < 2)
return ESBoolean.makeBoolean(false);
ESUser u = (ESUser) thisObject;
if (u.user == null)
@@ -434,8 +471,10 @@ public class HopExtension {
}
class UserRegister extends BuiltinFunctionObject {
- UserRegister (String name, Evaluator evaluator, FunctionPrototype fp) {
+ RequestEvaluator reval;
+ UserRegister (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
super (fp, evaluator, name, 2);
+ this.reval = reval;
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length < 2)
@@ -444,7 +483,7 @@ public class HopExtension {
if (unode == null)
return ESNull.theNull;
else
- return fesi.getNodeWrapper (unode);
+ return reval.getNodeWrapper (unode);
}
}
@@ -471,7 +510,7 @@ public class HopExtension {
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 ()));
+ DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.onSince));
return date;
}
}
@@ -484,7 +523,7 @@ public class HopExtension {
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 ()));
+ DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.lastTouched));
return date;
}
}
@@ -509,20 +548,28 @@ public class HopExtension {
if (arguments.length == 0)
return new ESString ("");
String defval = (arguments.length > 1) ? arguments[1].toString () : "";
- return new ESString (app.getProperty (arguments[0].toString (), defval));
+ return new ESString (app.props.getProperty (arguments[0].toString (), defval));
}
}
- class GlobalAuthenticate extends BuiltinFunctionObject {
- GlobalAuthenticate (String name, Evaluator evaluator, FunctionPrototype fp) {
+ /**
+ * Get a parsed Skin from the central skin cache if possible, otherwise create it
+ */
+ class GlobalGetSkin extends BuiltinFunctionObject {
+ GlobalGetSkin (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 ()));
-
+ if (arguments.length != 1 || ESNull.theNull.equals (arguments[0]))
+ throw new EcmaScriptException ("getSkin must be called with one String argument!");
+ String str = arguments[0].toString ();
+ Skin skin = (Skin) app.skincache.get (str);
+ if (skin == null) {
+ skin = new Skin (str);
+ app.skincache.put (str, skin);
+ }
+ return new ESWrapper (skin, evaluator);
}
}
@@ -535,14 +582,8 @@ public class HopExtension {
}
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 = (Skin) app.skincache.get (str);
- if (skin == null) {
- skin = new Skin (str, app);
- app.skincache.put (str, skin);
- }
- return new ESWrapper (skin, evaluator);
+ throw new EcmaScriptException ("createSkin must be called with one String argument!");
+ return new ESWrapper (new Skin (arguments[0].toString()), evaluator);
}
}
@@ -550,29 +591,25 @@ public class HopExtension {
* Render a skin
*/
class RenderSkin extends BuiltinFunctionObject {
+ RequestEvaluator reval;
boolean global;
boolean asString;
- RenderSkin (String name, Evaluator evaluator, FunctionPrototype fp, boolean global, boolean asString) {
+ RenderSkin (String name, Evaluator evaluator, FunctionPrototype fp,
+ RequestEvaluator reval, boolean global, boolean asString) {
super (fp, evaluator, name, 1);
+ this.reval = reval;
this.global = global;
this.asString = asString;
}
- public ESValue callFunction (ESObject thisObj, ESValue[] arguments) throws EcmaScriptException {
+ public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length < 1 || arguments.length > 2 || arguments[0] ==null || arguments[0] == ESNull.theNull)
- throw new EcmaScriptException ("renderSkin requires one argument containing the skin name and an optional parameter object argument");
+ 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;
- HashMap params = null;
- if (arguments.length > 1 && arguments[1] instanceof ESObject) {
- // create an parameter object to pass to the skin
- ESObject paramObject = (ESObject) arguments[1];
- params = new HashMap ();
- for (Enumeration en=paramObject.getProperties(); en.hasMoreElements(); ) {
- String propname = (String) en.nextElement();
- params.put (propname, paramObject.getProperty (propname, propname.hashCode()).toJavaObject());
- }
- }
+ Skin skin = null;
+ ESNode handlerNode = global ? null : (ESNode) thisObject;
+ 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) {
@@ -581,41 +618,16 @@ public class HopExtension {
skin = (Skin) obj;
}
- // if res.skinpath is set, transform it into an array of java objects
- // (strings for directory names and INodes for internal, db-stored skinsets)
- ResponseTrans res = fesi.getResponse();
- Object[] skinpath = res.getTranslatedSkinpath ();
- if (skinpath == null) {
- skinpath = new Object[0];
- Object rawSkinpath = res.getSkinpath ();
- if (rawSkinpath != null && rawSkinpath instanceof JSWrapper) {
- JSWrapper jsw = (JSWrapper) rawSkinpath;
- ESObject eso = jsw.getESObject ();
- if (eso instanceof ArrayPrototype) {
- ArrayPrototype array = (ArrayPrototype) eso;
- skinpath = new Object[array.size()];
- for (int i=0; i 0) {
- String uname = arguments[0].toString ().trim ();
- user = app.getUserNode (uname);
- }
- if (user == null)
- return ESNull.theNull;
- return fesi.getNodeWrapper (user);
+ 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) {
+ RequestEvaluator reval;
+ GlobalGetUserBySession (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
super (fp, evaluator, name, 1);
+ this.reval = reval;
}
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 fesi.getNodeWrapper (user.getNode ());
+ User user = null;
+ if (arguments.length > 0) {
+ String sid = arguments[0].toString ().trim ();
+ user = app.getUser (sid);
+ }
+ if (user == null || user.uid == null)
+ return ESNull.theNull;
+ user.touch ();
+ return reval.getNodeWrapper (user.getNode ());
}
}
class GlobalGetAllUsers extends BuiltinFunctionObject {
- GlobalGetAllUsers (String name, Evaluator evaluator, FunctionPrototype fp) {
+ RequestEvaluator reval;
+ GlobalGetAllUsers (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
super (fp, evaluator, name, 1);
+ this.reval = reval;
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
INode users = app.getUserRoot ();
@@ -678,37 +696,30 @@ public class HopExtension {
}
class GlobalGetActiveUsers extends BuiltinFunctionObject {
- GlobalGetActiveUsers (String name, Evaluator evaluator, FunctionPrototype fp) {
+ RequestEvaluator reval;
+ GlobalGetActiveUsers (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
super (fp, evaluator, name, 1);
+ this.reval = reval;
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
Hashtable sessions = (Hashtable) app.sessions.clone ();
+ int l = sessions.size ();
ESObject ap = this.evaluator.getArrayPrototype();
ArrayPrototype theArray = new ArrayPrototype (ap, this.evaluator);
- theArray.setSize (sessions.size ());
+ theArray.setSize(l);
int i=0;
- // Hashtable visited = new Hashtable ();
+ 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 (fesi.getNodeWrapper (u), i++);
- // if (u.uid != null) visited.put (u.uid, u);
- // }
+ if (u.uid == null || !visited.containsKey (u.uid)) {
+ theArray.setElementAt (reval.getNodeWrapper (u.getNode ()), 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);
@@ -759,7 +770,7 @@ public class HopExtension {
return new ESString (age.toString ());
} catch (Exception e) {
- app.logEvent ("Error formatting date: "+e);
+ IServer.getLogger().log ("Error formatting date: "+e);
e.printStackTrace ();
return new ESString ("");
}
@@ -810,17 +821,6 @@ public class HopExtension {
}
}
- 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) {
@@ -865,7 +865,7 @@ public class HopExtension {
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 ());
+ 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
@@ -877,7 +877,7 @@ public class HopExtension {
parser.parse (new InputSource ((Reader) p));
return ESLoader.normalizeObject (parser.getDocument(), evaluator);
} catch (Exception noluck) {
- app.logEvent ("Error creating XML document: "+noluck);
+ IServer.getLogger().log ("Error creating XML document: "+noluck);
}
return ESNull.theNull;
}
@@ -894,7 +894,7 @@ public class HopExtension {
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 ());
+ 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
@@ -906,7 +906,7 @@ public class HopExtension {
parser.parse (new InputSource ((Reader) p));
return ESLoader.normalizeObject (parser.getDocument(), evaluator);
} catch (Exception noluck) {
- app.logEvent ("Error creating HTML document: "+noluck);
+ IServer.getLogger().log ("Error creating HTML document: "+noluck);
}
return ESNull.theNull;
}
@@ -924,12 +924,24 @@ public class HopExtension {
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);
+ IServer.getLogger().log ("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);
@@ -940,52 +952,16 @@ public class HopExtension {
}
}
- class NodeClearCache extends BuiltinFunctionObject {
- NodeClearCache (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.clearCache ());
- }
- }
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 {
- Object elem = thisObject.toJavaObject ();
+ INode n = ((ESNode) thisObject).getNode ();
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.
- Object 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 = app.getParentElement (skinElem);
- }
-
- if (skin != null) {
- return renderSkin (skin, basicHref, skinElem);
- }
- }
- return new ESString (basicHref);
- }
- private ESString renderSkin (Skin skin, String path, Object skinElem) throws EcmaScriptException {
- fesi.getResponse().pushStringBuffer ();
- HashMap param = new HashMap ();
- param.put ("path", path);
- skin.render (fesi.getRequestEvaluator(), skinElem, param);
- return new ESString (fesi.getResponse().popStringBuffer ().trim ());
+ return new ESString (app.getNodeHref (n, tmpname));
+
}
}
@@ -1002,7 +978,7 @@ public class HopExtension {
double d = from <= to ? 1.0 : -1.0;
for (double i=from; i*d<=to*d; i+=step) {
if (Math.abs (i%1) < l) {
- int j = (int) i;
+ int j = (int) i;
b.append (""+j);
@@ -1015,7 +991,165 @@ public class HopExtension {
b.append ("");
return b.toString ();
}
+
+ private String getNodeChooserDD (String name, INode collection, INode target, String teaser) {
+ StringBuffer buffer = new StringBuffer ("");
+ if (collection.contains (target) == -1) {
+ buffer.append ("");
+ buffer.append (HtmlEncoder.encodeAll (teaser));
+ }
+ 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 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/framework/core/NodeConstructor.java
similarity index 60%
rename from src/helma/scripting/fesi/NodeConstructor.java
rename to src/helma/framework/core/NodeConstructor.java
index c549b447..5223a804 100644
--- a/src/helma/scripting/fesi/NodeConstructor.java
+++ b/src/helma/framework/core/NodeConstructor.java
@@ -1,10 +1,8 @@
// NodeConstructor.java
// Copyright (c) Hannes Wallnöfer 2000
-package helma.scripting.fesi;
+package helma.framework.core;
-import helma.objectmodel.db.Node;
-import helma.framework.core.*;
import FESI.Data.*;
import FESI.Exceptions.*;
import FESI.Interpreter.*;
@@ -15,14 +13,14 @@ import FESI.Interpreter.*;
*/
public class NodeConstructor extends BuiltinFunctionObject {
-
- FesiEvaluator fesi;
+
+ RequestEvaluator reval;
String typename;
- public NodeConstructor (String name, FunctionPrototype fp, FesiEvaluator fesi) {
- super(fp, fesi.getEvaluator (), name, 1);
+ public NodeConstructor (String name, FunctionPrototype fp, RequestEvaluator reval) {
+ super(fp, reval.evaluator, name, 1);
typename = name;
- this.fesi = fesi;
+ this.reval = reval;
}
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
@@ -31,33 +29,32 @@ public class NodeConstructor extends BuiltinFunctionObject {
public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
ESNode node = null;
- Application app = fesi.getApplication ();
if ("Node".equals (typename) || "hopobject".equalsIgnoreCase (typename)) {
- String nodeName = null;
- if (arguments.length > 0 && arguments[0] != null)
- nodeName = arguments[0].toString();
- Node n = new Node (nodeName, (String) null, app.getWrappedNodeManager ());
- node = new ESNode (fesi.getPrototype ("hopobject"), this.evaluator, n, fesi);
- fesi.putNodeWrapper (node.getNode (), node);
+ if (arguments.length == 0) {
+ node = new ESNode (reval.esNodePrototype, this.evaluator, null, reval);
+ reval.objectcache.put (node.getNode (), node);
+ } else {
+ node = new ESNode (reval.esNodePrototype, this.evaluator, arguments[0], 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 = fesi.getPrototype (typename);
- Node n = new Node (typename, typename, app.getWrappedNodeManager ());
- node = new ESNode (op, fesi.getEvaluator (), n, fesi);
+ ObjectPrototype op = reval.getPrototype (typename);
+ node = new ESNode (op, reval.evaluator, typename, reval);
node.setPrototype (typename);
- node.getNode ().setDbMapping (app.getDbMapping (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 (fesi.getEvaluator(), node, "constructor", arguments);
+ if (op.getProperty("constructor", "constructor".hashCode()) instanceof ConstructedFunctionObject)
+ node.doIndirectCall (reval.evaluator, node, "constructor", arguments);
else
- node.doIndirectCall (fesi.getEvaluator(), node, typename, arguments);
+ node.doIndirectCall (reval.evaluator, node, typename, arguments);
} catch (Exception ignore) {}
}
return node;
@@ -68,9 +65,9 @@ public class NodeConstructor extends BuiltinFunctionObject {
}
public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException {
- if ("prototype".equals (propertyName))
- return fesi.getPrototype (typename);
- return super.getProperty(propertyName, hash);
+ if ("prototype".equals (propertyName))
+ return reval.getPrototype (typename);
+ return super.getProperty(propertyName, hash);
}
public String[] getSpecialPropertyNames() {
diff --git a/src/helma/framework/core/Prototype.java b/src/helma/framework/core/Prototype.java
index 6a64b5a3..d3af6d62 100644
--- a/src/helma/framework/core/Prototype.java
+++ b/src/helma/framework/core/Prototype.java
@@ -3,13 +3,12 @@
package helma.framework.core;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.*;
import java.io.*;
import helma.framework.*;
-import helma.scripting.*;
import helma.objectmodel.*;
-import helma.util.Updatable;
+import FESI.Data.*;
+import FESI.Exceptions.EcmaScriptException;
/**
@@ -25,65 +24,54 @@ public class Prototype {
String id;
String name;
Application app;
- public HashMap templates, functions, actions, skins, updatables;
+ Hashtable templates, functions, actions, skins;
+ File codeDir;
long lastUpdate;
- Prototype parent;
+ DbMapping dbmap;
- // Tells us whether this prototype is used to script a generic Java object,
- // as opposed to a Helma objectmodel node object.
- boolean isJavaPrototype;
+ Prototype prototype;
- public Prototype (String name, Application app) {
- // app.logEvent ("Constructing Prototype "+app.getName()+"/"+name);
+
+ public Prototype (File codeDir, Application app) {
+
+ IServer.getLogger().log ("Constructing Prototype "+app.getName()+"/"+codeDir.getName ());
+
+ this.codeDir = codeDir;
this.app = app;
- this.name = name;
- isJavaPrototype = app.isJavaPrototype (name);
- lastUpdate = 0; // System.currentTimeMillis ();
- }
+ this.name = codeDir.getName ();
+
+ File propfile = new File (codeDir, "type.properties");
+ SystemProperties props = new SystemProperties (propfile.getAbsolutePath ());
+ dbmap = new DbMapping (app, name, props);
+
+ lastUpdate = System.currentTimeMillis ();
- /**
- * Return the application this prototype is a part of
- */
- public Application getApplication () {
- return app;
}
- /**
- * Set the parent prototype of this prototype, i.e. the prototype this one inherits from.
- */
- public void setParentPrototype (Prototype parent) {
- // this is not allowed for the hopobject and global prototypes
- if ("hopobject".equalsIgnoreCase (name) || "global".equalsIgnoreCase (name))
- return;
-
- Prototype old = this.parent;
- this.parent = parent;
+ public Action getActionOrTemplate (String aname) {
- // if parent has changed, update ES-prototypes in request evaluators
- if (parent != old) {
- /* Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
- while (evals.hasNext ()) {
- try {
- RequestEvaluator reval = (RequestEvaluator) evals.next ();
- ObjectPrototype op = reval.getPrototype (getName());
- // use hopobject (node) as prototype even if prototype is null -
- // this is the case if no hopobject directory exists
- ObjectPrototype opp = parent == null ?
- reval.esNodePrototype : reval.getPrototype (parent.getName ());
- // don't think this is possible, but check anyway
- if (opp == null)
- opp = reval.esNodePrototype;
- op.setPrototype (opp);
- } catch (Exception ignore) {
- }
- } */
- }
+ Action retval = null;
+ if (aname == null || "".equals (aname))
+ aname = "main";
+ retval = (Action) actions.get (aname);
+ // check if it's allowed to access templates via URL
+ // this should be cached in the future
+ if (retval == null && "true".equalsIgnoreCase (app.props.getProperty ("exposetemplates")))
+ retval = (Action) templates.get (aname);
+ // if still not found, check if the action is defined for the generic node prototype
+ if (retval == null && this != app.typemgr.nodeProto && app.typemgr.nodeProto != null)
+ retval = app.typemgr.nodeProto.getActionOrTemplate (aname);
+ return retval;
}
- public Prototype getParentPrototype () {
- return parent;
+ public void setPrototype (Prototype prototype) {
+ this.prototype = prototype;
+ }
+
+ public Prototype getPrototype () {
+ return prototype;
}
public Template getTemplate (String tmpname) {
@@ -94,8 +82,8 @@ public class Prototype {
return (FunctionFile) functions.get (ffname);
}
- public ActionFile getActionFile (String afname) {
- return (ActionFile) actions.get (afname);
+ public Action getAction (String afname) {
+ return (Action) actions.get (afname);
}
public SkinFile getSkinFile (String sfname) {
@@ -110,29 +98,131 @@ public class Prototype {
return null;
}
+ public File getCodeDir () {
+ return codeDir;
+ }
+
+ public synchronized boolean checkCodeDir () {
+
+ boolean retval = false;
+ String[] list = codeDir.list ();
+
+ for (int i=0; i lastUpdate) {
+ lastUpdate = System.currentTimeMillis ();
+ try {
+ app.typemgr.updatePrototype (this.name, codeDir, this);
+ // TypeManager.broadcaster.broadcast ("Finished update for prototype "+name+" @ "+new Date ()+" ");
+ } catch (Exception x) {
+ IServer.getLogger().log ("Error building function protos in prototype: "+x);
+ // TypeManager.broadcaster.broadcast ("Error updating prototype "+name+" in application "+app.getName()+": "+x.getMessage ()+" ");
+ }
+ retval = true;
+ }
+ }
+ }
+ return retval;
+ }
+
public String getName () {
return name;
}
- Updatable[] upd = null;
- public Updatable[] getUpdatables () {
- if (upd == null) {
- upd = new Updatable[updatables.size()];
- int i = 0;
- for (Iterator it = updatables.values().iterator(); it.hasNext(); ) {
- upd[i++] = (Updatable) it.next();
- }
+
+ public void initRequestEvaluator (RequestEvaluator reval) {
+ ObjectPrototype op = null;
+ if ("user".equalsIgnoreCase (name))
+ op = reval.esUserPrototype;
+ else if ("global".equalsIgnoreCase (name))
+ op = reval.global;
+ else if ("hopobject".equalsIgnoreCase (name))
+ op = reval.esNodePrototype;
+ else {
+ op = new ObjectPrototype (reval.esNodePrototype, reval.evaluator);
+ try {
+ op.putProperty ("prototypename", new ESString (name), "prototypename".hashCode ());
+ } catch (EcmaScriptException ignore) {}
+ }
+ reval.putPrototype (name, op);
+
+ // Register a constructor for all types except global.
+ // This will first create a node and then call the actual (scripted) constructor on it.
+ if (!"global".equalsIgnoreCase (name)) {
+ try {
+ FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype();
+ reval.global.putHiddenProperty (name, new NodeConstructor (name, fp, reval));
+ } catch (EcmaScriptException ignore) {}
+ }
+
+ for (Enumeration en = functions.elements(); en.hasMoreElements(); ) {
+ FunctionFile ff = (FunctionFile) en.nextElement ();
+ ff.updateRequestEvaluator (reval);
+ }
+ for (Enumeration en = templates.elements(); en.hasMoreElements(); ) {
+ Template tmp = (Template) en.nextElement ();
+ try {
+ tmp.updateRequestEvaluator (reval);
+ } catch (EcmaScriptException ignore) {}
+ }
+ for (Enumeration en = actions.elements(); en.hasMoreElements(); ) {
+ Action act = (Action) en.nextElement ();
+ try {
+ act.updateRequestEvaluator (reval);
+ } catch (EcmaScriptException ignore) {}
}
- return upd;
-
}
-
-
-
- public String toString () {
- return "[Prototype "+ app.getName()+"/"+name+"]";
- }
-
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/framework/core/RequestEvaluator.java b/src/helma/framework/core/RequestEvaluator.java
index 96ce003c..c72a7f32 100644
--- a/src/helma/framework/core/RequestEvaluator.java
+++ b/src/helma/framework/core/RequestEvaluator.java
@@ -3,52 +3,70 @@
package helma.framework.core;
-import helma.objectmodel.*;
-import helma.objectmodel.db.*;
-import helma.framework.*;
-import helma.scripting.*;
-import helma.util.*;
import java.util.*;
+import java.io.*;
+import helma.objectmodel.*;
+import helma.objectmodel.db.Transactor;
+import helma.framework.*;
+import helma.framework.extensions.*;
+import helma.xmlrpc.fesi.*;
+import helma.util.*;
+import Acme.LruHashtable;
+import FESI.Data.*;
+import FESI.Interpreter.*;
+import FESI.Exceptions.*;
/**
- * This class does the work for incoming requests. It holds a transactor thread
- * and an EcmaScript evaluator to get the work done. Incoming threads are
+ * This class does the work for incoming requests. It holds a transactor thread
+ * and an EcmaScript evaluator to get the work done. Incoming threads are
* blocked until the request has been serviced by the evaluator, or the timeout
* specified by the application has passed. In the latter case, the evaluator thread
- * is killed and an error message is returned.
+ * is killed and an error message is returned.
*/
public class RequestEvaluator implements Runnable {
- public Application app;
+ Application app;
protected boolean initialized;
- public RequestTrans req;
- public ResponseTrans res;
+ RequestTrans req;
+ ResponseTrans res;
volatile Transactor rtx;
- // the object on which to invoke a function, if specified
- Object thisObject;
-
- // the method to be executed
String method;
-
- // the user object associated with the current request
+ ESObject current;
User user;
-
- // arguments passed to the function
- Object[] args;
-
- // the object path of the request we're evaluating
- List requestPath;
-
- // the result of the
+ Vector args;
+ ESValue[] esargs;
+ ESValue esresult;
Object result;
-
- // the exception thrown by the evaluator, if any.
Exception exception;
+ protected ArrayPrototype reqPath;
+ private ESRequestData reqData;
+
+ // vars for FESI EcmaScript support
+ protected Evaluator evaluator;
+ protected ObjectPrototype esNodePrototype;
+ protected ObjectPrototype esUserPrototype;
+ protected LruHashtable objectcache;
+ protected Hashtable prototypes;
+
+ GlobalObject global;
+ HopExtension hopx;
+ MailExtension mailx;
+ FesiRpcServer xmlrpc;
+ ESAppNode appnode;
+ static String[] extensions = new String[] {
+ "FESI.Extensions.BasicIO",
+ "FESI.Extensions.FileIO",
+ "helma.xmlrpc.fesi.FesiRpcExtension",
+ "helma.framework.extensions.ImageExtension",
+ "helma.framework.extensions.FtpExtension",
+ "helma.framework.extensions.Database",
+ "FESI.Extensions.JavaAccess",
+ "FESI.Extensions.OptionalRegExp"};
// the type of request to be serviced
int reqtype;
@@ -57,13 +75,49 @@ public class RequestEvaluator implements Runnable {
static final int XMLRPC = 2; // via XML-RPC
static final int INTERNAL = 3; // generic function call, e.g. by scheduler
+ INode root, userroot, currentNode;
/**
- * Create a new RequestEvaluator for this application.
+ * Build a RenderContext from a RequestTrans. Checks if the path is the user home node ("user")
+ * or a subnode of it. Otherwise, the data root of the site is used. Two arrays are built, one
+ * that contains the data nodes, and anotherone with the corresponding Prototypes or Prototype.Parts.
*/
public RequestEvaluator (Application app) {
- this.app = app;
+ this.app = app;
+ this.objectcache = new LruHashtable (100, .80f);
+ this.prototypes = new Hashtable ();
+ initEvaluator ();
initialized = false;
+ // startThread ();
+ }
+
+
+ // init Script Evaluator
+ private void initEvaluator () {
+ try {
+ evaluator = new Evaluator();
+ global = evaluator.getGlobalObject();
+ for (int i=0; i 50)
- throw new RuntimeException ("Path too long");
- String[] pathItems = new String [ntokens];
- for (int i=0; i 1) {
+ next = st.nextToken ();
+ if ("user".equalsIgnoreCase (next)) {
+ currentNode = user.getNode ();
+ ntokens -=1;
+ if (currentNode != null)
+ reqPath.putProperty (1, getNodeWrapper (currentNode));
+ } else if ("users".equalsIgnoreCase (next)) {
+ currentNode = app.getUserRoot ();
+ ntokens -=1;
+ isProperty = true;
+ } else {
+ currentNode = currentNode.getSubnode (next);
+ ntokens -=1;
+ if (currentNode != null)
+ reqPath.putProperty (1, getNodeWrapper (currentNode));
}
}
+
+ for (int i=1; i 50) throw new RuntimeException ("Path too deep");
+ }
- if (currentElement == null)
+ if (currentNode == null)
throw new FrameworkException ("Object not found.");
- if (action == null)
- action = getAction (currentElement, null);
+ Prototype p = app.getPrototype (currentNode);
+ next = st.nextToken ();
+ if (p != null)
+ action = p.getActionOrTemplate (next);
+
+ if (p == null || action == null) {
+ currentNode = currentNode.getSubnode (next);
+ if (currentNode == null)
+ throw new FrameworkException ("Object or Action '"+next+"' not found.");
+ p = app.getPrototype (currentNode);
+ // add to reqPath array
+ if (currentNode != null && currentNode.getState() != INode.VIRTUAL)
+ reqPath.putProperty (reqPath.size(), getNodeWrapper (currentNode));
+ if (p != null)
+ action = p.getActionOrTemplate ("main");
+ }
+
+ current = getNodeWrapper (currentNode);
- if (action == null)
- throw new FrameworkException ("Action not found");
}
+ if (action == null)
+ throw new FrameworkException ("Action not found");
+
} catch (FrameworkException notfound) {
if (error != null)
// we already have an error and the error template wasn't found,
@@ -207,81 +280,27 @@ public class RequestEvaluator implements Runnable {
throw new RuntimeException ();
// The path could not be resolved. Check if there is a "not found" action
// specified in the property file.
- res.status = 404;
String notFoundAction = app.props.getProperty ("notFound", "notfound");
- currentElement = root;
- action = getAction (currentElement, notFoundAction);
+ Prototype p = app.getPrototype (root);
+ action = p.getActionOrTemplate (notFoundAction);
if (action == null)
throw new FrameworkException (notfound.getMessage ());
+ current = getNodeWrapper (root);
}
- localrtx.timer.endEvent (txname+" init");
- /////////////////////////////////////////////////////////////////////////////
- // end of path resolution section
+ localrtx.timer.endEvent (requestPath+" init");
- /////////////////////////////////////////////////////////////////////////////
- // beginning of execution section
try {
- localrtx.timer.beginEvent (txname+" execute");
-
- int actionDot = action.lastIndexOf (".");
- boolean isAction = actionDot == -1;
- // set the req.action property, cutting off the _action suffix
- if (isAction)
- req.action = action.substring (0, action.length()-7);
- else
- req.action = action;
-
- // try calling onRequest() function on object before
- // calling the actual action
- try {
- app.scriptingEngine.invoke (currentElement, "onRequest", new Object[0], globals, this);
- } catch (RedirectException redir) {
- throw redir;
- } catch (Exception ignore) {
- // function is not defined or caused an exception, ignore
+ localrtx.timer.beginEvent (requestPath+" execute");
+ current.doIndirectCall (evaluator, current, action.getFunctionName (), new ESValue[0]);
+ if (res.mainSkin != null) {
+ Skin mainSkin = getSkin (null, res.mainSkin);
+ if (mainSkin != null)
+ mainSkin.render (this, null, null);
}
-
- // do the actual action invocation
- if (isAction) {
- app.scriptingEngine.invoke (currentElement, action, new Object[0], globals, this);
- } else {
- Skin skin = app.skinmgr.getSkinInternal (app.appDir, app.getPrototype(currentElement).getName(),
- action.substring (0, actionDot), action.substring (actionDot+1));
- if (skin != null)
- skin.render (this, currentElement, null);
- else
- throw new RuntimeException ("Skin "+action+" not found in "+req.path);
- }
-
- // check if the script set the name of a skin to render in res.skin
- if (res.skin != null) {
- int dot = res.skin.indexOf (".");
- Object skinObject = null;
- String skinName = res.skin;
- if (dot > -1) {
- String soname = res.skin.substring (0, dot);
- int l = requestPath.size();
- for (int i=l-1; i>=0; i--) {
- Object pathelem = requestPath.get (i);
- if (soname.equalsIgnoreCase (app.getPrototypeName (pathelem))) {
- skinObject = pathelem;
- break;
- }
- }
-
- if (skinObject == null)
- throw new RuntimeException ("Skin "+res.skin+" not found in path.");
- skinName = res.skin.substring (dot+1);
- }
- Object[] skinNameArg = new Object[1];
- skinNameArg[0] = skinName;
- app.scriptingEngine.invoke (skinObject, "renderSkin", skinNameArg, globals, this);
- }
-
- localrtx.timer.endEvent (txname+" execute");
+ localrtx.timer.endEvent (requestPath+" execute");
} catch (RedirectException redirect) {
- // res.redirect = redirect.getMessage ();
+ res.redirect = redirect.getMessage ();
// if there is a message set, save it on the user object for the next request
if (res.message != null)
user.message = res.message;
@@ -295,12 +314,12 @@ public class RequestEvaluator implements Runnable {
} catch (ConcurrencyException x) {
res.reset ();
- if (++tries < 8) {
+ if (++tries < 5) {
// try again after waiting some period
abortTransaction (true);
try {
// wait a bit longer with each try
- int base = 800 * tries;
+ int base = 500 * tries;
Thread.currentThread ().sleep ((long) (base + Math.random ()*base*2));
} catch (Exception ignore) {}
continue;
@@ -308,8 +327,6 @@ public class RequestEvaluator implements Runnable {
abortTransaction (false);
if (error == null) {
app.errorCount += 1;
- // set done to false so that the error will be processed
- done = false;
error = "Couldn't complete transaction due to heavy object traffic (tried "+tries+" times)";
} else {
// error in error action. use traditional minimal error message
@@ -322,7 +339,7 @@ public class RequestEvaluator implements Runnable {
abortTransaction (false);
- app.logEvent ("### Exception in "+app.getName()+"/"+req.path+": "+x);
+ IServer.getLogger().log ("### Exception in "+app.getName()+"/"+req.path+": "+x);
// Dump the profiling data to System.err
if (app.debug) {
((Transactor) Thread.currentThread ()).timer.dump (System.err);
@@ -337,8 +354,6 @@ public class RequestEvaluator implements Runnable {
res.reset ();
if (error == null) {
app.errorCount += 1;
- // set done to false so that the error will be processed
- done = false;
error = x.getMessage ();
if (error == null || error.length() == 0)
error = x.toString ();
@@ -357,31 +372,42 @@ public class RequestEvaluator implements Runnable {
root = app.getDataRoot ();
- HashMap globals = new HashMap ();
- globals.put ("root", root);
- globals.put ("res", res);
- globals.put ("app", app.getAppNode());
-
- currentElement = root;
+ global.putHiddenProperty ("root", getNodeWrapper (root));
+ global.deleteProperty("user", "user".hashCode());
+ global.deleteProperty ("req", "req".hashCode());
+ global.putHiddenProperty ("res", ESLoader.normalizeValue(new ResponseTrans (), evaluator));
+ global.deleteProperty ("path", "path".hashCode());
+ global.putHiddenProperty ("app", appnode);
+ // convert arguments
+ int l = args.size ();
+ current = getNodeWrapper (root);
if (method.indexOf (".") > -1) {
StringTokenizer st = new StringTokenizer (method, ".");
int cnt = st.countTokens ();
for (int i=1; iError in application '"+app.getName()+"': Request timed out. ");
@@ -532,12 +562,11 @@ public class RequestEvaluator implements Runnable {
}
- public synchronized Object invokeXmlRpc (String method, Object[] args) throws Exception {
+ public synchronized Object invokeXmlRpc (String method, Vector args) throws Exception {
this.reqtype = XMLRPC;
this.user = null;
this.method = method;
this.args = args;
- this.res = new ResponseTrans ();
result = null;
exception = null;
@@ -552,19 +581,24 @@ public class RequestEvaluator implements Runnable {
return result;
}
- protected Object invokeDirectFunction (Object obj, String functionName, Object[] args) throws Exception {
- return app.scriptingEngine.invoke (obj, functionName, args, null, this);
- }
-
- public synchronized Object invokeFunction (Object object, String functionName, Object[] args)
+ public synchronized ESValue invokeFunction (INode node, String functionName, ESValue[] args)
throws Exception {
- reqtype = INTERNAL;
- user = null;
- thisObject = object;
- method = functionName;
- this.args =args;
- this.res = new ResponseTrans ();
- result = null;
+ ESObject obj = null;
+ if (node == null)
+ obj = global;
+ else
+ obj = getNodeWrapper (node);
+ return invokeFunction (obj, functionName, args);
+ }
+
+ public synchronized ESValue invokeFunction (ESObject obj, String functionName, ESValue[] args)
+ throws Exception {
+ this.reqtype = INTERNAL;
+ this.user = null;
+ this.current = obj;
+ this.method = functionName;
+ this.esargs = args;
+ esresult = ESNull.theNull;
exception = null;
checkThread ();
@@ -576,18 +610,17 @@ public class RequestEvaluator implements Runnable {
if (exception != null)
throw (exception);
- return result;
+ return esresult;
}
- public synchronized Object invokeFunction (User user, String functionName, Object[] args)
+ public synchronized ESValue invokeFunction (User user, String functionName, ESValue[] args)
throws Exception {
- reqtype = INTERNAL;
+ this.reqtype = INTERNAL;
this.user = user;
- thisObject = null;
- method = functionName;
- this.args = args;
- res = new ResponseTrans ();
- result = null;
+ this.current = null;
+ this.method = functionName;
+ this.esargs = args;
+ esresult = ESNull.theNull;
exception = null;
checkThread ();
@@ -599,7 +632,7 @@ public class RequestEvaluator implements Runnable {
if (exception != null)
throw (exception);
- return result;
+ return esresult;
}
@@ -608,9 +641,9 @@ public class RequestEvaluator implements Runnable {
* notify.
*/
public synchronized void stopThread () {
- app.logEvent ("Stopping Thread "+rtx);
+ IServer.getLogger().log ("Stopping Thread "+rtx);
Transactor t = rtx;
- // evaluator.thread = null;
+ evaluator.thread = null;
rtx = null;
if (t != null) {
if (reqtype != NONE) {
@@ -632,48 +665,276 @@ public class RequestEvaluator implements Runnable {
throw new ApplicationStoppedException ();
if (rtx == null || !rtx.isAlive()) {
- // app.logEvent ("Starting Thread");
+ // IServer.getLogger().log ("Starting Thread");
rtx = new Transactor (this, app.threadgroup, app.nmgr);
- // evaluator.thread = rtx;
+ evaluator.thread = rtx;
rtx.start ();
} else {
notifyAll ();
}
}
-
+ public Skin getSkin (ESObject thisObject, String skinname) {
+ INode n = null;
+ Prototype proto = null;
+ if (thisObject != null && thisObject instanceof ESNode) {
+ n = ((ESNode) thisObject).getNode ();
+ proto = app.getPrototype (n);
+ } else // the requested skin is global
+ proto = app.typemgr.getPrototype ("global");
+ Skin skin = null;
+ if (proto != null)
+ skin = proto.getSkin (skinname);
+ // if we have a thisObject and didn't find the skin, try in hopobject
+ if (skin == null && n != null) {
+ proto = app.typemgr.getPrototype ("hopobject");
+ if (proto != null)
+ skin = proto.getSkin (skinname);
+ }
+ return skin;
+ }
+
/**
- * Check if an action with a given name is defined for a scripted object. If it is,
- * return the action's function name. Otherwise, return null.
+ * Returns a node wrapper only if it already exists in the cache table. This is used
+ * in those places when wrappers have to be updated if they already exist.
*/
- public String getAction (Object obj, String action) {
- if (obj == null)
+ public ESNode getNodeWrapperFromCache (INode n) {
+ if (n == null)
return null;
- // check if this is a public skin, i.e. something with an extension
- // like "home.html"
- if (action != null && action.indexOf (".") > -1) {
- int dot = action.lastIndexOf (".");
- String extension = action.substring (dot+1);
- String contentType = app.skinExtensions.getProperty (extension);
- if (contentType != null) {
- res.contentType = contentType;
- return action;
- } else
- return null;
- } else {
- String act = action == null ? "main_action" : action+"_action";
- try {
- if (app.scriptingEngine.hasFunction (obj, act, this))
- return act;
- } catch (ScriptingException x) {
- return null;
- }
- }
- return null;
+ return (ESNode) objectcache.get (n);
}
+ public ESNode getNodeWrapper (INode n) {
+
+ if (n == null)
+ return null;
+
+ ESNode esn = (ESNode) objectcache.get (n);
+
+ if (esn == null || esn.getNode() != n) {
+ ObjectPrototype op = null;
+ String protoname = n.getPrototype ();
+
+ // set the DbMapping of the node according to its prototype.
+ // this *should* be done on the objectmodel level, but isn't currently
+ // for embedded nodes since there's not enough type info at the objectmodel level
+ // for those nodes.
+ if (protoname != null && protoname.length() > 0 && n.getDbMapping () == null) {
+ n.setDbMapping (app.getDbMapping (protoname));
+ }
+
+ try {
+ op = (ObjectPrototype) prototypes.get (protoname);
+ } catch (Exception ignore) {}
+
+ if (op == null)
+ op = esNodePrototype; // no prototype found for this node.
+
+ if ("user".equalsIgnoreCase (protoname))
+ esn = new ESUser (n, this);
+ else
+ esn = new ESNode (op, evaluator, n, this);
+
+ objectcache.put (n, esn);
+ // IServer.getLogger().log ("Wrapper for "+n+" created");
+ }
+
+ return esn;
+ }
+
+ public ObjectPrototype getPrototype (String protoName) {
+ return (ObjectPrototype) prototypes.get (protoName);
+ }
+
+ public void putPrototype (String protoName, ObjectPrototype op) {
+ prototypes.put (protoName, op);
+ }
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/framework/core/Skin.java b/src/helma/framework/core/Skin.java
index a61263b4..bda48aed 100644
--- a/src/helma/framework/core/Skin.java
+++ b/src/helma/framework/core/Skin.java
@@ -1,136 +1,69 @@
// Skin.java
// Copyright (c) Hannes Wallnöfer 2001
-
+
package helma.framework.core;
-import helma.framework.*;
-import helma.scripting.*;
-import helma.objectmodel.INode;
-import helma.objectmodel.ConcurrencyException;
-import helma.util.HtmlEncoder;
-import java.net.URLEncoder;
-import java.io.*;
import java.util.*;
+import java.io.*;
+import helma.framework.*;
+import FESI.Data.*;
+import FESI.Exceptions.*;
+import helma.objectmodel.INode;
+import helma.objectmodel.IServer;
+
/**
- * This represents a Helma skin, i.e. a template created from containing Macro tags
- * that will be dynamically evaluated.. It uses the request path array
- * from the RequestEvaluator object to resolve Macro handlers by type name.
+ * This represents a HOP skin, i.e. a template created from JavaScript. It uses the request path array
+ * from the RequestEvaluator object to resolve dynamic tokens.
*/
public class Skin {
- Macro[] parts;
- Application app;
- char[] source;
- int sourceLength;
- HashSet sandbox;
+ Object[] parts;
- /**
- * Create a skin without any restrictions on which macros are allowed to be called from it
- */
- public Skin (String content, Application app) {
- this (content, app, null);
+ public Skin (String content) {
+ parse (content);
}
- /**
- * Create a skin with a sandbox which contains the names of macros allowed to be called
- */
- public Skin (String content, Application app, HashSet sandbox) {
- this.app = app;
- this.sandbox = sandbox;
- source = content.toCharArray ();
- sourceLength = source.length;
- parse ();
- }
+ public void parse (String content) {
- /**
- * Create a skin without any restrictions on the macros from a char array.
- */
- public Skin (char[] content, int length, Application app) {
- this.app = app;
- this.sandbox = null;
- this.source = content;
- this.sourceLength = length;
- parse ();
- }
+ Vector partBuffer = new Vector ();
+ int l = content.length ();
+ char cnt[] = new char[l];
+ content.getChars (0, l, cnt, 0);
- /**
- * Parse a skin object from source text
- */
- private void parse () {
-
- ArrayList partBuffer = new ArrayList ();
-
- int start = 0;
- for (int i = 0; i < sourceLength-1; i++) {
- if (source[i] == '<' && source[i+1] == '%') {
- // found macro start tag
+ int lastIdx = 0;
+ for (int i = 0; i < l-1; i++) {
+ if (cnt[i] == '<' && cnt[i+1] == '%') {
int j = i+2;
- // search macr end tag
- while (j < sourceLength-1 && (source[j] != '%' || source[j+1] != '>')) {
+ while (j < l-1 && (cnt[j] != '%' || cnt[j+1] != '>')) {
j++;
}
if (j > i+2) {
- partBuffer.add (new Macro (i, j+2));
- start = j+2;
+ if (i - lastIdx > 0)
+ partBuffer.addElement (new String (cnt, lastIdx, i - lastIdx));
+ String macrotext = new String (cnt, i+2, (j-i)-2);
+ partBuffer.addElement (new Macro (macrotext));
+ lastIdx = j+2;
}
i = j+1;
}
}
+ if (lastIdx < l)
+ partBuffer.addElement (new String (cnt, lastIdx, l - lastIdx));
- parts = new Macro[partBuffer.size()];
- partBuffer.toArray (parts);
- }
-
- /**
- * Get the raw source text this skin was parsed from
- */
- public String getSource () {
- return new String (source, 0, sourceLength);
- }
-
- /**
- * Render this skin
- */
- public void render (RequestEvaluator reval, Object thisObject, HashMap paramObject) throws RedirectException {
+ parts = partBuffer.toArray ();
+ }
+ public void render (RequestEvaluator reval, ESNode thisNode, ESObject paramObject) {
if (parts == null)
- reval.res.writeCharArray (source, 0, sourceLength);
-
- int written = 0;
+ return;
for (int i=0; i written)
- reval.res.writeCharArray (source, written, parts[i].start-written);
- parts[i].render (reval, thisObject, paramObject);
- written = parts[i].end;
+ if (parts[i] instanceof Macro)
+ ((Macro) parts[i]).render (reval, thisNode, paramObject);
+ else
+ reval.res.write (parts[i]);
}
- if (written < sourceLength)
- reval.res.writeCharArray (source, written, sourceLength-written);
- }
-
- /**
- * Check if a certain macro is present in this skin. The macro name is in handler.name notation
- */
- public boolean containsMacro (String macroname) {
- for (int i=0; i=0; i--) {
- Object pathelem = reval.requestPath.get (i);
- if (handler.equalsIgnoreCase (app.getPrototypeName (pathelem))) {
- handlerObject = pathelem;
+ if (handler.equalsIgnoreCase (((ESNode) reval.reqPath.getProperty(i)).getPrototypeName())) {
+ handlerObject = (ESNode) reval.reqPath.getProperty(i);
break;
}
}
}
- // the macro handler object couldn't be found
- if (handlerObject == null)
- objectFound = false;
-
} else {
// this is a global macro with no handler specified
- handlerObject = null;
+ handlerObject = reval.global;
}
- if (objectFound) {
- // check if a function called name_macro is defined.
- // if so, the macro evaluates to the function. Otherwise,
- // a property/field with the name is used, if defined.
- Object v = null;
- if (app.scriptingEngine.hasFunction (handlerObject, name+"_macro", reval)) {
- // System.err.println ("Getting macro from function");
- v = app.scriptingEngine.invoke (handlerObject, name+"_macro", arguments, null, reval);
- } else {
- // System.err.println ("Getting macro from property");
- v = app.scriptingEngine.get (handlerObject, name, reval);
- }
- if (v != null)
- writeToResponse (v.toString (), reval.res);
+ if (handlerObject != null) {
+ ESValue v = handlerObject.doIndirectCall (reval.evaluator, handlerObject, name+"_macro", arguments);
+ if (v != ESUndefined.theUndefined && v != ESNull.theNull)
+ reval.res.write (v);
} else {
- String msg = "[HopMacro unhandled: "+getFullName()+"]";
+ String msg = "[HopMacro unhandled: "+handler+"."+name+"]";
reval.res.write (" "+msg+" ");
- app.logEvent (msg);
+ IServer.getLogger().log (msg);
}
- } catch (RedirectException redir) {
- throw redir;
- } catch (ConcurrencyException concur) {
- throw concur;
} catch (Exception x) {
- x.printStackTrace();
String msg = "[HopMacro error: "+x+"]";
reval.res.write (" "+msg+" ");
- app.logEvent (msg);
+ IServer.getLogger().log (msg);
}
}
private void renderFromResponse (RequestEvaluator reval) {
- Object value = null;
- // as a transitional solution, try to get the value from the
- // hardcoded fields in the response object. If not present, try
- // the response object's data object.
- if ("title".equals (name))
- value = reval.res.title;
- else if ("head".equals (name))
- value = reval.res.head;
- else if ("body".equals (name))
- value = reval.res.body;
- else if ("message".equals (name))
- value = reval.res.message;
- if (value == null)
- value = reval.res.get (name);
- if (value != null)
- writeToResponse (value.toString (), reval.res);
+ if ("title".equals (name) && reval.res.title != null)
+ reval.res.write (reval.res.title);
+ else if ("head".equals (name) && reval.res.head != null)
+ reval.res.write (reval.res.head);
+ else if ("body".equals (name) && reval.res.body != null)
+ reval.res.write (reval.res.body);
+ else if ("message".equals (name) && reval.res.message != null)
+ reval.res.write (reval.res.message);
}
private void renderFromRequest (RequestEvaluator reval) {
Object value = reval.req.get (name);
if (value != null)
- writeToResponse (value.toString (), reval.res);
+ reval.res.write (value);
}
- private void renderFromParam (RequestEvaluator reval, HashMap paramObject) {
+ private void renderFromParam (RequestEvaluator reval, ESObject paramObject) {
if (paramObject == null)
reval.res.write ("[HopMacro error: Skin requires a parameter object]");
else {
- Object value = paramObject.get (name);
- if (value != null)
- writeToResponse (value.toString (), reval.res);
+ try {
+ ESValue value = paramObject.getProperty (name, name.hashCode());
+ if (value != null && value != ESUndefined.theUndefined)
+ reval.res.write (value);
+ } catch (EcmaScriptException ignore) {}
}
}
- /**
- * Utility method for writing text out to the response object.
- */
- void writeToResponse (String text, ResponseTrans res) {
- if (text == null || text.length() == 0)
- return;
- String encoding = (String) parameters.get ("encoding");
- String prefix = (String) parameters.get ("prefix");
- String suffix = (String) parameters.get ("suffix");
- res.write (prefix);
- res.write (encode (text, encoding));
- res.write (suffix);
- }
-
- /**
- * Utility method for performing different kind of character
- * encodings on the macro output.
- */
- String encode (String text, String encoding) {
- if (encoding == null || text == null)
- return text;
- if ("html".equalsIgnoreCase (encoding))
- return HtmlEncoder.encode (text);
- if ("xml".equalsIgnoreCase (encoding))
- return HtmlEncoder.encodeXml (text);
- if ("form".equalsIgnoreCase (encoding))
- return HtmlEncoder.encodeFormValue (text);
- if ("url".equalsIgnoreCase (encoding))
- return URLEncoder.encode (text);
- return text;
- }
-
-
public String toString () {
- return "[HopMacro: "+getFullName()+"]";
+ return "[HopMacro: "+handler+","+name+"]";
}
-
- /**
- * Return the full name of the macro in handler.name notation
- */
- public String getFullName () {
- if (fullname == null) {
- if (handler == null)
- fullname = name;
- else
- fullname = handler+"."+name;
- }
- return fullname;
- }
-
}
+
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/framework/core/SkinFile.java b/src/helma/framework/core/SkinFile.java
index cd00bad4..2a3f8f8a 100644
--- a/src/helma/framework/core/SkinFile.java
+++ b/src/helma/framework/core/SkinFile.java
@@ -5,7 +5,7 @@ package helma.framework.core;
import java.util.*;
import java.io.*;
-import helma.util.Updatable;
+import helma.objectmodel.IServer;
/**
@@ -13,7 +13,7 @@ import helma.util.Updatable;
*/
-public class SkinFile implements Updatable {
+public class SkinFile {
String name;
Prototype prototype;
@@ -30,65 +30,28 @@ public class SkinFile implements Updatable {
this.skin = null;
}
- /**
- * Create a skinfile without a file, passing the skin body directly. This is used for
- * Skins contained in zipped applications. The whole update mechanism is bypassed
- * by immediately setting the skin member.
- */
- public SkinFile (String body, String name, Prototype proto) {
- this.prototype = proto;
- this.app = proto.app;
- this.name = name;
- this.file = null;
- this.skin = new Skin (body, app);
- }
- /**
- * Create a skinfile without that doesn't belong to a prototype, or at
- * least it doesn't know about its prototype and isn't managed by the prototype.
- */
- public SkinFile (File file, String name, Application app) {
- this.prototype = null;
- this.app = app;
- this.name = name;
- this.file = file;
- this.skin = null;
- }
+ public void update (File f) {
+ this.file = f;
- /**
- * 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 (skin != null && lastmod != file.lastModified ()) || !file.exists ();
- }
+ long fmod = file.lastModified ();
+ // we only update this if we already have read the skin
+ if (skin == null || lastmod == fmod)
+ return;
-
- public void update () {
-
- if (!file.exists ()) {
- // remove skin from prototype
- if (prototype != null) {
- prototype.skins.remove (name);
- prototype.updatables.remove (file.getName());
- }
- } else {
- // we only need to update if the skin has already been initialized
- if (skin != null)
- read ();
- }
+ read ();
}
private void read () {
try {
FileReader reader = new FileReader (file);
char c[] = new char[(int) file.length()];
- int length = reader.read (c);
+ reader.read (c);
reader.close();
- skin = new Skin (c, length, app);
+ skin = new Skin (new String (c));
} catch (IOException x) {
- app.logEvent ("Error reading Skin "+file+": "+x);
+ IServer.getLogger().log ("Error reading Skin "+file+": "+x);
}
lastmod = file.lastModified ();
@@ -99,15 +62,45 @@ public class SkinFile implements Updatable {
read ();
return skin;
}
-
- public String getName () {
- return name;
- }
- public String toString () {
- return prototype.getName()+"/"+file.getName();
- }
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/framework/core/SkinManager.java b/src/helma/framework/core/SkinManager.java
deleted file mode 100644
index 45d7d4a2..00000000
--- a/src/helma/framework/core/SkinManager.java
+++ /dev/null
@@ -1,141 +0,0 @@
-// SkinManager.java
-// Copyright (c) Hannes Wallnöfer 2002
-
-package helma.framework.core;
-
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.Iterator;
-import helma.objectmodel.INode;
-import java.io.*;
-
-
-/**
- * Manages skins for a Helma application
- */
-
-
-public class SkinManager {
-
- Application app;
- Map skincache;
-
- public SkinManager (Application app) {
- this.app = app;
- skincache = new WeakHashMap ();
- }
-
- public Skin getSkin (Object object, String skinname, Object[] skinpath) {
- Prototype proto = app.getPrototype (object);
- String key = new StringBuffer(proto.getName()).append ("/").append (skinname)
- .append ("#").append (skinpath.hashCode()).toString ();
- // System.err.print ("SKINKEY: "+key);
- Skin skin = (Skin) skincache.get (key);
- if (skin != null) {
- // System.err.println (" ... cached");
- return skin;
- }
- // System.err.println (" ... uncached");
- skin = getSkin (proto, skinname, "skin", skinpath);
- if (skin != null)
- skincache.put (key, skin);
- return skin;
- }
-
-
- protected Skin getSkin (Prototype proto, String skinname, String extension, Object[] skinpath) {
- if (proto == null)
- return null;
- Skin skin = null;
- // First check if the skin has been already used within the execution of this request
- // check for skinsets set via res.skinpath property
- do {
- if (skinpath != null) {
- for (int i=0; i -1) {
@@ -115,7 +105,7 @@ public class Template extends ActionFile {
templateBody.append ((char) c);
c = lineReader.read ();
}
- } catch (IOException srx) {}
+ }
nextLine = st.hasMoreTokens () ? st.nextToken () : null;
@@ -130,7 +120,7 @@ public class Template extends ActionFile {
// 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 0) {
- try {
- FunctionFile ff = new FunctionFile (tmpfile, tmpname, proto);
- updatables.put (list[i], ff);
- nfunc.put (tmpname, ff);
- } catch (Throwable x) {
- app.logEvent ("Error creating prototype: "+x);
- }
-
- } else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) {
- try {
- ActionFile af = new ActionFile (tmpfile, tmpname, proto);
- updatables.put (list[i], af);
- nact.put (tmpname, af);
- } catch (Throwable x) {
- app.logEvent ("Error creating prototype: "+x);
- }
- } else if (list[i].endsWith (app.skinExtension)) {
- try {
- SkinFile sf = new SkinFile (tmpfile, tmpname, proto);
- updatables.put (list[i], sf);
- nskins.put (tmpname, sf);
- } catch (Throwable x) {
- app.logEvent ("Error creating prototype: "+x);
- }
- }
- }
- }
-
- // Create and register type properties file
- File propfile = new File (dir, "type.properties");
- SystemProperties props = new SystemProperties (propfile.getAbsolutePath ());
- DbMapping dbmap = new DbMapping (app, name, props);
- updatables.put ("type.properties", dbmap);
-
-
- proto.templates = ntemp;
- proto.functions = nfunc;
- proto.actions = nact;
- proto.skins = nskins;
- proto.updatables = updatables;
-
- // init prototype on evaluators that are already initialized.
- /* Iterator evals = getRegisteredRequestEvaluators ();
- while (evals.hasNext ()) {
- RequestEvaluator reval = (RequestEvaluator) evals.next ();
- proto.initRequestEvaluator (reval);
- }*/
- app.scriptingEngine.updatePrototype (proto);
-
- }
-
-
- /**
- * Update a prototype based on the directory which defines it.
- */
- public void updatePrototype (String name, File dir, Prototype proto) {
-
- boolean needsUpdate = false;
- HashSet updatables = null;
-
- // our plan is to do as little as possible, so first check if anything has changed at all...
- for (Iterator i = proto.updatables.values().iterator(); i.hasNext(); ) {
- Updatable upd = (Updatable) i.next();
- if (upd.needsUpdate ()) {
- if (updatables == null)
- updatables = new HashSet ();
- needsUpdate = true;
- updatables.add (upd);
- }
- }
-
- // check if file have been created since last update
- if (proto.lastUpdate < dir.lastModified ()) {
- String[] list = dir.list();
- for (int i=0; i 0) {
try {
FunctionFile ff = new FunctionFile (tmpfile, tmpname, proto);
- proto.updatables.put (list[i], ff);
- proto.functions.put (tmpname, ff);
+ nfunc.put (tmpname, ff);
} catch (Throwable x) {
- app.logEvent ("Error updating prototype: "+x);
+ IServer.getLogger().log ("Error creating prototype: "+x);
}
- } else if (list[i].endsWith (app.actionExtension)) {
+ } else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) {
try {
- ActionFile af = new ActionFile (tmpfile, tmpname, proto);
- proto.updatables.put (list[i], af);
- proto.actions.put (tmpname, af);
+ Action af = new Action (tmpfile, tmpname, proto);
+ nact.put (tmpname, af);
} catch (Throwable x) {
- app.logEvent ("Error updating prototype: "+x);
+ IServer.getLogger().log ("Error creating prototype: "+x);
}
+ } else if (list[i].endsWith (app.skinExtension)) {
+ try {
+ SkinFile sf = new SkinFile (tmpfile, tmpname, proto);
+ nskins.put (tmpname, sf);
+ } catch (Throwable x) {
+ IServer.getLogger().log ("Error creating prototype: "+x);
+ }
+ }
+ }
+ proto.templates = ntemp;
+ proto.functions = nfunc;
+ proto.actions = nact;
+ proto.skins = nskins;
- } else if (list[i].endsWith (app.skinExtension)) {
- SkinFile sf = new SkinFile (tmpfile, tmpname, proto);
- proto.updatables.put (list[i], sf);
- proto.skins.put (tmpname, sf);
- }
+ // init prototype on evaluators that are already initialized.
+ Iterator evals = getRegisteredRequestEvaluators ();
+ while (evals.hasNext ()) {
+ RequestEvaluator reval = (RequestEvaluator) evals.next ();
+ proto.initRequestEvaluator (reval);
}
- // next go through existing updatables
- if (updatables != null) {
- for (Iterator i = updatables.iterator(); i.hasNext(); ) {
- Updatable upd = (Updatable) i.next();
-
- if (upd.needsUpdate ()) {
- if (upd instanceof DbMapping)
- rewire = true;
- try {
- upd.update ();
- } catch (Exception x) {
- if (upd instanceof DbMapping)
- app.logEvent ("Error updating db mapping for type "+name+": "+x);
- else
- app.logEvent ("Error updating "+upd+" of prototye type "+name+": "+x);
- }
- }
- }
- }
- app.scriptingEngine.updatePrototype (proto);
}
- /*public void initRequestEvaluator (RequestEvaluator reval) {
+ public void updatePrototype (String name, File dir, Prototype proto) {
+ // IServer.getLogger().log ("updating prototype "+name);
+
+ String list[] = dir.list();
+ Hashtable ntemp = new Hashtable ();
+ Hashtable nfunc = new Hashtable ();
+ Hashtable nact = new Hashtable ();
+ Hashtable nskins = new Hashtable ();
+
+ for (int i=0; i 0) {
+ FunctionFile ff = proto.getFunctionFile (tmpname);
+ try {
+ if (ff == null) {
+ ff = new FunctionFile (tmpfile, tmpname, proto);
+ idleSeconds = 0;
+ } else if (ff.lastmod != tmpfile.lastModified ()) {
+ ff.update (tmpfile);
+ idleSeconds = 0;
+ }
+ } catch (Throwable x) {
+ IServer.getLogger().log ("Error updating prototype: "+x);
+ }
+ nfunc.put (tmpname, ff);
+
+ } else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) {
+ Action af = proto.getAction (tmpname);
+ try {
+ if (af == null) {
+ af = new Action (tmpfile, tmpname, proto);
+ idleSeconds = 0;
+ } else if (af.lastmod != tmpfile.lastModified ()) {
+ af.update (tmpfile);
+ idleSeconds = 0;
+ }
+ } catch (Throwable x) {
+ IServer.getLogger().log ("Error updating prototype: "+x);
+ }
+ nact.put (tmpname, af);
+
+ } else if (list[i].endsWith (app.skinExtension)) {
+ SkinFile sf = proto.getSkinFile (tmpname);
+ try {
+ if (sf == null) {
+ sf = new SkinFile (tmpfile, tmpname, proto);
+ idleSeconds = 0;
+ } else if (sf.lastmod != tmpfile.lastModified ()) {
+ sf.update (tmpfile);
+ idleSeconds = 0;
+ }
+ } catch (Throwable x) {
+ IServer.getLogger().log ("Error updating prototype: "+x);
+ }
+ nskins.put (tmpname, sf);
+
+ } else if ("type.properties".equalsIgnoreCase (list[i])) {
+ try {
+ if (proto.dbmap.read ()) {
+ idleSeconds = 0;
+ rewire = true;
+ }
+ } catch (Exception ignore) {
+ IServer.getLogger().log ("Error updating db mapping for type "+name+": "+ignore);
+ }
+ }
+ }
+ proto.templates = ntemp;
+ proto.functions = nfunc;
+ proto.actions = nact;
+ proto.skins = nskins;
+ }
+
+
+
+ public void initRequestEvaluator (RequestEvaluator reval) {
if (!registeredEvaluators.contains (reval))
registeredEvaluators.add (reval);
- for (Iterator it = prototypes.values().iterator(); it.hasNext(); ) {
- Prototype p = (Prototype) it.next ();
+ for (Enumeration en = prototypes.elements(); en.hasMoreElements(); ) {
+ Prototype p = (Prototype) en.nextElement ();
p.initRequestEvaluator (reval);
}
reval.initialized = true;
@@ -405,7 +331,103 @@ public class TypeManager {
public int countRegisteredRequestEvaluators () {
return registeredEvaluators.size ();
- } */
+ }
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/framework/core/User.java b/src/helma/framework/core/User.java
index 7ce3e1e9..839c372f 100644
--- a/src/helma/framework/core/User.java
+++ b/src/helma/framework/core/User.java
@@ -7,46 +7,29 @@ import java.io.*;
import java.util.*;
import java.net.URLEncoder;
import helma.objectmodel.*;
-import helma.objectmodel.db.*;
/**
- * This represents a user who is currently using the Hop application. This does
- * not just comprend registered users, but anybody who happens to surf the site.
- * Depending on whether the user is logged in or not, the user object holds a
- * persistent user node or just a transient cache node
+ * This represents a user who is currently using the HOP application. This does
+ * not just comprend registered users, but anybody who happens to surf the site.
*/
public class User implements Serializable {
Application app;
String sessionID;
-
- // the unique id (login name) for the user, if logged in
- String uid;
-
- // the handle to this user's persistent db node, if logged in
- NodeHandle nhandle;
-
- // the transient cache node. This stays the same across logins and logouts.
- // If logged out, this also represents the user's main node.
- TransientNode cache;
-
- DbMapping umap;
+ String uid, nid;
long onSince, lastTouched;
-
- // used to remember messages to the user between requests -
- // used for redirects.
+ Node cache;
+ DbMapping umap;
String message;
public User (String sid, Application app) {
this.uid = null;
- this.nhandle = null;
- this.app = app;
- setNode (null);
- umap = app.getDbMapping ("user");
- cache = new TransientNode ("[session cache]");
- cache.setPrototype ("user");
- cache.setDbMapping (umap);
+ this.nid = null;
+ this.app = app;
+ setNode (null);
+ cache = new Node (sid);
+ cache.setPrototype ("user");
sessionID = sid;
onSince = System.currentTimeMillis ();
lastTouched = onSince;
@@ -54,38 +37,26 @@ public class User implements Serializable {
/**
- * This is used to turn for login and logout.
- * Calling this weith a DB Node object will turn an anonymous user into a registered or known one.
- * The user object remains the same, but he or she gets some persistent storage.
- * On the other side, calling this method with a parameter value of null is means the user
- * is logged out and will be represented by its transient cache node.
+ * This is used to turn an anonymous user into a registered or known one.
+ * The user object remains the same, but she gets some persistent storage.
*/
public void setNode (INode n) {
// IServer.getLogger().log ("esn = "+esn);
if (n == null) {
- nhandle = null;
+ nid = null;
uid = null;
} else {
- uid = n.getElementName ();
- nhandle = ((Node) n).getHandle ();
+ uid = n.getNameOrID ();
+ nid = n.getID ();
+ umap = n.getDbMapping ();
}
- // System.err.println ("User.setNode: "+nhandle);
}
public INode getNode () {
- if (nhandle == null) {
+ if (uid == null) {
return cache;
} else {
- // in some special cases, a user's node handle may go bad, for instance
- // if something bad happens during registration. For this reason, we check
- // if the handle actually works. If not, it is reset to the transient cache, which
- // means the user is logged out.
- Node n = nhandle.getNode (app.nmgr.safe);
- if (n == null) {
- setNode (null);
- return cache;
- }
- return n;
+ return app.nmgr.safe.getNode (nid, umap);
}
}
@@ -98,37 +69,39 @@ public class User implements Serializable {
lastTouched = System.currentTimeMillis ();
}
- public long lastTouched () {
+ public long touched () {
return lastTouched;
}
-
- public long onSince () {
- return onSince;
- }
-
- /**
- * Get the persistent user id of a registered user. This is usually the user name, or
- * null if the user is not logged in.
- */
- public String getUID () {
- return uid;
- }
-
- /**
- * Return the transient cache node for this user.
- */
- public INode getCache () {
- return cache;
- }
-
- /**
- * Reset the session cache node, clearing all properties.
- * This is done by recreating the cache node object.
- */
- public void clearCache () {
- cache = new TransientNode ("[session cache]");
- cache.setPrototype ("user");
- cache.setDbMapping (umap);
- }
+
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/framework/core/ZippedAppFile.java b/src/helma/framework/core/ZippedAppFile.java
deleted file mode 100644
index f3032629..00000000
--- a/src/helma/framework/core/ZippedAppFile.java
+++ /dev/null
@@ -1,186 +0,0 @@
-// ZippedFile.java
-// Copyright (c) Hannes Wallnöfer 2001
-
-package helma.framework.core;
-
-import java.util.*;
-import java.util.zip.*;
-import java.io.*;
-import helma.framework.*;
-import helma.scripting.*;
-import helma.util.Updatable;
-import helma.util.SystemProperties;
-import helma.objectmodel.db.DbMapping;
-
-/**
- * This represents a Zip-File which may contain other Updatables for one or more prototypes.
- */
-
-
-public class ZippedAppFile implements Updatable {
-
- Application app;
- File file;
- long lastmod;
-
-
- public ZippedAppFile (File file, Application app) {
- this.app = app;
- this.file = file;
- // System.err.println ("CREATING ZIP FILE "+this);
- }
-
-
- /**
- * 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 {
-
- ZipFile zip = null;
- // collect created protos - we need this to check DbMappings for each created
- // prototype afterwards
- HashSet newPrototypes = new HashSet ();
- try {
- lastmod = file.lastModified ();
- // System.err.println ("UPDATING ZIP FILE "+this);
- zip = new ZipFile (file);
- for (Enumeration en = zip.entries (); en.hasMoreElements (); ) {
- ZipEntry entry = (ZipEntry) en.nextElement ();
- String ename = entry.getName ();
- StringTokenizer st = new StringTokenizer (ename, "/");
- if (st.countTokens () == 2) {
- String dir = st.nextToken ();
- String fname = st.nextToken ();
- // System.err.println ("ZIPENTRY: "+ dir +" ~ "+fname);
- Prototype proto = app.typemgr.getPrototype (dir);
- if (proto == null) {
- proto = app.typemgr.createPrototype (dir);
- newPrototypes.add (proto);
- }
- if (fname.endsWith (".hac")) {
- String name = fname.substring (0, fname.lastIndexOf ("."));
- String content = getZipEntryContent (zip, entry);
- // System.err.println ("["+content+"]");
- ActionFile act = new ActionFile (content, name, proto);
- proto.actions.put (name, act);
- }
- else if (fname.endsWith (".hsp")) {
- String name = fname.substring (0, fname.lastIndexOf ("."));
- String content = getZipEntryContent (zip, entry);
- // System.err.println ("["+content+"]");
- Template tmp = new Template (content, name, proto);
- proto.templates.put (name, tmp);
- }
- else if (fname.endsWith (".skin")) {
- String name = fname.substring (0, fname.lastIndexOf ("."));
- String content = getZipEntryContent (zip, entry);
- // System.err.println ("["+content+"]");
- SkinFile skin = new SkinFile (content, name, proto);
- proto.skins.put (name, skin);
- }
- else if (fname.endsWith (".js")) {
- String name = fname.substring (0, fname.lastIndexOf ("."));
- String content = getZipEntryContent (zip, entry);
- // System.err.println ("["+content+"]");
- FunctionFile ff = new FunctionFile (content, name, proto);
- proto.functions.put (name, ff);
- }
- else if ("type.properties".equalsIgnoreCase (fname)) {
- String name = fname.substring (0, fname.lastIndexOf ("."));
- SystemProperties props = new SystemProperties (zip.getInputStream (entry));
- // DbMapping does its own registering, just construct it.
- new DbMapping (app, proto.getName (), props);
- }
- }
- }
- for (Iterator it = newPrototypes.iterator (); it.hasNext (); ) {
- Prototype proto = (Prototype) it.next ();
- if (app.getDbMapping (proto.getName ()) == null) {
- // DbMapping doesn't exist, we still need to create one
- SystemProperties props = new SystemProperties ();
- // DbMapping does its own registering, just construct it.
- new DbMapping (app, proto.getName (), props);
- }
- }
- } catch (Throwable x) {
- System.err.println ("Error updating ZipFile: "+x);
- } finally {
- try {
- zip.close ();
- } catch (Exception ignore) {}
- }
- }
-
- }
-
- void remove () {
- app.typemgr.zipfiles.remove (file.getName());
- // System.err.println ("REMOVING ZIP FILE "+this);
- }
-
-
- public String getZipEntryContent (ZipFile zip, ZipEntry entry) throws IOException {
- int size = (int) entry.getSize ();
- char[] c = new char[size];
- InputStreamReader reader = new InputStreamReader (zip.getInputStream (entry));
- reader.read (c);
- return new String (c);
- }
-
-
- public String toString () {
- return file.getName();
- }
-
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/helma/framework/demo/SimplePathElement.java b/src/helma/framework/demo/SimplePathElement.java
deleted file mode 100644
index b18b8286..00000000
--- a/src/helma/framework/demo/SimplePathElement.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// SimplePathElement.java
-// Copyright Hannes Wallnöfer 2001
-
-package helma.framework.demo;
-
-import helma.framework.IPathElement;
-
-/**
- * This is an example implementation for the helma.framework.IPathElement interface.
- * It creates any child element which is requested on the fly without ever asking.
- */
-
-public class SimplePathElement implements IPathElement {
-
- String name;
- String prototype;
- IPathElement parent;
-
- /**
- * Constructor for the root element.
- */
- public SimplePathElement () {
- name = "root";
- prototype = "root";
- parent = null;
- }
-
- /**
- * Constructor for non-root elements.
- */
- public SimplePathElement (String n, IPathElement p) {
- name = n;
- prototype = "hopobject";
- parent = p;
- }
-
- /**
- * Returns a child element for this object, creating it on the fly.
- */
- public IPathElement getChildElement (String n) {
- return new SimplePathElement (n, this);
- }
-
- /**
- * Returns this object's parent element
- */
- public IPathElement getParentElement () {
- return parent;
- }
-
- /**
- * Returns the element name to be used for this object.
- */
- public String getElementName () {
- return name;
- }
-
- /**
- * Returns the name of the scripting prototype to be used for this object.
- * This will be "root" for the root element and "hopobject for everything else.
- */
- public String getPrototype () {
- return prototype;
- }
-
- /**
- * Returns a string representation of this element.
- */
- public String toString () {
- return "SimplePathElement "+name;
- }
-
-}
-
diff --git a/src/helma/scripting/fesi/extensions/Database.java b/src/helma/framework/extensions/Database.java
similarity index 98%
rename from src/helma/scripting/fesi/extensions/Database.java
rename to src/helma/framework/extensions/Database.java
index b30f2077..845a5046 100644
--- a/src/helma/scripting/fesi/extensions/Database.java
+++ b/src/helma/framework/extensions/Database.java
@@ -16,12 +16,11 @@
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-// Modified to use Helma database connections, Hannes Wallnöfer 2000
+// Modified to use HOP database connections, Hannes Wallnöfer 2000
-package helma.scripting.fesi.extensions;
+package helma.framework.extensions;
-import helma.framework.core.Application;
-import helma.objectmodel.db.DbSource;
+import helma.objectmodel.*;
import FESI.Parser.*;
import FESI.AST.*;
import FESI.Interpreter.*;
@@ -60,12 +59,13 @@ class ESDatabase extends ESObject {
ESDatabase(ESObject prototype,
Evaluator evaluator,
ESObject esRowSetPrototype,
- DbSource dbsource, int flag) {
+ String dbsource, int flag) {
super(prototype, evaluator);
this.esRowSetPrototype = esRowSetPrototype; // specific to an evaluator
try {
- connection = dbsource.getConnection ();
- driverName = dbsource.getDriverName ();
+ DbSource src = (DbSource) IServer.dbSources.get (dbsource.toLowerCase ());
+ connection = src.getConnection ();
+ this.driverName = src.getDriverName ();
} catch (Exception e) {
// System.err.println("##Cannot find driver class: " + e);
// e.printStackTrace();
@@ -717,17 +717,11 @@ 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) {
@@ -737,17 +731,13 @@ public class Database extends Extension {
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);
+ esRowSetPrototype, arguments[0].toString(), 0);
return db;
}
}
-
+
class GlobalObjectDatabase extends BuiltinFunctionObject {
GlobalObjectDatabase(String name, Evaluator evaluator, FunctionPrototype fp) {
super(fp, evaluator, name, 1);
diff --git a/src/helma/scripting/fesi/extensions/ESMail.java b/src/helma/framework/extensions/ESMail.java
similarity index 80%
rename from src/helma/scripting/fesi/extensions/ESMail.java
rename to src/helma/framework/extensions/ESMail.java
index 5bd5883a..3db40051 100644
--- a/src/helma/scripting/fesi/extensions/ESMail.java
+++ b/src/helma/framework/extensions/ESMail.java
@@ -2,7 +2,7 @@
// Copyright (c) Hannes Wallnöfer 1998-2000
-package helma.scripting.fesi.extensions;
+package helma.framework.extensions;
import javax.mail.*;
import javax.mail.internet.*;
@@ -10,18 +10,19 @@ import javax.activation.*;
import java.io.*;
import java.util.*;
import helma.framework.core.*;
-import helma.util.*;
+import helma.objectmodel.*;
import FESI.Data.*;
import FESI.Interpreter.*;
import FESI.Exceptions.*;
/**
* A JavaScript wrapper around a JavaMail message class to send
- * mail via SMTP from Helma
+ * mail via SMTP from HOP
*/
public class ESMail extends ESObject implements Serializable {
+ INode node;
MailExtension mailx;
Properties mprops;
MimeMessage message;
@@ -56,7 +57,7 @@ public class ESMail extends ESObject implements Serializable {
Session session = Session.getDefaultInstance(props, null);
message = new MimeMessage (session);
} catch (Throwable t) {
- this.evaluator.reval.app.logEvent ("Error in mail constructor: "+t);
+ IServer.getLogger().log ("caught in mail constructor: "+t);
}
}
@@ -93,16 +94,20 @@ public class ESMail extends ESObject implements Serializable {
multipart = new MimeMultipart ();
}
for (int i=0; i 0) {
- websrv = new Acme.Serve.Serve (webport, sysProps);
- }
-
- String xmlparser = sysProps.getProperty ("xmlparser");
- if (xmlparser != null)
- XmlRpc.setDriver (xmlparser);
- // XmlRpc.setDebug (true);
- xmlrpc = new WebServer (port+1);
- if (paranoid) {
- xmlrpc.setParanoid (true);
- String xallow = sysProps.getProperty ("allowXmlRpc");
- if (xallow != null) {
- StringTokenizer st = new StringTokenizer (xallow, " ,;");
- while (st.hasMoreTokens ())
- xmlrpc.acceptClient (st.nextToken ());
- }
- }
- getLogger().log ("Starting XML-RPC server on port "+(port+1));
-
- // the following seems not to be necessary after all ...
- // System.setSecurityManager(new RMISecurityManager());
- if (paranoid) {
- HopSocketFactory factory = new HopSocketFactory ();
- String rallow = sysProps.getProperty ("allowWeb");
- if (rallow != null) {
- StringTokenizer st = new StringTokenizer (rallow, " ,;");
- while (st.hasMoreTokens ())
- factory.addAddress (st.nextToken ());
- }
- RMISocketFactory.setSocketFactory (factory);
- }
-
- if (websrv == null) {
- getLogger().log ("Starting server on port "+port);
- LocateRegistry.createRegistry (port);
- }
-
-
- // start application framework
- appsProps = new SystemProperties (appsPropfile);
- appManager = new ApplicationManager (port, hopHome, appsProps, this);
-
-
- } catch (Exception gx) {
- getLogger().log ("Error initializing embedded database: "+gx);
- gx.printStackTrace ();
- return;
- }
-
- // start applications
- appManager.startAll ();
-
- // start embedded web server
- if (websrv != null) {
- Thread webthread = new Thread (websrv, "WebServer");
- webthread.start ();
- }
-
- int count = 0;
- while (Thread.currentThread () == mainThread) {
- try {
- mainThread.sleep (3000l);
- } catch (InterruptedException ie) {}
- try {
- appManager.checkForChanges ();
- } catch (Exception x) {
- getLogger().log ("Caught in app manager loop: "+x);
- }
- }
-
- }
-
- /**
- * Get an Iterator over the applications currently running on this Server.
- */
- public Object[] getApplications () {
- return appManager.getApplications ();
- }
-
- /**
- * Get an Application by name
- */
- public Application getApplication(String name) {
- return appManager.getApplication(name);
- }
-
- /**
- * Get a logger to use for output in this server.
- */
- protected static Logger getLogger () {
- if (logger == null) {
- String logDir = sysProps.getProperty ("logdir");
- if (logDir == null || "console".equalsIgnoreCase (logDir)) {
- logger = new Logger (System.out);
- } else {
- File helper = new File (logDir);
- if (hopHome != null && !helper.isAbsolute ())
- helper = new File (hopHome, logDir);
- logDir = helper.getAbsolutePath ();
- logger = Logger.getLogger (logDir, "hop");
- }
- }
- return logger;
- }
-
- /**
- * Get the Home directory of this server.
- */
- public static File getHopHome () {
- return hopHome;
- }
-
- /**
- * Get the main Server
- */
- public static Server getServer() {
- return server;
- }
-
- /**
- * Get the Server's XML-RPC web server.
- */
- public static WebServer getXmlRpcServer() {
- return xmlrpc;
- }
-
- /**
- * A primitive method to check whether a server is already running on our port.
- */
- private void checkRunning () throws Exception {
- try {
- java.net.Socket socket = new java.net.Socket ("localhost", port);
- } catch (Exception x) {
- return;
- }
- // if we got so far, another server is already running on this port and db
- throw new Exception ("Error: Server already running on this port");
- }
-
- public static String getProperty( String key ) {
- return (String)sysProps.get(key);
- }
-
- public static SystemProperties getProperties() {
- return sysProps;
- }
-
- public static File getAppsHome() {
- String appHome = sysProps.getProperty ("appHome");
- if (appHome != null && !"".equals (appHome.trim()))
- return new File (appHome);
- else
- return new File (hopHome, "apps");
- }
-
- public void startApplication(String name) {
- appManager.start (name);
- appManager.register (name);
- }
-
- public void stopApplication(String name) {
- appManager.stop (name);
- }
-
- /**
- * method from helma.framework.IPathElement
- */
- public String getElementName() {
- return "root";
- }
-
- /**
- * method from helma.framework.IPathElement,
- * returning active applications
- */
- public IPathElement getChildElement(String name) {
- return appManager.getApplication(name);
- }
-
- /**
- * method from helma.framework.IPathElement
- */
- public IPathElement getParentElement() {
- return null;
- }
-
- /**
- * method from helma.framework.IPathElement
- */
- public String getPrototype() {
- return "root";
- }
-}
diff --git a/src/helma/util/mime/LanguageTag.java b/src/helma/mime/LanguageTag.java
similarity index 99%
rename from src/helma/util/mime/LanguageTag.java
rename to src/helma/mime/LanguageTag.java
index a1f42b13..ea7b86e2 100644
--- a/src/helma/util/mime/LanguageTag.java
+++ b/src/helma/mime/LanguageTag.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT, INRIA and Keio, 1999
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
import java.util.*;
import java.io.*;
diff --git a/src/helma/util/mime/MimeHeaderHolder.java b/src/helma/mime/MimeHeaderHolder.java
similarity index 98%
rename from src/helma/util/mime/MimeHeaderHolder.java
rename to src/helma/mime/MimeHeaderHolder.java
index 886563dd..81c92f6d 100644
--- a/src/helma/util/mime/MimeHeaderHolder.java
+++ b/src/helma/mime/MimeHeaderHolder.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
import java.io.*;
diff --git a/src/helma/util/mime/MimeHeaders.java b/src/helma/mime/MimeHeaders.java
similarity index 99%
rename from src/helma/util/mime/MimeHeaders.java
rename to src/helma/mime/MimeHeaders.java
index ff682b2e..67438c7a 100644
--- a/src/helma/util/mime/MimeHeaders.java
+++ b/src/helma/mime/MimeHeaders.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
import java.io.*;
import java.util.*;
diff --git a/src/helma/util/mime/MimeHeadersFactory.java b/src/helma/mime/MimeHeadersFactory.java
similarity index 96%
rename from src/helma/util/mime/MimeHeadersFactory.java
rename to src/helma/mime/MimeHeadersFactory.java
index a91ab8cd..4d161842 100644
--- a/src/helma/util/mime/MimeHeadersFactory.java
+++ b/src/helma/mime/MimeHeadersFactory.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
/**
* A Mime header factory, that will build instances of the MimeHeaders class
diff --git a/src/helma/util/mime/MimeParser.java b/src/helma/mime/MimeParser.java
similarity index 99%
rename from src/helma/util/mime/MimeParser.java
rename to src/helma/mime/MimeParser.java
index e40b426c..9166b5f0 100644
--- a/src/helma/util/mime/MimeParser.java
+++ b/src/helma/mime/MimeParser.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
import java.util.*;
import java.io.* ;
diff --git a/src/helma/util/mime/MimeParserException.java b/src/helma/mime/MimeParserException.java
similarity index 91%
rename from src/helma/util/mime/MimeParserException.java
rename to src/helma/mime/MimeParserException.java
index f4b05a98..778f849e 100644
--- a/src/helma/util/mime/MimeParserException.java
+++ b/src/helma/mime/MimeParserException.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
public class MimeParserException extends Exception {
diff --git a/src/helma/util/mime/MimeParserFactory.java b/src/helma/mime/MimeParserFactory.java
similarity index 96%
rename from src/helma/util/mime/MimeParserFactory.java
rename to src/helma/mime/MimeParserFactory.java
index 41e94044..1ef3e6fa 100644
--- a/src/helma/util/mime/MimeParserFactory.java
+++ b/src/helma/mime/MimeParserFactory.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
/**
* This class is used by the MimeParser, to create new MIME message holders.
diff --git a/src/helma/util/mime/MimeType.java b/src/helma/mime/MimeType.java
similarity index 99%
rename from src/helma/util/mime/MimeType.java
rename to src/helma/mime/MimeType.java
index 7cc85fa7..1c2ee5e0 100644
--- a/src/helma/util/mime/MimeType.java
+++ b/src/helma/mime/MimeType.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
import java.util.*;
import java.io.*;
diff --git a/src/helma/util/mime/MimeTypeFormatException.java b/src/helma/mime/MimeTypeFormatException.java
similarity index 91%
rename from src/helma/util/mime/MimeTypeFormatException.java
rename to src/helma/mime/MimeTypeFormatException.java
index 227a4bbe..e8788ac8 100644
--- a/src/helma/util/mime/MimeTypeFormatException.java
+++ b/src/helma/mime/MimeTypeFormatException.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
public class MimeTypeFormatException extends Exception {
diff --git a/src/helma/util/mime/MultipartInputStream.java b/src/helma/mime/MultipartInputStream.java
similarity index 99%
rename from src/helma/util/mime/MultipartInputStream.java
rename to src/helma/mime/MultipartInputStream.java
index 5bb0b3ce..830156cf 100644
--- a/src/helma/util/mime/MultipartInputStream.java
+++ b/src/helma/mime/MultipartInputStream.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
import java.io.* ;
diff --git a/src/helma/util/mime/Utils.java b/src/helma/mime/Utils.java
similarity index 99%
rename from src/helma/util/mime/Utils.java
rename to src/helma/mime/Utils.java
index 3889ff76..99cf43b5 100644
--- a/src/helma/util/mime/Utils.java
+++ b/src/helma/mime/Utils.java
@@ -3,7 +3,7 @@
// (c) COPYRIGHT MIT and INRIA, 1998.
// Please first read the full copyright statement in file COPYRIGHT.html
-package helma.util.mime;
+package helma.mime;
import java.util.Hashtable;
diff --git a/src/helma/objectmodel/DbMapping.java b/src/helma/objectmodel/DbMapping.java
new file mode 100644
index 00000000..4cc031cc
--- /dev/null
+++ b/src/helma/objectmodel/DbMapping.java
@@ -0,0 +1,510 @@
+// DbMapping.java
+// Copyright (c) Hannes Wallnöfer 1998-2000
+
+package helma.objectmodel;
+
+import helma.framework.core.Application;
+import helma.objectmodel.db.WrappedNodeManager;
+import java.util.*;
+import java.sql.*;
+import com.workingdogs.village.*;
+
+/**
+ * A DbMapping describes how a certain type of Nodes is to mapped to a
+ * relational database table. Basically it consists of a set of JavaScript property-to-
+ * Database row bindings which are represented by instances of the Relation class.
+ */
+
+public class DbMapping {
+
+ Application app;
+ String typename;
+
+ SystemProperties props;
+
+ DbSource source;
+ String table;
+
+ String[] parent; // list of properties to try for parent
+ Boolean[] anonymous; // are parent relations anonymous or not?
+ DbMapping subnodes;
+ DbMapping properties;
+ private Relation subnodesRel;
+ private Relation propertiesRel;
+
+ // Map of property names to Relations objects
+ public Hashtable prop2db;
+ // Map of db columns to Relations objects
+ public Hashtable db2prop;
+
+ String idField;
+ String nameField;
+
+ // descriptor for key generation method
+ private String idgen;
+ // remember last key generated for this table
+ public long lastID;
+
+
+ Schema schema = null;
+ KeyDef keydef = null;
+
+ private long lastTypeChange;
+ public long lastDataChange;
+
+ public DbMapping () {
+
+ prop2db = new Hashtable ();
+ db2prop = new Hashtable ();
+
+ parent = null;
+ subnodes = null;
+ properties = null;
+ idField = "id";
+ }
+
+ public DbMapping (Application app, String typename, SystemProperties props) {
+
+ this.app = app;
+ this.typename = typename;
+
+ prop2db = new Hashtable ();
+ db2prop = new Hashtable ();
+
+ parent = null;
+ subnodes = null;
+ properties = null;
+ idField = "id";
+
+ this.props = props;
+ read ();
+
+ app.putDbMapping (typename, this);
+ }
+
+ /**
+ * Read the mapping from the Properties. Return true if the properties were changed.
+ * The read is split in two, this method and the rewire method. The reason is that in order
+ * for rewire to work, all other db mappings must have been initialized and registered.
+ */
+ public synchronized boolean read () {
+
+ long lastmod = props.lastModified ();
+ if (lastmod == lastTypeChange)
+ return false;
+
+ this.table = props.getProperty ("_tablename");
+ this.idgen = props.getProperty ("_idgen");
+
+ String sourceName = props.getProperty ("_datasource");
+ if (sourceName != null)
+ source = (DbSource) IServer.dbSources.get (sourceName.toLowerCase ());
+
+ // id field must not be null, default is "id"
+ idField = props.getProperty ("_id", "id");
+
+ nameField = props.getProperty ("_name");
+
+ lastTypeChange = lastmod;
+ // set the cached schema & keydef to null so it's rebuilt the next time around
+ schema = null;
+ keydef = null;
+ return true;
+ }
+
+ /**
+ * This is the second part of the property reading process, called after the first part has been
+ * completed on all other mappings in this application
+ */
+ public synchronized void rewire () {
+
+ // if (table != null && source != null) {
+ // IServer.getLogger().log ("set data source for "+typename+" to "+source);
+ Hashtable p2d = new Hashtable ();
+ Hashtable d2p = new Hashtable ();
+
+ for (Enumeration e=props.keys(); e.hasMoreElements(); ) {
+ String propName = (String) e.nextElement ();
+
+ try {
+ if (!propName.startsWith ("_") && propName.indexOf (".") < 0) {
+ String dbField = props.getProperty (propName);
+ Relation rel = new Relation (dbField, propName, this, props);
+ p2d.put (propName, rel);
+ if (rel.localField != null)
+ d2p.put (rel.localField, rel);
+ // IServer.getLogger().log ("Mapping "+propName+" -> "+dbField);
+ }
+ } catch (Exception x) {
+ IServer.getLogger ().log ("Error in type.properties: "+x.getMessage ());
+ }
+ }
+
+ prop2db = p2d;
+ db2prop = d2p;
+
+ String ano = props.getProperty ("_anonymous");
+ if (ano != null) {
+ // comma-separated list of true/false values
+ StringTokenizer st = new StringTokenizer (ano, ",; ");
+ anonymous = new Boolean[st.countTokens()];
+ for (int i=0; i=0; i--) {
+ path[i] = p;
+ p = p.getParent ();
+ }
+ return path;
+ }
public void setName (String name) {
- // if (name.indexOf('/') > -1)
- // throw new RuntimeException ("The name of the node must not contain \"/\".");
+ if (name.indexOf('/') > -1)
+ throw new RuntimeException ("The name of the node must not contain \"/\".");
if (name == null || name.trim().length() == 0)
this.name = id;
else
@@ -195,12 +245,15 @@ public class TransientNode implements INode, Serializable {
nodeMap.put (elem.getID (), elem);
nodes.insertElementAt (elem, where);
- if (elem instanceof TransientNode) {
- TransientNode node = (TransientNode) elem;
+ if (elem instanceof Node) {
+ Node node = (Node) elem;
if (node.parent == null) {
node.parent = this;
node.anonymous = true;
}
+ if (node.parent != null && (node.parent != this || !node.anonymous)) {
+ node.registerLink (this);
+ }
}
lastmodified = System.currentTimeMillis ();
@@ -224,7 +277,7 @@ public class TransientNode implements INode, Serializable {
boolean anon = false;
if (nm == null || "".equals (nm.trim ()))
anon = true;
- INode n = new TransientNode (nm);
+ INode n = new Node (nm);
if (anon)
addNode (n, where);
else
@@ -236,19 +289,11 @@ public class TransientNode implements INode, Serializable {
/**
* register a node that links to this node.
*/
- /* protected void registerLink (TransientNode from) {
+ protected void registerLink (Node from) {
if (links == null)
links = new Vector ();
if (!links.contains (from))
links.addElement (from);
- } */
-
- public IPathElement getParentElement () {
- return getParent ();
- }
-
- public IPathElement getChildElement (String name) {
- return getNode (name, false);
}
public INode getSubnode (String name) {
@@ -257,18 +302,18 @@ public class TransientNode implements INode, Serializable {
public INode getSubnode (String name, boolean inherit) {
StringTokenizer st = new StringTokenizer (name, "/");
- TransientNode retval = this, runner;
+ Node retval = this, runner;
while (st.hasMoreTokens () && retval != null) {
runner = retval;
String next = st.nextToken().trim().toLowerCase ();
if ("".equals (next))
retval = this;
else
- retval = runner.nodeMap == null ? null : (TransientNode) runner.nodeMap.get (next);
+ retval = runner.nodeMap == null ? null : (Node) runner.nodeMap.get (next);
if (retval == null)
- retval = (TransientNode) runner.getNode (next, inherit);
+ retval = (Node) runner.getNode (next, inherit);
if (retval == null && inherit && runner == this && parent != null)
- retval = (TransientNode) parent.getSubnode (next, inherit);
+ retval = (Node) parent.getSubnode (next, inherit);
}
return retval;
}
@@ -296,11 +341,11 @@ public class TransientNode implements INode, Serializable {
public void removeNode (INode node) {
// IServer.getLogger().log ("removing: "+ node);
releaseNode (node);
- TransientNode n = (TransientNode) node;
+ Node n = (Node) node;
if (n.getParent () == this && n.anonymous) {
int l = n.links == null ? 0 : n.links.size (); // notify nodes that link to n that n is going down.
for (int i = 0; i < l; i++) {
- TransientNode link = (TransientNode) n.links.elementAt (i);
+ Node link = (Node) n.links.elementAt (i);
link.releaseNode (n);
}
if (n.proplinks != null) {
@@ -310,12 +355,12 @@ public class TransientNode implements INode, Serializable {
p.node.propMap.remove (p.propname.toLowerCase ());
} catch (Exception ignore) {}
}
- /* for (Enumeration e2 = n.properties (); e2.hasMoreElements (); ) {
+ for (Enumeration e2 = n.properties (); e2.hasMoreElements (); ) {
// tell all nodes that are properties of n that they are no longer used as such
Property p = (Property) n.get ((String) e2.nextElement (), false);
if (p != null && p.type == Property.NODE)
p.unregisterNode ();
- } */
+ }
// remove all subnodes, giving them a chance to destroy themselves.
Vector v = new Vector (); // removeElement modifies the Vector we are enumerating, so we are extra careful.
for (Enumeration e3 = n.getSubnodes (); e3.hasMoreElements (); ) {
@@ -323,7 +368,7 @@ public class TransientNode implements INode, Serializable {
}
int m = v.size ();
for (int i=0; i -1)
+ filename = fname + name.substring (ndot);
+ else
+ filename = fname;
+ } else {
+ filename = fname;
+ }
+ }
+ File file = new File (base, filename);
+ FileOutputStream fout = new FileOutputStream (file);
+ fout.write (getContent ());
+ fout.close ();
+ return filename;
+ } catch (Exception x) {
+ return null;
+ }
+ }
+
+ public String getText () {
+ if (content != null) {
+ if (getContentType ().indexOf ("text/") == 0) {
+ return new String (content);
+ } else {
+ return null;
+ }
+ }
+ return null;
+ }
+
+
+ public String getHref (INode root, INode userroot, String tmpname, String prefix) {
+ return prefix + getUrl (root, userroot, tmpname);
+ }
+
+ public String getUrl (INode root, INode userroot, String tmpname) {
throw new RuntimeException ("HREFs on transient (non-db based) Nodes not supported");
- } */
+ }
public long lastModified () {
@@ -583,29 +750,26 @@ public class TransientNode implements INode, Serializable {
}
public String toString () {
- return "TransientNode " + name;
+ return "Node " + name;
}
+ protected Node convert (INode n) {
+ Hashtable ntable = new Hashtable ();
+ Node converted = new Node (n, ntable, false);
+ return converted;
+ }
+
INode cacheNode;
/**
- * Get the cache node for this node. This can
- * be used to store transient cache data per node
- * from Javascript.
+ * Get the cache node for this node. This can be used to store transient cache data per node from Javascript.
*/
public synchronized INode getCacheNode () {
if (cacheNode == null)
- cacheNode = new TransientNode();
+ cacheNode = new Node();
return cacheNode;
}
- /**
- * Reset the cache node for this node.
- */
- public synchronized void clearCacheNode () {
- cacheNode = null;
- }
-
}
diff --git a/src/helma/objectmodel/NodeDataSource.java b/src/helma/objectmodel/NodeDataSource.java
new file mode 100644
index 00000000..47aca47e
--- /dev/null
+++ b/src/helma/objectmodel/NodeDataSource.java
@@ -0,0 +1,46 @@
+// NodeDataSource.java
+// Copyright (c) Hannes Wallnöfer 1999-2000
+
+package helma.objectmodel;
+
+import javax.activation.*;
+import java.io.*;
+
+/**
+ * Makes Nodes usable as Datasources in the Java Activation Framework (JAF)
+ */
+
+public class NodeDataSource implements DataSource {
+
+ private INode node;
+ private String name;
+
+ public NodeDataSource (INode node) {
+ this.node = node;
+ this.name = node.getName ();
+ }
+
+ public NodeDataSource (INode node, String name) {
+ this.node = node;
+ this.name = name;
+ }
+
+
+ public InputStream getInputStream() throws IOException {
+ return new ByteArrayInputStream(node.getContent ());
+ }
+
+ public OutputStream getOutputStream () throws IOException {
+ throw new IOException ("Can't write to Node object.");
+ }
+
+ public String getContentType() {
+ return node.getContentType ();
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+}
diff --git a/src/helma/objectmodel/Property.java b/src/helma/objectmodel/Property.java
index 4592e903..71a0f7c2 100644
--- a/src/helma/objectmodel/Property.java
+++ b/src/helma/objectmodel/Property.java
@@ -4,10 +4,7 @@
package helma.objectmodel;
import helma.util.*;
-import java.util.Vector;
-import java.util.Hashtable;
-import java.util.Date;
-import java.util.Enumeration;
+import java.util.*;
import java.io.*;
import java.text.*;
@@ -15,11 +12,11 @@ import java.text.*;
* A property implementation for Nodes stored inside a database.
*/
-public final class Property implements IProperty, Serializable {
+public final class Property implements IProperty, Serializable, Cloneable {
protected String propname;
- protected TransientNode node;
+ protected Node node;
public String svalue;
public boolean bvalue;
@@ -31,11 +28,11 @@ public final class Property implements IProperty, Serializable {
public int type;
- public Property (TransientNode node) {
+ public Property (Node node) {
this.node = node;
}
- public Property (String propname, TransientNode node) {
+ public Property (String propname, Node node) {
this.propname = propname;
this.node = node;
}
@@ -66,16 +63,39 @@ public final class Property implements IProperty, Serializable {
public void setStringValue (String value) throws ParseException {
if (type == NODE)
- this.nvalue = null;
+ unregisterNode ();
+ // IServer.getLogger().log ("setting string value of property "+propname + " to "+value);
+ if (type == DATE) {
+ SimpleDateFormat dateformat = new SimpleDateFormat ();
+ dateformat.setLenient (true);
+ Date date = dateformat.parse (value);
+ this.lvalue = date.getTime ();
+ return;
+ }
+ if (type == BOOLEAN) {
+ if ("true".equalsIgnoreCase (value))
+ this.bvalue = true;
+ else if ("false".equalsIgnoreCase (value))
+ this.bvalue = false;
+ return;
+ }
+ if (type == INTEGER) {
+ this.lvalue = Long.parseLong (value);
+ return;
+ }
+ if (type == FLOAT) {
+ this.dvalue = new Double (value).doubleValue ();
+ return;
+ }
if (type == JAVAOBJECT)
this.jvalue = null;
- type = STRING;
this.svalue = value;
+ type = STRING;
}
public void setIntegerValue (long value) {
if (type == NODE)
- this.nvalue = null;
+ unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
type = INTEGER;
@@ -84,7 +104,7 @@ public final class Property implements IProperty, Serializable {
public void setFloatValue (double value) {
if (type == NODE)
- this.nvalue = null;
+ unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
type = FLOAT;
@@ -93,7 +113,7 @@ public final class Property implements IProperty, Serializable {
public void setDateValue (Date value) {
if (type == NODE)
- this.nvalue = null;
+ unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
type = DATE;
@@ -102,7 +122,7 @@ public final class Property implements IProperty, Serializable {
public void setBooleanValue (boolean value) {
if (type == NODE)
- this.nvalue = null;
+ unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
type = BOOLEAN;
@@ -112,18 +132,58 @@ public final class Property implements IProperty, Serializable {
public void setNodeValue (INode value) {
if (type == JAVAOBJECT)
this.jvalue = null;
+ if (type == NODE && nvalue != value) {
+ unregisterNode ();
+ registerNode (value);
+ } else if (type != NODE)
+ registerNode (value);
type = NODE;
this.nvalue = value;
}
public void setJavaObjectValue (Object value) {
if (type == NODE)
- this.nvalue = null;
+ unregisterNode ();
type = JAVAOBJECT;
this.jvalue = value;
}
+ /**
+ * tell a the value node that it is no longer used as a property.
+ */
+ protected void unregisterNode () {
+ if (nvalue != null && nvalue instanceof Node) {
+ Node n = (Node) nvalue;
+ if (!n.anonymous && propname.equals (n.getName()) && this.node == n.getParent()) {
+ // this is the "main" property of a named node, so handle this as a total delete.
+ IServer.getLogger().log ("deleting named property");
+ if (n.proplinks != null) {
+ for (Enumeration e = n.proplinks.elements (); e.hasMoreElements (); ) {
+ Property p = (Property) e.nextElement ();
+ p.node.propMap.remove (p.propname.toLowerCase ());
+ }
+ }
+ if (n.links != null) {
+ for (Enumeration e = n.links.elements (); e.hasMoreElements (); ) {
+ Node n2 = (Node) e.nextElement ();
+ n2.releaseNode (n);
+ }
+ }
+
+ } else {
+ n.unregisterPropLink (this);
+ }
+ }
+ }
+
+ /**
+ * tell the value node that it is being used as a property value.
+ */
+ protected void registerNode (INode n) {
+ if (n != null && n instanceof Node)
+ ((Node) n).registerPropLink (this);
+ }
public String getStringValue () {
switch (type) {
@@ -141,7 +201,7 @@ public final class Property implements IProperty, Serializable {
case NODE:
return nvalue.getName ();
case JAVAOBJECT:
- return jvalue == null ? null : jvalue.toString ();
+ return jvalue.toString ();
}
return "";
}
@@ -187,9 +247,86 @@ public final class Property implements IProperty, Serializable {
return null;
}
+ public String getEditor () {
+ switch (type) {
+ case STRING:
+ return "password".equalsIgnoreCase (propname) ?
+ " " :
+ " " ;
+ case BOOLEAN:
+ return ""+bvalue+" "+!bvalue+" ";
+ case INTEGER:
+ return " " ;
+ case FLOAT:
+ return " " ;
+ case DATE:
+ SimpleDateFormat format = new SimpleDateFormat ("dd.MM.yy hh:mm");
+ String date = format.format (new Date (lvalue));
+ return " ";
+ case NODE:
+ return " ";
+ }
+ return "";
+ }
+
+ private String escape (String s) {
+ char c[] = new char[s.length()];
+ s.getChars (0, c.length, c, 0);
+ StringBuffer b = new StringBuffer ();
+ int copyfrom = 0;
+ for (int i = 0; i < c.length; i++) {
+ switch (c[i]) {
+ case '\\':
+ case '"':
+ if (i-copyfrom > 0)
+ b.append (c, copyfrom, i-copyfrom);
+ b.append ('\\');
+ b.append (c[i]);
+ copyfrom = i+1;
+ }
+ }
+ if (c.length-copyfrom > 0)
+ b.append (c, copyfrom, c.length-copyfrom);
+ return b.toString ();
+ }
public int getType () {
return type;
}
+ public String getTypeString () {
+ switch (type) {
+ case STRING:
+ return "string";
+ case BOOLEAN:
+ return "boolean";
+ case DATE:
+ return "date";
+ case INTEGER:
+ return "integer";
+ case FLOAT:
+ return "float";
+ case NODE:
+ return "node";
+ }
+ return "";
+ }
+
+
+ public Object clone () {
+ try {
+ Property c = (Property) super.clone();
+ c.propname = this.propname;
+ c.svalue = this.svalue;
+ c.bvalue = this.bvalue;
+ c.lvalue = this.lvalue;
+ c.dvalue = this.dvalue;
+ c.type = this.type;
+ return c;
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen, since we are Cloneable
+ throw new InternalError ();
+ }
+ }
+
}
diff --git a/src/helma/objectmodel/Relation.java b/src/helma/objectmodel/Relation.java
new file mode 100644
index 00000000..2228ae94
--- /dev/null
+++ b/src/helma/objectmodel/Relation.java
@@ -0,0 +1,341 @@
+// Relation.java
+// Copyright (c) Hannes Wallnöfer 1997-2000
+
+package helma.objectmodel;
+
+import helma.framework.core.Application;
+import java.util.Properties;
+
+/**
+ * This describes how a property of a persistent Object is stored in a
+ * relational database table. This can be either a scalar property (string, date, number etc.)
+ * or a reference to one or more other objects.
+ */
+public class Relation {
+
+ // TODO: explain hop mapping types
+ public final static int INVALID = -1;
+ public final static int PRIMITIVE = 0;
+ public final static int FORWARD = 1;
+ public final static int BACKWARD = 2;
+ public final static int DIRECT = 3;
+
+ public DbMapping home;
+ public DbMapping other;
+ public String propname;
+ protected String localField, remoteField;
+ public int direction;
+
+ public boolean virtual;
+ public boolean readonly;
+ public boolean aggressiveLoading;
+ public boolean aggressiveCaching;
+ public boolean subnodesAreProperties;
+ public String order;
+ public String groupbyorder;
+ public String groupby;
+ public String prototype;
+
+ Relation filter = null; // additional relation used to filter subnodes
+
+ /**
+ * This constructor is used to directly construct a Relation, as opposed to reading it from a proerty file
+ */
+ public Relation (DbMapping other, String localField, String remoteField, int direction, boolean subnodesAreProperties) {
+ this.other = other;
+ this.localField = localField;
+ this.remoteField = remoteField;
+ this.direction = direction;
+ this.subnodesAreProperties = subnodesAreProperties;
+ }
+
+ /**
+ * Reads a relation entry from a line in a properties file.
+ */
+ public Relation (String desc, String propname, DbMapping home, Properties props) {
+
+ this.home = home;
+ this.propname = propname;
+ other = null;
+ Application app = home.getApplication ();
+ boolean mountpoint = false;
+
+ if (desc == null || "".equals (desc.trim ())) {
+ if (propname != null) {
+ direction = PRIMITIVE;
+ localField = propname;
+ } else {
+ direction = INVALID;
+ localField = propname;
+ }
+ } else {
+ desc = desc.trim ();
+ String descLower = desc.toLowerCase ();
+ if (descLower.startsWith ("[virtual]")) {
+ desc = desc.substring (9).trim ();
+ virtual = true;
+ } else if (descLower.startsWith ("[collection]")) {
+ desc = desc.substring (12).trim ();
+ virtual = true;
+ } else if (descLower.startsWith ("[mountpoint]")) {
+ desc = desc.substring (12).trim ();
+ virtual = true;
+ mountpoint = true;
+ } else {
+ virtual = false;
+ }
+ if (descLower.startsWith ("[readonly]")) {
+ desc = desc.substring (10).trim ();
+ readonly = true;
+ } else {
+ readonly = false;
+ }
+ if (desc.indexOf ("<") > -1) {
+ direction = BACKWARD;
+ int lt = desc.indexOf ("<");
+ int dot = desc.indexOf (".");
+ String otherType = dot < 0 ? desc.substring (1).trim () : desc.substring (1, dot).trim ();
+ other = app.getDbMapping (otherType);
+ if (other == null)
+ throw new RuntimeException ("DbMapping for "+otherType+" not found from "+home.typename);
+ remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
+ localField = lt < 0 ? null : desc.substring (0, lt).trim ();
+ if (mountpoint) prototype = otherType;
+ } else if (desc.indexOf (">") > -1) {
+ direction = FORWARD;
+ int bt = desc.indexOf (">");
+ int dot = desc.indexOf (".");
+ String otherType = dot > -1 ? desc.substring (bt+1, dot).trim () : desc.substring (bt+1).trim ();
+ other = app.getDbMapping (otherType);
+ if (other == null)
+ throw new RuntimeException ("DbMapping for "+otherType+" not found from "+home.typename);
+ localField = desc.substring (0, bt).trim ();
+ remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
+ if (mountpoint) prototype = otherType;
+ } else if (desc.indexOf (".") > -1) {
+ direction = DIRECT;
+ int dot = desc.indexOf (".");
+ String otherType = desc.substring (0, dot).trim ();
+ other = app.getDbMapping (otherType);
+ if (other == null)
+ throw new RuntimeException ("DbMapping for "+otherType+" not found from "+home.typename);
+ remoteField = desc.substring (dot+1).trim ();
+ localField = null;
+ if (mountpoint) prototype = otherType;
+ } else {
+ if (virtual) {
+ direction = DIRECT;
+ other = app.getDbMapping (desc);
+ if (other == null)
+ throw new RuntimeException ("DbMapping for "+desc+" not found from "+home.typename);
+ remoteField = localField = null;
+ if (mountpoint) prototype = desc;
+ } else {
+ direction = PRIMITIVE;
+ localField = desc.trim ();
+ }
+ }
+ }
+ String loading = props.getProperty (propname+".loadmode");
+ aggressiveLoading = loading != null && "aggressive".equalsIgnoreCase (loading.trim());
+ String caching = props.getProperty (propname+".cachemode");
+ aggressiveCaching = caching != null && "aggressive".equalsIgnoreCase (caching.trim());
+ // get order property
+ order = props.getProperty (propname+".order");
+ if (order != null && order.trim().length() == 0) order = null;
+ // get group by property
+ groupby = props.getProperty (propname+".groupby");
+ if (groupby != null && groupby.trim().length() == 0)
+ groupby = null;
+ if (groupby != null) {
+ groupbyorder = props.getProperty (propname+".groupby.order");
+ if (groupbyorder != null && groupbyorder.trim().length() == 0)
+ groupbyorder = null;
+ }
+ // check if subnode condition should be applied for property relations
+ if ("_properties".equalsIgnoreCase (propname) || virtual) {
+ String subnodes2props = props.getProperty (propname+".aresubnodes");
+ subnodesAreProperties = "true".equalsIgnoreCase (subnodes2props);
+ if (virtual) {
+ String subnodefilter = props.getProperty (propname+".subnoderelation");
+ if (subnodefilter != null) {
+ filter = new Relation (subnodefilter, propname+".subnoderelation", home, props);
+ filter.groupby = groupby;
+ }
+ }
+ }
+ }
+
+ public boolean isReference () {
+ return direction > PRIMITIVE;
+ }
+
+ public boolean usesPrimaryKey () {
+ if (other == null)
+ return false;
+ if (remoteField == null)
+ // if remote field is null, it is assumed that it points to the primary key
+ return true;
+ return remoteField.equalsIgnoreCase (other.getIDField());
+ }
+
+ public Relation getFilter () {
+ return filter;
+ }
+
+ /**
+ * Gets a key string to cache a node with a specific value for this relation. If the
+ * Relation uses the primary key return just the key value, otherwise include info on the
+ * used column or even the base node to avoid collisions.
+ */
+ public String getKeyID (INode home, String kval) {
+ // if the column is not the primary key, we add the column name to the key
+ if ((direction == DIRECT || direction == FORWARD) && !usesPrimaryKey ()) {
+ // check if the subnode relation also has to be considered
+ if (subnodesAreProperties)
+ return "["+home.getID()+"]"+remoteField+"="+kval; // HACK
+ else
+ return remoteField+"="+kval;
+ } else {
+ return kval;
+ }
+ }
+
+ /**
+ * Get the local column name for this relation to use in where clauses of select statements.
+ * This uses the home node's id as fallback if local field is not specified.
+ */
+ public String getLocalField () {
+ // only assume local field is primary key if other objects "point" to this object
+ if (localField == null && direction == BACKWARD)
+ return home.getIDField ();
+ return localField;
+ }
+
+ /**
+ * Return the local field name for updates. This is the same as getLocalField, but does not return the
+ * primary key name as a fallback.
+ */
+ public String getDbField () {
+ return localField;
+ }
+
+ /**
+ * Get the "remote" column name for this relation. Uses the remote node's id as fallback if the remote field is not specified.
+ */
+ public String getRemoteField () {
+ // only assume remote field is primary key if this relation "points" to an object
+ if (remoteField == null && direction == FORWARD)
+ return other.getIDField ();
+ return remoteField;
+ }
+
+
+ /**
+ * Return a Relation that defines the subnodes of a virtual node.
+ */
+ public Relation getVirtualSubnodeRelation () {
+ if (!virtual)
+ throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation");
+ if (filter != null)
+ return filter;
+ Relation vr = new Relation (other, localField, remoteField, direction, subnodesAreProperties);
+ vr.groupby = groupby;
+ vr.groupbyorder = groupbyorder;
+ vr.order = order;
+ vr.filter = filter;
+ return vr;
+ }
+
+ /**
+ * Return a Relation that defines the properties of a virtual node.
+ */
+ public Relation getVirtualPropertyRelation () {
+ if (!virtual)
+ throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation");
+ Relation vr = new Relation (other, localField, remoteField, direction, subnodesAreProperties);
+ vr.groupby = groupby;
+ vr.groupbyorder = groupbyorder;
+ vr.order = order;
+ vr.filter = filter;
+ return vr;
+ }
+
+ /**
+ * Return a Relation that defines the subnodes of a group-by node.
+ */
+ public Relation getGroupbySubnodeRelation () {
+ if (groupby == null)
+ throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
+ if (filter != null)
+ return filter;
+ Relation vr = new Relation (other, localField, remoteField, direction, true);
+ vr.order = order;
+ return vr;
+ }
+
+ /**
+ * Return a Relation that defines the properties of a group-by node.
+ */
+ public Relation getGroupbyPropertyRelation () {
+ if (groupby == null)
+ throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
+ Relation vr = new Relation (other, localField, remoteField, direction, true);
+ vr.order = order;
+ return vr;
+ }
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/util/SystemProperties.java b/src/helma/objectmodel/SystemProperties.java
similarity index 75%
rename from src/helma/util/SystemProperties.java
rename to src/helma/objectmodel/SystemProperties.java
index 01c0a4e4..46ea658b 100644
--- a/src/helma/util/SystemProperties.java
+++ b/src/helma/objectmodel/SystemProperties.java
@@ -1,8 +1,9 @@
// Property.java
// Copyright (c) Hannes Wallnöfer 1997-2000
-package helma.util;
+package helma.objectmodel;
+import helma.util.*;
import java.util.*;
import java.io.*;
@@ -19,27 +20,11 @@ public final class SystemProperties extends Properties {
private File file;
private long lastread, lastcheck;
- final static long cacheTime = 1500l;
-
public SystemProperties () {
this (null, null);
}
- public SystemProperties (InputStream in) {
- this (null, null);
- try {
- load (in);
- } catch (Exception x) {
- System.err.println ("Error reading properties from file "+file+": "+x);
- } finally {
- try {
- in.close ();
- } catch (Exception ignore) {}
- }
- lastread = System.currentTimeMillis ();
- }
-
public SystemProperties (String filename) {
this (filename, null);
}
@@ -49,7 +34,7 @@ public final class SystemProperties extends Properties {
}
public SystemProperties (String filename, Properties defaultProps) {
- // System.err.println ("building sysprops with file "+filename+" and node "+node);
+ // IServer.getLogger().log ("building sysprops with file "+filename+" and node "+node);
this.defaultProps = defaultProps;
props = defaultProps == null ?
new Properties () : new Properties (defaultProps);
@@ -79,7 +64,7 @@ public final class SystemProperties extends Properties {
load (bpin);
bpin.close ();
} catch (Exception x) {
- System.err.println ("Error reading properties from file "+file+": "+x);
+ IServer.getLogger().log ("Error reading properties from file "+file+": "+x);
}
lastread = System.currentTimeMillis ();
props = newProps;
@@ -124,42 +109,30 @@ public final class SystemProperties extends Properties {
}
public String getProperty (String name) {
- if (System.currentTimeMillis () - lastcheck > cacheTime)
+ if (System.currentTimeMillis () - lastcheck > 1500l)
checkFile ();
return props.getProperty (name.toLowerCase());
}
public String getProperty (String name, String defaultValue) {
- if (System.currentTimeMillis () - lastcheck > cacheTime)
+ if (System.currentTimeMillis () - lastcheck > 1500l)
checkFile ();
return props.getProperty (name.toLowerCase(), defaultValue);
}
public Enumeration keys () {
- if (System.currentTimeMillis () - lastcheck > cacheTime)
+ if (System.currentTimeMillis () - lastcheck > 1500l)
checkFile ();
return props.keys();
}
public Enumeration elements () {
- if (System.currentTimeMillis () - lastcheck > cacheTime)
+ if (System.currentTimeMillis () - lastcheck > 1500l)
checkFile ();
return props.elements();
}
- public int size() {
- if (System.currentTimeMillis () - lastcheck > cacheTime)
- checkFile ();
- return props.size();
- }
-
- public String toString () {
- return props.toString ();
- }
-
}
-
-
diff --git a/src/helma/main/ApplicationManager.java b/src/helma/objectmodel/db/ApplicationManager.java
similarity index 61%
rename from src/helma/main/ApplicationManager.java
rename to src/helma/objectmodel/db/ApplicationManager.java
index 3cbb0d05..ac11a41d 100644
--- a/src/helma/main/ApplicationManager.java
+++ b/src/helma/objectmodel/db/ApplicationManager.java
@@ -1,10 +1,9 @@
// ApplicationManager.java
// Copyright (c) Hannes Wallnöfer 1998-2000
-package helma.main;
+package helma.objectmodel.db;
-import java.util.Hashtable;
-import java.util.Enumeration;
+import java.util.*;
import java.io.*;
import java.lang.reflect.*;
import java.rmi.*;
@@ -13,27 +12,27 @@ import helma.framework.*;
import helma.framework.core.*;
import helma.objectmodel.*;
import helma.servlet.*;
-import helma.util.SystemProperties;
import Acme.Serve.*;
import javax.servlet.Servlet;
/**
- * This class is responsible for starting and stopping Helma applications.
+ * This class is responsible for starting and stopping HOP applications.
*/
public class ApplicationManager {
private Hashtable applications;
private int port;
- private File hopHome;
+ private File appHome, dbHome;
private SystemProperties props;
private Server server;
private long lastModified;
- public ApplicationManager (int port, File hopHome, SystemProperties props, Server server) {
+ public ApplicationManager (int port, File appHome, File dbHome, SystemProperties props, Server server) {
this.port = port;
- this.hopHome = hopHome;
+ this.appHome = appHome;
+ this.dbHome = dbHome;
this.props = props;
this.server = server;
applications = new Hashtable ();
@@ -60,65 +59,60 @@ public class ApplicationManager {
}
}
} catch (Exception mx) {
- Server.getLogger().log ("Error starting applications: "+mx);
+ IServer.getLogger().log ("Error starting applications: "+mx);
}
lastModified = System.currentTimeMillis ();
}
}
- void start (String appName) {
- Server.getLogger().log ("Building application "+appName);
+
+ private void start (String appName) {
+ IServer.getLogger().log ("Building application "+appName);
try {
- Application app = new Application (appName, hopHome, Server.sysProps, Server.dbProps);
+ Application app = new Application (appName, dbHome, appHome);
applications.put (appName, app);
// if we're running with the embedded web server, set app base uri to /appname
- if (server.websrv != null && !"base".equalsIgnoreCase (appName))
+ if (server.websrv != null)
app.setBaseURI ("/"+java.net.URLEncoder.encode (appName));
- // the application is started later in the register method, when it's bound
- app.init ();
+ app.start ();
} catch (Exception x) {
- Server.getLogger().log ("Error creating application "+appName+": "+x);
+ IServer.getLogger().log ("Error creating application "+appName+": "+x);
x.printStackTrace ();
}
}
- void stop (String appName) {
- Server.getLogger().log ("Stopping application "+appName);
+ private void stop (String appName) {
+ IServer.getLogger().log ("Stopping application "+appName);
try {
Application app = (Application) applications.get (appName);
if (server.websrv == null) {
Naming.unbind ("//:"+port+"/"+appName);
} else {
- // server.websrv.removeServlet ("/"+appName+"/");
+ server.websrv.removeServlet ("/"+appName+"/");
server.websrv.removeServlet ("/"+appName+"/*");
}
app.stop ();
- Server.getLogger().log ("Unregistered application "+appName);
+ IServer.getLogger().log ("Unregistered application "+appName);
} catch (Exception x) {
- Server.getLogger().log ("Couldn't unregister app: "+x);
+ IServer.getLogger().log ("Couldn't unregister app: "+x);
}
applications.remove (appName);
}
- void register (String appName) {
+ private void register (String appName) {
try {
- Server.getLogger().log ("Binding application "+appName);
+ IServer.getLogger().log ("Binding application "+appName);
Application app = (Application) applications.get (appName);
if (server.websrv == null) {
Naming.rebind ("//:"+port+"/"+appName, app);
} else {
AcmeServletClient servlet = new AcmeServletClient (app);
- if ("base".equalsIgnoreCase (appName))
- server.websrv.setDefaultServlet (servlet);
- else {
- // server.websrv.addServlet ("/"+appName+"/", servlet);
- server.websrv.addServlet ("/"+appName+"/*", servlet);
- }
+ server.websrv.addServlet ("/"+appName+"/", servlet);
+ server.websrv.addServlet ("/"+appName+"/*", servlet);
}
- app.start ();
} catch (Exception x) {
- Server.getLogger().log ("Couldn't register and start app: "+x);
+ IServer.getLogger().log ("Couldn't register app: "+x);
}
}
@@ -134,27 +128,16 @@ public class ApplicationManager {
}
if (server.websrv != null) {
File staticContent = new File (server.getHopHome(), "static");
- Server.getLogger().log("Serving static content from "+staticContent.getAbsolutePath());
+ IServer.getLogger().log("Serving static content from "+staticContent.getAbsolutePath());
AcmeFileServlet fsrv = new AcmeFileServlet (staticContent);
server.websrv.addServlet ("/static/", fsrv);
server.websrv.addServlet ("/static/*", fsrv);
}
lastModified = System.currentTimeMillis ();
} catch (Exception mx) {
- Server.getLogger().log ("Error starting applications: "+mx);
+ IServer.getLogger().log ("Error starting applications: "+mx);
mx.printStackTrace ();
}
}
- /**
- * Get an enumeration of all currently running applications.
- */
- public Object[] getApplications () {
- return applications.values ().toArray ();
- }
-
- public Application getApplication(String name) {
- return (Application)applications.get(name);
- }
-
}
diff --git a/src/helma/objectmodel/db/DbKey.java b/src/helma/objectmodel/db/DbKey.java
deleted file mode 100644
index ff8b5041..00000000
--- a/src/helma/objectmodel/db/DbKey.java
+++ /dev/null
@@ -1,130 +0,0 @@
-// DbKey.java
-// Copyright (c) Hannes Wallnöfer 1998-2000
-
-package helma.objectmodel.db;
-
-import java.io.Serializable;
-
-
-/**
- * This is the internal representation of a database key. It is constructed
- * out of the database URL, the table name, the user name and the database
- * key of the node and unique within each Helma application. Currently only
- * single keys are supported.
- */
-public final class DbKey implements Key, Serializable {
-
- // the name of the prototype which defines the storage of this object.
- // this is the name of the object's prototype, or one of its ancestors.
- // If null, the object is stored in the embedded db.
- private final String storageName;
- // the id that defines this key's object within the above storage space
- private final String id;
-
- // lazily initialized hashcode
- private transient int hashcode = 0;
-
- /**
- * make a key for a persistent Object, describing its datasource and id.
- */
- public DbKey (DbMapping dbmap, String id) {
- this.id = id;
- this.storageName = dbmap == null ? null : dbmap.getStorageTypeName ();
- }
-
-
-
- public boolean equals (Object what) {
- if (what == this)
- return true;
- try {
- DbKey k = (DbKey) what;
- return (storageName == k.storageName || storageName.equals (k.storageName)) &&
- (id == k.id || id.equals (k.id));
- } catch (Exception x) {
- return false;
- }
- }
-
- public int hashCode () {
- if (hashcode == 0) {
- hashcode = storageName == null ?
- 17 + 37*id.hashCode () :
- 17 + 37*storageName.hashCode() + +37*id.hashCode ();
- }
- return hashcode;
- }
-
- public Key getParentKey () {
- return null;
- }
-
- public String getStorageName () {
- return storageName;
- }
-
- public String getID () {
- return id;
- }
-
- public String toString () {
- return storageName == null ? "["+id+"]" : storageName+"["+id+"]";
- }
-
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/helma/objectmodel/db/DbMapping.java b/src/helma/objectmodel/db/DbMapping.java
deleted file mode 100644
index b2ac7a06..00000000
--- a/src/helma/objectmodel/db/DbMapping.java
+++ /dev/null
@@ -1,725 +0,0 @@
-// DbMapping.java
-// Copyright (c) Hannes Wallnöfer 1998-2000
-
-package helma.objectmodel.db;
-
-import helma.framework.core.Application;
-import helma.util.Updatable;
-import helma.util.SystemProperties;
-import java.util.HashMap;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.StringTokenizer;
-import java.sql.*;
-import com.workingdogs.village.*;
-
-/**
- * A DbMapping describes how a certain type of Nodes is to mapped to a
- * relational database table. Basically it consists of a set of JavaScript property-to-
- * Database row bindings which are represented by instances of the Relation class.
- */
-
-public class DbMapping implements Updatable {
-
- // DbMappings belong to an application
- Application app;
- // prototype name of this mapping
- String typename;
-
- int version;
-
- // properties from where the mapping is read
- SystemProperties props;
-
- // name of data source to which this mapping writes
- DbSource source;
- // name of datasource
- String sourceName;
- // name of db table
- String table;
-
- // list of properties to try for parent
- ParentInfo[] parent;
-
- // Relations describing subnodes and properties.
- Relation subnodesRel;
- Relation propertiesRel;
-
- // if this defines a subnode mapping with groupby layer, we need a DbMapping for those groupby nodes
- DbMapping groupbyMapping;
-
- // Map of property names to Relations objects
- HashMap prop2db;
- // Map of db columns to Relations objects
- HashMap db2prop;
-
- // db field used as primary key
- private String idField;
- // db field used as object name
- String nameField;
- // db field used to identify name of prototype to use for object instantiation
- String protoField;
-
- // name of parent prototype, if any
- String extendsProto;
- // dbmapping of parent prototype, if any
- DbMapping parentMapping;
-
- // db field that specifies the prototype of an object
- String prototypeField;
-
- // descriptor for key generation method
- private String idgen;
- // remember last key generated for this table
- long lastID;
-
- // the (village) schema of the database table
- Schema schema = null;
- // the (village) keydef of the db table
- KeyDef keydef = null;
-
- // timestamp of last modification of the mapping (type.properties)
- long lastTypeChange;
- // timestamp of last modification of an object of this type
- long lastDataChange;
-
- /**
- * Create an empty DbMapping
- */
- public DbMapping (Application app) {
-
- this.app = app;
-
- prop2db = new HashMap ();
- db2prop = new HashMap ();
-
- parent = null;
-
- idField = null;
- }
-
- /**
- * Create a DbMapping from a type.properties property file
- */
- public DbMapping (Application app, String typename, SystemProperties props) {
-
- this.app = app;
- this.typename = typename;
-
- prop2db = new HashMap ();
- db2prop = new HashMap ();
-
- parent = null;
-
- idField = null;
-
- this.props = props;
- update ();
-
- app.putDbMapping (typename, this);
- }
-
- /**
- * Tell the type manager whether we need update() to be called
- */
- public boolean needsUpdate () {
- return props.lastModified () != lastTypeChange;
- }
-
-
- /**
- * Read the mapping from the Properties. Return true if the properties were changed.
- * The read is split in two, this method and the rewire method. The reason is that in order
- * for rewire to work, all other db mappings must have been initialized and registered.
- */
- public synchronized void update () {
-
- // determin file format version of type.properties file
- String versionInfo = props.getProperty ("_version");
- if ("1.2".equals (versionInfo))
- version = 1;
- else
- version = 0;
-
- table = props.getProperty (version == 0 ? "_tablename" : "_table");
- idgen = props.getProperty ("_idgen");
- // see if there is a field which specifies the prototype of objects, if different prototypes
- // can be stored in this table
- prototypeField = props.getProperty ("_prototypefield");
- // see if this prototype extends (inherits from) any other prototype
- extendsProto = props.getProperty ("_extends");
-
- sourceName = props.getProperty (version == 0 ? "_datasource" : "_db");
- if (sourceName != null) {
- source = app.getDbSource (sourceName);
- if (source == null) {
- app.logEvent ("*** Data Source for prototype "+typename+" does not exist: "+sourceName);
- app.logEvent ("*** accessing or storing a "+typename+" object will cause an error.");
- }
- }
-
- // if id field is null, we assume "ID" as default. We don't set it
- // however, so that if null we check the parent prototype first.
- idField = props.getProperty ("_id");
-
- nameField = props.getProperty ("_name");
-
- protoField = props.getProperty ("_prototype");
-
- String parentMapping = props.getProperty ("_parent");
- if (parentMapping != null) {
- // comma-separated list of properties to be used as parent
- StringTokenizer st = new StringTokenizer (parentMapping, ",;");
- parent = new ParentInfo[st.countTokens()];
- for (int i=0; i "+dbField);
- }
- } catch (Exception x) {
- app.logEvent ("Error in type.properties: "+x.getMessage ());
- }
- }
-
- prop2db = p2d;
- db2prop = d2p;
-
- if (version == 1) {
- String subnodeMapping = props.getProperty ("_children");
- if (subnodeMapping != null) {
- try {
- // check if subnode relation already exists. If so, reuse it
- if (subnodesRel == null)
- subnodesRel = new Relation (subnodeMapping, "_children", this, props);
- subnodesRel.update (subnodeMapping, props, version);
- if (subnodesRel.accessor != null)
- propertiesRel = subnodesRel;
-
- } catch (Exception x) {
- app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
- // subnodesRel = null;
- }
- } else
- subnodesRel = null;
- } else {
- String subnodeMapping = props.getProperty ("_subnodes");
- if (subnodeMapping != null) {
- try {
- // check if subnode relation already exists. If so, reuse it
- if (subnodesRel == null)
- subnodesRel = new Relation (subnodeMapping, "_subnodes", this, props);
- subnodesRel.update (subnodeMapping, props, version);
-
- } catch (Exception x) {
- app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
- // subnodesRel = null;
- }
- } else
- subnodesRel = null;
-
- String propertiesMapping = props.getProperty ("_properties");
- if (propertiesMapping != null) {
- try {
- // check if property relation already exists. If so, reuse it
- if (propertiesRel == null)
- propertiesRel = new Relation (propertiesMapping, "_properties", this, props);
- propertiesRel.update (propertiesMapping, props, version);
-
- // take over groupby flag from subnodes, if properties are subnodes
- if (propertiesRel.subnodesAreProperties && subnodesRel != null) {
- propertiesRel.groupby = subnodesRel.groupby;
- propertiesRel.constraints = subnodesRel.constraints;
- propertiesRel.filter = subnodesRel.filter;
- }
-
- } catch (Exception x) {
- app.logEvent ("Error reading _properties relation for "+typename+": "+x.getMessage ());
- // propertiesRel = null;
- }
- } else
- propertiesRel = null;
- }
-
- if (groupbyMapping != null) {
- initGroupbyMapping ();
- groupbyMapping.lastTypeChange = this.lastTypeChange;
- }
- }
-
-
- /**
- * Get a JDBC connection for this DbMapping.
- */
- public Connection getConnection () throws ClassNotFoundException, SQLException {
- // if source was previously not available, check again
- if (source == null && sourceName != null)
- source = app.getDbSource (sourceName);
- if (sourceName == null && parentMapping != null)
- return parentMapping.getConnection ();
- if (source == null) {
- if (sourceName == null)
- throw new SQLException ("Tried to get Connection from non-relational embedded data source.");
- else
- throw new SQLException ("Datasource is not defined: "+sourceName+".");
- }
- return source.getConnection ();
- }
-
- /**
- * Get the DbSource object for this DbMapping. The DbSource describes a JDBC
- * data source including URL, JDBC driver, username and password.
- */
- public DbSource getDbSource () {
- if (source == null && parentMapping != null)
- return parentMapping.getDbSource ();
- return source;
- }
-
- /**
- * Get the URL of the data source used for this mapping.
- */
- public String getSourceID () {
- if (source == null && parentMapping != null)
- return parentMapping.getSourceID ();
- return source == null ? "" : source.url;
- }
-
- /**
- * Get the table name used for this type mapping.
- */
- public String getTableName () {
- if (source == null && parentMapping != null)
- return parentMapping.getTableName ();
- return table;
- }
-
- /**
- * Get the application this DbMapping belongs to.
- */
- public Application getApplication () {
- return app;
- }
-
- /**
- * Get the name of this mapping's application
- */
- public String getAppName () {
- return app.getName();
- }
-
- /**
- * Get the name of the object type this DbMapping belongs to.
- */
- public String getTypeName () {
- return typename;
- }
-
- /**
- * Get the name of this type's parent type, if any.
- */
- public String getExtends () {
- return extendsProto;
- }
-
- /**
- * Get the primary key column name for objects using this mapping.
- */
- public String getIDField () {
- if (idField == null && parentMapping != null)
- return parentMapping.getIDField ();
- return idField == null ? "ID" : idField;
- }
-
- /**
- * Get the column used for (internal) names of objects of this type.
- */
- public String getNameField () {
- if (nameField == null && parentMapping != null)
- return parentMapping.getNameField ();
- return nameField;
- }
-
- /**
- * Get the column used for names of prototype.
- */
- public String getPrototypeField () {
- if (protoField == null && parentMapping != null)
- return parentMapping.getPrototypeField ();
- return protoField;
- }
-
-
- /**
- * Translate a database column name to an object property name according to this mapping.
- */
- public String columnNameToProperty (String columnName) {
- if (columnName == null)
- return null;
- if (table == null && parentMapping != null)
- return parentMapping.columnNameToProperty (columnName);
- Relation rel = (Relation) db2prop.get (columnName.toUpperCase ());
- if (rel != null && (rel.reftype == Relation.PRIMITIVE || rel.reftype == Relation.REFERENCE))
- return rel.propName;
- return null;
- }
-
- /**
- * Translate an object property name to a database column name according to this mapping.
- */
- public String propertyToColumnName (String propName) {
- if (propName == null)
- return null;
- if (table == null && parentMapping != null)
- return parentMapping.propertyToColumnName (propName);
- Relation rel = (Relation) prop2db.get (propName);
- if (rel != null && (rel.reftype == Relation.PRIMITIVE || rel.reftype == Relation.REFERENCE))
- return rel.columnName;
- return null;
- }
-
- /**
- * Translate a database column name to an object property name according to this mapping.
- */
- public Relation columnNameToRelation (String columnName) {
- if (columnName == null)
- return null;
- if (table == null && parentMapping != null)
- return parentMapping.columnNameToRelation (columnName);
- return (Relation) db2prop.get (columnName.toUpperCase ());
- }
-
- /**
- * Translate an object property name to a database column name according to this mapping.
- */
- public Relation propertyToRelation (String propName) {
- if (propName == null)
- return null;
- if (table == null && parentMapping != null)
- return parentMapping.propertyToRelation (propName);
- return (Relation) prop2db.get (propName);
- }
-
-
- /**
- * This returns the parent info array, which tells an object of this type how to
- * determine its parent object.
- */
- public synchronized ParentInfo[] getParentInfo () {
- if (parent == null && parentMapping != null)
- return parentMapping.getParentInfo ();
- return parent;
- }
-
-
- public DbMapping getSubnodeMapping () {
- if (subnodesRel != null)
- return subnodesRel.otherType;
- if (parentMapping != null)
- return parentMapping.getSubnodeMapping ();
- return null;
- }
-
-
- public DbMapping getExactPropertyMapping (String propname) {
- Relation rel = getExactPropertyRelation (propname);
- return rel != null ? rel.otherType : null;
- }
-
- public DbMapping getPropertyMapping (String propname) {
- Relation rel = getPropertyRelation (propname);
- if (rel != null) {
- // if this is a virtual node, it doesn't have a dbmapping
- if (rel.virtual && rel.prototype == null)
- return null;
- else
- return rel.otherType;
- }
- return null;
- }
-
- /**
- * If subnodes are grouped by one of their properties, return the
- * db-mapping with the right relations to create the group-by nodes
- */
- public synchronized DbMapping getGroupbyMapping () {
- if (subnodesRel == null || subnodesRel.groupby == null)
- return null;
- if (groupbyMapping == null) {
- initGroupbyMapping ();
- }
- return groupbyMapping;
- }
-
- /**
- * Initialize the dbmapping used for group-by nodes.
- */
- private void initGroupbyMapping () {
- // if a prototype is defined for groupby nodes, use that
- // if mapping doesn' exist or isn't defined, create a new (anonymous internal) one
- groupbyMapping = new DbMapping (app);
- // If a mapping is defined, make the internal mapping inherit from
- // the defined named prototype.
- if (subnodesRel.groupbyprototype != null)
- groupbyMapping.parentMapping = app.getDbMapping (subnodesRel.groupbyprototype);
- groupbyMapping.subnodesRel = subnodesRel.getGroupbySubnodeRelation ();
- if (propertiesRel != null)
- groupbyMapping.propertiesRel = propertiesRel.getGroupbyPropertyRelation ();
- else
- groupbyMapping.propertiesRel = subnodesRel.getGroupbyPropertyRelation ();
- groupbyMapping.typename = subnodesRel.groupbyprototype;
- }
-
- /* public void setPropertyMapping (DbMapping pm) {
- properties = pm;
- } */
-
- /* public void setSubnodeRelation (Relation rel) {
- subnodesRel = rel;
- } */
-
- public void setPropertyRelation (Relation rel) {
- propertiesRel = rel;
- }
-
- public Relation getSubnodeRelation () {
- if (subnodesRel == null && parentMapping != null)
- return parentMapping.getSubnodeRelation ();
- return subnodesRel;
- }
-
- public Relation getPropertyRelation () {
- if (propertiesRel == null && parentMapping != null)
- return parentMapping.getPropertyRelation ();
- return propertiesRel;
- }
-
- public Relation getPropertyRelation (String propname) {
- if (propname == null)
- return getPropertyRelation ();
- // first try finding an exact match for the property name
- Relation rel = getExactPropertyRelation (propname);
- // if not defined, return the generic property mapping
- if (rel == null)
- rel = getPropertyRelation ();
- return rel;
- }
-
- public Relation getExactPropertyRelation (String propname) {
- if (propname == null)
- return null;
- Relation rel = (Relation) prop2db.get (propname.toLowerCase());
- if (rel == null && parentMapping != null)
- rel = parentMapping.getExactPropertyRelation (propname);
- return rel;
- }
-
- public String getSubnodeGroupby () {
- if (subnodesRel == null && parentMapping != null)
- return parentMapping.getSubnodeGroupby ();
- return subnodesRel == null ? null : subnodesRel.groupby;
- }
-
- public String getIDgen () {
- if (idgen == null && parentMapping != null)
- return parentMapping.getIDgen ();
- return idgen;
- }
-
-
- public WrappedNodeManager getWrappedNodeManager () {
- if (app == null)
- throw new RuntimeException ("Can't get node manager from internal db mapping");
- return app.getWrappedNodeManager ();
- }
-
- /**
- * Tell whether this data mapping maps to a relational database table. This returns true
- * if a datasource is specified, even if it is not a valid one. Otherwise, objects with invalid
- * mappings would be stored in the embedded db instead of an error being thrown, which is
- * not what we want.
- */
- public boolean isRelational () {
- if (sourceName != null)
- return true;
- if (parentMapping != null)
- return parentMapping.isRelational ();
- return false;
- }
-
- /**
- * Return a Village Schema object for this DbMapping.
- */
- public synchronized Schema getSchema () throws ClassNotFoundException, SQLException, DataSetException {
- if (!isRelational ())
- throw new SQLException ("Can't get Schema for non-relational data mapping");
- if (source == null && parentMapping != null)
- return parentMapping.getSchema ();
- // Use local variable s to avoid synchronization (schema may be nulled elsewhere)
- Schema s = schema;
- if (s != null)
- return s;
- schema = new Schema ().schema (getConnection (), table, "*");
- return schema;
- }
-
- /**
- * Return true if the column identified by the parameter is a string type. This is
- * used in query building to determine if a value needs to be quoted.
- */
- public boolean isStringColumn (String columnName) throws SQLException {
- try {
- Schema s = getSchema ();
- if (s == null)
- throw new SQLException ("Error retrieving relational schema for "+this);
- Column c = s.getColumn (columnName);
- if (c == null)
- throw new SQLException ("Column "+columnName+" not found in "+this);
- return c.isString () || c.isVarBinary () || c.isLongVarBinary ();
- } catch (Exception x) {
- throw new SQLException (x.getMessage ());
- }
- }
-
- /**
- * Return a Village Schema object for this DbMapping.
- */
- public synchronized KeyDef getKeyDef () {
- if (!isRelational ())
- throw new RuntimeException ("Can't get KeyDef for non-relational data mapping");
- if (source == null && parentMapping != null)
- return parentMapping.getKeyDef ();
- // Use local variable s to avoid synchronization (keydef may be nulled elsewhere)
- KeyDef k = keydef;
- if (k != null)
- return k;
- keydef = new KeyDef ().addAttrib (getIDField ());
- return keydef;
- }
-
- public String toString () {
- if (typename == null)
- return "[unspecified internal DbMapping]";
- else
- return ("["+app.getName()+"."+typename+"]");
- }
-
- public long getLastTypeChange () {
- return lastTypeChange;
- }
-
-
- public long getLastDataChange () {
- return lastDataChange;
- }
-
- public void notifyDataChange () {
- lastDataChange = System.currentTimeMillis ();
- if (parentMapping != null && source == null)
- parentMapping.notifyDataChange ();
- }
-
- public synchronized long getNewID (long dbmax) {
- if (parentMapping != null && source == null)
- return parentMapping.getNewID (dbmax);
- lastID = Math.max (dbmax+1, lastID+1);
- return lastID;
- }
-
- public HashMap getProp2DB () {
- if (table == null && parentMapping != null)
- return parentMapping.getProp2DB ();
- return prop2db;
- }
-
- public Iterator getDBPropertyIterator () {
- if (table == null && parentMapping != null)
- return parentMapping.getDBPropertyIterator ();
- return db2prop.values ().iterator ();
- }
-
- /**
- * Return the name of the prototype which specifies the storage location
- * (dbsource + tablename) for this type, or null if it is stored in the embedded
- * db.
- */
- public String getStorageTypeName () {
- if (table == null && parentMapping != null)
- return parentMapping.getStorageTypeName ();
- return sourceName == null ? null : typename;
- }
-
- /**
- * Tell if another DbMapping is storage-compatible to this one, i.e. it is stored in the same table or
- * embedded database.
- */
- public boolean isStorageCompatible (DbMapping other) {
- if (other == null)
- return !isRelational ();
- if (isRelational ())
- return getTableName().equals (other.getTableName ()) &&
- getDbSource().equals (other.getDbSource ());
- return !other.isRelational ();
- }
-
- /**
- * Return true if this db mapping represents the prototype indicated
- * by the string argument, either itself or via one of its parent prototypes.
- */
- public boolean isInstanceOf (String other) {
- if (typename != null && typename.equals (other))
- return true;
- DbMapping p = parentMapping;
- while (p != null) {
- if (p.typename != null && p.typename.equals (other))
- return true;
- p = p.parentMapping;
- }
- return false;
- }
-
-
- public DbMapping getParentMapping () {
- return parentMapping;
- }
-
-}
-
diff --git a/src/helma/objectmodel/db/DbSource.java b/src/helma/objectmodel/db/DbSource.java
deleted file mode 100644
index 5e0a5c4c..00000000
--- a/src/helma/objectmodel/db/DbSource.java
+++ /dev/null
@@ -1,120 +0,0 @@
-// DbSource.java
-// Copyright (c) Hannes Wallnöfer 1999-2000
-
-package helma.objectmodel.db;
-
-import java.sql.*;
-import java.util.Hashtable;
-import helma.util.SystemProperties;
-
-/**
- * This class describes a releational data source (URL, driver, user and password).
- */
-
-public class DbSource {
-
- private String name;
- private SystemProperties props;
- private static SystemProperties defaultProps = null;
- protected String url;
- private String driver;
- protected String user;
- private String password;
-
- private long lastRead = 0l;
-
- public DbSource (String name, SystemProperties props) throws ClassNotFoundException {
- this.name = name;
- this.props = props;
- init ();
- }
-
- public Connection getConnection () throws ClassNotFoundException, SQLException {
- Transactor tx = (Transactor) Thread.currentThread ();
- Connection con = tx.getConnection (this);
- boolean fileUpdated = props.lastModified () > lastRead;
- if (!fileUpdated && defaultProps != null)
- fileUpdated = defaultProps.lastModified () > lastRead;
- if (con == null || con.isClosed () || fileUpdated) {
- init ();
- Class.forName (driver);
- con = DriverManager.getConnection (url, user, password);
- // If we wanted to use SQL transactions, we'd set autoCommit to
- // false here and make commit/rollback invocations in Transactor methods;
- // System.err.println ("Created new Connection to "+url);
- tx.registerConnection (this, con);
- //////////////////////////////////////////////
- /* DatabaseMetaData meta = con.getMetaData ();
- ResultSet tables = meta.getCatalogs ();
- while (tables.next())
- System.err.println ("********* TABLE: "+ tables.getObject (1));
- ResultSet types = meta.getTypeInfo ();
- while (types.next())
- System.err.println ("******* TYPE: "+types.getObject(1) +" - "+types.getObject(2)+" - "+types.getObject(6));
- */
- }
- return con;
- }
-
- private void init () throws ClassNotFoundException {
- lastRead = defaultProps == null ? props.lastModified () : Math.max (props.lastModified (), defaultProps.lastModified ());
- url = props.getProperty (name+".url");
- driver = props.getProperty (name+".driver");
- Class.forName (driver);
- user = props.getProperty (name+".user");
- password = props.getProperty (name+".password");
- }
-
- public String getDriverName () {
- return driver;
- }
-
- public String getName () {
- return name;
- }
-
- public static void setDefaultProps (SystemProperties props) {
- defaultProps = props;
- }
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/helma/objectmodel/db/DbWrapper.java b/src/helma/objectmodel/db/DbWrapper.java
index 38435894..c9c81a5c 100644
--- a/src/helma/objectmodel/db/DbWrapper.java
+++ b/src/helma/objectmodel/db/DbWrapper.java
@@ -24,15 +24,13 @@ public class DbWrapper {
volatile long txncount=0;
private File dbBaseDir;
- private NodeManager nmgr;
private String dbHome;
- public DbWrapper (String dbHome, String dbFilename, NodeManager nmgr, boolean useTx) throws DbException {
-
- this.dbHome = dbHome;
- this.nmgr = nmgr;
+ public DbWrapper (String dbHome, String dbFilename, boolean useTx) throws DbException {
try {
+
+ this.dbHome = dbHome;
dbBaseDir = new File (dbHome);
if (!dbBaseDir.exists())
dbBaseDir.mkdirs();
@@ -73,12 +71,12 @@ public class DbWrapper {
loaded = true;
} catch (NoClassDefFoundError noclass) {
- nmgr.app.logEvent ("Warning: Using internal file based db as fallback.");
- nmgr.app.logEvent ("Reason: "+noclass);
+ Server.getLogger().log ("Warning: Using internal file based db as fallback.");
+ Server.getLogger().log ("Reason: "+noclass);
loaded = false;
} catch (UnsatisfiedLinkError nolib) {
- nmgr.app.logEvent ("Warning: Using internal file based db as fallback.");
- nmgr.app.logEvent ("Reason: "+nolib);
+ Server.getLogger().log ("Warning: Using internal file based db as fallback.");
+ Server.getLogger().log ("Reason: "+nolib);
loaded = false;
}
@@ -91,7 +89,7 @@ public class DbWrapper {
// closing the dbenv leads to segfault when app is restarted
// dbenv.close (0);
// dbenv.remove (dbHome, Db.DB_FORCE);
- nmgr.app.logEvent ("Closed Berkeley DB");
+ Server.getLogger ().log ("Closed Berkeley DB");
}
}
@@ -128,7 +126,7 @@ public class DbWrapper {
dbenv.txn_checkpoint (0, 0, 0); // for berkeley 3.0, remove third 0 parameter
txncount = 0;
lastCheckpoint = now;
- nmgr.app.logEvent ("Spent "+(System.currentTimeMillis()-now)+" in checkpoint");
+ Server.getLogger().log ("Spent "+(System.currentTimeMillis()-now)+" in checkpoint");
}
public IDGenerator getIDGenerator (DbTxn txn, String kstr) throws Exception {
@@ -222,7 +220,7 @@ public class DbWrapper {
value.set_size (vbuf.length);
db.put (txn, key, value, 0);
- // nmgr.app.logEvent ("saved "+obj+", size = "+vbuf.length);
+ // IServer.getLogger().log ("saved "+obj+", size = "+vbuf.length);
}
private void deleteFromDB (DbTxn txn, String kstr) throws Exception {
diff --git a/src/helma/objectmodel/db/ExternalizableVector.java b/src/helma/objectmodel/db/ExternalizableVector.java
index bcea489d..71f30a1d 100644
--- a/src/helma/objectmodel/db/ExternalizableVector.java
+++ b/src/helma/objectmodel/db/ExternalizableVector.java
@@ -4,14 +4,14 @@
package helma.objectmodel.db;
import java.io.*;
-import java.util.ArrayList;
+import java.util.*;
/**
* A subclass of Vector that implements the Externalizable interface in order
* to be able to control how it is serialized and deserialized.
*/
-public class ExternalizableVector extends ArrayList implements Externalizable {
+public class ExternalizableVector extends Vector implements Externalizable {
static final long serialVersionUID = 2316243615310540423L;
@@ -19,7 +19,7 @@ public class ExternalizableVector extends ArrayList implements Externalizable {
try {
int size = in.readInt ();
for (int i=0; i= 3)
+ else if (version == 3)
prototype = (String) in.readObject ();
- // if the input version is < 5, we have to do some conversion to make this object work
- if (version < 5) {
- if (rawParentID != null)
- parentHandle = new NodeHandle (new DbKey (null, rawParentID));
- if (subnodes != null) {
- for (int i=0; i 0) {
- setName (propvalue);
- anonymous = false;
- // nameProp = localrel.propName;
- } else {
- anonymous = true;
- }
+ if (anonymous && parentmap != null) {
+ Relation prel = parentmap.getPropertyRelation();
+ if (prel != null && prel.subnodesAreProperties && !prel.usesPrimaryKey ()) try {
+ Relation localrel = dbmap.columnNameToProperty (prel.getRemoteField ());
+ String propvalue = getString (localrel.propname, false);
+ if (propvalue != null && propvalue.length() > 0) {
+ setName (propvalue);
+ anonymous = false;
+ // nameProp = localrel.propname;
}
- } catch (Exception ignore) {
- // just fall back to default method
- }
+ } catch (Exception ignore) {} // just fall back to ID
}
return anonymous || name == null || name.length() == 0 ? id : name;
}
@@ -484,7 +440,7 @@ public final class Node implements INode, Serializable {
b.insert (0, divider);
else
divider = "/";
- b.insert (0, p.getElementName ());
+ b.insert (0, p.getNameOrID ());
p = p.getParent ();
loopWatch++;
@@ -496,6 +452,24 @@ public final class Node implements INode, Serializable {
return b.toString ();
}
+ public INode[] getPath () {
+ int pathSize = 1;
+ INode p = getParent ();
+
+ while (p != null) {
+ pathSize +=1;
+ p = p.getParent ();
+ if (pathSize > 100) // sanity check
+ break;
+ }
+ INode path[] = new INode[pathSize];
+ p = this;
+ for (int i = pathSize-1; i>=0; i--) {
+ path[i] = p;
+ p = p.getParent ();
+ }
+ return path;
+ }
public String getPrototype () {
if (prototype == null && propMap != null) {
@@ -515,7 +489,8 @@ public final class Node implements INode, Serializable {
public void setDbMapping (DbMapping dbmap) {
if (this.dbmap != dbmap) {
this.dbmap = dbmap;
- // primaryKey = null;
+ primaryKey = null;
+ ((Transactor) Thread.currentThread()).visitCleanNode (this);
}
}
@@ -524,23 +499,11 @@ public final class Node implements INode, Serializable {
}
public Key getKey () {
- if (state == TRANSIENT) {
- Thread.dumpStack ();
- throw new RuntimeException ("getKey called on transient Node: "+this);
- }
- if (dbmap == null && prototype != null && nmgr != null)
- dbmap = nmgr.getDbMapping (prototype);
if (primaryKey == null)
- primaryKey = new DbKey (dbmap, id);
+ primaryKey = new Key (dbmap, id);
return primaryKey;
}
- public NodeHandle getHandle () {
- if (handle == null)
- handle = new NodeHandle (this);
- return handle;
- }
-
public void setSubnodeRelation (String rel) {
if ((rel == null && this.subnodeRelation == null)
|| (rel != null && rel.equalsIgnoreCase (this.subnodeRelation)))
@@ -561,8 +524,7 @@ public final class Node implements INode, Serializable {
public void setName (String name) {
// "/" is used as delimiter, so it's not a legal char
if (name.indexOf('/') > -1)
- return;
- // throw new RuntimeException ("The name of the node must not contain \"/\".");
+ throw new RuntimeException ("The name of the node must not contain \"/\".");
if (name == null || name.trim().length() == 0)
this.name = id; // use id as name
else
@@ -574,7 +536,8 @@ public final class Node implements INode, Serializable {
* the ID + DB map combo.
*/
public void setParent (Node parent) {
- parentHandle = parent == null ? null : parent.getHandle ();
+ this.parentID = parent == null ? null : parent.getID();
+ this.parentmap = parent == null ? null : parent.getDbMapping();
}
/**
@@ -584,31 +547,32 @@ public final class Node implements INode, Serializable {
*/
public void setParent (Node parent, String propertyName) {
// we only do that for relational nodes.
- if (!isRelational ())
+ if (dbmap == null || !dbmap.isRelational ())
return;
- NodeHandle oldParentHandle = parentHandle;
- parentHandle = parent == null ? null : parent.getHandle ();
- // mark parent as set, otherwise getParent will try to
- // determine the parent again when called.
- lastParentSet = System.currentTimeMillis ();
- if (parentHandle == null || parentHandle.equals (oldParentHandle))
+ String oldParentID = parentID;
+ parentID = parent == null ? null : parent.getID();
+ parentmap = parent == null ? null : parent.getDbMapping();
+
+ if (parentID == null || parentID.equals (oldParentID))
// nothing changed, no need to find access property
return;
- if (parent != null && propertyName == null) {
+ if (propertyName == null) {
// see if we can find out the propertyName by ourselfes by looking at the
// parent's property relation
String newname = null;
- DbMapping parentmap = parent.getDbMapping ();
if (parentmap != null) {
// first try to retrieve name via generic property relation of parent
Relation prel = parentmap.getPropertyRelation ();
- if (prel != null && prel.otherType == dbmap && prel.accessor != null) {
+ if (prel != null && prel.other == dbmap && prel.direction == Relation.DIRECT) {
// reverse look up property used to access this via parent
- Relation proprel = dbmap.columnNameToRelation (prel.accessor);
- if (proprel != null && proprel.propName != null)
- newname = getString (proprel.propName, false);
+ String dbfield = prel.getRemoteField ();
+ if (dbfield != null) {
+ Relation proprel = (Relation) dbmap.db2prop.get (dbfield);
+ if (proprel != null && proprel.propname != null)
+ newname = getString (proprel.propname, false);
+ }
}
}
@@ -626,66 +590,31 @@ public final class Node implements INode, Serializable {
}
- /**
- * Get parent, retrieving it if necessary.
- */
public INode getParent () {
// check what's specified in the type.properties for this node.
- ParentInfo[] parentInfo = null;
- if (isRelational () && (lastParentSet < dbmap.getLastTypeChange() || lastParentSet < lastmodified))
- parentInfo = dbmap.getParentInfo ();
+ String[] parentProps = null;
+ if (dbmap != null && dbmap.isRelational ())
+ parentProps = dbmap.getParentPropNames ();
// check if current parent candidate matches presciption, if not, try to get it
- if (parentInfo != null && state != TRANSIENT) {
- for (int i=0; i i)
+ anonymous = ano[i].booleanValue();
+ return pn;
}
}
}
// fall back to heuristic parent (the node that fetched this one from db)
- if (parentHandle == null)
+ if (parentID == null)
return null;
- return parentHandle.getNode (nmgr);
- }
-
-
- /**
- * Get parent, using cached info if it exists.
- */
- public Node getCachedParent () {
- if (parentHandle == null)
- return null;
- return parentHandle.getNode (nmgr);
+ return nmgr.getNode (parentID, parentmap);
}
@@ -703,25 +632,19 @@ public final class Node implements INode, Serializable {
if (elem instanceof Node)
node = (Node) elem;
else
- throw new RuntimeException ("Can't add fixed-transient node to a persistent node");
-
- // only lock node if it has to be modified for a change in subnodes
- if (!ignoreSubnodeChange ())
- checkWriteLock ();
- node.checkWriteLock ();
-
- // if subnodes are defined via realation, make sure its constraints are enforced.
- if (dbmap != null && dbmap.getSubnodeRelation () != null)
- dbmap.getSubnodeRelation ().setConstraints (this, node);
-
+ node = convert (elem);
// if the new node is marked as TRANSIENT and this node is not, mark new node as NEW
if (state != TRANSIENT && node.state == TRANSIENT)
node.makePersistentCapable ();
String n = node.getName();
-
- // if (n.indexOf('/') > -1)
- // throw new RuntimeException ("\"/\" found in Node name.");
+ if (n.indexOf('/') > -1)
+ throw new RuntimeException ("\"/\" found in Node name.");
+
+ // only lock node if it has to be modified for a change in subnodes
+ if (!ignoreSubnodeChange ())
+ checkWriteLock ();
+ node.checkWriteLock ();
// only mark this node as modified if subnodes are not in relational db
// pointing to this node.
@@ -736,16 +659,16 @@ public final class Node implements INode, Serializable {
if (dbmap != null) {
Relation srel = dbmap.getSubnodeRelation ();
if (srel != null && srel.groupby != null) try {
- Relation groupbyRel = srel.otherType.columnNameToRelation (srel.groupby);
+ Relation groupbyRel = (Relation) srel.other.db2prop.get (srel.groupby);
String groupbyProp = (groupbyRel != null) ?
- groupbyRel.propName : srel.groupby;
+ groupbyRel.propname : srel.groupby;
String groupbyValue = node.getString (groupbyProp, false);
INode groupbyNode = getNode (groupbyValue, false);
// if group-by node doesn't exist, we'll create it
if (groupbyNode == null)
groupbyNode = getGroupbySubnode (groupbyValue, true);
groupbyNode.addNode (node);
-
+ checkBackLink (node);
return node;
} catch (Exception x) {
System.err.println ("Error adding groupby: "+x);
@@ -757,25 +680,30 @@ public final class Node implements INode, Serializable {
if (where < 0 || where > numberOfNodes ())
where = numberOfNodes ();
+ if (node.getParent () != null) {
+ // this makes the job of addLink, which means that addLink and addNode
+ // are functionally equivalent now.
+ if (node.getParent () != this || !node.anonymous) {
+ node.registerLink (this);
+ }
+ }
- NodeHandle nhandle = node.getHandle ();
- if (subnodes != null && subnodes.contains (nhandle)) {
+ if (subnodes != null && subnodes.contains (node.getID ())) {
// Node is already subnode of this - just move to new position
- subnodes.remove (nhandle);
+ subnodes.removeElement (node.getID ());
where = Math.min (where, numberOfNodes ());
- subnodes.add (where, nhandle);
+ subnodes.insertElementAt (node.getID (), where);
} else {
- if (subnodes == null)
- subnodes = new ExternalizableVector ();
- subnodes.add (where, nhandle);
+ if (subnodes == null) subnodes = new ExternalizableVector ();
+ subnodes.insertElementAt (node.getID (), where);
// check if properties are subnodes (_properties.aresubnodes=true)
if (dbmap != null && node.dbmap != null) {
Relation prel = dbmap.getPropertyRelation();
- if (prel != null && prel.accessor != null) {
- Relation localrel = node.dbmap.columnNameToRelation (prel.accessor);
+ if (prel != null && prel.subnodesAreProperties && !prel.usesPrimaryKey ()) {
+ Relation localrel = node.dbmap.columnNameToProperty (prel.getRemoteField ());
// if no relation from db column to prop name is found, assume that both are equal
- String propname = localrel == null ? prel.accessor : localrel.propName;
+ String propname = localrel == null ? prel.getRemoteField() : localrel.propname;
String prop = node.getString (propname, false);
if (prop != null && prop.length() > 0) {
INode old = getNode (prop, false);
@@ -783,38 +711,47 @@ public final class Node implements INode, Serializable {
unset (prop);
removeNode (old);
}
+ // throw new RuntimeException ("Property "+prop+" is already defined for "+this);
setNode (prop, node);
}
}
}
- if (!"root".equalsIgnoreCase (node.getPrototype ())) {
- // avoid calling getParent() because it would return bogus results for the not-anymore transient node
- Node nparent = node.parentHandle == null ? null : node.parentHandle.getNode (nmgr);
- // if the node doesn't have a parent yet, or it has one but it's transient while we are
- // persistent, make this the nodes new parent.
- if (nparent == null || (state != TRANSIENT && nparent.getState () == TRANSIENT)) {
- node.setParent (this);
- node.anonymous = true;
- } else if (nparent != null && (nparent != this || !node.anonymous)) {
- // this makes the additional job of addLink, registering that we have a link to a node in our
- // subnodes that actually sits somewhere else. This means that addLink and addNode
- // are actually the same now.
- node.registerLinkFrom (this);
- }
+ if (node.getParent () == null && !"root".equalsIgnoreCase (node.getPrototype ())) {
+ node.setParent (this);
+ node.anonymous = true;
}
}
+ checkBackLink (node);
+
lastmodified = System.currentTimeMillis ();
lastSubnodeChange = lastmodified;
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_ADDED, node));
return node;
}
+ private void checkBackLink (Node node) {
+ // check if the subnode is in relational db and needs to link back to this
+ // in order to make it a subnode
+ if (dbmap != null) {
+ Relation srel = dbmap.getSubnodeRelation ();
+ if (srel != null && srel.direction == Relation.BACKWARD) {
+ Relation backlink = srel.other.columnNameToProperty (srel.getRemoteField());
+ if (backlink != null && backlink.propname != null) {
+ if (node.get (backlink.propname, false) == null) {
+ if (this.state == VIRTUAL)
+ node.setString (backlink.propname, getNonVirtualHomeID());
+ else
+ node.setString (backlink.propname, getID());
+ }
+ }
+ }
+ }
+ }
public INode createNode () {
- // create new node at end of subnode array
- return createNode (null, numberOfNodes ());
+ return createNode (null, numberOfNodes ()); // create new node at end of subnode array
}
public INode createNode (int where) {
@@ -831,7 +768,7 @@ public final class Node implements INode, Serializable {
boolean anon = false;
if (nm == null || "".equals (nm.trim ()))
anon = true;
- Node n = new Node (nm, null, nmgr);
+ Node n = new Node (nm, nmgr);
if (anon)
addNode (n, where);
else
@@ -841,101 +778,78 @@ public final class Node implements INode, Serializable {
/**
- * register a node that links to this node so we can notify it when we cease to exist.
- * this is only necessary if we are a non-relational node, since for relational nodes
- * the referring object will notice that we've gone at runtime.
+ * register a node that links to this node.
*/
- protected void registerLinkFrom (Node from) {
- if (isRelational ())
- return;
- if (from.getState () == TRANSIENT)
- return;
+ protected void registerLink (Node from) {
if (links == null)
links = new ExternalizableVector ();
- Object fromHandle = from.getHandle ();
- if (!links.contains (fromHandle))
- links.add (fromHandle);
+ Object fromID = from.getID ();
+ if (!links.contains (fromID))
+ links.addElement (fromID);
}
- /**
- * This implements the getChild() method of the IPathElement interface
- */
- public IPathElement getChildElement (String name) {
- IPathElement child = (IPathElement) getSubnode (name);
- if (child == null)
- child = (IPathElement) getNode (name, false);
- return child;
- }
+ public INode getSubnode (String path) {
+ StringTokenizer st = new StringTokenizer (path, "/");
+ Node retval = this, runner;
- /**
- * This implements the getParentElement() method of the IPathElement interface
- */
- public IPathElement getParentElement () {
- return getParent ();
- }
+ while (st.hasMoreTokens () && retval != null) {
+ runner = retval;
+ String next = st.nextToken().trim().toLowerCase ();
+ if ("".equals (next)) {
+ retval = this;
+ } else {
+ runner.loadNodes ();
+ boolean found = runner.subnodes == null ? false : runner.subnodes.contains (next);
- public INode getSubnode (String subid) {
- // System.err.println ("GETSUBNODE : "+this+" > "+subid);
- if ("".equals (subid)) {
- return this;
- }
-
- Node retval = null;
-
- if (subid != null) {
-
- loadNodes ();
- if (subnodes == null || subnodes.size() == 0)
- return null;
-
- NodeHandle nhandle = null;
- int l = subnodes.size ();
- for (int i=0; i index) {
// check if there is a group-by relation
- retval = ((NodeHandle) subnodes.get (index)).getNode (nmgr);
-
- if (retval != null && retval.parentHandle == null && !"root".equalsIgnoreCase (retval.getPrototype ())) {
+ if (srel != null && srel.groupby != null)
+ retval = nmgr.getNode (this, (String) subnodes.elementAt (index), srel);
+ else
+ retval = nmgr.getNode ((String) subnodes.elementAt (index), smap);
+ if (retval != null && retval.parentID == null && !"root".equalsIgnoreCase (retval.getPrototype ())) {
retval.setParent (this);
retval.anonymous = true;
}
@@ -948,65 +862,67 @@ public final class Node implements INode, Serializable {
if (subnodes == null)
subnodes = new ExternalizableVector ();
- NodeHandle ghandle = new NodeHandle (new SyntheticKey (getKey(), sid));
- if (subnodes.contains (ghandle) || create) try {
- DbMapping groupbyMapping = dbmap.getGroupbyMapping ();
- boolean relational = groupbyMapping.getSubnodeMapping ().isRelational ();
+ if (subnodes.contains (sid) || create) try {
+ Relation srel = dbmap.getSubnodeRelation ();
+ Relation prel = dbmap.getPropertyRelation ();
+ boolean relational = srel.other != null && srel.other.isRelational ();
if (relational || create) {
- Node node = relational ? new Node (this, sid, nmgr, null) : new Node ("groupby-"+sid, null, nmgr);
+ Node node = relational ? new Node (this, sid, nmgr, null) : new Node ("groupby-"+sid, nmgr);
// set "groupname" property to value of groupby field
node.setString ("groupname", sid);
if (relational) {
- node.setDbMapping (groupbyMapping);
+ DbMapping dbm = new DbMapping ();
+ Relation gsrel = srel.getGroupbySubnodeRelation();
+ dbm.setSubnodeMapping (srel.other);
+ dbm.setSubnodeRelation (gsrel);
+ if (prel != null) {
+ dbm.setPropertyMapping (prel.other);
+ dbm.setPropertyRelation (prel.getGroupbyPropertyRelation());
+ }
+ node.setDbMapping (dbm);
+ String snrel = "WHERE "+srel.groupby +"='"+sid+"'";
+ if (gsrel.direction == Relation.BACKWARD)
+ snrel += " AND "+gsrel.getRemoteField()+"='"+getNonVirtualHomeID()+"'";
+ if (gsrel.order != null)
+ snrel += " ORDER BY "+gsrel.order;
+ node.setSubnodeRelation (snrel);
} else {
setNode (sid, node);
- subnodes.add (node.getHandle ());
+ subnodes.addElement (node.getID ());
}
- node.setPrototype (groupbyMapping.getTypeName ());
- nmgr.evictKey (node.getKey ());
return node;
}
} catch (Exception noluck) {
- nmgr.logEvent ("Error creating group-by node for "+sid+": "+noluck);
- noluck.printStackTrace();
+ IServer.getLogger ().log ("Error creating group-by node for "+sid+": "+noluck);
}
return null;
}
public boolean remove () {
checkWriteLock ();
- try {
- if (!anonymous)
- getParent ().unset (name);
- else
- getParent ().removeNode (this);
- } catch (Exception x) {
- return false;
- }
+ if (anonymous)
+ getParent ().unset (name);
+ else
+ getParent ().removeNode (this);
return true;
}
public void removeNode (INode node) {
- // nmgr.logEvent ("removing: "+ node);
+ IServer.getLogger().log ("removing: "+ node);
Node n = (Node) node;
checkWriteLock ();
n.checkWriteLock ();
-
- // need to query parent before releaseNode is called, since this may change the parent
- // to the next option described in the type.properties _parent info
- INode parent = n.getParent ();
releaseNode (n);
-
- if (parent == this) {
+ if (n.getParent () == this) {
n.deepRemoveNode ();
} else {
// removed just a link, not the main node.
if (n.links != null) {
- n.links.remove (getHandle ());
+ n.links.removeElement (this.id);
if (n.state == CLEAN) n.markAs (MODIFIED);
}
}
@@ -1018,7 +934,7 @@ public final class Node implements INode, Serializable {
*/
protected void releaseNode (Node node) {
if (subnodes != null)
- subnodes.remove (node.getHandle ());
+ subnodes.removeElement (node.getID ());
lastSubnodeChange = System.currentTimeMillis ();
@@ -1026,20 +942,20 @@ public final class Node implements INode, Serializable {
// which needs to be unset
if (dbmap != null) {
Relation srel = dbmap.getSubnodeRelation ();
- /*if (srel != null && srel.reftype == Relation.BACKWARD) {
- Relation backlink = srel.otherType.columnNameToRelation (srel.getRemoteField ());
- if (backlink != null && id.equals (node.getString (backlink.propName, false)))
- node.unset (backlink.propName);
- } */
+ if (srel != null && srel.direction == Relation.BACKWARD) {
+ Relation backlink = srel.other.columnNameToProperty (srel.getRemoteField ());
+ if (backlink != null && id.equals (node.getString (backlink.propname, false)))
+ node.unset (backlink.propname);
+ }
}
- // check if subnodes are also accessed as properties. If so, also unset the property
+ // check if subnodes are handled as virtual fs
if (dbmap != null && node.dbmap != null) {
Relation prel = dbmap.getPropertyRelation();
- if (prel != null && prel.accessor != null) {
- Relation localrel = node.dbmap.columnNameToRelation (prel.accessor);
+ if (prel != null && prel.subnodesAreProperties && !prel.usesPrimaryKey ()) {
+ Relation localrel = node.dbmap.columnNameToProperty (prel.getRemoteField());
// if no relation from db column to prop name is found, assume that both are equal
- String propname = localrel == null ? prel.accessor : localrel.propName;
+ String propname = localrel == null ? prel.getRemoteField () : localrel.propname;
String prop = node.getString (propname, false);
if (prop != null && getNode (prop, false) == node)
unset (prop);
@@ -1053,7 +969,7 @@ public final class Node implements INode, Serializable {
// Server.throwNodeEvent (new NodeEvent (node, NodeEvent.NODE_REMOVED));
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_REMOVED, node));
lastmodified = System.currentTimeMillis ();
- // nmgr.logEvent ("released node "+node +" from "+this+" oldobj = "+what);
+ // IServer.getLogger().log ("released node "+node +" from "+this+" oldobj = "+what);
if (state == CLEAN) markAs (MODIFIED);
}
@@ -1064,13 +980,23 @@ public final class Node implements INode, Serializable {
*/
protected void deepRemoveNode () {
- // notify nodes that link to this node being deleted.
+ // notify nodes that link to this node that it is being deleted.
int l = links == null ? 0 : links.size ();
for (int i = 0; i < l; i++) {
- NodeHandle lhandle = (NodeHandle) links.get (i);
- Node link = lhandle.getNode (nmgr);
- if (link != null)
- link.releaseNode (this);
+ // TODO: solve dbmap problem
+ Node link = nmgr.getNode ((String) links.elementAt (i), null);
+ if (link != null) link.releaseNode (this);
+ }
+
+ // clean up all nodes that use n as a property
+ if (proplinks != null) {
+ for (Enumeration e1 = proplinks.elements (); e1.hasMoreElements (); ) try {
+ String pid = (String) e1.nextElement ();
+ Node pnode = nmgr.getNode (pid, null);
+ if (pnode != null) {
+ IServer.getLogger().log("Warning: Can't unset node property of "+pnode.getFullName ());
+ }
+ } catch (Exception ignore) {}
}
// tell all nodes that are properties of n that they are no longer used as such
@@ -1086,16 +1012,16 @@ public final class Node implements INode, Serializable {
// the parent info is not 100% accurate for them.
if (subnodes != null) {
Vector v = new Vector ();
- // remove modifies the Vector we are enumerating, so we are extra careful.
+ // removeElement modifies the Vector we are enumerating, so we are extra careful.
for (Enumeration e3 = getSubnodes (); e3.hasMoreElements(); ) {
- v.add (e3.nextElement());
+ v.addElement (e3.nextElement());
}
int m = v.size ();
for (int i=0; i= lastSubnodeFetch || subnodes == null) {
@@ -1201,7 +1124,7 @@ public final class Node implements INode, Serializable {
// return true if a change in subnodes can be ignored because it is
// stored in the subnodes themselves.
Relation rel = dbmap == null ? null : dbmap.getSubnodeRelation();
- return (rel != null && rel.otherType != null && rel.otherType.isRelational());
+ return (rel != null && rel.other != null && rel.other.isRelational() && rel.direction == Relation.BACKWARD);
}
/**
@@ -1209,17 +1132,13 @@ public final class Node implements INode, Serializable {
*/
public Enumeration properties () {
- if (dbmap != null && dbmap.getProp2DB ().size() > 0)
+ if (dbmap != null && dbmap.prop2db.size() > 0)
// return the properties defined in type.properties, if there are any
- return new Enumeration () {
- Iterator i = dbmap.getProp2DB().keySet().iterator();
- public boolean hasMoreElements() {return i.hasNext();}
- public Object nextElement () {return i.next();}
- };
+ return dbmap.prop2db.keys();
Relation prel = dbmap == null ? null : dbmap.getPropertyRelation ();
- if (prel != null && prel.accessor != null && !prel.subnodesAreProperties
- && prel.otherType != null && prel.otherType.isRelational ())
+ if (prel != null && prel.direction == Relation.DIRECT && !prel.subnodesAreProperties
+ && prel.other != null && prel.other.isRelational ())
// return names of objects from a relational db table
return nmgr.getPropertyNames (this, prel).elements ();
else if (propMap != null)
@@ -1240,11 +1159,11 @@ public final class Node implements INode, Serializable {
}
public String getParentInfo () {
- return "anonymous:"+anonymous+",parentHandle"+parentHandle+",parent:"+getParent();
+ return "anonymous:"+anonymous+",parentID:"+parentID+",parentmap:"+parentmap+",parent:"+getParent();
}
protected Property getProperty (String propname, boolean inherit) {
- // nmgr.logEvent ("GETTING PROPERTY: "+propname);
+ // IServer.getLogger().log ("GETTING PROPERTY: "+propname);
if (propname == null)
return null;
Property prop = propMap == null ? null : (Property) propMap.get (propname.toLowerCase ());
@@ -1254,59 +1173,45 @@ public final class Node implements INode, Serializable {
DbMapping pmap = dbmap == null ? null : dbmap.getExactPropertyMapping (propname);
if (pmap != null && prop != null && prop.type != IProperty.NODE) {
// this is a relational node stored by id but we still think it's just a string. fix it
- prop.nhandle = new NodeHandle (new DbKey (pmap, prop.getStringValue ()));
+ prop.nvalueID = prop.getStringValue ();
prop.type = IProperty.NODE;
}
- // the property does not exist in our propmap - see if we can create it on the fly,
- // either because it is mapped from a relational database or defined as virtual node
+
if (prop == null && dbmap != null) {
Relation prel = dbmap.getPropertyRelation (propname);
- Relation srel = dbmap.getSubnodeRelation ();
- if (prel == null && srel != null && srel.groupby != null)
- prel = srel;
if (prel == null)
prel = dbmap.getPropertyRelation ();
- if (prel != null) {
- // if what we want is a virtual node, fetch anyway.
- if (state == TRANSIENT && prel.virtual) {
- INode node = new Node (propname, prel.getPrototype (), nmgr);
- node.setDbMapping (prel.getVirtualMapping ());
- setNode (propname, node);
- prop = (Property) propMap.get (propname);
- // if this is from relational database only fetch if this node is itself persistent.
- } else if (state != TRANSIENT && (prel.virtual || prel.accessor != null || prel.groupby != null)) {
- // this may be a relational node stored by property name
- try {
- Node pn = nmgr.getNode (this, propname, prel);
- if (pn != null) {
- if (pn.parentHandle == null && !"root".equalsIgnoreCase (pn.getPrototype ())) {
- pn.setParent (this);
- pn.name = propname;
- pn.anonymous = false;
- }
- prop = new Property (propname, this, pn);
+ if (prel != null && (prel.direction == Relation.DIRECT || prel.virtual)) {
+ // this *may* be a relational node stored by property name
+ try {
+ Node pn = nmgr.getNode (this, propname, prel);
+ if (pn != null) {
+ if (pn.parentID == null && !"root".equalsIgnoreCase (pn.getPrototype ())) {
+ pn.setParent (this);
+ pn.name = propname;
+ pn.anonymous = false;
}
- } catch (RuntimeException nonode) {
- // wasn't a node after all
+ prop = new Property (propname, this, pn);
}
+ } catch (RuntimeException nonode) {
+ // wasn't a node after all
}
}
}
-
- if (prop == null && inherit && getParent () != null && state != TRANSIENT) {
+ if (prop == null && inherit && getParent () != null) {
prop = ((Node) getParent ()).getProperty (propname, inherit);
}
return prop;
}
- /* public String getString (String propname, String defaultValue, boolean inherit) {
+ public String getString (String propname, String defaultValue, boolean inherit) {
String propValue = getString (propname, inherit);
return propValue == null ? defaultValue : propValue;
- } */
+ }
public String getString (String propname, boolean inherit) {
- // propname = propname.toLowerCase ();
+ propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getStringValue ();
@@ -1315,7 +1220,7 @@ public final class Node implements INode, Serializable {
}
public long getInteger (String propname, boolean inherit) {
- // propname = propname.toLowerCase ();
+ propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getIntegerValue ();
@@ -1324,7 +1229,7 @@ public final class Node implements INode, Serializable {
}
public double getFloat (String propname, boolean inherit) {
- // propname = propname.toLowerCase ();
+ propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getFloatValue ();
@@ -1333,7 +1238,7 @@ public final class Node implements INode, Serializable {
}
public Date getDate (String propname, boolean inherit) {
- // propname = propname.toLowerCase ();
+ propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getDateValue ();
@@ -1343,7 +1248,7 @@ public final class Node implements INode, Serializable {
public boolean getBoolean (String propname, boolean inherit) {
- // propname = propname.toLowerCase ();
+ propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getBooleanValue ();
@@ -1352,7 +1257,7 @@ public final class Node implements INode, Serializable {
}
public INode getNode (String propname, boolean inherit) {
- // propname = propname.toLowerCase ();
+ propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getNodeValue ();
@@ -1361,7 +1266,7 @@ public final class Node implements INode, Serializable {
}
public Object getJavaObject (String propname, boolean inherit) {
- // propname = propname.toLowerCase ();
+ propname = propname.toLowerCase ();
Property prop = getProperty (propname, inherit);
try {
return prop.getJavaObjectValue ();
@@ -1370,7 +1275,7 @@ public final class Node implements INode, Serializable {
}
public void setString (String propname, String value) {
- // nmgr.logEvent ("setting String prop");
+ // IServer.getLogger().log ("setting String prop");
checkWriteLock ();
if (propMap == null)
@@ -1395,17 +1300,15 @@ public final class Node implements INode, Serializable {
}
// check if this may have an effect on the node's URL when using subnodesAreProperties
- // but only do this if we already have a parent set, i.e. if we are already stored in the db
- Node parent = parentHandle == null ? null : (Node) getParent ();
+ INode parent = getParent ();
- if (dbmap != null && parent != null && parent.getDbMapping() != null) {
+ if (parent != null && parent.getDbMapping() != null) {
// check if this node is already registered with the old name; if so, remove it.
// then set parent's property to this node for the new name value
- DbMapping parentmap = parent.getDbMapping ();
+ parentmap = parent.getDbMapping ();
Relation prel = parentmap.getPropertyRelation ();
- String dbcolumn = dbmap.propertyToColumnName (propname);
- if (prel != null && prel.accessor != null && prel.accessor.equals (dbcolumn)) {
+ if (prel != null && prel.subnodesAreProperties && propname.equals (prel.getRemoteField())) {
INode n = parent.getNode (value, false);
if (n != null && n != this) {
parent.unset (value);
@@ -1418,7 +1321,7 @@ public final class Node implements INode, Serializable {
parent.unset (oldvalue);
parent.addNode (this);
// let the node cache know this key's not for this node anymore.
- nmgr.evictKey (new SyntheticKey (parent.getKey (), oldvalue));
+ nmgr.evictKey (new Key (prel.other, prel.getKeyID (parent, oldvalue)));
}
}
parent.setNode (value, this);
@@ -1426,25 +1329,6 @@ public final class Node implements INode, Serializable {
}
}
- // check if the property we're setting specifies the prototype of this object.
- if (dbmap != null && dbmap.getPrototypeField () != null) {
- String pn = dbmap.columnNameToProperty (dbmap.getPrototypeField ());
- if (propname.equals (pn)) {
- DbMapping newmap = nmgr.getDbMapping (value);
- if (newmap != null) {
- // see if old and new prototypes have same storage - otherwise type change is ignored
- String oldStorage = dbmap.getStorageTypeName ();
- String newStorage = newmap.getStorageTypeName ();
- if ((oldStorage == null && newStorage == null) ||
- (oldStorage != null && oldStorage.equals (newStorage))) {
- dbmap.notifyDataChange ();
- newmap.notifyDataChange ();
- this.dbmap = newmap;
- this.prototype = value;
- }
- }
- }
- }
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis ();
@@ -1453,7 +1337,7 @@ public final class Node implements INode, Serializable {
}
public void setInteger (String propname, long value) {
- // nmgr.logEvent ("setting bool prop");
+ // IServer.getLogger().log ("setting bool prop");
checkWriteLock ();
if (propMap == null)
@@ -1476,7 +1360,7 @@ public final class Node implements INode, Serializable {
}
public void setFloat (String propname, double value) {
- // nmgr.logEvent ("setting bool prop");
+ // IServer.getLogger().log ("setting bool prop");
checkWriteLock ();
if (propMap == null)
@@ -1499,7 +1383,7 @@ public final class Node implements INode, Serializable {
}
public void setBoolean (String propname, boolean value) {
- // nmgr.logEvent ("setting bool prop");
+ // IServer.getLogger().log ("setting bool prop");
checkWriteLock ();
if (propMap == null)
@@ -1523,7 +1407,7 @@ public final class Node implements INode, Serializable {
public void setDate (String propname, Date value) {
- // nmgr.logEvent ("setting date prop");
+ // IServer.getLogger().log ("setting date prop");
checkWriteLock ();
if (propMap == null)
@@ -1546,7 +1430,7 @@ public final class Node implements INode, Serializable {
}
public void setJavaObject (String propname, Object value) {
- // nmgr.logEvent ("setting jobject prop");
+ // IServer.getLogger().log ("setting jobject prop");
checkWriteLock ();
if (propMap == null)
@@ -1569,25 +1453,14 @@ public final class Node implements INode, Serializable {
}
public void setNode (String propname, INode value) {
- // nmgr.logEvent ("setting node prop");
-
- // check if types match, otherwise throw exception
- DbMapping nmap = dbmap == null ? null : dbmap.getPropertyMapping (propname);
- if (nmap != null && nmap != value.getDbMapping()) {
- if (value.getDbMapping () == null)
- value.setDbMapping (nmap);
- else if (!nmap.isStorageCompatible (value.getDbMapping ()))
- throw new RuntimeException ("Can't set "+propname+" to object with prototype "+value.getPrototype()+", was expecting "+nmap.getTypeName());
- }
-
+ // IServer.getLogger().log ("setting node prop");
checkWriteLock ();
Node n = null;
if (value instanceof Node)
n = (Node) value;
else
- throw new RuntimeException ("Can't add fixed-transient node to a persistent node");
-
+ n = convert (value);
// if the new node is marked as TRANSIENT and this node is not, mark new node as NEW
if (state != TRANSIENT && n.state == TRANSIENT)
n.makePersistentCapable ();
@@ -1596,18 +1469,27 @@ public final class Node implements INode, Serializable {
// check if the main identity of this node is as a named property
// or as an anonymous node in a collection
- if (n.parentHandle == null && n.adoptName && !"root".equalsIgnoreCase (n.getPrototype ())) {
+ if (n.getParent () == null && n.adoptName && !"root".equalsIgnoreCase (n.getPrototype ())) {
n.setParent (this);
n.name = propname;
n.anonymous = false;
- }
+ // IServer.getLogger().log ("adopted named node: "+n.getFullName ());
+ } // else IServer.getLogger().log ("not adopted: "+n.getFullName ());
+ if (propMap == null)
+ propMap = new Hashtable ();
propname = propname.trim ();
String p2 = propname.toLowerCase ();
- Property prop = propMap == null ? null : (Property) propMap.get (p2);
+ DbMapping nmap = dbmap == null ? null : dbmap.getPropertyMapping (propname);
+ if (nmap != null && nmap != n.getDbMapping()) {
+ n.setDbMapping (nmap);
+ n.setPrototype (nmap.getTypeName ());
+ }
+
+ Property prop = (Property) propMap.get (p2);
if (prop != null) {
- if (prop.type == IProperty.NODE && n.getHandle ().equals (prop.nhandle)) {
+ if (prop.type == IProperty.NODE && n.getID ().equals (prop.nvalueID)) {
// nothing to do, just clean up locks and return
if (state == CLEAN) clearWriteLock ();
if (n.state == CLEAN) n.clearWriteLock ();
@@ -1619,40 +1501,23 @@ public final class Node implements INode, Serializable {
prop.setNodeValue (n);
Relation rel = dbmap == null ? null : dbmap.getPropertyRelation (propname);
-
- if (rel == null || rel.reftype == Relation.REFERENCE || rel.virtual ||
- rel.otherType == null || !rel.otherType.isRelational()) {
+ if (rel == null || rel.direction == Relation.FORWARD || rel.virtual || rel.other == null || !rel.other.isRelational()) {
// the node must be stored as explicit property
- if (propMap == null)
- propMap = new Hashtable ();
propMap.put (p2, prop);
- if (state == CLEAN) markAs (MODIFIED);
- }
-
- /* if (rel != null && rel.reftype == Relation.REFERENCE && !rel.usesPrimaryKey ()) {
- // if the relation for this property doesn't use the primary key of the value object, make a
- // secondary key object with the proper db column
- String kval = n.getString (rel.otherType.columnNameToProperty (rel.getRemoteField ()), false);
- prop.nhandle = new NodeHandle (new DbKey (n.getDbMapping (), kval, rel.getRemoteField ()));
- } */
-
- // don't check node in transactor cache if node is transient -
- // this is done anyway when the node becomes persistent.
- if (n.state != TRANSIENT) {
- // check node in with transactor cache
- String nID = n.getID();
- DbMapping dbm = n.getDbMapping ();
- Transactor tx = (Transactor) Thread.currentThread ();
- tx.visitCleanNode (new DbKey (dbm, nID), n);
- // if the field is not the primary key of the property, also register it
- if (rel != null && rel.accessor != null && state != TRANSIENT) {
- Key secKey = new SyntheticKey (getKey (), propname);
- nmgr.evictKey (secKey);
- tx.visitCleanNode (secKey, n);
- }
- }
+ }
+ String nID = n.getID();
+ // check node in with transactor cache
+ Transactor tx = (Transactor) Thread.currentThread ();
+ tx.visitCleanNode (new Key (nmap, nID), n);
+ // if the field is not the primary key of the property, also register it
+ if (rel != null && !rel.getKeyID(this, p2).equals (nID))
+ tx.visitCleanNode (new Key (rel.other, rel.getKeyID(this, p2)), n);
+
+ // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_ADDED, n));
+ // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis ();
+ if (state == CLEAN) markAs (MODIFIED);
if (n.state == DELETED) n.markAs (MODIFIED);
}
@@ -1677,6 +1542,200 @@ public final class Node implements INode, Serializable {
} catch (Exception ignore) {}
}
+ protected void registerPropLink (INode n) {
+ if (proplinks == null)
+ proplinks = new ExternalizableVector ();
+ String plid = n.getID ();
+ if (!proplinks.contains (plid))
+ proplinks.addElement (n.getID ());
+ if (state == CLEAN || state == DELETED)
+ markAs (MODIFIED);
+ }
+
+ protected void unregisterPropLink (INode n) {
+ if (proplinks != null)
+ proplinks.removeElement (n.getID ());
+ // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.NODE_REMOVED));
+ // Server.throwNodeEvent (new NodeEvent (n, NodeEvent.SUBNODE_REMOVED, this));
+ if (state == CLEAN)
+ markAs (MODIFIED);
+ }
+
+
+ public void sanityCheck () {
+ checkSubnodes ();
+ checkProperties ();
+ checkLinks ();
+ checkPropLinks ();
+ if (getParent () == null && !"root".equals (name)) {
+ System.out.println ("*** parent: "+parentID+": "+this.getName ());
+ }
+ }
+
+
+ private void checkLinks () {
+ Vector v = links == null ? null : (Vector) links.clone ();
+ int l = v == null ? 0 : v.size ();
+ for (int i = 0; i < l; i++) {
+ String k = (String) v.elementAt (i);
+ Node link = nmgr.getNode (k, null);
+ if (link == null) {
+ links.removeElement (k);
+ System.out.println ("**** link "+k+": "+this.getFullName ());
+ markAs (MODIFIED);
+ }
+ }
+ }
+
+ private void checkPropLinks () {
+ Vector v = proplinks == null ? null : (Vector) proplinks.clone ();
+ int l = v == null ? 0 : v.size ();
+ for (int i = 0; i < l; i++) {
+ String k = (String) v.elementAt (i);
+ Node link = nmgr.getNode (k, null);
+ if (link == null) {
+ proplinks.removeElement (k);
+ System.out.println ("**** proplink "+k+": "+this.getFullName ());
+ markAs (MODIFIED);
+ }
+ }
+ }
+
+ private void checkSubnodes () {
+ Vector v = subnodes == null ? null : (Vector) subnodes.clone ();
+ int l = v == null ? 0 : v.size ();
+ for (int i = 0; i < l; i++) {
+ String k = (String) v.elementAt (i);
+ Node link = nmgr.getNode (k, null);
+ if (link == null) {
+ subnodes.removeElement (k);
+ System.out.println ("**** subnode "+k+": "+this.getFullName ());
+ markAs (MODIFIED);
+ }
+ }
+ }
+
+ private void checkProperties () {
+ Hashtable ht = propMap == null ? new Hashtable () : (Hashtable) propMap.clone ();
+ for (Enumeration ps = ht.elements (); ps.hasMoreElements (); ) {
+ Property p = (Property) ps.nextElement ();
+ if (p.getType () == IProperty.NODE && p.getNodeValue () == null) {
+ System.out.println ("**** property "+p.propname+"->"+p.nvalueID+": "+this.getFullName ());
+ // INode par = getParent ();
+ // if (par != null)
+ // par.removeNode (this);
+ // markAs (DELETED);
+ }
+ }
+
+ }
+
+ /**
+ * content-related
+ */
+
+ public boolean isText () throws IOException {
+ return getContentType().indexOf ("text/") == 0;
+ }
+
+ public boolean isBinary () throws IOException {
+ return getContentType().indexOf ("text/") != 0;
+ }
+
+ public String getContentType () {
+ if (contentType == null)
+ return "text/plain";
+ return contentType;
+ }
+
+ public void setContentType (String type) {
+ checkWriteLock ();
+ contentType = type;
+ lastmodified = System.currentTimeMillis ();
+ if (state == CLEAN) markAs (MODIFIED);
+ }
+
+ public int getContentLength () {
+ if (content == null)
+ return 0;
+ return content.length;
+ }
+
+ public void setContent (byte cnt[], String type) {
+ checkWriteLock ();
+
+ if (type != null)
+ contentType = type;
+ content = cnt;
+ lastmodified = System.currentTimeMillis ();
+ // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.CONTENT_CHANGED));
+ if (state == CLEAN) markAs (MODIFIED);
+ }
+
+
+ public void setContent (String cstr) {
+ checkWriteLock ();
+
+ content = cstr.getBytes ();
+ lastmodified = System.currentTimeMillis ();
+ // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.CONTENT_CHANGED));
+ if (state == CLEAN) markAs (MODIFIED);
+ }
+
+ public byte[] getContent () {
+
+ if (content == null || content.length == 0)
+ return "".getBytes ();
+
+ byte retval[] = new byte[content.length];
+ System.arraycopy (content, 0, retval, 0, content.length);
+ // IServer.getLogger().log ("copied "+retval.length+ " bytes");
+ return retval;
+ }
+
+ public String getText () {
+ if (content != null) {
+ if (getContentType ().startsWith ("text/")) {
+ return new String (content);
+ } else {
+ return null;
+ }
+ }
+ return null;
+ }
+
+
+ public String getHref (INode root, INode userroot, String tmpname, String prefix) {
+ return prefix + getUrl (root, userroot, tmpname);
+ }
+
+
+ /**
+ * Get the path to eiter the general data-root or the user root, depending on
+ * where this node is located.
+ */
+ public String getUrl (INode root, INode userroot, String tmpname) {
+ // String fullname = "";
+ String divider = "/";
+ StringBuffer b = new StringBuffer ();
+ INode p = this;
+ int loopWatch = 0;
+ while (p != null && p.getParent () != null && p != root && p != userroot) {
+ b.insert (0, divider);
+ b.insert (0, UrlEncoder.encode (p.getNameOrID ()));
+
+ if ("user".equals (p.getPrototype ())) {
+ b.insert (0, "users"+divider);
+ break;
+ }
+ p = p.getParent ();
+
+ if (loopWatch++ > 10)
+ break;
+ }
+ return b.toString()+UrlEncoder.encode (tmpname);
+ }
+
public long lastModified () {
return lastmodified;
}
@@ -1689,106 +1748,63 @@ public final class Node implements INode, Serializable {
return "HopObject " + name;
}
- /**
- * Tell whether this node is stored inside a relational db. This doesn't mean
- * it actually is stored in a relational db, just that it would be, if the node was
- * persistent
- */
- public boolean isRelational () {
- return dbmap != null && dbmap.isRelational ();
- }
+ /**
+ * Recursively convert other implementations of INode into helma.objectmodel.db.Node.
+ */
+ protected Node convert (INode n) {
+ Hashtable ntable = new Hashtable ();
+ Node converted = new Node (n, ntable, false, nmgr);
+ return converted;
+ }
/**
* Recursively turn node status from TRANSIENT to NEW so that the Transactor will
* know it has to insert this node.
*/
protected void makePersistentCapable () {
- if (state == TRANSIENT) {
- state = NEW;
- // generate a real, persistent ID for this object
- id = nmgr.generateID (dbmap);
- getHandle ().becomePersistent ();
- Transactor current = (Transactor) Thread.currentThread ();
- current.visitNode (this);
- current.visitCleanNode (this);
- for (Enumeration e = getSubnodes (); e.hasMoreElements (); ) {
- Node n = (Node) e.nextElement ();
- if (n.state == TRANSIENT)
+ for (Enumeration e = getSubnodes (); e.hasMoreElements (); ) {
+ Node n = (Node) e.nextElement ();
+ if (n.state == TRANSIENT)
+ n.makePersistentCapable ();
+ }
+ for (Enumeration e = properties (); e.hasMoreElements (); ) {
+ IProperty next = get ((String) e.nextElement (), false);
+ if (next != null && next.getType () == IProperty.NODE) {
+ Node n = (Node) next.getNodeValue ();
+ if (n != null && n.state == TRANSIENT)
n.makePersistentCapable ();
}
- for (Enumeration e = properties (); e.hasMoreElements (); ) {
- IProperty next = get ((String) e.nextElement (), false);
- if (next != null && next.getType () == IProperty.NODE) {
- Node n = (Node) next.getNodeValue ();
- if (n != null && n.state == TRANSIENT)
- n.makePersistentCapable ();
- }
- }
}
+ state = NEW;
}
/**
- * Get the cache node for this node. This can be
- * used to store transient cache data per node from Javascript.
+ * Get the cache node for this node. This can be used to store transient cache data per node from Javascript.
*/
public synchronized INode getCacheNode () {
if (cacheNode == null)
- cacheNode = new TransientNode();
+ cacheNode = new helma.objectmodel.Node();
return cacheNode;
}
- /**
- * Reset the cache node for this node.
- */
- public synchronized void clearCacheNode () {
- cacheNode = null;
- }
-
-
- /**
- * This method walks down node path to the first non-virtual node and return it.
- * limit max depth to 3, since there shouldn't be more then 2 layers of virtual nodes.
- */
- public INode getNonVirtualParent () {
+ // walk down node path to the first non-virtual node and return its id.
+ // limit max depth to 3, since there shouldn't be more then 2 layers of virtual nodes.
+ public String getNonVirtualHomeID () {
INode node = this;
for (int i=0; i<3; i++) {
if (node == null) break;
if (node.getState() != Node.VIRTUAL)
- return node;
+ return node.getID ();
node = node.getParent ();
}
return null;
}
-
- /**
- * Instances of this class may be used to mark an entry in the object cache as null.
- * This method tells the caller whether this is the case.
- */
- public boolean isNullNode () {
- return nmgr == null;
- }
-
- /**
- * We overwrite hashCode to make it dependant from the prototype. That way, when the prototype
- * changes, the node will automatically get a new ESNode wrapper, since they're cached in a hashtable.
- * You gotta love these hash code tricks ;-)
- */
- public int hashCode () {
- if (prototype == null)
- return super.hashCode ();
- else
- return super.hashCode () + prototype.hashCode ();
- }
-
- public void dump () {
- System.err.println ("subnodes: "+subnodes);
- System.err.println ("properties: "+propMap);
- System.err.println ("links: "+links);
+ public void dumpSubnodes () {
+ System.err.println (subnodes);
}
}
-
diff --git a/src/helma/objectmodel/db/NodeHandle.java b/src/helma/objectmodel/db/NodeHandle.java
deleted file mode 100644
index 3908d0e3..00000000
--- a/src/helma/objectmodel/db/NodeHandle.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// NodeHandle.java
-// Copyright (c) Hannes Wallnöfer 1998-2000
-
-package helma.objectmodel.db;
-
-import helma.objectmodel.*;
-import java.io.Serializable;
-
-/**
- * This class is a handle or reference to a Node. This is to abstract from different
- * methods of reference: Transient Nodes are referred to directly, while persistent
- * nodes are referred to via key/node manager.
- *
- * A handle is used to refer to a node in a safe way over a longer period.
- * While a direct reference may point to a node that has been evicted from the cache
- * and reinstanciated since being set, NodeHandle will always return an up-to-date
- * instance of its node.
- */
-
-public final class NodeHandle implements INodeState, Serializable {
-
- // direct reference to the node
- private Node node;
-
- // the node's key
- private Key key;
-
- // cached DbMapping
- private transient DbMapping dbmap;
-
- static final long serialVersionUID = 3067763116576910931L;
-
- /**
- * Builds a handle for a node
- */
- public NodeHandle (Node node) {
- int state = node.getState ();
- if (state == TRANSIENT) {
- this.node = node;
- key = null;
- } else {
- this.node = null;
- key = node.getKey ();
- }
- }
-
- /**
- * Builds a handle given a node's retrieval information. At the time this is called,
- * the node is ususally not yet created. It will be fetched on demand when accessed by
- * application code.
- */
- public NodeHandle (Key key) {
- this.node = null;
- this.key = key;
- }
-
- /**
- * Get the node described by this node handle
- */
- public Node getNode (WrappedNodeManager nodemgr) {
- if (node != null)
- return node;
- return nodemgr.getNode (key);
- }
-
- /**
- * Get the key for the node described by this handle. This may only be called on persistent Nodes.
- */
- public Key getKey () {
- if (key == null)
- throw new RuntimeException ("getKey called on transient Node");
- return key;
- }
-
- /**
- * Get the ID for the node described by this handle. This may only be called on persistent Nodes.
- */
- public String getID () {
- if (key == null)
- return node.getID ();
- return key.getID ();
- }
-
- private Object getObject () {
- if (node != null)
- return node;
- else
- return key;
- }
-
- public boolean equals (Object other) {
- try {
- return getObject ().equals (((NodeHandle) other).getObject ());
- } catch (Exception x) {
- return false;
- }
- }
-
- /**
- * This is to notify the handle that the underlying node is becoming
- * persistent and we have to refer to it via the key from now on.
- */
- protected void becomePersistent () {
- if (node != null) {
- key = node.getKey ();
- node = null;
- }
- }
-
-
- public String toString () {
- if (node != null)
- return "NodeHandle[transient:"+node+"]";
- else
- return "NodeHandle["+key+"]";
- }
-
-}
-
diff --git a/src/helma/objectmodel/db/NodeManager.java b/src/helma/objectmodel/db/NodeManager.java
index 0021e732..c1e754b9 100644
--- a/src/helma/objectmodel/db/NodeManager.java
+++ b/src/helma/objectmodel/db/NodeManager.java
@@ -3,13 +3,16 @@
package helma.objectmodel.db;
+import java.io.*;
+import java.util.Vector;
+import java.util.Properties;
import helma.util.CacheMap;
import helma.objectmodel.*;
import helma.framework.core.Application;
import com.sleepycat.db.*;
import java.sql.*;
-import java.io.*;
-import java.util.*;
+import java.util.Vector;
+import java.util.Enumeration;
import com.workingdogs.village.*;
/**
@@ -20,12 +23,10 @@ import com.workingdogs.village.*;
public final class NodeManager {
- protected Application app;
+ private Application app;
private CacheMap cache;
- private Replicator replicator;
-
protected DbWrapper db;
protected IDGenerator idgen;
@@ -37,29 +38,15 @@ public final class NodeManager {
// a wrapper that catches some Exceptions while accessing this NM
public final WrappedNodeManager safe;
-
- /**
- * Create a new NodeManager for Application app. An embedded database will be
- * created in dbHome if one doesn't already exist.
- */
public NodeManager (Application app, String dbHome, Properties props) throws DbException {
this.app = app;
int cacheSize = Integer.parseInt (props.getProperty ("cachesize", "1000"));
// Make actual cache size bigger, since we use it only up to the threshold
// cache = new CacheMap ((int) Math.ceil (cacheSize/0.75f), 0.75f);
cache = new CacheMap (cacheSize, 0.75f);
- cache.setLogger (app.getLogger ("event"));
- app.logEvent ("set up node cache ("+cacheSize+")");
+ IServer.getLogger().log ("set up node cache ("+cacheSize+")");
safe = new WrappedNodeManager (this);
- // nullNode = new Node ();
-
- String replicationUrl = props.getProperty ("replicationUrl");
- if (replicationUrl != null) {
- replicator = new Replicator ();
- replicator.addUrl (replicationUrl);
- } else
- replicator = null;
// get the initial id generator value
String idb = props.getProperty ("idBaseValue");
@@ -68,7 +55,7 @@ public final class NodeManager {
idBaseValue = Math.max (1l, idBaseValue); // 0 and 1 are reserved for root nodes
} catch (NumberFormatException ignore) {}
- db = new DbWrapper (dbHome, helma.main.Server.dbFilename, this, helma.main.Server.useTransactions);
+ db = new DbWrapper (dbHome, Server.dbFilename, Server.useTransactions);
initDb ();
logSql = "true".equalsIgnoreCase(props.getProperty ("logsql"));
@@ -103,7 +90,6 @@ public final class NodeManager {
node.nmgr = safe;
} catch (ObjectNotFoundException notfound) {
node = new Node ("root", "0", "root", safe);
- node.setDbMapping (app.getDbMapping ("root"));
db.save (txn, node.getID (), node);
registerNode (node); // register node with nodemanager cache
}
@@ -113,7 +99,6 @@ public final class NodeManager {
node.nmgr = safe;
} catch (ObjectNotFoundException notfound) {
node = new Node ("users", "1", null, safe);
- node.setDbMapping (app.getDbMapping ("__userroot__"));
db.save (txn, node.getID (), node);
registerNode (node); // register node with nodemanager cache
}
@@ -130,23 +115,11 @@ public final class NodeManager {
}
- /**
- * Shut down this node manager. This is called when the application using this
- * node manager is stopped.
- */
public void shutdown () throws DbException {
db.shutdown ();
- if (cache != null) {
- synchronized (cache) {
- cache.clear ();
- cache = null;
- }
- }
+ this.cache = null;
}
- /**
- * Delete a node from the database.
- */
public void deleteNode (Node node) throws Exception {
if (node != null) {
String id = node.getID ();
@@ -159,16 +132,16 @@ public final class NodeManager {
}
- /**
- * Get a node by key.
- */
- public Node getNode (Key key) throws Exception {
+ public Node getNode (String kstr, DbMapping dbmap) throws Exception {
+
+ if (kstr == null)
+ return null;
Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNode "+kstr);
// it would be a good idea to reuse key objects one day.
- // Key key = new Key (dbmap, kstr);
+ Key key = new Key (dbmap, kstr);
// See if Transactor has already come across this node
Node node = tx.getVisitedNode (key);
@@ -184,22 +157,11 @@ public final class NodeManager {
// The requested node isn't in the shared cache. Synchronize with key to make sure only one
// version is fetched from the database.
- if (key instanceof SyntheticKey) {
- Node parent = getNode (key.getParentKey ());
- Relation rel = parent.dbmap.getPropertyRelation (key.getID());
- if (rel == null || rel.groupby != null)
- node = parent.getGroupbySubnode (key.getID (), true);
- else if (rel != null)
- node = getNode (parent, key.getID (), rel);
- else
- node = null;
- } else
- node = getNodeByKey (tx.txn, (DbKey) key);
-
+ node = getNodeByKey (db, tx.txn, kstr, dbmap);
if (node != null) {
synchronized (cache) {
Node oldnode = (Node) cache.put (node.getKey (), node);
- if (oldnode != null && !oldnode.isNullNode() && oldnode.getState () != Node.INVALID) {
+ if (oldnode != null && oldnode.getState () != Node.INVALID) {
cache.put (node.getKey (), oldnode);
node = oldnode;
}
@@ -216,9 +178,6 @@ public final class NodeManager {
}
- /**
- * Get a node by relation, using the home node, the relation and a key to apply.
- */
public Node getNode (Node home, String kstr, Relation rel) throws Exception {
if (kstr == null)
@@ -227,16 +186,13 @@ public final class NodeManager {
Transactor tx = (Transactor) Thread.currentThread ();
Key key = null;
- // check what kind of object we're looking for and make an apropriate key
- if (rel.virtual || rel.groupby != null || !rel.usesPrimaryKey())
- // a key for a virtually defined object that's never actually stored in the db
- // or a key for an object that represents subobjects grouped by some property, generated on the fly
- key = new SyntheticKey (home.getKey (), kstr);
+ // If what we want is a virtual node create a "synthetic" key
+ if (rel.virtual || rel.groupby != null)
+ key = new Key ((String) null, home.getKey ().getVirtualID (kstr));
+ // if a key for a node from within the DB
else
- // if a key for a node from within the DB
- // FIXME: This should never apply, since for every relation-based loading Synthetic Keys are used. Right?
- key = new DbKey (rel.otherType, kstr);
-
+ key = new Key (rel.other, rel.getKeyID (home, kstr));
+
// See if Transactor has already come across this node
Node node = tx.getVisitedNode (key);
@@ -244,36 +200,19 @@ public final class NodeManager {
// we used to refresh the node in the main cache here to avoid the primary key entry being
// flushed from cache before the secondary one (risking duplicate nodes in cache) but
// we don't need to since we fetched the node from the threadlocal transactor cache and
- // didn't refresh it in the main cache.
+ // didn't refresh it in the main cache.
return node;
}
// try to get the node from the shared cache
node = (Node) cache.get (key);
- // check if we can use the cached node without further checks.
- // we need further checks for subnodes fetched by name if the subnodes were changed.
- if (node != null && node.getState() != Node.INVALID && !rel.virtual && !rel.usesPrimaryKey ()) {
- // check if node is null node (cached null)
- if (node.isNullNode ()) {
- if (node.created() < rel.otherType.getLastDataChange ())
- node = null; // cached null not valid anymore
- // apply different consistency checks for groupby nodes and database nodes:
- // for group nodes, check if they're contained
- } else if (rel.groupby != null) {
- if (home.contains (node) < 0)
- node = null;
- // for database nodes, check if constraints are fulfilled
- } else if (!rel.checkConstraints (home, node)) {
- node = null;
- }
- }
-
if (node == null || node.getState() == Node.INVALID) {
// The requested node isn't in the shared cache. Synchronize with key to make sure only one
// version is fetched from the database.
- node = getNodeByRelation (tx.txn, home, kstr, rel);
+
+ node = getNodeByRelation (db, tx.txn, home, kstr, rel);
if (node != null) {
@@ -283,28 +222,15 @@ public final class NodeManager {
// check if node is already in cache with primary key
Node oldnode = (Node) cache.put (primKey, node);
// no need to check for oldnode != node because we fetched a new node from db
- if (oldnode != null && !oldnode.isNullNode() && oldnode.getState () != Node.INVALID) {
+ if (oldnode != null && oldnode.getState () != Node.INVALID) {
cache.put (primKey, oldnode);
- if (!keyIsPrimary) {
+ if (!keyIsPrimary)
cache.put (key, oldnode);
- }
node = oldnode;
- } else if (!keyIsPrimary) {
- // cache node with secondary key
+ } else if (!keyIsPrimary) // cache node with secondary key
cache.put (key, node);
- }
} // synchronized
- } else {
- // node fetched from db is null, cache result using nullNode
- synchronized (cache) {
- Node oldnode = (Node) cache.put (key, new Node ());
- // we ignore the case that onother thread has created the node in the meantime
- return null;
- }
}
- } else if (node.isNullNode ()) {
- // the nullNode caches a null value, i.e. an object that doesn't exist
- return null;
} else {
// update primary key in cache to keep it from being flushed, see above
if (!rel.usesPrimaryKey ()) {
@@ -327,17 +253,12 @@ public final class NodeManager {
return node;
}
- /**
- * Register a node in the node cache.
- */
+
public void registerNode (Node node) {
cache.put (node.getKey (), node);
}
- /**
- * Remove a node from the node cache. If at a later time it is accessed again, it will be
- * refetched from the database.
- */
+
public void evictNode (Node node) {
node.setState (INode.INVALID);
cache.remove (node.getKey ());
@@ -356,10 +277,6 @@ public final class NodeManager {
////////////////////////////////////////////////////////////////////////
- /**
- * Insert a new node in the embedded database or a relational database table, depending
- * on its db mapping.
- */
public void insertNode (DbWrapper db, DbTxn txn, Node node) throws Exception {
Transactor tx = (Transactor) Thread.currentThread ();
@@ -370,7 +287,7 @@ public final class NodeManager {
if (dbm == null || !dbm.isRelational ()) {
db.save (txn, node.getID (), node);
} else {
- app.logEvent ("inserting relational node: "+node.getID ());
+ IServer.getLogger().log ("inserting relational node: "+node.getID ());
TableDataSet tds = null;
try {
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
@@ -381,11 +298,10 @@ public final class NodeManager {
if (nameField != null)
rec.setValue (nameField, node.getName ());
- for (Iterator i=dbm.getProp2DB().entrySet().iterator(); i.hasNext(); ) {
- Map.Entry e = (Map.Entry) i.next ();
- String propname = (String) e.getKey ();
- Relation rel = (Relation) e.getValue ();
+ for (Enumeration e=dbm.prop2db.keys(); e.hasMoreElements(); ) {
+ String propname = (String) e.nextElement ();
Property p = node.getProperty (propname, false);
+ Relation rel = dbm.propertyToColumnName (propname);
if (p != null && rel != null) {
switch (p.getType ()) {
@@ -406,7 +322,7 @@ public final class NodeManager {
rec.setValue (rel.getDbField(), p.getFloatValue ());
break;
case IProperty.NODE:
- if (rel.reftype == Relation.REFERENCE) {
+ if (rel.direction == Relation.FORWARD) {
// INode n = p.getNodeValue ();
// String foreignID = n == null ? null : n.getID ();
rec.setValue (rel.getDbField(), p.getStringValue ());
@@ -418,26 +334,18 @@ public final class NodeManager {
rec.setValueNull (rel.getDbField());
}
}
-
- if (dbm.getPrototypeField () != null) {
- rec.setValue (dbm.getPrototypeField (), node.getPrototype ());
- }
rec.markForInsert ();
tds.save ();
} finally {
- if (tds != null) try {
+ if (tds != null) {
tds.close ();
- } catch (Exception ignore) {}
+ }
}
- dbm.notifyDataChange ();
+ dbm.lastDataChange = System.currentTimeMillis ();
}
// tx.timer.endEvent ("insertNode "+node);
}
- /**
- * Updates a modified node in the embedded db or an external relational database, depending
- * on its database mapping.
- */
public void updateNode (DbWrapper db, DbTxn txn, Node node) throws Exception {
Transactor tx = (Transactor) Thread.currentThread ();
@@ -457,57 +365,46 @@ public final class NodeManager {
int updated = 0;
- for (Iterator i=dbm.getProp2DB().entrySet().iterator(); i.hasNext(); ) {
- Map.Entry e = (Map.Entry) i.next ();
- String propname = (String) e.getKey ();
- Relation rel = (Relation) e.getValue ();
-
- // skip properties that don't need to be updated before fetching them
- if (rel != null && (rel.readonly || rel.virtual ||
- (rel.reftype != Relation.REFERENCE && rel.reftype != Relation.PRIMITIVE)))
- continue;
-
+ for (Enumeration e=dbm.prop2db.keys(); e.hasMoreElements(); ) {
+ String propname = (String) e.nextElement ();
Property p = node.getProperty (propname, false);
+ Relation rel = dbm.propertyToColumnName (propname);
+ if (rel != null && rel.readonly)
+ continue;
if (p != null && rel != null) {
if (p.dirty) {
switch (p.getType ()) {
case IProperty.STRING:
- updated++;
rec.setValue (rel.getDbField(), p.getStringValue ());
break;
case IProperty.BOOLEAN:
- updated++;
rec.setValue (rel.getDbField(), p.getBooleanValue ());
break;
case IProperty.DATE:
- updated++;
Timestamp t = new Timestamp (p.getDateValue ().getTime ());
rec.setValue (rel.getDbField(), t);
break;
case IProperty.INTEGER:
- updated++;
rec.setValue (rel.getDbField(), p.getIntegerValue ());
break;
case IProperty.FLOAT:
- updated++;
rec.setValue (rel.getDbField(), p.getFloatValue ());
break;
case IProperty.NODE:
- if (!rel.virtual && rel.reftype == Relation.REFERENCE) {
+ if (rel.direction == Relation.FORWARD) {
// INode n = p.getNodeValue ();
// String foreignID = n == null ? null : n.getID ();
- updated++;
rec.setValue (rel.getDbField(), p.getStringValue ());
}
break;
}
+ updated++;
p.dirty = false;
}
} else if (rel != null && rel.getDbField() != null) {
-
updated++;
rec.setValueNull (rel.getDbField());
}
@@ -519,24 +416,21 @@ public final class NodeManager {
tds.save ();
}
} finally {
- if (tds != null) try {
+ if (tds != null) {
tds.close ();
- } catch (Exception ignore) {}
+ }
}
- dbm.notifyDataChange ();
+ dbm.lastDataChange = System.currentTimeMillis ();
}
// update may cause changes in the node's parent subnode array
if (node.isAnonymous()) {
- Node parent = node.getCachedParent ();
+ Node parent = (Node) node.getParent ();
if (parent != null)
parent.lastSubnodeChange = System.currentTimeMillis ();
}
// tx.timer.endEvent ("updateNode "+node);
}
- /**
- * Performs the actual deletion of a node from either the embedded or an external SQL database.
- */
public void deleteNode (DbWrapper db, DbTxn txn, Node node) throws Exception {
Transactor tx = (Transactor) Thread.currentThread ();
@@ -553,11 +447,10 @@ public final class NodeManager {
st = con.createStatement ();
st.executeUpdate ("DELETE FROM "+dbm.getTableName ()+" WHERE "+dbm.getIDField ()+" = "+node.getID ());
} finally {
- if (st != null) try {
+ if (st != null)
st.close ();
- } catch (Exception ignore) {}
}
- dbm.notifyDataChange ();
+ dbm.lastDataChange = System.currentTimeMillis ();
}
// node may still be cached via non-primary keys. mark as invalid
node.setState (Node.INVALID);
@@ -579,28 +472,20 @@ public final class NodeManager {
String q = "SELECT MAX("+map.getIDField()+") FROM "+map.getTableName();
qds = new QueryDataSet (con, q);
qds.fetchRecords ();
- // check for empty table
- if (qds.size () == 0) {
- long currMax = map.getNewID (0);
- retval = Long.toString (currMax);
- } else {
- long currMax = qds.getRecord (0).getValue (1).asLong ();
- currMax = map.getNewID (currMax);
- retval = Long.toString (currMax);
- }
+ long currMax = qds.getRecord (0).getValue (1).asLong ();
+ currMax = Math.max (currMax+1, map.lastID+1);
+ map.lastID = currMax;
+ retval = Long.toString (currMax);
} finally {
// tx.timer.endEvent ("generateID "+map);
- if (qds != null) try {
+ if (qds != null) {
qds.close ();
- } catch (Exception ignore) {}
+ }
}
return retval;
}
- /**
- * Generate a new ID from an Oracle sequence.
- */
public String generateID (DbMapping map) throws Exception {
Transactor tx = (Transactor) Thread.currentThread ();
@@ -613,12 +498,12 @@ public final class NodeManager {
String q = "SELECT "+map.getIDgen()+".nextval FROM dual";
qds = new QueryDataSet (con, q);
qds.fetchRecords ();
- retval = qds.getRecord (0).getValue (1).asString ();
+ retval = qds.getRecord (0).getValue (1).asString ();
} finally {
// tx.timer.endEvent ("generateID "+map);
- if (qds != null) try {
+ if (qds != null) {
qds.close ();
- } catch (Exception ignore) {}
+ }
}
return retval;
}
@@ -628,69 +513,59 @@ public final class NodeManager {
* Loades subnodes via subnode relation. Only the ID index is loaded, the nodes are
* loaded later on demand.
*/
- public List getNodeIDs (Node home, Relation rel) throws Exception {
+ public Vector getNodeIDs (Node home, Relation rel) throws Exception {
Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNodeIDs "+home);
- if (rel == null || rel.otherType == null || !rel.otherType.isRelational ()) {
+ if (rel == null || rel.other == null || !rel.other.isRelational ()) {
// this should never be called for embedded nodes
- throw new RuntimeException ("NodeMgr.getNodeIDs called for non-relational node "+home);
+ throw new RuntimeException ("NodeMgr.countNodes called for non-relational node "+home);
} else {
- List retval = new ArrayList ();
+ Vector retval = new Vector ();
// if we do a groupby query (creating an intermediate layer of groupby nodes),
// retrieve the value of that field instead of the primary key
- String idfield = rel.groupby == null ? rel.otherType.getIDField () : rel.groupby;
- Connection con = rel.otherType.getConnection ();
- String table = rel.otherType.getTableName ();
+ String idfield = rel.groupby == null ? rel.other.getIDField () : rel.groupby;
+ Connection con = rel.other.getConnection ();
+ String table = rel.other.getTableName ();
- Statement stmt = null;
+ QueryDataSet qds = null;
try {
-
- String q = null;
-
+ Relation subrel = rel;
+ if (subrel.getFilter () != null)
+ subrel = subrel.getFilter ();
+
if (home.getSubnodeRelation() != null) {
// subnode relation was explicitly set
- q = "SELECT "+idfield+" FROM "+table+" "+home.getSubnodeRelation();
+ qds = new QueryDataSet (con, "SELECT "+idfield+" FROM "+table+" "+home.getSubnodeRelation());
} else {
- // let relation object build the query
- q = "SELECT "+idfield+" FROM "+table + rel.buildQuery (home, home.getNonVirtualParent (), null, " WHERE ", true);
+ String q = "SELECT "+idfield+" FROM "+table;
+ if (subrel.direction == Relation.BACKWARD) {
+ String homeid = home.getNonVirtualHomeID (); // home.getState() == Node.VIRTUAL ? home.parentID : home.getID ();
+ q += " WHERE "+subrel.getRemoteField()+" = '"+homeid+"'";
+ }
+ // set order, if specified and if not using subnode's relation
+ if (rel.groupby != null)
+ q += " GROUP BY "+rel.groupby+" ORDER BY "+(rel.groupbyorder == null ? rel.groupby : rel.groupbyorder);
+ else if (rel.order != null)
+ q += " ORDER BY "+rel.order;
+ qds = new QueryDataSet (con, q);
}
if (logSql)
- app.logEvent ("### getNodeIDs: "+q);
+ IServer.getLogger().log ("### getNodeIDs: "+qds.getSelectString());
- stmt = con.createStatement ();
- if (rel.maxSize > 0)
- stmt.setMaxRows (rel.maxSize);
- ResultSet result = stmt.executeQuery (q);
-
- // problem: how do we derive a SyntheticKey from a not-yet-persistent Node?
- Key k = rel.groupby != null ? home.getKey (): null;
- while (result.next ()) {
- String kstr = result.getString (1);
- // jump over null values - this can happen especially when the selected
- // column is a group-by column.
- if (kstr == null)
- continue;
- // make the proper key for the object, either a generic DB key or a groupby key
- Key key = rel.groupby == null ?
- (Key) new DbKey (rel.otherType, kstr) :
- (Key) new SyntheticKey (k, kstr);
- retval.add (new NodeHandle (key));
- // if these are groupby nodes, evict nullNode keys
- if (rel.groupby != null) {
- Node n = (Node) cache.get (key);
- if (n != null && n.isNullNode ())
- evictKey (key);
- }
+ qds.fetchRecords ();
+ for (int i=0; i 0)
- tds.fetchRecords (rel.maxSize);
- else
- tds.fetchRecords ();
-
+ if (logSql)
+ IServer.getLogger().log ("### getNodes: "+tds.getSelectString());
+
+ tds.fetchRecords ();
for (int i=0; i 0 ? Math.min (rel.maxSize, retval) : retval;
+ return retval;
}
}
@@ -822,16 +694,16 @@ public final class NodeManager {
Transactor tx = (Transactor) Thread.currentThread ();
// tx.timer.beginEvent ("getNodeIDs "+home);
- if (rel == null || rel.otherType == null || !rel.otherType.isRelational ()) {
+ if (rel == null || rel.other == null || !rel.other.isRelational ()) {
// this should never be called for embedded nodes
- throw new RuntimeException ("NodeMgr.getPropertyNames called for non-relational node "+home);
+ throw new RuntimeException ("NodeMgr.countNodes called for non-relational node "+home);
} else {
Vector retval = new Vector ();
// if we do a groupby query (creating an intermediate layer of groupby nodes),
// retrieve the value of that field instead of the primary key
- String namefield = rel.accessor;
- Connection con = rel.otherType.getConnection ();
- String table = rel.otherType.getTableName ();
+ String namefield = rel.getRemoteField ();
+ Connection con = rel.other.getConnection ();
+ String table = rel.other.getTableName ();
QueryDataSet qds = null;
@@ -840,7 +712,7 @@ public final class NodeManager {
qds = new QueryDataSet (con, q);
if (logSql)
- app.logEvent ("### getPropertyNames: "+qds.getSelectString());
+ IServer.getLogger().log ("### getPropertyNames: "+qds.getSelectString());
qds.fetchRecords ();
for (int i=0; i 5) {
+ where.append (" and ");
+ where.append (nodesubrel.trim().substring(5).trim());
+ } else {
+ Relation subrel = home.getDbMapping().getSubnodeRelation ();
+ if (subrel != null) {
+ if (subrel.getFilter () != null)
+ subrel = subrel.getFilter ();
+ if (subrel != null && subrel.direction == Relation.BACKWARD) {
+ where.append (" and ");
+ where.append (subrel.getRemoteField());
+ where.append (" = '");
+ where.append (homeid);
+ where.append ("'");
+ }
+ }
+ }
+ }
- if (home.getSubnodeRelation () != null) {
- // combine our key with the constraints in the manually set subnode relation
- StringBuffer where = new StringBuffer ();
- where.append (rel.accessor);
- where.append (" = '");
- where.append (escape(kstr));
- where.append ("' AND ");
- where.append (home.getSubnodeRelation ().trim().substring(5).trim());
- tds.where (where.toString ());
- } else
- tds.where (rel.buildQuery (home, home.getNonVirtualParent (), kstr, "", false));
+ tds.where (where.toString ());
if (logSql)
- app.logEvent ("### getNodeByRelation: "+tds.getSelectString());
+ IServer.getLogger().log ("### getNodeByRelation: "+tds.getSelectString());
tds.fetchRecords ();
@@ -962,7 +867,7 @@ public final class NodeManager {
if (tds.size () > 1)
throw new RuntimeException ("More than one value returned by query.");
Record rec = tds.getRecord (0);
- node = new Node (rel.otherType, rec, safe);
+ node = new Node (rel.other, rec, safe);
// Check if node is already cached with primary Key.
if (!rel.usesPrimaryKey()) {
@@ -974,9 +879,9 @@ public final class NodeManager {
}
} finally {
- if (tds != null) try {
+ if (tds != null) {
tds.close ();
- } catch (Exception ignore) {}
+ }
}
}
return node;
@@ -984,83 +889,183 @@ public final class NodeManager {
// a utility method to escape single quotes
private String escape (String str) {
- if (str == null)
- return null;
- if (str.indexOf ("'") < 0)
- return str;
- int l = str.length();
+ if (str == null)
+ return null;
+ if (str.indexOf ("'") < 0)
+ return str;
+ int l = str.length();
StringBuffer sbuf = new StringBuffer (l + 10);
- for (int i=0; i -1;
- String d = named ? desc.substring (0, n) : desc;
-
- int dot = d.indexOf (".");
- if (dot > -1) {
- propname = d.substring (0, dot).trim();
- virtualname = d.substring (dot+1).trim();
- } else {
- propname = d.trim();
- virtualname = null;
- }
-
- isroot = "root".equals (propname);
- // System.err.println ("created "+this);
- }
-
- public String toString () {
- return "ParentInfo["+propname+","+virtualname+","+named+"]";
- }
-
-}
diff --git a/src/helma/objectmodel/db/Property.java b/src/helma/objectmodel/db/Property.java
index b7da69c1..f1392d10 100644
--- a/src/helma/objectmodel/db/Property.java
+++ b/src/helma/objectmodel/db/Property.java
@@ -23,8 +23,8 @@ public final class Property implements IProperty, Serializable, Cloneable {
protected boolean bvalue;
protected long lvalue;
protected double dvalue;
- // protected String nvalueID;
- protected NodeHandle nhandle;
+ protected String nvalueID;
+ private transient DbMapping dbm;
protected Object jvalue;
protected int type;
@@ -40,11 +40,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
type = in.readInt ();
switch (type) {
case STRING:
- // try to convert from old format
- if (node.version < 7)
- svalue = in.readUTF ();
- else
- svalue = (String) in.readObject ();
+ svalue = in.readUTF ();
break;
case BOOLEAN:
bvalue = in.readBoolean ();
@@ -57,11 +53,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
dvalue = in.readDouble ();
break;
case NODE:
- // try to convert from old format
- if (node.version > 4)
- nhandle = (NodeHandle) in.readObject ();
- else
- nhandle = new NodeHandle (new DbKey (null, in.readUTF ()));
+ nvalueID = in.readUTF ();
break;
case JAVAOBJECT:
jvalue = in.readObject ();
@@ -73,12 +65,15 @@ public final class Property implements IProperty, Serializable, Cloneable {
}
private void writeObject (ObjectOutputStream out) throws IOException {
+ // don't even start if this is a non-serializable Java object
+ if (type == JAVAOBJECT && jvalue != null && !(jvalue instanceof Serializable))
+ return;
out.writeUTF (propname);
out.writeObject (node);
out.writeInt (type);
switch (type) {
case STRING:
- out.writeObject (svalue);
+ out.writeUTF (svalue);
break;
case BOOLEAN:
out.writeBoolean (bvalue);
@@ -91,13 +86,10 @@ public final class Property implements IProperty, Serializable, Cloneable {
out.writeDouble (dvalue);
break;
case NODE:
- out.writeObject (nhandle);
+ out.writeUTF (nvalueID);
break;
case JAVAOBJECT:
- if (jvalue != null && !(jvalue instanceof Serializable))
- out.writeObject (null);
- else
- out.writeObject (jvalue);
+ out.writeObject (jvalue);
break;
}
}
@@ -117,7 +109,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
public Property (String propname, Node node, Node value) {
this (propname, node);
type = NODE;
- nhandle = value == null ? null : value.getHandle ();
+ nvalueID = value == null ? null : value.getID ();
dirty = true;
}
@@ -148,11 +140,41 @@ public final class Property implements IProperty, Serializable, Cloneable {
public void setStringValue (String value) {
if (type == NODE)
unregisterNode ();
+ // IServer.getLogger().log ("setting string value of property "+propname + " to "+value);
+ // mark property as dirty
+ dirty = true;
+ // if this is not a string property, try to parse a value out of it
+ if (type == DATE) {
+ SimpleDateFormat dateformat = new SimpleDateFormat ();
+ try {
+ dateformat.setLenient (true);
+ Date date = dateformat.parse (value);
+ this.lvalue = date.getTime ();
+ return;
+ } catch (ParseException nodate) {
+ IServer.getLogger().log ("Couldn't parse date: was expecting something like "+dateformat.format (new Date()));
+ // store as plain string
+ }
+ }
+ if (type == BOOLEAN) {
+ if ("true".equalsIgnoreCase (value))
+ this.bvalue = true;
+ else if ("false".equalsIgnoreCase (value))
+ this.bvalue = false;
+ return;
+ }
+ if (type == INTEGER) {
+ this.lvalue = Long.parseLong (value);
+ return;
+ }
+ if (type == FLOAT) {
+ this.dvalue = new Double (value).doubleValue ();
+ return;
+ }
if (type == JAVAOBJECT)
this.jvalue = null;
- type = STRING;
this.svalue = value;
- dirty = true;
+ type = STRING;
}
@@ -197,16 +219,39 @@ public final class Property implements IProperty, Serializable, Cloneable {
}
public void setNodeValue (Node value) {
- // value.checkWriteLock ();
+ value.checkWriteLock ();
if (type == NODE)
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
-
- // registerNode (value);
+ registerNode (value);
type = NODE;
-
- nhandle = value.getHandle ();
+ if (node.dbmap != null) {
+ Relation rel = node.dbmap.getPropertyRelation (propname);
+ if (rel != null && rel.other != null) {
+ DbMapping vmap = value.getDbMapping ();
+ // check if actual type matches expected type
+ if (rel.other != vmap && (!rel.virtual || rel.prototype != null)) {
+ throw new RuntimeException ("Can't assign property: expected prototype "+rel.other+", got "+vmap);
+ }
+ // check if this is a forward relation, i.e. if we point to a field in the value object
+ // if so, we may use something else than the object's id to refer to it.
+ if (!rel.virtual && rel.direction == Relation.FORWARD) {
+ if (rel.usesPrimaryKey ()) {
+ this.nvalueID = value.getID ();
+ } else try {
+ this.nvalueID = value.getString (vmap.columnNameToProperty (rel.getRemoteField()).propname, false);
+ } catch (Exception x) {
+ throw new RuntimeException ("Can't set "+propname+" to "+value+": error retrieving target property");
+ }
+ this.dbm = null;
+ dirty = true;
+ return;
+ }
+ }
+ }
+ this.nvalueID = value == null ? null : value.getID ();
+ this.dbm = value == null ? null : value.getDbMapping ();
dirty = true;
}
@@ -223,39 +268,48 @@ public final class Property implements IProperty, Serializable, Cloneable {
* If this was the "main" property for the node, also remove all other references.
*/
protected void unregisterNode () {
- Node nvalue = null;
- if (nhandle != null)
- nvalue = nhandle.getNode (node.nmgr);
-
- DbMapping nvmap = null;
- Relation nvrel = null;
- if (node.dbmap != null) {
- nvmap = node.dbmap.getPropertyMapping (propname);
- nvrel = node.dbmap.getPropertyRelation (propname);
- }
-
- if (nvalue == null)
- return;
-
- nvalue.checkWriteLock ();
- // check if the property node is also a subnode
- // BUG: this doesn't work because properties for subnode/properties are never stored and therefore
- // never reused.
- if (nvrel != null && nvrel.subnodesAreProperties) {
- node.removeNode (nvalue);
- }
- // only need to call unregisterPropLink if the value node is not stored in a relational db
- // also, getParent is heuristical/implicit for relational nodes, so we don't do deepRemoveNode
- // based on that for relational nodes.
- if (nvmap == null || !nvmap.isRelational()) {
- if (!nvalue.isAnonymous() && propname.equals (nvalue.getName()) && this.node == nvalue.getParent()) {
- // this is the "main" property of a named node, so handle this as a cascading delete.
- nvalue.deepRemoveNode ();
+ if (nvalueID != null) {
+ DbMapping nvmap = null;
+ Relation nvrel = null;
+ if (node.dbmap != null) {
+ nvmap = node.dbmap.getPropertyMapping (propname);
+ nvrel = node.dbmap.getPropertyRelation (propname);
+ }
+ Node nvalue = node.nmgr.getNode (nvalueID, nvmap);
+ if (nvalue == null)
+ return;
+ nvalue.checkWriteLock ();
+ // check if the property node is also a subnode
+ // BUG: this doesn't work because properties for subnode/properties are never stored and therefore
+ // never reused.
+ if (nvrel != null && nvrel.subnodesAreProperties) {
+ node.removeNode (nvalue);
+ }
+ // only need to call unregisterPropLink if the value node is not stored in a relational db
+ // also, getParent is heuristical/implicit for relational nodes, so we don't do deepRemoveNode
+ // based on that for relational nodes.
+ if (nvmap == null || !nvmap.isRelational()) {
+ if (!nvalue.isAnonymous() && propname.equals (nvalue.getName()) && this.node == nvalue.getParent()) {
+ // this is the "main" property of a named node, so handle this as a cascading delete.
+ nvalue.deepRemoveNode ();
+ } else {
+ nvalue.unregisterPropLink (this.node);
+ }
}
}
}
+ /**
+ * Tell the value node that it is being used as a property value.
+ */
+ protected void registerNode (Node n) {
+ // only need to call registerPropLink if the value node is not stored in a relational db
+ if (n != null && (n.dbmap == null || !n.dbmap.isRelational())) {
+ n.registerPropLink (this.node);
+ }
+ }
+
public String getStringValue () {
switch (type) {
case STRING:
@@ -270,9 +324,9 @@ public final class Property implements IProperty, Serializable, Cloneable {
case FLOAT:
return Double.toString (dvalue);
case NODE:
- return nhandle.getID ();
+ return nvalueID;
case JAVAOBJECT:
- return jvalue == null ? null : jvalue.toString ();
+ return jvalue.toString ();
}
return "";
}
@@ -307,10 +361,46 @@ public final class Property implements IProperty, Serializable, Cloneable {
}
public INode getNodeValue () {
-
- if (nhandle != null) {
- Node n = nhandle.getNode (node.nmgr);
- if (n != null) return n;
+
+ if (type == NODE && nvalueID != null) {
+ Relation rel = null;
+ if (dbm == null && node.dbmap != null) {
+ // try to get DbMap for property, if it isn't known yet
+ rel = node.dbmap.getPropertyRelation (propname);
+ // figure out db mapping from relation
+ if (rel != null) {
+ // is the property a virtual node containing objects from relational db?
+ if (rel.virtual && rel.other.isRelational ())
+ return node.nmgr.getNode (node, propname, rel);
+ else if (!rel.virtual && rel.direction == Relation.FORWARD)
+ return node.nmgr.getNode (node, nvalueID, rel);
+ // avoid setting dbm for virtual and groupby relations, except for
+ // [mountpoint] kind of prototyped virtual nodes
+ else if ((!rel.virtual || rel.prototype != null) && rel.groupby == null)
+ dbm = rel.other;
+ }
+ }
+
+ // we have what we need, now get the node from the node manager
+ Node retval = node.nmgr.getNode (nvalueID, dbm);
+ if (retval != null && retval.parentID == null && !"root".equalsIgnoreCase (retval.getPrototype ())) {
+ retval.setParent (node);
+ retval.setName (propname);
+ retval.anonymous = false;
+ }
+
+ if (retval != null && retval.getDbMapping () == null && rel != null && rel.virtual && rel.prototype == null) {
+ // a virtual node whose child nodes are not relational -
+ // set up dbmapping that describes subnodes and properties
+ DbMapping _dbm = new DbMapping ();
+ _dbm.setSubnodeMapping (rel.other);
+ _dbm.setPropertyMapping (rel.other);
+ _dbm.setSubnodeRelation (rel.getVirtualSubnodeRelation());
+ _dbm.setPropertyRelation (rel.getVirtualPropertyRelation());
+ retval.setDbMapping (_dbm);
+ }
+
+ return retval;
}
return null;
}
@@ -321,9 +411,91 @@ public final class Property implements IProperty, Serializable, Cloneable {
return null;
}
+ public String getEditor () {
+ switch (type) {
+ case STRING:
+ return "password".equalsIgnoreCase (propname) ?
+ " " :
+ " " ;
+ case BOOLEAN:
+ return ""+bvalue+" "+!bvalue+" ";
+ case INTEGER:
+ return " " ;
+ case FLOAT:
+ return " " ;
+ case DATE:
+ SimpleDateFormat format = new SimpleDateFormat ("dd.MM.yy hh:mm");
+ String date = format.format (new Date (lvalue));
+ return " ";
+ case NODE:
+ DbMapping nvmap = null;
+ if (node.dbmap != null)
+ nvmap = node.dbmap.getPropertyMapping (propname);
+ return " ";
+ }
+ return "";
+ }
+
+ private String escape (String s) {
+ char c[] = new char[s.length()];
+ s.getChars (0, c.length, c, 0);
+ StringBuffer b = new StringBuffer ();
+ int copyfrom = 0;
+ for (int i = 0; i < c.length; i++) {
+ switch (c[i]) {
+ case '\\':
+ case '"':
+ if (i-copyfrom > 0)
+ b.append (c, copyfrom, i-copyfrom);
+ b.append ('\\');
+ b.append (c[i]);
+ copyfrom = i+1;
+ }
+ }
+ if (c.length-copyfrom > 0)
+ b.append (c, copyfrom, c.length-copyfrom);
+ return b.toString ();
+ }
public int getType () {
return type;
+
+ }
+
+ public String getTypeString () {
+ switch (type) {
+ case STRING:
+ return "string";
+ case BOOLEAN:
+ return "boolean";
+ case DATE:
+ return "date";
+ case INTEGER:
+ return "integer";
+ case FLOAT:
+ return "float";
+ case NODE:
+ return "node";
+ }
+ return "";
+ }
+
+
+ public Object clone () {
+ try {
+ Property c = (Property) super.clone();
+ c.propname = this.propname;
+ c.svalue = this.svalue;
+ c.bvalue = this.bvalue;
+ c.lvalue = this.lvalue;
+ c.dvalue = this.dvalue;
+ c.nvalueID = this.nvalueID;
+ c.type = this.type;
+ return c;
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen, since we are Cloneable
+ throw new InternalError ();
+ }
}
}
diff --git a/src/helma/objectmodel/db/Relation.java b/src/helma/objectmodel/db/Relation.java
deleted file mode 100644
index 03814497..00000000
--- a/src/helma/objectmodel/db/Relation.java
+++ /dev/null
@@ -1,773 +0,0 @@
-// Relation.java
-// Copyright (c) Hannes Wallnöfer 1997-2000
-
-package helma.objectmodel.db;
-
-import helma.objectmodel.*;
-import helma.framework.core.Application;
-import java.util.Properties;
-import java.util.Vector;
-import java.sql.SQLException;
-
-/**
- * This describes how a property of a persistent Object is stored in a
- * relational database table. This can be either a scalar property (string, date, number etc.)
- * or a reference to one or more other objects.
- */
-public class Relation {
-
- // these constants define different type of property-to-db-mappings
-
- // there is an error in the description of this relation
- public final static int INVALID = -1;
- // a mapping of a non-object, scalar type
- public final static int PRIMITIVE = 0;
- // a 1-to-1 relation, i.e. a field in the table is a foreign key to another object
- public final static int REFERENCE = 1;
- // a 1-to-many relation, a field in another table points to objects of this type
- public final static int COLLECTION = 2;
- // direct mapping is a very powerful feature: objects of some types can be directly accessed
- // by one of their properties/db fields.
- // public final static int DIRECT = 3;
-
- // the DbMapping of the type we come from
- DbMapping ownType;
- // the DbMapping of the prototype we link to, unless this is a "primitive" (non-object) relation
- DbMapping otherType;
-
- // if this relation defines a virtual node, we need to provide a DbMapping for these virtual nodes
- DbMapping virtualMapping;
-
- Relation virtualRelation;
- Relation groupRelation;
-
- String propName;
- String columnName;
-
- int reftype;
-
- Constraint[] constraints;
-
- boolean virtual;
- boolean readonly;
- boolean aggressiveLoading;
- boolean aggressiveCaching;
- boolean subnodesAreProperties;
- String accessor; // db column used to access objects through this relation
- String order;
- String groupbyorder;
- String groupby;
- String prototype;
- String groupbyprototype;
- String filter;
- int maxSize = 0;
-
- // Relation subnoderelation = null; // additional relation used to filter subnodes for virtual nodes
-
- /**
- * This constructor makes a copy of an existing relation. Not all fields are copied, just those
- * which are needed in groupby- and virtual nodes defined by this relation.
- */
- public Relation (Relation rel) {
- this.ownType = rel.ownType;
- this.otherType = rel.otherType;
- this.propName = rel.propName;
- this.columnName = rel.columnName;
- this.reftype = rel.reftype;
- this.constraints = rel.constraints;
- this.accessor = rel.accessor;
- this.maxSize = rel.maxSize;
- this.subnodesAreProperties = rel.subnodesAreProperties;
- }
-
- /**
- * Reads a relation entry from a line in a properties file.
- */
- public Relation (String desc, String propName, DbMapping ownType, Properties props) {
- this.ownType = ownType;
- this.propName = propName;
- otherType = null;
- }
-
- public void update (String desc, Properties props, int version) {
- if (version == 0)
- update_v0 (desc, props);
- else if (version == 1)
- update_v1 (desc, props);
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////
- // parse methods for file format v0
- ////////////////////////////////////////////////////////////////////////////////////////////
-
- private void update_v0 (String desc, Properties props) {
- boolean mountpoint = false;
- Vector cnst = null;
-
- if (desc == null || "".equals (desc.trim ())) {
- if (propName != null) {
- reftype = PRIMITIVE;
- columnName = propName;
- } else {
- reftype = INVALID;
- columnName = propName;
- }
- } else {
- desc = desc.trim ();
- String descLower = desc.toLowerCase ();
- if (descLower.startsWith ("[virtual]")) {
- desc = desc.substring (9).trim ();
- virtual = true;
- } else if (descLower.startsWith ("[collection]")) {
- desc = desc.substring (12).trim ();
- virtual = true;
- } else if (descLower.startsWith ("[mountpoint]")) {
- desc = desc.substring (12).trim ();
- virtual = true;
- mountpoint = true;
- } else {
- virtual = false;
- }
- if (descLower.startsWith ("[readonly]")) {
- desc = desc.substring (10).trim ();
- readonly = true;
- } else {
- readonly = false;
- }
- }
-
- // parse the basic properties of this mapping
- parseMapping_v0 (desc, mountpoint);
-
- // the following options only apply to object relations
- if (reftype != PRIMITIVE && reftype != INVALID) {
-
- cnst = new Vector ();
-
- Constraint c = parseConstraint_v0 (desc);
-
- if (c != null)
- cnst.add (c);
-
- parseOptions_v0 (cnst, props);
-
- constraints = new Constraint[cnst.size()];
- cnst.copyInto (constraints);
- }
- }
-
- /**
- * Parse a line describing a mapping of a property field. If the mapping is a
- * object reference of a collection of objects, put any constraints in the Vector.
- */
- protected void parseMapping_v0 (String desc, boolean mountpoint) {
-
- Application app = ownType.getApplication ();
-
- if (desc.indexOf ("<") > -1) {
- reftype = COLLECTION;
- int lt = desc.indexOf ("<");
- int dot = desc.indexOf (".");
- String other = dot < 0 ? desc.substring (lt+1).trim () : desc.substring (lt+1, dot).trim ();
- otherType = app.getDbMapping (other);
- if (otherType == null)
- throw new RuntimeException ("DbMapping for "+other+" not found from "+ownType.typename);
- columnName = null;
- if (mountpoint)
- prototype = other;
- } else if (desc.indexOf (">") > -1) {
- reftype = REFERENCE;
- int bt = desc.indexOf (">");
- int dot = desc.indexOf (".");
- String other = dot > -1 ? desc.substring (bt+1, dot).trim () : desc.substring (bt+1).trim ();
- otherType = app.getDbMapping (other);
- if (otherType == null)
- throw new RuntimeException ("DbMapping for "+other+" not found from "+ownType.typename);
- columnName = desc.substring (0, bt).trim ();
- if (mountpoint)
- prototype = other;
- } else if (desc.indexOf (".") > -1) {
- reftype = COLLECTION;
- int dot = desc.indexOf (".");
- String other = desc.substring (0, dot).trim ();
- otherType = app.getDbMapping (other);
- if (otherType == null)
- throw new RuntimeException ("DbMapping for "+other+" not found from "+ownType.typename);
- columnName = null;
- // set accessor
- accessor = desc.substring (dot+1).trim ();
- if (mountpoint)
- prototype = other;
- } else {
- if (virtual) {
- reftype = COLLECTION;
- otherType = app.getDbMapping (desc);
- if (otherType == null)
- throw new RuntimeException ("DbMapping for "+desc+" not found from "+ownType.typename);
- if (mountpoint)
- prototype = desc;
- } else {
- reftype = PRIMITIVE;
- columnName = desc.trim ();
- }
- }
- }
-
-
- /**
- * Parse a line describing a mapping of a property field. If the mapping is a
- * object reference of a collection of objects, put any constraints in the Vector.
- */
- protected Constraint parseConstraint_v0 (String desc) {
- if (desc.indexOf ("<") > -1) {
- int lt = desc.indexOf ("<");
- int dot = desc.indexOf (".");
- String remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
- String localField = lt <= 0 ? null : desc.substring (0, lt).trim ();
- return new Constraint (localField, otherType.getTableName (), remoteField, false);
- } else if (desc.indexOf (">") > -1) {
- int bt = desc.indexOf (">");
- int dot = desc.indexOf (".");
- String localField = desc.substring (0, bt).trim ();
- String remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
- return new Constraint (localField, otherType.getTableName (), remoteField, false);
- }
- return null;
- }
-
- protected void parseOptions_v0 (Vector cnst, Properties props) {
- String loading = props.getProperty (propName+".loadmode");
- aggressiveLoading = loading != null && "aggressive".equalsIgnoreCase (loading.trim());
- String caching = props.getProperty (propName+".cachemode");
- aggressiveCaching = caching != null && "aggressive".equalsIgnoreCase (caching.trim());
- // get order property
- order = props.getProperty (propName+".order");
- if (order != null && order.trim().length() == 0)
- order = null;
- // get additional filter property
- filter = props.getProperty (propName+".filter");
- if (filter != null && filter.trim().length() == 0)
- filter = null;
- // get max size of collection
- String max = props.getProperty (propName+".maxSize");
- if (max != null) try {
- maxSize = Integer.parseInt (max);
- } catch (NumberFormatException nfe) {
- maxSize = 0;
- }
- // get group by property
- groupby = props.getProperty (propName+".groupby");
- if (groupby != null && groupby.trim().length() == 0)
- groupby = null;
- if (groupby != null) {
- groupbyorder = props.getProperty (propName+".groupby.order");
- if (groupbyorder != null && groupbyorder.trim().length() == 0)
- groupbyorder = null;
- groupbyprototype = props.getProperty (propName+".groupby.prototype");
- if (groupbyprototype != null && groupbyprototype.trim().length() == 0)
- groupbyprototype = null;
- // aggressive loading and caching is not supported for groupby-nodes
- aggressiveLoading = aggressiveCaching = false;
- }
- // check if subnode condition should be applied for property relations
- if ("_properties".equalsIgnoreCase (propName) || virtual) {
- String subnodes2props = props.getProperty (propName+".aresubnodes");
- subnodesAreProperties = "true".equalsIgnoreCase (subnodes2props);
- if (virtual) {
- String subnodefilter = props.getProperty (propName+".subnoderelation");
- if (subnodefilter != null) {
- Constraint c = parseConstraint_v0 (subnodefilter);
- if (c != null) {
- cnst.add (c);
- }
- }
- }
- // update virtual mapping, if it already exists
- if (virtualMapping != null) {
- virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
- virtualMapping.propertiesRel = getVirtualPropertyRelation ();
- virtualMapping.lastTypeChange = ownType.lastTypeChange;
- }
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////
- // parse methods for file format v1
- ////////////////////////////////////////////////////////////////////////////////////////////
-
- private void update_v1 (String desc, Properties props) {
- Application app = ownType.getApplication ();
- if (desc == null || "".equals (desc.trim ())) {
- if (propName != null) {
- reftype = PRIMITIVE;
- columnName = propName;
- } else {
- reftype = INVALID;
- columnName = propName;
- }
- } else {
- desc = desc.trim ();
- int open = desc.indexOf ("(");
- int close = desc.indexOf (")");
- if (open > -1 && close > open) {
- String ref = desc.substring (0, open).trim ();
- String proto = desc.substring (open+1, close).trim ();
- if ("collection".equalsIgnoreCase (ref)) {
- virtual = !"_children".equalsIgnoreCase (propName);
- reftype = COLLECTION;
- } else if ("mountpoint".equalsIgnoreCase (ref)) {
- virtual = true;
- reftype = COLLECTION;
- prototype = proto;
- } else if ("object".equalsIgnoreCase (ref)) {
- virtual = false;
- reftype = REFERENCE;
- } else {
- throw new RuntimeException ("Invalid property Mapping: "+desc);
- }
- otherType = app.getDbMapping (proto);
- if (otherType == null)
- throw new RuntimeException ("DbMapping for "+proto+" not found from "+ownType.typename);
- } else {
- virtual = false;
- columnName = desc;
- reftype = PRIMITIVE;
- }
- String rdonly = props.getProperty (desc+".readonly");
- if (rdonly != null && "true".equalsIgnoreCase (rdonly)) {
- readonly = true;
- } else {
- readonly = false;
- }
- }
- // the following options only apply to object and collection relations
- if (reftype != PRIMITIVE && reftype != INVALID) {
-
- Vector newConstraints = new Vector ();
- parseOptions_v1 (newConstraints, props);
-
- constraints = new Constraint[newConstraints.size()];
- newConstraints.copyInto (constraints);
- }
- }
-
-
- protected void parseOptions_v1 (Vector cnst, Properties props) {
- String loading = props.getProperty (propName+".loadmode");
- aggressiveLoading = loading != null && "aggressive".equalsIgnoreCase (loading.trim());
- String caching = props.getProperty (propName+".cachemode");
- aggressiveCaching = caching != null && "aggressive".equalsIgnoreCase (caching.trim());
- // get order property
- order = props.getProperty (propName+".order");
- if (order != null && order.trim().length() == 0)
- order = null;
- // get additional filter property
- filter = props.getProperty (propName+".filter");
- if (filter != null && filter.trim().length() == 0)
- filter = null;
- // get max size of collection
- String max = props.getProperty (propName+".maxSize");
- if (max != null) try {
- maxSize = Integer.parseInt (max);
- } catch (NumberFormatException nfe) {
- maxSize = 0;
- }
- // get group by property
- groupby = props.getProperty (propName+".group");
- if (groupby != null && groupby.trim().length() == 0)
- groupby = null;
- if (groupby != null) {
- groupbyorder = props.getProperty (propName+".group.order");
- if (groupbyorder != null && groupbyorder.trim().length() == 0)
- groupbyorder = null;
- groupbyprototype = props.getProperty (propName+".group.prototype");
- if (groupbyprototype != null && groupbyprototype.trim().length() == 0)
- groupbyprototype = null;
- // aggressive loading and caching is not supported for groupby-nodes
- aggressiveLoading = aggressiveCaching = false;
- }
- // check if subnode condition should be applied for property relations
- accessor = props.getProperty (propName+".accessname");
- if (accessor != null)
- subnodesAreProperties = true;
- // parse contstraints
- String local = props.getProperty (propName+".local");
- String foreign = props.getProperty (propName+".foreign");
- if (local != null && foreign != null) {
- cnst.addElement (new Constraint (local, otherType.getTableName (), foreign, false));
- columnName = local;
- }
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Does this relation describe a virtual (collection) node?
- */
- public boolean isVirtual () {
- return virtual;
- }
-
- /**
- * Tell if this relation represents a primitive (scalar) value mapping.
- */
- public boolean isPrimitive () {
- return reftype == PRIMITIVE;
- }
-
- /**
- * Return the prototype to be used for object reached by this relation
- */
- public String getPrototype () {
- return prototype;
- }
-
- /**
- * Return the name of the local property this relation is defined for
- */
- public String getPropName () {
- return propName;
- }
-
-
- /**
- * Add a constraint to the current list of constraints
- */
- protected void addConstraint (Constraint c) {
- if (constraints == null) {
- constraints = new Constraint[1];
- constraints[0] = c;
- } else {
- Constraint[] nc = new Constraint[constraints.length+1];
- System.arraycopy (constraints, 0, nc, 0, constraints.length);
- nc[nc.length-1] = c;
- constraints = nc;
- }
- }
-
-
- public boolean usesPrimaryKey () {
- if (otherType != null) {
- if (reftype == REFERENCE)
- return constraints.length == 1 && constraints[0].foreignKeyIsPrimary ();
- if (reftype == COLLECTION)
- return accessor == null || accessor.equalsIgnoreCase (otherType.getIDField ());
- }
- return false;
- }
-
- public String getAccessor () {
- return accessor;
- }
-
- public Relation getSubnodeRelation () {
- // return subnoderelation;
- return null;
- }
-
-
- /**
- * Return the local field name for updates.
- */
- public String getDbField () {
- return columnName;
- }
-
-
- public DbMapping getVirtualMapping () {
- if (!virtual)
- return null;
- if (virtualMapping == null) {
- virtualMapping = new DbMapping (ownType.app);
- virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
- virtualMapping.propertiesRel = getVirtualPropertyRelation ();
- }
- return virtualMapping;
- }
-
-
- /**
- * Return a Relation that defines the subnodes of a virtual node.
- */
- Relation getVirtualSubnodeRelation () {
- if (!virtual)
- throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation");
- Relation vr = new Relation (this);
- vr.groupby = groupby;
- vr.groupbyorder = groupbyorder;
- vr.groupbyprototype = groupbyprototype;
- vr.order = order;
- vr.filter = filter;
- vr.constraints = constraints;
- vr.aggressiveLoading = aggressiveLoading;
- vr.aggressiveCaching = aggressiveCaching;
- return vr;
- }
-
- /**
- * Return a Relation that defines the properties of a virtual node.
- */
- Relation getVirtualPropertyRelation () {
- if (!virtual)
- throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation");
- Relation vr = new Relation (this);
- vr.groupby = groupby;
- vr.groupbyorder = groupbyorder;
- vr.groupbyprototype = groupbyprototype;
- vr.order = order;
- vr.filter = filter;
- vr.constraints = constraints;
- return vr;
- }
-
- /**
- * Return a Relation that defines the subnodes of a group-by node.
- */
- Relation getGroupbySubnodeRelation () {
- if (groupby == null)
- throw new RuntimeException ("getGroupbySubnodeRelation called on non-group-by relation");
- Relation vr = new Relation (this);
- vr.order = order;
- vr.prototype = groupbyprototype;
- vr.filter = filter;
- vr.constraints = constraints;
- vr.addConstraint (new Constraint (null, null, groupby, true));
- return vr;
- }
-
- /**
- * Return a Relation that defines the properties of a group-by node.
- */
- Relation getGroupbyPropertyRelation () {
- if (groupby == null)
- throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
- Relation vr = new Relation (this);
- vr.order = order;
- vr.prototype = groupbyprototype;
- vr.filter = filter;
- vr.constraints = constraints;
- vr.addConstraint (new Constraint (null, null, groupby, true));
- return vr;
- }
-
-
- /**
- * Build the second half of an SQL select statement according to this relation
- * and a local object.
- */
- public String buildQuery (INode home, INode nonvirtual, String kstr, String pre, boolean useOrder) throws SQLException {
- StringBuffer q = new StringBuffer ();
- String prefix = pre;
- if (kstr != null) {
- q.append (prefix);
- String accessColumn = accessor == null ? otherType.getIDField () : accessor;
- q.append (accessColumn);
- q.append (" = ");
- // check if column is string type and value needs to be quoted
- if (otherType.isStringColumn (accessColumn)) {
- q.append ("'");
- q.append (escape (kstr));
- q.append ("'");
- } else
- q.append (escape (kstr));
- prefix = " AND ";
- }
- for (int i=0; i child.created())
- return false;
- for (int i=0; i"+otherType+"]" + c;
- }
-
- /**
- * The Constraint class represents a part of the where clause in the query used to
- * establish a relation between database mapped objects.
- */
- class Constraint {
-
- String localName;
- String tableName;
- String foreignName;
- boolean isGroupby;
-
- Constraint (String local, String table, String foreign, boolean groupby) {
- localName = local;
- tableName = table;
- foreignName = foreign;
- isGroupby = groupby;
- }
-
- public void addToQuery (StringBuffer q, INode home, INode nonvirtual) throws SQLException {
- String local = null;
- INode ref = isGroupby ? home : nonvirtual;
- if (localName == null || localName.equalsIgnoreCase (ref.getDbMapping ().getIDField ()))
- local = ref.getID ();
- else {
- String homeprop = ownType.columnNameToProperty (localName);
- local = ref.getString (homeprop, false);
- }
- q.append (foreignName);
- q.append (" = ");
- if (otherType.isStringColumn (foreignName)) {
- q.append ("'");
- q.append (escape (local));
- q.append ("'");
- } else
- q.append (escape (local));
- }
-
- public boolean foreignKeyIsPrimary () {
- return foreignName == null || foreignName.equalsIgnoreCase (otherType.getIDField ());
- }
-
- public String foreignProperty () {
- return otherType.columnNameToProperty (foreignName);
- }
-
- public String localProperty () {
- return ownType.columnNameToProperty (localName);
- }
-
- public String toString () {
- return ownType+"."+localName+"="+tableName+"."+foreignName;
- }
- }
-
-}
-
-
diff --git a/src/helma/objectmodel/db/Replicator.java b/src/helma/objectmodel/db/Replicator.java
deleted file mode 100644
index a949704c..00000000
--- a/src/helma/objectmodel/db/Replicator.java
+++ /dev/null
@@ -1,158 +0,0 @@
-// Replicator.java
-// Copyright (c) Hannes Wallnöfer 2001
-
-package helma.objectmodel.db;
-
-import helma.framework.IReplicatedApp;
-import java.rmi.*;
-import java.util.*;
-
-/**
- * This class replicates the updates of transactions to other applications via RMI
- */
-
-public class Replicator implements Runnable {
-
- Vector urls;
- Vector apps;
- Vector add, delete, currentAdd, currentDelete;
- Thread runner;
-
- public Replicator () {
- urls = new Vector ();
- apps = new Vector ();
- add = new Vector ();
- delete = new Vector ();
- runner = new Thread (this);
- runner.start ();
- }
-
- public void addUrl (String url) {
- urls.addElement (url);
- }
-
- public void addApp (IReplicatedApp app) {
- apps.addElement (app);
- }
-
- public void run () {
- while (Thread.currentThread () == runner) {
- if (prepareReplication ()) {
- for (int i=0; i 0)
+ p.put ("java.library.path", libpath+System.getProperty("path.separator")+libdir.getCanonicalPath());
+ else
+ p.put ("java.library.path", libdir.getCanonicalPath());
+
+ paranoid = "true".equalsIgnoreCase (sysProps.getProperty ("paranoid"));
+
+ String language = sysProps.getProperty ("language");
+ String country = sysProps.getProperty ("country");
+ String timezone = sysProps.getProperty ("timezone");
+
+ if (language != null && country != null)
+ Locale.setDefault (new Locale (language, country));
+ if (timezone != null)
+ TimeZone.setDefault (TimeZone.getTimeZone (timezone));
+
+ getLogger().log ("Locale = "+Locale.getDefault());
+ getLogger().log ("TimeZone = "+TimeZone.getDefault());
+
+ dbSources = new Hashtable ();
+
+ new Server ();
+
+ }
+
+ public Server () {
+
+ try {
+ checkRunning (); // check if a server is already running with this db
+ } catch (Exception running) {
+ System.out.println (running.getMessage ());
+ System.exit (1);
+ }
+
+ // nmgr = new NodeManager (this, sysProps);
+
+ mainThread = new Thread (this);
+ mainThread.start ();
+ }
+
+ public void run () {
+
+ try {
+
+ // set up dbSources
+ try {
+ dbProps = new SystemProperties (dbPropfile);
+ String sources = dbProps.getProperty ("sources", "");
+ StringTokenizer st = new StringTokenizer (sources, ",; ");
+ String next = null;
+ while (st.hasMoreTokens ()) try {
+ next = st.nextToken ();
+ new DbSource (next);
+ } catch (Exception wrong) {
+ getLogger().log ("Error creating DbSource "+next);
+ getLogger().log ("Reason: "+wrong);
+ }
+ } catch (Exception x) {
+ getLogger().log ("Error loading data source properties: "+x);
+ }
+
+ // start embedded web server if port is specified
+ if (webport > 0) {
+ websrv = new Acme.Serve.Serve (webport, sysProps);
+ }
+
+ String xmlparser = sysProps.getProperty ("xmlparser");
+ if (xmlparser != null)
+ XmlRpc.setDriver (xmlparser);
+ // XmlRpc.setDebug (true);
+ xmlrpc = new WebServer (port+1);
+ if (paranoid) {
+ xmlrpc.setParanoid (true);
+ String xallow = sysProps.getProperty ("allowXmlRpc");
+ if (xallow != null) {
+ StringTokenizer st = new StringTokenizer (xallow, " ,;");
+ while (st.hasMoreTokens ())
+ xmlrpc.acceptClient (st.nextToken ());
+ }
+ }
+ getLogger().log ("Starting XML-RPC server on port "+(port+1));
+
+ // the following seems not to be necessary after all ...
+ // System.setSecurityManager(new RMISecurityManager());
+ if (paranoid) {
+ HopSocketFactory factory = new HopSocketFactory ();
+ String rallow = sysProps.getProperty ("allowWeb");
+ if (rallow != null) {
+ StringTokenizer st = new StringTokenizer (rallow, " ,;");
+ while (st.hasMoreTokens ())
+ factory.addAddress (st.nextToken ());
+ }
+ RMISocketFactory.setSocketFactory (factory);
+ }
+
+ if (websrv == null) {
+ getLogger().log ("Starting server on port "+port);
+ LocateRegistry.createRegistry (port);
+ }
+
+
+ // start application framework
+ String appDir = sysProps.getProperty ("apphome", "apps");
+ File appHome = new File (appDir);
+ if (hopHome != null && !appHome.isAbsolute())
+ appHome = new File (hopHome, appDir);
+ appsProps = new SystemProperties (appsPropfile);
+ File dbHome = new File (dbDir);
+ appManager = new ApplicationManager (port, appHome, dbHome, appsProps, this);
+
+
+ } catch (Exception gx) {
+ getLogger().log ("Error initializing embedded database: "+gx);
+ gx.printStackTrace ();
+ /* try {
+ transactor.abort ();
+ } catch (Exception ignore) {} */
+ return;
+ }
+
+ // start applications
+ appManager.startAll ();
+
+ // start embedded web server
+ if (websrv != null) {
+ Thread webthread = new Thread (websrv, "WebServer");
+ webthread.start ();
+ }
+
+ int count = 0;
+ while (Thread.currentThread () == mainThread) {
+ try {
+ mainThread.sleep (3000l);
+ } catch (InterruptedException ie) {}
+ try {
+ appManager.checkForChanges ();
+ } catch (Exception x) {
+ getLogger().log ("Caught in app manager loop: "+x);
+ }
+ }
+
+ }
+
+
+ private void checkRunning () throws Exception {
+ try {
+ java.net.Socket socket = new java.net.Socket ("localhost", port);
+ } catch (Exception x) {
+ return;
+ }
+ // if we got so far, another server is already running on this port and db
+ throw new Exception ("Error: Server already running on this port");
}
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/helma/objectmodel/db/SyntheticKey.java b/src/helma/objectmodel/db/SyntheticKey.java
deleted file mode 100644
index 7f1911ac..00000000
--- a/src/helma/objectmodel/db/SyntheticKey.java
+++ /dev/null
@@ -1,123 +0,0 @@
-// SyntheticKey.java
-// Copyright (c) Hannes Wallnöfer 1998-2000
-
-package helma.objectmodel.db;
-
-import java.io.Serializable;
-
-/**
- * This is the internal key for an object that is not - or not directly - fetched from a db,
- * but derived from another object. This is useful for all kinds of object accessed via a
- * symbolic name from another object, like objects mounted via a property name column,
- * virtual nodes and groupby nodes.
- */
-public final class SyntheticKey implements Key, Serializable {
-
- private final Key parentKey;
- private final String name;
-
- // lazily initialized hashcode
- private transient int hashcode = 0;
-
-
- /**
- * make a key for a persistent Object, describing its datasource and id.
- */
- public SyntheticKey (Key key, String name) {
- this.parentKey = key;
- this.name = name;
- }
-
-
- public boolean equals (Object what) {
- if (what == this)
- return true;
- try {
- SyntheticKey k = (SyntheticKey) what;
- return parentKey.equals (k.parentKey) &&
- (name == k.name || name.equals (k.name));
- } catch (Exception x) {
- return false;
- }
- }
-
- public int hashCode () {
- if (hashcode == 0)
- hashcode = 17 + 37*name.hashCode () + 37*parentKey.hashCode ();
- return hashcode;
- }
-
-
- public Key getParentKey () {
- return parentKey;
- }
-
- public String getID () {
- return name;
- }
-
- public String getStorageName () {
- return null;
- }
-
- public String toString () {
- return parentKey+"/"+name;
- }
-
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/helma/objectmodel/db/Transactor.java b/src/helma/objectmodel/db/Transactor.java
index 66d2c3d9..f2a587b6 100644
--- a/src/helma/objectmodel/db/Transactor.java
+++ b/src/helma/objectmodel/db/Transactor.java
@@ -22,7 +22,6 @@ public class Transactor extends Thread {
// List of nodes to be updated
private HashMap nodes;
- private ArrayList nodesArray;
// List of visited clean nodes
private HashMap cleannodes;
// Is a transaction in progress?
@@ -45,7 +44,6 @@ public class Transactor extends Thread {
super (group, runnable, group.getName ());
this.nmgr = nmgr;
nodes = new HashMap ();
- nodesArray = new ArrayList ();
cleannodes = new HashMap ();
sqlCon = new HashMap ();
active = false;
@@ -58,7 +56,6 @@ public class Transactor extends Thread {
Key key = node.getKey ();
if (!nodes.containsKey (key)) {
nodes.put (key, node);
- nodesArray.add (node);
}
}
}
@@ -67,7 +64,6 @@ public class Transactor extends Thread {
if (node != null) {
Key key = node.getKey ();
nodes.remove (key);
- nodesArray.remove (node);
}
}
@@ -114,7 +110,6 @@ public class Transactor extends Thread {
abort ();
nodes.clear ();
- nodesArray.clear ();
cleannodes.clear ();
txn = nmgr.db.beginTransaction ();
active = true;
@@ -130,44 +125,36 @@ public class Transactor extends Thread {
}
int ins = 0, upd = 0, dlt = 0;
- int l = nodesArray.size ();
+ int l = nodes.size ();
- Replicator replicator = nmgr.getReplicator ();
+ for (Iterator i=nodes.values().iterator(); i.hasNext (); ) {
+ Node node = (Node) i.next ();
- for (int i=0; i append to StringBuffer
- if ( childNode.getNodeType()==org.w3c.dom.Node.TEXT_NODE ) {
- textcontent.append( childNode.getNodeValue().trim() );
- continue;
- }
-
- // it's some kind of element (property or child)
- if ( childNode.getNodeType()==org.w3c.dom.Node.ELEMENT_NODE ) {
-
- Element childElement = (Element)childNode;
-
- // get the basic key we have to look for in the properties-table
- domKey = (element.getNodeName()+"."+childElement.getNodeName()).toLowerCase();
-
- // is there a childtext-2-property mapping?
- if ( props!=null && props.containsKey(domKey+"._text") ) {
- helmaKey = (String)props.get(domKey+"._text");
- if( helmaKey.equals("") )
- // if property is set but without value, read elementname for this mapping
- helmaKey = childElement.getNodeName().replace(':',defaultSeparator);
- if (DEBUG) debug("childtext-2-property mapping, helmaKey " + helmaKey + " for domKey " + domKey );
- if ( helmaNode.getString(helmaKey,false)==null ) {
- helmaNode.setString( helmaKey, XmlUtil.getTextContent(childNode) );
- if (DEBUG) debug("childtext-2-property mapping, setting " + helmaKey + " as string" );
- }
- continue;
- }
-
- //
- // is there a simple child-2-property mapping?
- // (lets the user define to use only one element and make this a property
- // and simply ignore other elements of the same name)
- if ( props!=null && props.containsKey(domKey+"._property") ) {
- helmaKey = (String)props.get(domKey+"._property");
- // if property is set but without value, read elementname for this mapping:
- if ( helmaKey.equals("") )
- helmaKey = childElement.getNodeName().replace(':',defaultSeparator);
- if (DEBUG) debug("child-2-property mapping, helmaKey " + helmaKey + " for domKey " + domKey);
- if ( helmaNode.getNode(helmaKey,false)==null ) {
- convert( childElement, helmaNode.createNode(helmaKey) );
- if (DEBUG) debug( "read " + childElement.toString() + helmaNode.getNode(helmaKey,false).toString() );
- }
- continue;
- }
-
-
- //
- // map it to one of the children-lists
- helma.objectmodel.INode newHelmaNode = null;
- String childrenMapping = (String)props.get(element.getNodeName().toLowerCase()+"._children");
- // do we need a mapping directly among _children of helmaNode?
- // can either be through property elname._children=_all or elname._children=childname
- if( childrenMapping!=null && ( childrenMapping.equals("_all") || childrenMapping.equals(childElement.getNodeName()) ) ) {
- newHelmaNode = convert(childElement, helmaNode.createNode(null) );
- }
- // which name to choose for a virtual subnode:
- helmaKey = (String)props.get(domKey);
- if ( helmaKey==null ) {
- helmaKey = childElement.getNodeName().replace(':',defaultSeparator);
- }
- // try to get the virtual node
- helma.objectmodel.INode worknode = helmaNode.getNode( helmaKey, false );
- if ( worknode==null ) {
- // if virtual node doesn't exist, create it
- worknode = helmaNode.createNode( helmaKey );
- }
- if (DEBUG) debug( "mounting child "+ childElement.getNodeName() + " at worknode " + worknode.toString() );
- // now mount it, possibly re-using the helmaNode that's been created before
- if ( newHelmaNode!=null ) {
- worknode.addNode(newHelmaNode);
- } else {
- convert( childElement, worknode.createNode( null ) );
- }
- }
- // forget about other types (comments etc)
- continue;
- }
-
- // if there's some text content for this element, map it:
- if ( textcontent.length()>0 ) {
- helmaKey = (String)props.get(element.getNodeName().toLowerCase()+"._text");
- if ( helmaKey==null )
- helmaKey = "text";
- helmaNode.setString(helmaKey, textcontent.toString().trim() );
- }
-
- return helmaNode;
- }
-
- /**
- * set element's attributes as properties of helmaNode
- */
- private INode attributes( Element element, INode helmaNode ) {
- NamedNodeMap nnm = element.getAttributes();
- int len = nnm.getLength();
- for ( int i=0; i");
- writeln ("");
- writeln ("" );
- write ("");
- write (node,null,0);
- writeln (" ");
- convertedNodes = null;
- return true;
- }
-
- /**
- * write a hopobject and print all its properties and children.
- * if node has already been fully printed, just make a reference here.
- */
- public void write (INode node, String name, int level) throws IOException {
- if ( ++level>maxLevels )
- return;
- prefix.append(indent);
- if ( convertedNodes.contains(node) ) {
- writeReferenceTag (node, name);
- } else {
- convertedNodes.addElement (node);
- writeTagOpen (node,name);
- writeProperties (node,level);
- writeChildren (node,level);
- writeTagClose (node,name);
- }
- prefix = prefix.delete( prefix.length()-indent.length(), Integer.MAX_VALUE );
- }
-
- /**
- * loop through properties and print them with their property-name
- * as elementname
- */
- private void writeProperties (INode node, int level) throws IOException {
- Enumeration e = node.properties();
- while ( e.hasMoreElements() ) {
- String key = (String)e.nextElement();
- IProperty prop = node.get(key,false);
- if ( prop!=null ) {
- int type = prop.getType();
- if( type==IProperty.NODE ) {
- write (node.getNode(key,false), key, level);
- } else {
- writeProperty (node.get(key,false));
- }
- }
- }
- }
-
- public void writeNullProperty (String key) throws IOException {
- write (prefix.toString());
- write (indent);
- write ("<");
- write (key);
- write (" hop:type=\"null\"/>");
- write (LINESEPARATOR);
- }
-
- /**
- * write a single property, set attribute type according to type,
- * apply xml-encoding.
- */
- public void writeProperty (IProperty property) throws IOException {
- write (prefix.toString());
- write (indent);
- write ("<");
- write (property.getName());
- switch (property.getType()) {
- case IProperty.BOOLEAN:
- write (" hop:type=\"boolean\"");
- break;
- case IProperty.FLOAT:
- write (" hop:type=\"float\"");
- break;
- case IProperty.INTEGER:
- write (" hop:type=\"integer\"");
- break;
- }
- if ( property.getType()==IProperty.DATE ) {
- write (" hop:type=\"date\"");
- SimpleDateFormat format = new SimpleDateFormat ( DATEFORMAT );
- write (">");
- write ( format.format (property.getDateValue()) );
- } else {
- write (">");
- write ( HtmlEncoder.encodeXml (property.getStringValue()) );
- }
- write ("");
- write (property.getName());
- write (">");
- write (LINESEPARATOR);
- }
-
- /**
- * loop through the children-array and print them as
- */
- private void writeChildren (INode node, int level) throws IOException {
- Enumeration e = node.getSubnodes();
- while (e.hasMoreElements()) {
- INode nextNode = (INode)e.nextElement();
- write (nextNode, "hop:child", level);
- }
- }
-
- /**
- * write an opening tag for a node. Include id and prototype, use a
- * name if parameter is non-empty.
- */
- public void writeTagOpen (INode node, String name) throws IOException {
- write (prefix.toString());
- write ("<");
- write ( (name==null)?"hopobject" : name);
- write (" hop:id=\"");
- write (getNodeIdentifier(node));
- write ("\" hop:prototype=\"");
- write (getNodePrototype(node));
- write ("\"");
- write (">");
- write (LINESEPARATOR);
- }
-
- /**
- * write a closing tag for a node
- * e.g.
- */
- public void writeTagClose (INode node, String name) throws IOException {
- write (prefix.toString());
- write ("");
- write ( (name==null)?"hopobject" : name);
- write (">");
- write (LINESEPARATOR);
- }
-
- /**
- * write a tag holding a reference to an element that has
- * been dumped before.
- * e.g.
- */
- public void writeReferenceTag (INode node, String name) throws IOException {
- write (prefix.toString());
- write ("<");
- write ( (name==null)?"hopobject" : name);
- write ( " hop:idref=\"");
- write (getNodeIdentifier(node));
- write ("\" hop:prototyperef=\"");
- write (getNodePrototype(node));
- write ("\"");
- write ("/>");
- write (LINESEPARATOR);
- }
-
- /**
- * retrieve prototype-string of a node, defaults to "hopobject"
- */
- private String getNodePrototype( INode node ) {
- if ( node.getPrototype()==null || "".equals(node.getPrototype()) ) {
- return "hopobject";
- } else {
- return node.getPrototype();
- }
- }
-
- /**
- * TransientNode produces a different ID each time we call the getID()-method
- * this is a workaround and uses hashCode if INode stands for a TransientNode.
- */
- private String getNodeIdentifier( INode node ) {
- try {
- TransientNode tmp = (TransientNode)node;
- return Integer.toString( tmp.hashCode() );
- } catch ( ClassCastException e ) {
- return node.getID();
- }
- }
-
- public void writeln(String str) throws IOException {
- write (str);
- write (LINESEPARATOR);
- }
-
-}
-
diff --git a/src/helma/scripting/ActionFile.java b/src/helma/scripting/ActionFile.java
deleted file mode 100644
index 4bceaf60..00000000
--- a/src/helma/scripting/ActionFile.java
+++ /dev/null
@@ -1,128 +0,0 @@
-// ActionFile.java
-// Copyright (c) Helma.org 1998-2002
-
-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;
-
-
-/**
- * An ActionFile is a file containing function code that is exposed as a URI
- * of objects of this class/type. It is
- * usually represented by a file with extension .hac (hop action file)
- * that contains the raw body of the function.
- */
-
-
-public class ActionFile implements Updatable {
-
- String name;
- String functionName;
- Prototype prototype;
- Application app;
- File file;
- String content;
- long lastmod;
-
-
- public ActionFile (File file, String name, Prototype proto) {
- this.prototype = proto;
- this.app = proto.getApplication ();
- this.name = name;
- functionName = getName()+"_action";
- this.file = file;
- this.content = null;
- if (file != null)
- update ();
- }
-
- public ActionFile (String content, String name, Prototype proto) {
- this.prototype = proto;
- this.app = proto.getApplication ();
- this.name = name;
- functionName = getName()+"_action";
- this.file = null;
- this.content = content;
- }
-
-
- /**
- * Abstract method that must be implemented by subclasses to update evaluators with
- * new content of action file.
- */
- // protected abstract void update (String content) throws Exception;
-
- /**
- * Abstract method that must be implemented by subclasses to remove
- * action from evaluators.
- */
- // protected abstract void remove ();
-
-
- /**
- * 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 ();
- content = new String (cbuf);
- // update (content);
- } catch (Exception filex) {
- app.logEvent ("*** Error reading action file "+file+": "+filex);
- }
- lastmod = file.lastModified ();
- }
- }
-
- protected void remove () {
- prototype.actions.remove (name);
- if (file != null)
- prototype.updatables.remove (file.getName());
- }
-
- public String getName () {
- return name;
- }
-
- public String getContent () {
- return content;
- }
-
- public String getFunctionName () {
- return functionName;
- }
-
- public Prototype getPrototype () {
- return prototype;
- }
-
- public Application getApplication () {
- return app;
- }
-
- public String toString () {
- return "ActionFile["+prototype.getName()+"/"+functionName+"]";
- }
-
-}
-
-
diff --git a/src/helma/scripting/FunctionFile.java b/src/helma/scripting/FunctionFile.java
deleted file mode 100644
index 85076c18..00000000
--- a/src/helma/scripting/FunctionFile.java
+++ /dev/null
@@ -1,153 +0,0 @@
-// 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;
-
-
-/**
- * This represents a File containing script functions for a given class/prototype.
- */
-
-
-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;
- 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 file != null && lastmod != file.lastModified ();
- }
-
-
- public void update () {
-
- if (file != null) {
- if (!file.exists ()) {
- remove ();
- } else {
- lastmod = file.lastModified ();
- // app.typemgr.readFunctionFile (file, prototype.getName ());
- // app.getScriptingEnvironment().evaluateFile (prototype, file);
- }
- } else {
- // app.getScriptingEnvironment().evaluateString (prototype, content);
- }
- }
-
- /* public void evaluate (ScriptingEnvironment env) {
- if (file != null)
- env.evaluateFile (prototype, file);
- else
- env.evaluateString (prototype, content);
- }*/
- public boolean hasFile () {
- return file != null;
- }
-
- public File getFile () {
- return file;
- }
-
- public String getContent () {
- return content;
- }
-
-
- 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
deleted file mode 100644
index 4ded3664..00000000
--- a/src/helma/scripting/ScriptingEnvironment.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// ScriptingEnvironment.java
-// Copyright (c) Hannes Wallnöfer 1998-2001
-
-package helma.scripting;
-
-import helma.framework.core.Application;
-import helma.framework.core.Prototype;
-import helma.framework.core.RequestEvaluator;
-import java.util.*;
-import java.io.File;
-
-/**
- * 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 (Application app, Properties props) throws ScriptingException;
-
- /**
- * A prototype has been updated and must be re-evaluated.
- */
- public void updatePrototype (Prototype prototype);
-
- /**
- * Invoke a function on some object, using the given arguments and global vars.
- */
- public Object invoke (Object thisObject, String functionName, Object[] args,
- HashMap globals, RequestEvaluator reval)
- throws ScriptingException;
-
- /**
- * Get a property on an object
- */
- public Object get (Object thisObject, String key, RequestEvaluator reval);
-
- /**
- * Return true if a function by that name is defined for that object.
- */
- public boolean hasFunction (Object thisObject, String functionName, RequestEvaluator reval)
- throws ScriptingException;
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/helma/scripting/ScriptingException.java b/src/helma/scripting/ScriptingException.java
deleted file mode 100644
index d738013b..00000000
--- a/src/helma/scripting/ScriptingException.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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/fesi/ESGenericObject.java b/src/helma/scripting/fesi/ESGenericObject.java
deleted file mode 100644
index c396bf74..00000000
--- a/src/helma/scripting/fesi/ESGenericObject.java
+++ /dev/null
@@ -1,109 +0,0 @@
-// ESGenericObject.java
-// Copyright (c) Hannes Wallnöfer 1998-2000
-
-
-package helma.scripting.fesi;
-
-import helma.framework.core.*;
-import helma.framework.IPathElement;
-import FESI.Interpreter.*;
-import FESI.Exceptions.*;
-import FESI.Data.*;
-import java.util.*;
-
-
-/**
- * A wrapper for a Java object that may or may not implement the IPathElement interface.
- */
-
-public class ESGenericObject extends ObjectPrototype {
-
- ESWrapper wrapper;
- Object wrappedObject;
-
- public ESGenericObject (ESObject prototype, Evaluator evaluator, Object obj) {
- super (prototype, evaluator);
- wrappedObject = obj;
- wrapper = new ESWrapper (obj, evaluator);
- }
-
-
- public String getESClassName () {
- return "GenericObject";
- }
-
- public String toString () {
- return wrappedObject.toString ();
- }
-
- public String toDetailString () {
- return wrapper.toDetailString ();
- }
-
-
- public void putProperty(String propertyName, ESValue propertyValue, int hash) throws EcmaScriptException {
- wrapper.putProperty (propertyName, propertyValue, hash);
- }
-
- public boolean hasProperty(String propertyName, int hash) throws EcmaScriptException {
- return super.hasProperty (propertyName, hash) || wrapper.hasProperty (propertyName, hash);
- }
-
- public boolean deleteProperty(String propertyName, int hash) throws EcmaScriptException {
- return wrapper.deleteProperty (propertyName, hash);
- }
-
- public ESValue getProperty (int i) throws EcmaScriptException {
- return wrapper.getProperty (i);
- }
-
- public void putProperty(int index, ESValue propertyValue) throws EcmaScriptException {
- wrapper.putProperty (index, propertyValue);
- }
-
-
- public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException {
- ESValue val = super.getProperty (propertyName, hash);
- if (val == null || val == ESUndefined.theUndefined)
- val = wrapper.getProperty (propertyName, hash);
- return val;
- }
-
- public ESValue doIndirectCall(Evaluator evaluator, ESObject thisObject, String functionName, ESValue[] arguments)
- throws EcmaScriptException, NoSuchMethodException {
- if (super.hasProperty (functionName, functionName.hashCode()))
- return super.doIndirectCall (evaluator, thisObject, functionName, arguments);
- return wrapper.doIndirectCall (evaluator, thisObject, functionName, arguments);
- }
-
- public Enumeration getAllProperties () {
- return wrapper.getProperties ();
- }
-
- public Enumeration getProperties () {
- return wrapper.getProperties ();
- }
-
- public Object toJavaObject () {
- return wrappedObject;
- }
-
- /**
- * 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 ESGenericObject) {
- ESGenericObject other = (ESGenericObject) what;
- return (wrappedObject.equals (other.wrappedObject));
- }
- return false;
- }
-
-}
-
-
diff --git a/src/helma/scripting/fesi/ESMapWrapper.java b/src/helma/scripting/fesi/ESMapWrapper.java
deleted file mode 100644
index dd1402e6..00000000
--- a/src/helma/scripting/fesi/ESMapWrapper.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// ESMapWrapper.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.*;
-
-
-
-/**
- * An EcmaScript object that makes stuff in a hashtable accessible as its properties
- */
-
-public class ESMapWrapper extends ESWrapper {
-
- private Map data;
- private FesiEvaluator fesi;
-
- public ESMapWrapper (FesiEvaluator fesi) {
- super (new Object(), fesi.getEvaluator ());
- this.fesi = fesi;
- }
-
- public ESMapWrapper (FesiEvaluator fesi, Map data) {
- super (new Object(), fesi.getEvaluator ());
- this.fesi = fesi;
- this.data = data;
- }
-
- public void setData (Map data) {
- this.data = data;
- }
-
- /**
- * Overridden to make the object read-only
- */
- public void putProperty(String propertyName, ESValue propertyValue, int hash) throws EcmaScriptException {
- if (data == null)
- data = new HashMap ();
- data.put (propertyName, propertyValue);
- }
-
- public boolean deleteProperty(String propertyName, int hash) throws EcmaScriptException {
- data.remove (propertyName);
- return true;
- }
-
- 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 fesi.getNodeWrapper ((INode) val);
- else if (val instanceof ESValue)
- return (ESValue) val;
- return ESLoader.normalizeValue(val, evaluator);
- }
-
-
- public Enumeration getAllProperties () {
- return getProperties ();
- }
-
- public Enumeration getProperties () {
- Object[] keys = data == null ? null : data.keySet().toArray ();
- return new Enum (keys);
- }
-
-
- class Enum implements Enumeration {
-
- Object[] elements;
- int pos;
-
- Enum (Object[] elements) {
- this.elements = elements;
- pos = 0;
- }
-
- public boolean hasMoreElements () {
- return elements != null && pos < elements.length;
- }
-
- public Object nextElement () {
- if (elements == null || pos >= elements.length)
- throw new NoSuchElementException ();
- return elements[pos++];
- }
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/helma/scripting/fesi/ESUser.java b/src/helma/scripting/fesi/ESUser.java
deleted file mode 100644
index 57819880..00000000
--- a/src/helma/scripting/fesi/ESUser.java
+++ /dev/null
@@ -1,121 +0,0 @@
-// ESUser.java
-// Copyright (c) Hannes Wallnöfer 1998-2000
-
-package helma.scripting.fesi;
-
-import helma.framework.core.*;
-import helma.objectmodel.*;
-import helma.objectmodel.db.Node;
-import FESI.Interpreter.*;
-import FESI.Exceptions.*;
-import FESI.Data.*;
-
-/**
- * The ESUser is a special kind of Node object that represents a user of
- * a Helma 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, FesiEvaluator eval, User user) {
- super (eval.getPrototype("user"), eval.getEvaluator(), 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 there is a user session object, we expose some of its properties.
- // Otherwise, we call the parent's class getProperty method.
- 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 this represents an active user object, we override
- // the cache property to come from the user session object
- // instead of the Node object.
- if ("cache".equals (propname) && user != null) {
- cache = user.getCache ();
- cacheWrapper.node = cache;
- 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) {
- // this only makes sense if this wrapper represents an active user
- if (user == null)
- return;
- // set the node on the transient user session object
- 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 Node)
- handle = ((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 () {
- // this only makes sense if this wrapper represents an active user
- if (user == null)
- return;
- node = user.getNode ();
- // set node handle to wrapped node
- if (node instanceof Node)
- handle = ((Node) node).getHandle ();
- else
- handle = null;
-
- }
-
- public boolean clearCache () {
- if (user != null)
- user.clearCache ();
- else
- super.clearCache ();
- return true;
- }
-
- public String toString () {
- return ("UserObject "+node.getName ());
- }
-
-}
-
diff --git a/src/helma/scripting/fesi/FesiEvaluator.java b/src/helma/scripting/fesi/FesiEvaluator.java
deleted file mode 100644
index 0097f0ec..00000000
--- a/src/helma/scripting/fesi/FesiEvaluator.java
+++ /dev/null
@@ -1,587 +0,0 @@
-// FesiScriptingEnvironment.java
-// Copyright (c) Hannes Wallnöfer 2002
-
-package helma.scripting.fesi;
-
-import helma.scripting.*;
-import helma.scripting.fesi.extensions.*;
-import helma.framework.*;
-import helma.framework.core.*;
-import helma.objectmodel.*;
-import helma.objectmodel.db.DbMapping;
-import helma.objectmodel.db.Relation;
-import helma.util.Updatable;
-import java.util.*;
-import java.io.*;
-import FESI.Data.*;
-import FESI.Interpreter.*;
-import FESI.Exceptions.*;
-import Acme.LruHashtable;
-
-/**
- * This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter.
- */
-
-public class FesiEvaluator {
-
- // the application we're running in
- public Application app;
-
- // The FESI evaluator
- Evaluator evaluator;
-
- // the global object
- GlobalObject global;
-
- // caching table for JavaScript object wrappers
- LruHashtable wrappercache;
-
- // table containing JavaScript prototypes
- Hashtable prototypes;
-
- // the request evaluator instance owning this fesi evaluator
- RequestEvaluator reval;
-
- // extensions loaded by this evaluator
- static String[] extensions = new String[] {
- "FESI.Extensions.BasicIO",
- "FESI.Extensions.FileIO",
- "helma.xmlrpc.fesi.FesiRpcExtension",
- "helma.scripting.fesi.extensions.ImageExtension",
- "helma.scripting.fesi.extensions.FtpExtension",
- "FESI.Extensions.JavaAccess",
- "FESI.Extensions.OptionalRegExp"};
-
- public FesiEvaluator (Application app, RequestEvaluator reval) {
- this.app = app;
- this.reval = reval;
- wrappercache = new LruHashtable (100, .80f);
- prototypes = new Hashtable ();
- try {
- evaluator = new Evaluator();
- evaluator.reval = this;
- global = evaluator.getGlobalObject();
- for (int i=0; i "+esv.getClass());
- if (esv instanceof ConstructedFunctionObject || esv instanceof FesiActionAdapter.ThrowException)
- op.deleteProperty (prop, prop.hashCode());
- } catch (Exception x) {}
- }
- }
-
-
-
- /**
- * Invoke a function on some object, using the given arguments and global vars.
- */
- public Object invoke (Object thisObject, String functionName, Object[] args, HashMap globals) throws ScriptingException {
- ESObject eso = null;
- if (thisObject == null)
- eso = global;
- else
- eso = getElementWrapper (thisObject);
-
- GlobalObject global = evaluator.getGlobalObject ();
-
- // if we are provided with global variables to set for this invocation,
- // remember the global variables before invocation to be able to reset them afterwards.
- Set globalVariables = null;
- try {
- ESValue[] esv = args == null ? new ESValue[0] : new ESValue[args.length];
- for (int i=0; i 0 && n.getDbMapping () == null) {
- n.setDbMapping (app.getDbMapping (protoname));
- }
-
- op = getPrototype (protoname);
-
- // no prototype found for this node?
- if (op == null)
- op = getPrototype("hopobject");
-
-
- DbMapping dbm = n.getDbMapping ();
- if (dbm != null && dbm.isInstanceOf ("user"))
- esn = new ESUser (n, this, null);
- else
- esn = new ESNode (op, evaluator, n, this);
-
- wrappercache.put (n, esn);
- // app.logEvent ("Wrapper for "+n+" created");
- }
-
- return esn;
- }
-
-
- /**
- * Register a new Node wrapper with the wrapper cache. This is used by the
- * Node constructor.
- */
- public void putNodeWrapper (INode n, ESNode esn) {
- wrappercache.put (n, esn);
- }
-
- /**
- * Get a scripting wrapper object for a user object. Active user objects are represented by
- * the special ESUser wrapper class.
- */
- public ESNode getNodeWrapper (User u) {
- if (u == null)
- return null;
-
- ESUser esn = (ESUser) wrappercache.get (u);
-
- if (esn == null) {
- esn = new ESUser (u.getNode(), this, u);
- wrappercache.put (u, esn);
- } else {
- // the user node may have changed (login/logout) while the ESUser was
- // lingering in the cache.
- esn.updateNodeFromUser ();
- }
-
- return esn;
- }
-
- /**
- * Return the RequestEvaluator owning and driving this FESI evaluator.
- */
- public RequestEvaluator getRequestEvaluator () {
- return reval;
- }
-
- /**
- * Return the Response object of the current evaluation context. Proxy method to RequestEvaluator.
- */
- public ResponseTrans getResponse () {
- return reval.res;
- }
-
- /**
- * Return the Request object of the current evaluation context. Proxy method to RequestEvaluator.
- */
- public RequestTrans getRequest () {
- return reval.req;
- }
-
- public synchronized void evaluateFile (Prototype prototype, File file) {
- try {
- FileReader fr = new FileReader (file);
- EvaluationSource es = new FileEvaluationSource (file.getPath (), null);
- updateEvaluator (prototype, fr, es);
- } catch (IOException iox) {
- app.logEvent ("Error updating function file: "+iox);
- }
- }
-
- public synchronized void evaluateString (Prototype prototype, String code) {
- StringReader reader = new StringReader (code);
- StringEvaluationSource es = new StringEvaluationSource (code, null);
- updateEvaluator (prototype, reader, es);
- }
-
- public synchronized void updateEvaluator (Prototype prototype, Reader reader, EvaluationSource source) {
-
- // HashMap priorProps = null;
- // HashSet newProps = null;
-
- try {
-
- ObjectPrototype op = 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
- 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 (Throwable 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);
- } */
-
- }
- }
-
-
-}
diff --git a/src/helma/scripting/fesi/FesiScriptingEnvironment.java b/src/helma/scripting/fesi/FesiScriptingEnvironment.java
deleted file mode 100644
index d58da662..00000000
--- a/src/helma/scripting/fesi/FesiScriptingEnvironment.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// FesiScriptingEnvironment.java
-// Copyright (c) Hannes Wallnöfer 2002
-
-package helma.scripting.fesi;
-
-import helma.scripting.*;
-import helma.framework.core.*;
-import java.util.*;
-import java.io.File;
-import FESI.Data.*;
-import FESI.Interpreter.*;
-import FESI.Exceptions.*;
-
-/**
- * This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter.
- */
-public class FesiScriptingEnvironment implements ScriptingEnvironment {
-
- Application app;
- Properties props;
- HashMap evaluators;
-
- /**
- * Initialize the environment using the given properties
- */
- public void init (Application app, Properties props) throws ScriptingException {
- this.app = app;
- this.props = props;
- evaluators = new HashMap ();
- }
-
-
- /**
- * A prototype has been updated and must be re-evaluated.
- */
- public void updatePrototype (Prototype prototype) {
- for (Iterator i = evaluators.values().iterator(); i.hasNext(); ) {
- FesiEvaluator fesi = (FesiEvaluator) i.next();
- fesi.evaluatePrototype (prototype);
- }
- }
-
- /**
- * Invoke a function on some object, using the given arguments and global vars.
- */
- public Object invoke (Object thisObject, String functionName, Object[] args,
- HashMap globals, RequestEvaluator reval)
- throws ScriptingException {
- // check if there is already a FesiEvaluator for this RequestEvaluator.
- // if not, create one.
- FesiEvaluator fesi = getEvaluator (reval);
- return fesi.invoke (thisObject, functionName, args, globals);
- }
-
- /**
- * Get a property on an object
- */
- public Object get (Object thisObject, String key, RequestEvaluator reval) {
- FesiEvaluator fesi = getEvaluator (reval);
- return fesi.getProperty (thisObject, key);
- }
-
- /**
- * Return true if a function by that name is defined for that object.
- */
- public boolean hasFunction (Object thisObject, String functionName, RequestEvaluator reval)
- throws ScriptingException {
- FesiEvaluator fesi = getEvaluator (reval);
- return fesi.hasFunction (thisObject, functionName);
- }
-
-
- Collection getEvaluators () {
- return evaluators.values();
- }
-
- FesiEvaluator getEvaluator (RequestEvaluator reval) {
- FesiEvaluator fesi = (FesiEvaluator) evaluators.get (reval);
- if (fesi == null) {
- fesi = new FesiEvaluator (app, reval);
- evaluators.put (reval, fesi);
- }
- return fesi;
- }
-}
diff --git a/src/helma/scripting/fesi/extensions/DomExtension.java b/src/helma/scripting/fesi/extensions/DomExtension.java
deleted file mode 100644
index 374c6c87..00000000
--- a/src/helma/scripting/fesi/extensions/DomExtension.java
+++ /dev/null
@@ -1,163 +0,0 @@
-package helma.scripting.fesi.extensions;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.FileNotFoundException;
-
-import FESI.Data.*;
-import FESI.Exceptions.*;
-import FESI.Extensions.*;
-import FESI.Interpreter.*;
-
-import helma.framework.core.Application;
-import helma.framework.core.RequestEvaluator;
-import helma.objectmodel.INode;
-import helma.objectmodel.db.Node;
-import helma.objectmodel.dom.*;
-import helma.scripting.fesi.ESNode;
-
-public class DomExtension extends Extension {
-
- private transient Evaluator evaluator = null;
-
- public DomExtension() {
- super();
- }
-
- public void initializeExtension(Evaluator evaluator) throws EcmaScriptException {
- this.evaluator = evaluator;
- GlobalObject go = evaluator.getGlobalObject();
- ObjectPrototype op = (ObjectPrototype) evaluator.getObjectPrototype();
- FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
-
- ESObject globalXml = new GlobalObjectXml("Xml", evaluator, fp);
- globalXml.putHiddenProperty ("length",new ESNumber(1));
- globalXml.putHiddenProperty ("load", new XmlLoad ("load", evaluator, fp));
- globalXml.putHiddenProperty ("save", new XmlSave ("save", evaluator, fp));
- globalXml.putHiddenProperty ("create", new XmlCreate ("create", evaluator, fp));
- globalXml.putHiddenProperty ("get", new XmlGet ("get", evaluator, fp));
- go.putHiddenProperty ("Xml", globalXml);
- }
-
- class GlobalObjectXml extends BuiltinFunctionObject {
- GlobalObjectXml(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 {
- throw new EcmaScriptException("Xml can't be instanced");
- }
- }
-
- class XmlSave extends BuiltinFunctionObject {
- XmlSave(String name, Evaluator evaluator, FunctionPrototype fp) {
- super(fp, evaluator, name, 1);
- }
- public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- if ( arguments==null || arguments.length<2 )
- throw new EcmaScriptException("not enough arguments");
- INode node = null;
- try {
- node = ((ESNode)arguments[1]).getNode();
- } catch ( Exception e ) {
- // we definitly need a node
- throw new EcmaScriptException("argument is not an hopobject");
- }
- try {
- File tmpFile = new File(arguments[0].toString()+".tmp."+XmlWriter.generateID());
- XmlWriter writer = new XmlWriter (tmpFile);
- boolean result = writer.write(node);
- writer.close();
- File finalFile = new File(arguments[0].toString());
- tmpFile.renameTo (finalFile);
- this.evaluator.reval.app.logEvent("wrote xml to " + finalFile.getAbsolutePath() );
- } catch (IOException io) {
- throw new EcmaScriptException (io.toString());
- }
- return ESBoolean.makeBoolean(true);
- }
- }
-
- class XmlCreate extends BuiltinFunctionObject {
- XmlCreate(String name, Evaluator evaluator, FunctionPrototype fp) {
- super(fp, evaluator, name, 1);
- }
- public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- if ( arguments==null || arguments.length==0 )
- throw new EcmaScriptException("not enough arguments");
- INode node = null;
- try {
- node = ((ESNode)arguments[0]).getNode();
- } catch ( Exception e ) {
- // we definitly need a node
- throw new EcmaScriptException("argument is not an hopobject");
- }
- try {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- XmlWriter writer = new XmlWriter (out);
- boolean result = writer.write(node);
- writer.flush();
- return new ESString (out.toString());
- } catch (IOException io) {
- throw new EcmaScriptException (io.toString());
- }
- }
- }
-
- class XmlLoad extends BuiltinFunctionObject {
- XmlLoad(String name, Evaluator evaluator, FunctionPrototype fp) {
- super(fp, evaluator, name, 1);
- }
- public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- if ( arguments==null || arguments.length==0 )
- throw new EcmaScriptException("no arguments for Xml.load()");
- INode node = null;
- try {
- node = ((ESNode)arguments[1]).getNode();
- } catch ( Exception e ) { //classcast, arrayindex etc
- // make sure we have a node, even if 2nd arg doesn't exist or is not a node
- node = new Node ( (String)null, (String)null, this.evaluator.reval.app.getWrappedNodeManager() );
- }
- try {
- XmlReader reader = new XmlReader ();
- INode result = reader.read (arguments[0].toString(),node);
- return this.evaluator.reval.getNodeWrapper (result);
- } catch ( NoClassDefFoundError e ) {
- throw new EcmaScriptException ("Can't load dom-capable xml parser.");
- } catch ( RuntimeException f ) {
- throw new EcmaScriptException (f.toString());
- }
- }
- }
-
- class XmlGet extends BuiltinFunctionObject {
- XmlGet(String name, Evaluator evaluator, FunctionPrototype fp) {
- super(fp, evaluator, name, 1);
- }
- public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
- if ( arguments==null || arguments.length==0 )
- throw new EcmaScriptException("Xml.get() needs a location as an argument");
- try {
- XmlConverter converter;
- if ( arguments.length>1 ) {
- converter = new XmlConverter (arguments[1].toString());
- } else {
- converter = new XmlConverter ();
- }
- INode node = new helma.objectmodel.db.Node ( (String)null, (String)null, this.evaluator.reval.app.getWrappedNodeManager() );
- INode result = converter.convert (arguments[0].toString(),node);
- return this.evaluator.reval.getNodeWrapper(result);
- } catch ( NoClassDefFoundError e ) {
- throw new EcmaScriptException("Can't load dom-capable xml parser.");
- } catch ( RuntimeException f ) {
- throw new EcmaScriptException(f.toString());
- }
- }
- }
-
-}
-
-
diff --git a/src/helma/servlet/AbstractServletClient.java b/src/helma/servlet/AbstractServletClient.java
deleted file mode 100644
index 2795c6d2..00000000
--- a/src/helma/servlet/AbstractServletClient.java
+++ /dev/null
@@ -1,300 +0,0 @@
-// ServletClient.java
-// Copyright (c) Hannes Wallnöfer, Raphael Spannocchi 1998-2000
-
-/* Portierung von helma.asp.AspClient auf Servlets */
-/* Author: Raphael Spannocchi Datum: 27.11.1998 */
-
-package helma.servlet;
-
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.*;
-import java.rmi.Naming;
-import java.rmi.RemoteException;
-import java.util.*;
-import helma.framework.*;
-import helma.util.*;
-
-/**
- * This is an abstract Hop servlet adapter. This class communicates with hop applications
- * via RMI. Subclasses are either one servlet per app, or one servlet that handles multiple apps
- */
-
-public abstract class AbstractServletClient extends HttpServlet {
-
- String host = null;
- int port = 0;
- int uploadLimit; // limit to HTTP uploads in kB
- String hopUrl;
- String cookieDomain;
- boolean caching;
- boolean debug;
-
- static final byte HTTP_GET = 0;
- static final byte HTTP_POST = 1;
-
- public void init (ServletConfig init) throws ServletException {
- super.init (init);
-
- host = init.getInitParameter ("host");
- if (host == null) host = "localhost";
-
- String portstr = init.getInitParameter ("port");
- port = portstr == null ? 5055 : Integer.parseInt (portstr);
-
- String upstr = init.getInitParameter ("uploadLimit");
- uploadLimit = upstr == null ? 1024 : Integer.parseInt (upstr);
-
- cookieDomain = init.getInitParameter ("cookieDomain");
-
- hopUrl = "//" + host + ":" + port + "/";
-
- debug = ("true".equalsIgnoreCase (init.getInitParameter ("debug")));
-
- caching = ! ("false".equalsIgnoreCase (init.getInitParameter ("caching")));
- }
-
-
- abstract IRemoteApp getApp (String appID) throws Exception;
-
- abstract void invalidateApp (String appID);
-
- abstract String getAppID (String reqpath);
-
- abstract String getRequestPath (String reqpath);
-
-
- public void doGet (HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- execute (request, response, HTTP_GET);
- }
-
- public void doPost (HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- execute (request, response, HTTP_POST);
- }
-
-
- protected void execute (HttpServletRequest request, HttpServletResponse response, byte method) {
- String protocol = request.getProtocol ();
- Cookie[] cookies = request.getCookies();
-
- // get app and path from original request path
- String pathInfo = request.getPathInfo ();
- String appID = getAppID (pathInfo);
- RequestTrans reqtrans = new RequestTrans (method);
- reqtrans.path = getRequestPath (pathInfo);
-
- try {
-
- // read and set http parameters
- for (Enumeration e = request.getParameterNames(); e.hasMoreElements(); ) {
- String nextKey = (String)e.nextElement();
- String[] paramValues = request.getParameterValues(nextKey);
- if (paramValues != null) {
- reqtrans.set (nextKey, paramValues[0]); // set to single string value
- if (paramValues.length > 1)
- reqtrans.set (nextKey+"_array", paramValues); // set string array
- }
- }
-
- // check for MIME file uploads
- String contentType = request.getContentType();
- if (contentType != null && contentType.indexOf("multipart/form-data")==0) {
- // File Upload
- Uploader up;
- try {
- if ((up = getUpload (request)) != null) {
- Hashtable upload = up.getParts ();
- for (Enumeration e = upload.keys(); e.hasMoreElements(); ) {
- String nextKey = (String) e.nextElement ();
- Object nextPart = upload.get (nextKey);
- reqtrans.set (nextKey, nextPart);
- }
- }
- } catch (Exception upx) {
- String uploadErr = upx.getMessage ();
- if (uploadErr == null || uploadErr.length () == 0)
- uploadErr = upx.toString ();
- reqtrans.set ("uploadError", uploadErr);
- }
- }
-
- // read cookies
- if (cookies != null) {
- for (int i=0; i < cookies.length;i++) try {
- // get Cookies
- String nextKey = cookies[i].getName ();
- String nextPart = cookies[i].getValue ();
- if ("HopSession".equals (nextKey))
- reqtrans.session = nextPart;
- else
- reqtrans.set (nextKey, nextPart);
- } catch (Exception badCookie) {}
- }
-
- // check if we need to create a session id
- if (reqtrans.session == null) {
- reqtrans.session = Long.toString (Math.round (Math.random ()*Long.MAX_VALUE), 16);
- reqtrans.session += "@"+Long.toString (System.currentTimeMillis (), 16);
- Cookie c = new Cookie("HopSession", reqtrans.session);
- c.setPath ("/");
- if (cookieDomain != null)
- c.setDomain (cookieDomain);
- response.addCookie(c);
- }
-
- // do standard HTTP variables
- String host = request.getHeader ("Host");
- if (host != null) {
- host = host.toLowerCase();
- reqtrans.set ("http_host", host);
- }
-
- String referer = request.getHeader ("Referer");
- if (referer != null)
- reqtrans.set ("http_referer", referer);
-
- String remotehost = request.getRemoteAddr ();
- if (remotehost != null)
- reqtrans.set ("http_remotehost", remotehost);
-
- String browser = request.getHeader ("User-Agent");
- if (browser != null)
- reqtrans.set ("http_browser", browser);
-
- String authorization = request.getHeader("authorization");
- if ( authorization != null )
- reqtrans.set ("authorization", authorization );
-
- // get RMI ref to application and execute request
- IRemoteApp app = getApp (appID);
- ResponseTrans restrans = null;
- try {
- restrans = app.execute (reqtrans);
- } catch (RemoteException cnx) {
- invalidateApp (appID);
- app = getApp (appID);
- app.ping ();
- restrans = app.execute (reqtrans);
- }
- writeResponse (response, restrans, cookies, protocol);
-
- } catch (Exception x) {
- invalidateApp (appID);
- try {
- response.setContentType ("text/html");
- Writer out = response.getWriter ();
- if (debug)
- out.write ("Error: " +x);
- else
- out.write ("This server is temporarily unavailable. Please check back later.");
- out.flush ();
- } catch (Exception io_e) {}
- }
- }
-
-
- void writeResponse (HttpServletResponse res, ResponseTrans trans, Cookie[] cookies, String protocol) {
-
- for (int i = 0; i < trans.countCookies(); i++) try {
- Cookie c = new Cookie(trans.getKeyAt(i), trans.getValueAt(i));
- c.setPath ("/");
- if (cookieDomain != null)
- c.setDomain (cookieDomain);
- int expires = trans.getDaysAt(i);
- if (expires > 0)
- c.setMaxAge(expires * 60*60*24); // Cookie time to live, days -> seconds
- res.addCookie(c);
- } catch (Exception ign) {}
-
- if (trans.getRedirect () != null) {
- try {
- res.sendRedirect(trans.getRedirect ());
- } catch(Exception io_e) {}
-
- } else {
-
- if (!trans.cache || ! caching) {
- // Disable caching of response.
- if (protocol == null || !protocol.endsWith ("1.1"))
- res.setHeader ("Pragma", "no-cache"); // for HTTP 1.0
- else
- res.setHeader ("Cache-Control", "no-cache"); // for HTTP 1.1
- }
- if ( trans.realm!=null )
- res.setHeader( "WWW-Authenticate", "Basic realm=\"" + trans.realm + "\"" );
- if (trans.status > 0)
- res.setStatus (trans.status);
- res.setContentLength (trans.getContentLength ());
- res.setContentType (trans.getContentType ());
- try {
- OutputStream out = res.getOutputStream ();
- out.write (trans.getContent ());
- out.close ();
- } catch(Exception io_e) {}
- }
- }
-
- private void redirectResponse (HttpServletRequest request, HttpServletResponse res, ResponseTrans trans, String url) {
- try {
- res.sendRedirect(url);
- } catch (Exception e) {
- System.err.println ("Exception at redirect: " + e + e.getMessage());
- }
- }
-
-
- public Uploader getUpload (HttpServletRequest request) throws Exception {
- int contentLength = request.getContentLength ();
- BufferedInputStream in = new BufferedInputStream (request.getInputStream ());
- Uploader up = null;
- try {
- if (contentLength > uploadLimit*1024) {
- // consume all input to make Apache happy
- byte b[] = new byte[1024];
- int read = 0;
- while (read > -1)
- read = in.read (b, 0, 1024);
- throw new RuntimeException ("Upload exceeds limit of "+uploadLimit+" kb.");
- }
- String contentType = request.getContentType ();
- up = new Uploader(uploadLimit);
- up.load (in, contentType, contentLength);
- } finally {
- try { in.close (); } catch (Exception ignore) {}
- }
- return up;
- }
-
-
- public Object getUploadPart(Uploader up, String name) {
- return up.getParts().get(name);
- }
-
-
- public String getServletInfo(){
- return new String("Hop Servlet Client");
- }
-
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/helma/servlet/AcmeFileServlet.java b/src/helma/servlet/AcmeFileServlet.java
index 9e836f6d..d2f4f003 100644
--- a/src/helma/servlet/AcmeFileServlet.java
+++ b/src/helma/servlet/AcmeFileServlet.java
@@ -60,12 +60,6 @@ public class AcmeFileServlet extends FileServlet
this.root = root;
}
- public void init (ServletConfig config) throws ServletException {
- super.init (config);
- // do nothing
- }
-
-
/// Services a single request from the client.
// @param req the servlet request
// @param req the servlet response
@@ -212,4 +206,3 @@ public class AcmeFileServlet extends FileServlet
}
-
diff --git a/src/helma/servlet/AcmeServletClient.java b/src/helma/servlet/AcmeServletClient.java
index 1c294f5c..eda5d42f 100644
--- a/src/helma/servlet/AcmeServletClient.java
+++ b/src/helma/servlet/AcmeServletClient.java
@@ -1,4 +1,4 @@
-// AcmeServletClient.java
+// ServletClient.java
// Copyright (c) Hannes Wallnoefer, Raphael Spannocchi 1998-2000
/* Portierung von helma.asp.AspClient auf Servlets */
@@ -12,63 +12,96 @@ import java.io.*;
import java.util.*;
import helma.framework.*;
import helma.framework.core.Application;
+import helma.objectmodel.Node;
import helma.util.Uploader;
/**
- * This is the Hop servlet adapter that uses the Acme servlet API clone and communicates
+ * This is the HOP servlet adapter that uses the Acme servlet API clone and communicates
* directly with hop applications instead of using RMI.
*/
-public class AcmeServletClient extends HttpServlet {
+public class AcmeServletClient extends HttpServlet{
private int uploadLimit; // limit to HTTP uploads in kB
private Hashtable apps;
private Application app;
private String cookieDomain;
+ private boolean caching;
private boolean debug;
- static final byte HTTP_GET = 0;
- static final byte HTTP_POST = 1;
public AcmeServletClient (Application app) {
this.app = app;
- this.uploadLimit = 1024; // generous 1mb upload limit
+ this.uploadLimit = 1024; // generous 1mb upload limit
}
- public void init (ServletConfig config) throws ServletException {
- super.init (config);
- // do nothing
+
+ public void service (HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ execute (request, response);
}
public void doGet (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
- execute (request, response, HTTP_GET);
+ execute (request, response);
}
-
+
public void doPost (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
- execute (request, response, HTTP_POST);
+ execute (request, response);
}
-
- private void execute (HttpServletRequest request, HttpServletResponse response, byte method) {
+
+
+ private void execute (HttpServletRequest request, HttpServletResponse response) {
String protocol = request.getProtocol ();
Cookie[] cookies = request.getCookies();
- try {
- RequestTrans reqtrans = new RequestTrans (method);
+ try {
+ RequestTrans reqtrans = new RequestTrans ();
+ // HACK - sessions not fully supported in Acme.Serve
+ // Thats ok, we dont need the session object, just the id.
+ reqtrans.session = request.getRequestedSessionId();
+ if (cookies != null) {
+ for (int i=0; i < cookies.length;i++) try { // get Cookies
+ String nextKey = cookies[i].getName ();
+ String nextPart = cookies[i].getValue ();
+ reqtrans.set (nextKey, nextPart);
+ } catch (Exception badCookie) {}
+ }
+ // get optional path info
+ String pathInfo = request.getServletPath ();
+ if (pathInfo != null) {
+ if (pathInfo.indexOf (app.getName()) == 1)
+ pathInfo = pathInfo.substring (app.getName().length()+1);
+ reqtrans.path = trim (pathInfo);
+ } else
+ reqtrans.path = "";
+
+ String host = request.getHeader ("Host");
+ if (host != null) {
+ host = host.toLowerCase();
+ reqtrans.set ("http_host", host);
+ }
+
+ String referer = request.getHeader ("Referer");
+ if (referer != null)
+ reqtrans.set ("http_referer", referer);
+
+ String remotehost = request.getRemoteAddr ();
+ if (remotehost != null)
+ reqtrans.set ("http_remotehost", remotehost);
+
+ String browser = request.getHeader ("User-Agent");
+ if (browser != null)
+ reqtrans.set ("http_browser", browser);
- // read and set http parameters
for (Enumeration e = request.getParameterNames(); e.hasMoreElements(); ) {
// Params parsen
String nextKey = (String)e.nextElement();
String[] paramValues = request.getParameterValues(nextKey);
- if (paramValues != null) {
- reqtrans.set (nextKey, paramValues[0]); // set to single string value
- if (paramValues.length > 1)
- reqtrans.set (nextKey+"_array", paramValues); // set string array
- }
- }
+ String nextValue = paramValues[0]; // Only take first value
+ reqtrans.set (nextKey, nextValue); // generic Header, Parameter
+ }
- // check for MIME file uploads
String contentType = request.getContentType();
if (contentType != null && contentType.indexOf("multipart/form-data")==0) {
// File Upload
@@ -90,51 +123,6 @@ public class AcmeServletClient extends HttpServlet {
}
}
- // HACK - sessions not fully supported in Acme.Serve
- // Thats ok, we dont need the session object, just the id.
- reqtrans.session = request.getRequestedSessionId();
-
- // get Cookies
- if (cookies != null) {
- for (int i=0; i < cookies.length;i++) try {
- String nextKey = cookies[i].getName ();
- String nextPart = cookies[i].getValue ();
- reqtrans.set (nextKey, nextPart);
- } catch (Exception badCookie) {}
- }
-
- // get optional path info
- String pathInfo = request.getServletPath ();
- if (pathInfo != null) {
- if (pathInfo.indexOf (app.getName()) == 1)
- pathInfo = pathInfo.substring (app.getName().length()+1);
- reqtrans.path = trim (pathInfo);
- } else
- reqtrans.path = "";
-
- // do standard HTTP variables
- String host = request.getHeader ("Host");
- if (host != null) {
- host = host.toLowerCase();
- reqtrans.set ("http_host", host);
- }
-
- String referer = request.getHeader ("Referer");
- if (referer != null)
- reqtrans.set ("http_referer", referer);
-
- String remotehost = request.getRemoteAddr ();
- if (remotehost != null)
- reqtrans.set ("http_remotehost", remotehost);
-
- String browser = request.getHeader ("User-Agent");
- if (browser != null)
- reqtrans.set ("http_browser", browser);
-
- String authorization = request.getHeader("authorization");
- if ( authorization != null )
- reqtrans.set ("authorization", authorization );
-
ResponseTrans restrans = null;
restrans = app.execute (reqtrans);
writeResponse (response, restrans, cookies, protocol);
@@ -154,38 +142,34 @@ public class AcmeServletClient extends HttpServlet {
}
- private void writeResponse (HttpServletResponse res, ResponseTrans trans, Cookie[] cookies, String protocol) {
+ private void writeResponse (HttpServletResponse res, ResponseTrans trans, Cookie[] cookies, String protocol) {
for (int i = 0; i < trans.countCookies(); i++) try {
- Cookie c = new Cookie(trans.getKeyAt(i), trans.getValueAt(i));
+ Cookie c = new Cookie(trans.getKeyAt(i), trans.getValueAt(i));
c.setPath ("/");
if (cookieDomain != null)
- c.setDomain (cookieDomain);
+ c.setDomain (cookieDomain);
int expires = trans.getDaysAt(i);
if (expires > 0)
- c.setMaxAge(expires * 60*60*24); // Cookie time to live, days -> seconds
- res.addCookie(c);
+ c.setMaxAge(expires * 60*60*24); // Cookie time to live, days -> seconds
+ res.addCookie(c);
} catch (Exception ign) {}
- if (trans.getRedirect () != null) {
- try {
- res.sendRedirect(trans.getRedirect ());
+ if (trans.redirect != null) {
+ try {
+ res.sendRedirect(trans.redirect);
} catch(Exception io_e) {}
} else {
-
- if (!trans.cache) {
+ if (!trans.cache || ! caching) {
// Disable caching of response.
if (protocol == null || !protocol.endsWith ("1.1"))
res.setHeader ("Pragma", "no-cache"); // for HTTP 1.0
else
res.setHeader ("Cache-Control", "no-cache"); // for HTTP 1.1
}
- if ( trans.realm!=null )
- res.setHeader( "WWW-Authenticate", "Basic realm=\"" + trans.realm + "\"" );
- if (trans.status > 0)
- res.setStatus (trans.status);
+ res.setStatus( HttpServletResponse.SC_OK );
res.setContentLength (trans.getContentLength ());
- res.setContentType (trans.getContentType ());
+ res.setContentType (trans.contentType);
try {
OutputStream out = res.getOutputStream ();
out.write (trans.getContent ());
@@ -198,7 +182,7 @@ public class AcmeServletClient extends HttpServlet {
try {
res.sendRedirect(url);
} catch (Exception e) {
- System.err.println ("Exception in redirect: " + e + e.getMessage());
+ System.err.println ("Exception bei redirect: " + e + e.getMessage());
}
}
@@ -226,8 +210,8 @@ public class AcmeServletClient extends HttpServlet {
}
- public String getServletInfo (){
- return new String("Hop ServletClient");
+ public String getServletInfo(){
+ return new String("Helma ServletClient");
}
@@ -268,4 +252,3 @@ public class AcmeServletClient extends HttpServlet {
-
diff --git a/src/helma/servlet/MultiServletClient.java b/src/helma/servlet/MultiServletClient.java
deleted file mode 100644
index c4e1d5b3..00000000
--- a/src/helma/servlet/MultiServletClient.java
+++ /dev/null
@@ -1,118 +0,0 @@
-// MultiServletClient.java
-// Copyright (c) Hannes Wallnöfer 2001
-
-
-package helma.servlet;
-
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.*;
-import java.rmi.Naming;
-import java.rmi.RemoteException;
-import java.util.HashMap;
-import helma.framework.IRemoteApp;
-
-/**
- * This is the HOP servlet adapter. This class communicates with any
- * Hop application on a given Hop server, extracting the application name
- * from the request path.
- */
-
-public class MultiServletClient extends AbstractServletClient {
-
- private HashMap apps = null;
-
- public void init (ServletConfig init) throws ServletException {
- super.init (init);
- apps = new HashMap ();
- super.init (init);
- }
-
- IRemoteApp getApp (String appID) throws Exception {
- IRemoteApp retval = (IRemoteApp) apps.get (appID);
- if (retval != null) {
- return retval;
- }
- retval = (IRemoteApp) Naming.lookup (hopUrl + appID);
- apps.put (appID, retval);
- return retval;
- }
-
- void invalidateApp (String appID) {
- apps.remove (appID);
- }
-
- String getAppID (String path) {
- if (path == null)
- throw new RuntimeException ("Invalid request path: "+path);
-
- char[] val = path.toCharArray ();
- int len = val.length;
- int st = 0;
-
- // advance to start of path
- while ((st < len) && (val[st] <= ' ' || val[st] == '/'))
- st++;
-
- // eat characters of first path element
- int end = st;
- while (end < len && val[end] != '/' && val[end] > 20)
- end++;
-
- return new String (val, st, end -st);
- }
-
- String getRequestPath (String path) {
- if (path == null)
- return "";
-
- char[] val = path.toCharArray ();
- int len = val.length;
- int st = 0;
-
- // advance to start of path
- while ((st < len) && (val[st] <= ' ' || val[st] == '/'))
- st++;
-
- // eat characters of first path element
- while (st < len && val[st] != '/')
- st++;
- if (st < len && val[st] == '/')
- st++;
-
- // eat away noise at end of path
- while ((st < len) && (val[len - 1] <= ' ' || val[len - 1] == '/'))
- len--;
-
- return ((st > 0) || (len < val.length)) ? new String (val, st, len-st) : path;
- }
-
- // for testing
- public static void main (String args[]) {
- AbstractServletClient client = new MultiServletClient ();
- // String path = "///appname/do/it/for/me///";
- String path = "appname";
- System.out.println (client.getAppID (path));
- System.out.println (client.getRequestPath (path));
- }
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/helma/servlet/ServletClient.java b/src/helma/servlet/ServletClient.java
index 67604adc..ecb107be 100644
--- a/src/helma/servlet/ServletClient.java
+++ b/src/helma/servlet/ServletClient.java
@@ -13,75 +13,283 @@ import java.rmi.Naming;
import java.rmi.RemoteException;
import java.util.*;
import helma.framework.*;
+import helma.objectmodel.Node;
import helma.util.*;
/**
- * This is the HOP servlet adapter. This class communicates with just
- * one Hop application.
+ * This is the HOP servlet adapter. This class communicates with hop applications
+ * via RMI.
*/
-public class ServletClient extends AbstractServletClient {
+public class ServletClient extends HttpServlet{
- private IRemoteApp app = null;
+ private String host = null;
+ private int port = 0;
+ private int uploadLimit; // limit to HTTP uploads in kB
+ private Hashtable apps;
private String appName;
+ private String appUrl;
+ private String cookieDomain;
+ private boolean caching;
+ private boolean debug;
- public void init (ServletConfig init) throws ServletException {
- super.init (init);
+
+ public void init (ServletConfig init) {
+ apps = new Hashtable();
appName = init.getInitParameter ("application");
- if (appName == null)
- appName = "base";
+ if (appName == null) appName = "base";
- super.init (init);
+ host = init.getInitParameter ("host");
+ if (host == null) host = "localhost";
+
+ String portstr = init.getInitParameter ("port");
+ port = portstr == null ? 5055 : Integer.parseInt (portstr);
+
+ String upstr = init.getInitParameter ("uploadLimit");
+ uploadLimit = upstr == null ? 500 : Integer.parseInt (upstr);
+
+ cookieDomain = init.getInitParameter ("cookieDomain");
+
+ appUrl = "//" + host + ":" + port + "/";
+ debug = ("true".equalsIgnoreCase (init.getInitParameter ("debug")));
+
+ caching = ! ("false".equalsIgnoreCase (init.getInitParameter ("caching")));
}
- IRemoteApp getApp (String appID) throws Exception {
- if (app != null)
- return app;
- app = (IRemoteApp) Naming.lookup (hopUrl + appName);
- return app;
+ private IRemoteApp getApp (String appID) throws Exception {
+ IRemoteApp retval = (IRemoteApp) apps.get (appID);
+ if (retval != null) {
+ return retval;
+ }
+ retval = (IRemoteApp) Naming.lookup (appUrl + appID);
+ apps.put (appID, retval);
+ return retval;
}
- void invalidateApp (String appID) {
- app = null;
+ public void doGet (HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ execute (appName, request, response);
+ }
+
+ public void doPost (HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ execute (appName, request, response);
+ }
+
+ // not used anymore
+ private void get(String appID, HttpServletRequest request, HttpServletResponse response) {
+ }
+
+ private void execute (String appID, HttpServletRequest request, HttpServletResponse response) {
+ String protocol = request.getProtocol ();
+ Cookie[] cookies = request.getCookies();
+ try {
+ RequestTrans reqtrans = new RequestTrans ();
+ if (cookies != null) {
+ for (int i=0; i < cookies.length;i++) try { // get Cookies
+ String nextKey = cookies[i].getName ();
+ String nextPart = cookies[i].getValue ();
+ if ("HopSession".equals (nextKey))
+ reqtrans.session = nextPart;
+ else
+ reqtrans.set (nextKey, nextPart);
+ } catch (Exception badCookie) {}
+ }
+
+ // check if we need to create a session id
+ if (reqtrans.session == null) {
+ reqtrans.session = Long.toString (Math.round (Math.random ()*Long.MAX_VALUE), 16);
+ reqtrans.session += "@"+Long.toString (System.currentTimeMillis (), 16);
+ Cookie c = new Cookie("HopSession", reqtrans.session);
+ c.setPath ("/");
+ if (cookieDomain != null)
+ c.setDomain (cookieDomain);
+ response.addCookie(c);
+ }
+
+ // get optional path info
+ String pathInfo = request.getPathInfo ();
+ if (pathInfo != null)
+ reqtrans.path = trim (pathInfo);
+ else
+ reqtrans.path = "";
+
+ String host = request.getHeader ("Host");
+ if (host != null) {
+ host = host.toLowerCase();
+ reqtrans.set ("http_host", host);
+ }
+
+ String referer = request.getHeader ("Referer");
+ if (referer != null)
+ reqtrans.set ("http_referer", referer);
+
+ String remotehost = request.getRemoteAddr ();
+ if (remotehost != null)
+ reqtrans.set ("http_remotehost", remotehost);
+
+ String browser = request.getHeader ("User-Agent");
+ if (browser != null)
+ reqtrans.set ("http_browser", browser);
+
+ for (Enumeration e = request.getParameterNames(); e.hasMoreElements(); ) {
+ // Params parsen
+ String nextKey = (String)e.nextElement();
+ String[] paramValues = request.getParameterValues(nextKey);
+ String nextValue = paramValues[0]; // Only take first value
+ reqtrans.set (nextKey, nextValue); // generic Header, Parameter
+ }
+
+ String contentType = request.getContentType();
+ if (contentType != null && contentType.indexOf("multipart/form-data")==0) {
+ // File Upload
+ Uploader up;
+ try {
+ if ((up = getUpload (uploadLimit, request)) != null) {
+ Hashtable upload = up.getParts ();
+ for (Enumeration e = upload.keys(); e.hasMoreElements(); ) {
+ String nextKey = (String) e.nextElement ();
+ Object nextPart = upload.get (nextKey);
+ reqtrans.set (nextKey, nextPart);
+ }
+ }
+ } catch (Exception upx) {
+ String uploadErr = upx.getMessage ();
+ if (uploadErr == null || uploadErr.length () == 0)
+ uploadErr = upx.toString ();
+ reqtrans.set ("uploadError", uploadErr);
+ }
+ }
+
+ // get RMI ref to application and execute request
+ IRemoteApp app = getApp (appID);
+ ResponseTrans restrans = null;
+ try {
+ restrans = app.execute (reqtrans);
+ } catch (RemoteException cnx) {
+ apps.remove (appID);
+ app = getApp (appID);
+ app.ping ();
+ restrans = app.execute (reqtrans);
+ }
+ writeResponse (response, restrans, cookies, protocol);
+
+ } catch (Exception x) {
+ apps.remove (appID);
+ try {
+ response.setContentType ("text/html");
+ Writer out = response.getWriter ();
+ if (debug)
+ out.write ("Error: " +x);
+ else
+ out.write ("This server is temporarily unavailable. Please check back later.");
+ out.flush ();
+ } catch (Exception io_e) {}
+ }
}
- String getAppID (String path) {
- return appName;
+
+ private void writeResponse (HttpServletResponse res, ResponseTrans trans, Cookie[] cookies, String protocol) {
+
+ for (int i = 0; i < trans.countCookies(); i++) try {
+ Cookie c = new Cookie(trans.getKeyAt(i), trans.getValueAt(i));
+ c.setPath ("/");
+ if (cookieDomain != null)
+ c.setDomain (cookieDomain);
+ int expires = trans.getDaysAt(i);
+ if (expires > 0)
+ c.setMaxAge(expires * 60*60*24); // Cookie time to live, days -> seconds
+ res.addCookie(c);
+ } catch (Exception ign) {}
+
+ if (trans.redirect != null) {
+ try {
+ res.sendRedirect(trans.redirect);
+ } catch(Exception io_e) {}
+
+ } else {
+ if (!trans.cache || ! caching) {
+ // Disable caching of response.
+ if (protocol == null || !protocol.endsWith ("1.1"))
+ res.setHeader ("Pragma", "no-cache"); // for HTTP 1.0
+ else
+ res.setHeader ("Cache-Control", "no-cache"); // for HTTP 1.1
+ }
+ res.setContentLength (trans.getContentLength ());
+ res.setContentType (trans.contentType);
+ try {
+ OutputStream out = res.getOutputStream ();
+ out.write (trans.getContent ());
+ out.close ();
+ } catch(Exception io_e) {}
+ }
+ }
+
+ private void redirectResponse (HttpServletRequest request, HttpServletResponse res, ResponseTrans trans, String url) {
+ try {
+ res.sendRedirect(url);
+ } catch (Exception e) {
+ System.err.println ("Exception at redirect: " + e + e.getMessage());
+ }
+ }
+
+
+ public Uploader getUpload (HttpServletRequest request) throws Exception {
+ return getUpload (500, request);
}
- String getRequestPath (String path) {
- // get request path
- if (path != null)
- return trim (path);
- else
- return "";
+ public Uploader getUpload (int maxKbytes, HttpServletRequest request) throws Exception {
+ int contentLength = request.getContentLength ();
+ BufferedInputStream in = new BufferedInputStream (request.getInputStream ());
+ Uploader up = null;
+ try {
+ if (contentLength > maxKbytes*1024) {
+ // consume all input to make Apache happy
+ byte b[] = new byte[1024];
+ int read = 0;
+ while (read > -1)
+ read = in.read (b, 0, 1024);
+ throw new RuntimeException ("Upload exceeds limit of "+maxKbytes+" kb.");
+ }
+ String contentType = request.getContentType ();
+ up = new Uploader(maxKbytes);
+ up.load (in, contentType, contentLength);
+ } finally {
+ try { in.close (); } catch (Exception ignore) {}
+ }
+ return up;
}
- String trim (String str) {
+
+ public Object getUploadPart(Uploader up, String name) {
+ return up.getParts().get(name);
+ }
+
+
+ public String getServletInfo(){
+ return new String("Helma ServletClient");
+ }
+
+
+ private String trim (String str) {
+
+ if (str == null)
+ return null;
char[] val = str.toCharArray ();
int len = val.length;
int st = 0;
- while ((st < len) && (val[st] <= ' ' || val[st] == '/'))
+ while ((st < len) && (val[st] <= ' ' || val[st] == '/')) {
st++;
-
- while ((st < len) && (val[len - 1] <= ' ' || val[len - 1] == '/'))
+ }
+ while ((st < len) && (val[len - 1] <= ' ' || val[len - 1] == '/')) {
len--;
-
+ }
return ((st > 0) || (len < val.length)) ? new String (val, st, len-st) : str;
}
- // for testing
- public static void main (String args[]) {
- AbstractServletClient client = new ServletClient ();
- String path = "///appname/do/it/for/me///";
- System.out.println (client.getAppID (path));
- System.out.println (client.getRequestPath (path));
- }
-
-
}
diff --git a/src/helma/servlet/StandaloneServletClient.java b/src/helma/servlet/StandaloneServletClient.java
deleted file mode 100644
index a81b3329..00000000
--- a/src/helma/servlet/StandaloneServletClient.java
+++ /dev/null
@@ -1,118 +0,0 @@
-// StandaloneServletClient.java
-// Copyright (c) Hannes Wallnöfer, 2001
-
-package helma.servlet;
-
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.*;
-import java.util.*;
-import helma.framework.*;
-import helma.framework.core.Application;
-import helma.objectmodel.*;
-import helma.util.*;
-
-/**
- * This is a standalone Hop servlet client, running a Hop application by itself.
- */
-
-public final class StandaloneServletClient extends AbstractServletClient {
-
- private Application app = null;
- private String appName;
- private String serverProps;
-
-
- public void init (ServletConfig init) throws ServletException {
- super.init (init);
- appName = init.getInitParameter ("application");
- serverProps = init.getInitParameter ("serverprops");
- }
-
- IRemoteApp getApp (String appID) {
- if (app == null)
- createApp ();
- return app;
- }
-
- /**
- * Create the application. Since we are synchronized only here, we
- * do another check if the app already exists and immediately return if it does.
- */
- synchronized void createApp () {
- if (app != null)
- return;
- try {
- File propfile = new File (serverProps);
- File hopHome = new File (propfile.getParent());
- SystemProperties sysProps = new SystemProperties (propfile.getAbsolutePath());
- app = new Application (appName, hopHome, sysProps, null);
- app.init ();
- app.start ();
- } catch (Exception x) {
- System.err.println ("Error starting Application "+appName+": "+x);
- x.printStackTrace ();
- }
- }
-
-
- /**
- * The servlet is being destroyed. Close and release the application if
- * it does exist.
- */
- public void destroy () {
- if (app != null) {
- try {
- app.stop ();
- } catch (Exception x) {
- System.err.println ("Error shutting down app "+app.getName()+": ");
- x.printStackTrace ();
- }
- }
- app = null;
- }
-
- void invalidateApp (String appID) {
- // app = null;
- }
-
- String getAppID (String path) {
- return appName;
- }
-
- String getRequestPath (String path) {
- // get request path
- if (path != null)
- return trim (path);
- else
- return "";
- }
-
- String trim (String str) {
- char[] val = str.toCharArray ();
- int len = val.length;
- int st = 0;
-
- while ((st < len) && (val[st] <= ' ' || val[st] == '/'))
- st++;
-
- while ((st < len) && (val[len - 1] <= ' ' || val[len - 1] == '/'))
- len--;
-
- return ((st > 0) || (len < val.length)) ? new String (val, st, len-st) : str;
- }
-
- // for testing
- public static void main (String args[]) {
- AbstractServletClient client = new ServletClient ();
- String path = "///appname/do/it/for/me///";
- System.out.println (client.getAppID (path));
- System.out.println (client.getRequestPath (path));
- }
-
-
-
-}
-
-
-
diff --git a/src/helma/util/CacheMap.java b/src/helma/util/CacheMap.java
index 97d52e93..4159403b 100644
--- a/src/helma/util/CacheMap.java
+++ b/src/helma/util/CacheMap.java
@@ -29,7 +29,7 @@
// Moved to helma.util to use java.util.HashMap instead of java.util.Hashtable
package helma.util;
-import java.util.HashMap;
+import java.util.*;
/// A Hashtable that expires least-recently-used objects.
//
@@ -60,9 +60,6 @@ public class CacheMap {
private HashMap oldTable;
private HashMap newTable;
- // the logger to output messages to
- private Logger logger = null;
-
/// Constructs a new, empty hashtable with the specified initial
// capacity and the specified load factor.
// Unlike a plain Hashtable, an LruHashtable will never grow or
@@ -187,8 +184,7 @@ public class CacheMap {
else {
if (newTable.size() >= eachCapacity) {
// Rotate the tables.
- if (logger != null)
- logger.log ("Rotating Cache tables at "+newTable.size()+"/"+oldTable.size()+" (new/old)");
+ helma.objectmodel.IServer.getLogger().log ("Rotating Cache tables at "+newTable.size()+"/"+oldTable.size()+" (new/old)");
oldTable = newTable;
newTable = new HashMap (eachCapacity, loadFactor);
}
@@ -213,10 +209,6 @@ public class CacheMap {
oldTable.clear ();
}
- /// Set the logger to use for debug and profiling output
- public void setLogger (Logger log) {
- this.logger = log;
- }
public synchronized Object[] getEntryArray () {
Object[] k1 = newTable.keySet().toArray();
@@ -227,9 +219,6 @@ public class CacheMap {
return k;
}
- public String toString () {
- return newTable.toString () + oldTable.toString () + hashCode ();
- }
}
diff --git a/src/helma/util/Crypt.java b/src/helma/util/Crypt.java
deleted file mode 100644
index f2f7952a..00000000
--- a/src/helma/util/Crypt.java
+++ /dev/null
@@ -1,629 +0,0 @@
-/****************************************************************************
- * jcrypt.java
- *
- * Java-based implementation of the unix crypt command
- *
- * Based upon C source code written by Eric Young, eay@psych.uq.oz.au
- *
- ****************************************************************************/
-
-package helma.util;
-
-
-public class Crypt {
-
- private static final int ITERATIONS = 16;
-
- private static final int con_salt[] =
- {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
- 0x0A, 0x0B, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
- 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
- 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
- 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
- 0x23, 0x24, 0x25, 0x20, 0x21, 0x22, 0x23, 0x24,
- 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C,
- 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
- 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C,
- 0x3D, 0x3E, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,
- };
-
- private static final boolean shifts2[] =
- {
- false, false, true, true, true, true, true, true,
- false, true, true, true, true, true, true, false
- };
-
- private static final int skb[][] =
- {
- {
- /* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
- 0x00000000, 0x00000010, 0x20000000, 0x20000010,
- 0x00010000, 0x00010010, 0x20010000, 0x20010010,
- 0x00000800, 0x00000810, 0x20000800, 0x20000810,
- 0x00010800, 0x00010810, 0x20010800, 0x20010810,
- 0x00000020, 0x00000030, 0x20000020, 0x20000030,
- 0x00010020, 0x00010030, 0x20010020, 0x20010030,
- 0x00000820, 0x00000830, 0x20000820, 0x20000830,
- 0x00010820, 0x00010830, 0x20010820, 0x20010830,
- 0x00080000, 0x00080010, 0x20080000, 0x20080010,
- 0x00090000, 0x00090010, 0x20090000, 0x20090010,
- 0x00080800, 0x00080810, 0x20080800, 0x20080810,
- 0x00090800, 0x00090810, 0x20090800, 0x20090810,
- 0x00080020, 0x00080030, 0x20080020, 0x20080030,
- 0x00090020, 0x00090030, 0x20090020, 0x20090030,
- 0x00080820, 0x00080830, 0x20080820, 0x20080830,
- 0x00090820, 0x00090830, 0x20090820, 0x20090830,
- },
- {
- /* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
- 0x00000000, 0x02000000, 0x00002000, 0x02002000,
- 0x00200000, 0x02200000, 0x00202000, 0x02202000,
- 0x00000004, 0x02000004, 0x00002004, 0x02002004,
- 0x00200004, 0x02200004, 0x00202004, 0x02202004,
- 0x00000400, 0x02000400, 0x00002400, 0x02002400,
- 0x00200400, 0x02200400, 0x00202400, 0x02202400,
- 0x00000404, 0x02000404, 0x00002404, 0x02002404,
- 0x00200404, 0x02200404, 0x00202404, 0x02202404,
- 0x10000000, 0x12000000, 0x10002000, 0x12002000,
- 0x10200000, 0x12200000, 0x10202000, 0x12202000,
- 0x10000004, 0x12000004, 0x10002004, 0x12002004,
- 0x10200004, 0x12200004, 0x10202004, 0x12202004,
- 0x10000400, 0x12000400, 0x10002400, 0x12002400,
- 0x10200400, 0x12200400, 0x10202400, 0x12202400,
- 0x10000404, 0x12000404, 0x10002404, 0x12002404,
- 0x10200404, 0x12200404, 0x10202404, 0x12202404,
- },
- {
- /* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
- 0x00000000, 0x00000001, 0x00040000, 0x00040001,
- 0x01000000, 0x01000001, 0x01040000, 0x01040001,
- 0x00000002, 0x00000003, 0x00040002, 0x00040003,
- 0x01000002, 0x01000003, 0x01040002, 0x01040003,
- 0x00000200, 0x00000201, 0x00040200, 0x00040201,
- 0x01000200, 0x01000201, 0x01040200, 0x01040201,
- 0x00000202, 0x00000203, 0x00040202, 0x00040203,
- 0x01000202, 0x01000203, 0x01040202, 0x01040203,
- 0x08000000, 0x08000001, 0x08040000, 0x08040001,
- 0x09000000, 0x09000001, 0x09040000, 0x09040001,
- 0x08000002, 0x08000003, 0x08040002, 0x08040003,
- 0x09000002, 0x09000003, 0x09040002, 0x09040003,
- 0x08000200, 0x08000201, 0x08040200, 0x08040201,
- 0x09000200, 0x09000201, 0x09040200, 0x09040201,
- 0x08000202, 0x08000203, 0x08040202, 0x08040203,
- 0x09000202, 0x09000203, 0x09040202, 0x09040203,
- },
- {
- /* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
- 0x00000000, 0x00100000, 0x00000100, 0x00100100,
- 0x00000008, 0x00100008, 0x00000108, 0x00100108,
- 0x00001000, 0x00101000, 0x00001100, 0x00101100,
- 0x00001008, 0x00101008, 0x00001108, 0x00101108,
- 0x04000000, 0x04100000, 0x04000100, 0x04100100,
- 0x04000008, 0x04100008, 0x04000108, 0x04100108,
- 0x04001000, 0x04101000, 0x04001100, 0x04101100,
- 0x04001008, 0x04101008, 0x04001108, 0x04101108,
- 0x00020000, 0x00120000, 0x00020100, 0x00120100,
- 0x00020008, 0x00120008, 0x00020108, 0x00120108,
- 0x00021000, 0x00121000, 0x00021100, 0x00121100,
- 0x00021008, 0x00121008, 0x00021108, 0x00121108,
- 0x04020000, 0x04120000, 0x04020100, 0x04120100,
- 0x04020008, 0x04120008, 0x04020108, 0x04120108,
- 0x04021000, 0x04121000, 0x04021100, 0x04121100,
- 0x04021008, 0x04121008, 0x04021108, 0x04121108,
- },
- {
- /* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
- 0x00000000, 0x10000000, 0x00010000, 0x10010000,
- 0x00000004, 0x10000004, 0x00010004, 0x10010004,
- 0x20000000, 0x30000000, 0x20010000, 0x30010000,
- 0x20000004, 0x30000004, 0x20010004, 0x30010004,
- 0x00100000, 0x10100000, 0x00110000, 0x10110000,
- 0x00100004, 0x10100004, 0x00110004, 0x10110004,
- 0x20100000, 0x30100000, 0x20110000, 0x30110000,
- 0x20100004, 0x30100004, 0x20110004, 0x30110004,
- 0x00001000, 0x10001000, 0x00011000, 0x10011000,
- 0x00001004, 0x10001004, 0x00011004, 0x10011004,
- 0x20001000, 0x30001000, 0x20011000, 0x30011000,
- 0x20001004, 0x30001004, 0x20011004, 0x30011004,
- 0x00101000, 0x10101000, 0x00111000, 0x10111000,
- 0x00101004, 0x10101004, 0x00111004, 0x10111004,
- 0x20101000, 0x30101000, 0x20111000, 0x30111000,
- 0x20101004, 0x30101004, 0x20111004, 0x30111004,
- },
- {
- /* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
- 0x00000000, 0x08000000, 0x00000008, 0x08000008,
- 0x00000400, 0x08000400, 0x00000408, 0x08000408,
- 0x00020000, 0x08020000, 0x00020008, 0x08020008,
- 0x00020400, 0x08020400, 0x00020408, 0x08020408,
- 0x00000001, 0x08000001, 0x00000009, 0x08000009,
- 0x00000401, 0x08000401, 0x00000409, 0x08000409,
- 0x00020001, 0x08020001, 0x00020009, 0x08020009,
- 0x00020401, 0x08020401, 0x00020409, 0x08020409,
- 0x02000000, 0x0A000000, 0x02000008, 0x0A000008,
- 0x02000400, 0x0A000400, 0x02000408, 0x0A000408,
- 0x02020000, 0x0A020000, 0x02020008, 0x0A020008,
- 0x02020400, 0x0A020400, 0x02020408, 0x0A020408,
- 0x02000001, 0x0A000001, 0x02000009, 0x0A000009,
- 0x02000401, 0x0A000401, 0x02000409, 0x0A000409,
- 0x02020001, 0x0A020001, 0x02020009, 0x0A020009,
- 0x02020401, 0x0A020401, 0x02020409, 0x0A020409,
- },
- {
- /* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
- 0x00000000, 0x00000100, 0x00080000, 0x00080100,
- 0x01000000, 0x01000100, 0x01080000, 0x01080100,
- 0x00000010, 0x00000110, 0x00080010, 0x00080110,
- 0x01000010, 0x01000110, 0x01080010, 0x01080110,
- 0x00200000, 0x00200100, 0x00280000, 0x00280100,
- 0x01200000, 0x01200100, 0x01280000, 0x01280100,
- 0x00200010, 0x00200110, 0x00280010, 0x00280110,
- 0x01200010, 0x01200110, 0x01280010, 0x01280110,
- 0x00000200, 0x00000300, 0x00080200, 0x00080300,
- 0x01000200, 0x01000300, 0x01080200, 0x01080300,
- 0x00000210, 0x00000310, 0x00080210, 0x00080310,
- 0x01000210, 0x01000310, 0x01080210, 0x01080310,
- 0x00200200, 0x00200300, 0x00280200, 0x00280300,
- 0x01200200, 0x01200300, 0x01280200, 0x01280300,
- 0x00200210, 0x00200310, 0x00280210, 0x00280310,
- 0x01200210, 0x01200310, 0x01280210, 0x01280310,
- },
- {
- /* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
- 0x00000000, 0x04000000, 0x00040000, 0x04040000,
- 0x00000002, 0x04000002, 0x00040002, 0x04040002,
- 0x00002000, 0x04002000, 0x00042000, 0x04042000,
- 0x00002002, 0x04002002, 0x00042002, 0x04042002,
- 0x00000020, 0x04000020, 0x00040020, 0x04040020,
- 0x00000022, 0x04000022, 0x00040022, 0x04040022,
- 0x00002020, 0x04002020, 0x00042020, 0x04042020,
- 0x00002022, 0x04002022, 0x00042022, 0x04042022,
- 0x00000800, 0x04000800, 0x00040800, 0x04040800,
- 0x00000802, 0x04000802, 0x00040802, 0x04040802,
- 0x00002800, 0x04002800, 0x00042800, 0x04042800,
- 0x00002802, 0x04002802, 0x00042802, 0x04042802,
- 0x00000820, 0x04000820, 0x00040820, 0x04040820,
- 0x00000822, 0x04000822, 0x00040822, 0x04040822,
- 0x00002820, 0x04002820, 0x00042820, 0x04042820,
- 0x00002822, 0x04002822, 0x00042822, 0x04042822,
- },
- };
-
- private static final int SPtrans[][] =
- {
- {
- /* nibble 0 */
- 0x00820200, 0x00020000, 0x80800000, 0x80820200,
- 0x00800000, 0x80020200, 0x80020000, 0x80800000,
- 0x80020200, 0x00820200, 0x00820000, 0x80000200,
- 0x80800200, 0x00800000, 0x00000000, 0x80020000,
- 0x00020000, 0x80000000, 0x00800200, 0x00020200,
- 0x80820200, 0x00820000, 0x80000200, 0x00800200,
- 0x80000000, 0x00000200, 0x00020200, 0x80820000,
- 0x00000200, 0x80800200, 0x80820000, 0x00000000,
- 0x00000000, 0x80820200, 0x00800200, 0x80020000,
- 0x00820200, 0x00020000, 0x80000200, 0x00800200,
- 0x80820000, 0x00000200, 0x00020200, 0x80800000,
- 0x80020200, 0x80000000, 0x80800000, 0x00820000,
- 0x80820200, 0x00020200, 0x00820000, 0x80800200,
- 0x00800000, 0x80000200, 0x80020000, 0x00000000,
- 0x00020000, 0x00800000, 0x80800200, 0x00820200,
- 0x80000000, 0x80820000, 0x00000200, 0x80020200,
- },
- {
- /* nibble 1 */
- 0x10042004, 0x00000000, 0x00042000, 0x10040000,
- 0x10000004, 0x00002004, 0x10002000, 0x00042000,
- 0x00002000, 0x10040004, 0x00000004, 0x10002000,
- 0x00040004, 0x10042000, 0x10040000, 0x00000004,
- 0x00040000, 0x10002004, 0x10040004, 0x00002000,
- 0x00042004, 0x10000000, 0x00000000, 0x00040004,
- 0x10002004, 0x00042004, 0x10042000, 0x10000004,
- 0x10000000, 0x00040000, 0x00002004, 0x10042004,
- 0x00040004, 0x10042000, 0x10002000, 0x00042004,
- 0x10042004, 0x00040004, 0x10000004, 0x00000000,
- 0x10000000, 0x00002004, 0x00040000, 0x10040004,
- 0x00002000, 0x10000000, 0x00042004, 0x10002004,
- 0x10042000, 0x00002000, 0x00000000, 0x10000004,
- 0x00000004, 0x10042004, 0x00042000, 0x10040000,
- 0x10040004, 0x00040000, 0x00002004, 0x10002000,
- 0x10002004, 0x00000004, 0x10040000, 0x00042000,
- },
- {
- /* nibble 2 */
- 0x41000000, 0x01010040, 0x00000040, 0x41000040,
- 0x40010000, 0x01000000, 0x41000040, 0x00010040,
- 0x01000040, 0x00010000, 0x01010000, 0x40000000,
- 0x41010040, 0x40000040, 0x40000000, 0x41010000,
- 0x00000000, 0x40010000, 0x01010040, 0x00000040,
- 0x40000040, 0x41010040, 0x00010000, 0x41000000,
- 0x41010000, 0x01000040, 0x40010040, 0x01010000,
- 0x00010040, 0x00000000, 0x01000000, 0x40010040,
- 0x01010040, 0x00000040, 0x40000000, 0x00010000,
- 0x40000040, 0x40010000, 0x01010000, 0x41000040,
- 0x00000000, 0x01010040, 0x00010040, 0x41010000,
- 0x40010000, 0x01000000, 0x41010040, 0x40000000,
- 0x40010040, 0x41000000, 0x01000000, 0x41010040,
- 0x00010000, 0x01000040, 0x41000040, 0x00010040,
- 0x01000040, 0x00000000, 0x41010000, 0x40000040,
- 0x41000000, 0x40010040, 0x00000040, 0x01010000,
- },
- {
- /* nibble 3 */
- 0x00100402, 0x04000400, 0x00000002, 0x04100402,
- 0x00000000, 0x04100000, 0x04000402, 0x00100002,
- 0x04100400, 0x04000002, 0x04000000, 0x00000402,
- 0x04000002, 0x00100402, 0x00100000, 0x04000000,
- 0x04100002, 0x00100400, 0x00000400, 0x00000002,
- 0x00100400, 0x04000402, 0x04100000, 0x00000400,
- 0x00000402, 0x00000000, 0x00100002, 0x04100400,
- 0x04000400, 0x04100002, 0x04100402, 0x00100000,
- 0x04100002, 0x00000402, 0x00100000, 0x04000002,
- 0x00100400, 0x04000400, 0x00000002, 0x04100000,
- 0x04000402, 0x00000000, 0x00000400, 0x00100002,
- 0x00000000, 0x04100002, 0x04100400, 0x00000400,
- 0x04000000, 0x04100402, 0x00100402, 0x00100000,
- 0x04100402, 0x00000002, 0x04000400, 0x00100402,
- 0x00100002, 0x00100400, 0x04100000, 0x04000402,
- 0x00000402, 0x04000000, 0x04000002, 0x04100400,
- },
- {
- /* nibble 4 */
- 0x02000000, 0x00004000, 0x00000100, 0x02004108,
- 0x02004008, 0x02000100, 0x00004108, 0x02004000,
- 0x00004000, 0x00000008, 0x02000008, 0x00004100,
- 0x02000108, 0x02004008, 0x02004100, 0x00000000,
- 0x00004100, 0x02000000, 0x00004008, 0x00000108,
- 0x02000100, 0x00004108, 0x00000000, 0x02000008,
- 0x00000008, 0x02000108, 0x02004108, 0x00004008,
- 0x02004000, 0x00000100, 0x00000108, 0x02004100,
- 0x02004100, 0x02000108, 0x00004008, 0x02004000,
- 0x00004000, 0x00000008, 0x02000008, 0x02000100,
- 0x02000000, 0x00004100, 0x02004108, 0x00000000,
- 0x00004108, 0x02000000, 0x00000100, 0x00004008,
- 0x02000108, 0x00000100, 0x00000000, 0x02004108,
- 0x02004008, 0x02004100, 0x00000108, 0x00004000,
- 0x00004100, 0x02004008, 0x02000100, 0x00000108,
- 0x00000008, 0x00004108, 0x02004000, 0x02000008,
- },
- {
- /* nibble 5 */
- 0x20000010, 0x00080010, 0x00000000, 0x20080800,
- 0x00080010, 0x00000800, 0x20000810, 0x00080000,
- 0x00000810, 0x20080810, 0x00080800, 0x20000000,
- 0x20000800, 0x20000010, 0x20080000, 0x00080810,
- 0x00080000, 0x20000810, 0x20080010, 0x00000000,
- 0x00000800, 0x00000010, 0x20080800, 0x20080010,
- 0x20080810, 0x20080000, 0x20000000, 0x00000810,
- 0x00000010, 0x00080800, 0x00080810, 0x20000800,
- 0x00000810, 0x20000000, 0x20000800, 0x00080810,
- 0x20080800, 0x00080010, 0x00000000, 0x20000800,
- 0x20000000, 0x00000800, 0x20080010, 0x00080000,
- 0x00080010, 0x20080810, 0x00080800, 0x00000010,
- 0x20080810, 0x00080800, 0x00080000, 0x20000810,
- 0x20000010, 0x20080000, 0x00080810, 0x00000000,
- 0x00000800, 0x20000010, 0x20000810, 0x20080800,
- 0x20080000, 0x00000810, 0x00000010, 0x20080010,
- },
- {
- /* nibble 6 */
- 0x00001000, 0x00000080, 0x00400080, 0x00400001,
- 0x00401081, 0x00001001, 0x00001080, 0x00000000,
- 0x00400000, 0x00400081, 0x00000081, 0x00401000,
- 0x00000001, 0x00401080, 0x00401000, 0x00000081,
- 0x00400081, 0x00001000, 0x00001001, 0x00401081,
- 0x00000000, 0x00400080, 0x00400001, 0x00001080,
- 0x00401001, 0x00001081, 0x00401080, 0x00000001,
- 0x00001081, 0x00401001, 0x00000080, 0x00400000,
- 0x00001081, 0x00401000, 0x00401001, 0x00000081,
- 0x00001000, 0x00000080, 0x00400000, 0x00401001,
- 0x00400081, 0x00001081, 0x00001080, 0x00000000,
- 0x00000080, 0x00400001, 0x00000001, 0x00400080,
- 0x00000000, 0x00400081, 0x00400080, 0x00001080,
- 0x00000081, 0x00001000, 0x00401081, 0x00400000,
- 0x00401080, 0x00000001, 0x00001001, 0x00401081,
- 0x00400001, 0x00401080, 0x00401000, 0x00001001,
- },
- {
- /* nibble 7 */
- 0x08200020, 0x08208000, 0x00008020, 0x00000000,
- 0x08008000, 0x00200020, 0x08200000, 0x08208020,
- 0x00000020, 0x08000000, 0x00208000, 0x00008020,
- 0x00208020, 0x08008020, 0x08000020, 0x08200000,
- 0x00008000, 0x00208020, 0x00200020, 0x08008000,
- 0x08208020, 0x08000020, 0x00000000, 0x00208000,
- 0x08000000, 0x00200000, 0x08008020, 0x08200020,
- 0x00200000, 0x00008000, 0x08208000, 0x00000020,
- 0x00200000, 0x00008000, 0x08000020, 0x08208020,
- 0x00008020, 0x08000000, 0x00000000, 0x00208000,
- 0x08200020, 0x08008020, 0x08008000, 0x00200020,
- 0x08208000, 0x00000020, 0x00200020, 0x08008000,
- 0x08208020, 0x00200000, 0x08200000, 0x08000020,
- 0x00208000, 0x00008020, 0x08008020, 0x08200000,
- 0x00000020, 0x08208000, 0x00208020, 0x00000000,
- 0x08000000, 0x08200020, 0x00008000, 0x00208020
- }
- };
-
- private static final int cov_2char[] =
- {
- 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
- 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44,
- 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C,
- 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
- 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62,
- 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
- 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72,
- 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
- };
-
- private static final int byteToUnsigned(byte b)
- {
- int value = (int)b;
-
- return(value >= 0 ? value : value + 256);
- }
-
- private static int fourBytesToInt(byte b[], int offset)
- {
- int value;
-
- value = byteToUnsigned(b[offset++]);
- value |= (byteToUnsigned(b[offset++]) << 8);
- value |= (byteToUnsigned(b[offset++]) << 16);
- value |= (byteToUnsigned(b[offset++]) << 24);
-
- return(value);
- }
-
- private static final void intToFourBytes(int iValue, byte b[], int offset)
- {
- b[offset++] = (byte)((iValue) & 0xff);
- b[offset++] = (byte)((iValue >>> 8 ) & 0xff);
- b[offset++] = (byte)((iValue >>> 16) & 0xff);
- b[offset++] = (byte)((iValue >>> 24) & 0xff);
- }
-
- private static final void PERM_OP(int a, int b, int n, int m, int results[])
- {
- int t;
-
- t = ((a >>> n) ^ b) & m;
- a ^= t << n;
- b ^= t;
-
- results[0] = a;
- results[1] = b;
- }
-
- private static final int HPERM_OP(int a, int n, int m)
- {
- int t;
-
- t = ((a << (16 - n)) ^ a) & m;
- a = a ^ t ^ (t >>> (16 - n));
-
- return(a);
- }
-
- private static int [] des_set_key(byte key[])
- {
- int schedule[] = new int[ITERATIONS * 2];
-
- int c = fourBytesToInt(key, 0);
- int d = fourBytesToInt(key, 4);
-
- int results[] = new int[2];
-
- PERM_OP(d, c, 4, 0x0f0f0f0f, results);
- d = results[0]; c = results[1];
-
- c = HPERM_OP(c, -2, 0xcccc0000);
- d = HPERM_OP(d, -2, 0xcccc0000);
-
- PERM_OP(d, c, 1, 0x55555555, results);
- d = results[0]; c = results[1];
-
- PERM_OP(c, d, 8, 0x00ff00ff, results);
- c = results[0]; d = results[1];
-
- PERM_OP(d, c, 1, 0x55555555, results);
- d = results[0]; c = results[1];
-
- d = (((d & 0x000000ff) << 16) | (d & 0x0000ff00) |
- ((d & 0x00ff0000) >>> 16) | ((c & 0xf0000000) >>> 4));
- c &= 0x0fffffff;
-
- int s, t;
- int j = 0;
-
- for(int i = 0; i < ITERATIONS; i ++)
- {
- if(shifts2[i])
- {
- c = (c >>> 2) | (c << 26);
- d = (d >>> 2) | (d << 26);
- }
- else
- {
- c = (c >>> 1) | (c << 27);
- d = (d >>> 1) | (d << 27);
- }
-
- c &= 0x0fffffff;
- d &= 0x0fffffff;
-
- s = skb[0][ (c ) & 0x3f ]|
- skb[1][((c >>> 6) & 0x03) | ((c >>> 7) & 0x3c)]|
- skb[2][((c >>> 13) & 0x0f) | ((c >>> 14) & 0x30)]|
- skb[3][((c >>> 20) & 0x01) | ((c >>> 21) & 0x06) |
- ((c >>> 22) & 0x38)];
-
- t = skb[4][ (d ) & 0x3f ]|
- skb[5][((d >>> 7) & 0x03) | ((d >>> 8) & 0x3c)]|
- skb[6][ (d >>>15) & 0x3f ]|
- skb[7][((d >>>21) & 0x0f) | ((d >>> 22) & 0x30)];
-
- schedule[j++] = ((t << 16) | (s & 0x0000ffff)) & 0xffffffff;
- s = ((s >>> 16) | (t & 0xffff0000));
-
- s = (s << 4) | (s >>> 28);
- schedule[j++] = s & 0xffffffff;
- }
- return(schedule);
- }
-
- private static final int D_ENCRYPT
- (
- int L, int R, int S, int E0, int E1, int s[]
- )
- {
- int t, u, v;
-
- v = R ^ (R >>> 16);
- u = v & E0;
- v = v & E1;
- u = (u ^ (u << 16)) ^ R ^ s[S];
- t = (v ^ (v << 16)) ^ R ^ s[S + 1];
- t = (t >>> 4) | (t << 28);
-
- L ^= SPtrans[1][(t ) & 0x3f] |
- SPtrans[3][(t >>> 8) & 0x3f] |
- SPtrans[5][(t >>> 16) & 0x3f] |
- SPtrans[7][(t >>> 24) & 0x3f] |
- SPtrans[0][(u ) & 0x3f] |
- SPtrans[2][(u >>> 8) & 0x3f] |
- SPtrans[4][(u >>> 16) & 0x3f] |
- SPtrans[6][(u >>> 24) & 0x3f];
-
- return(L);
- }
-
- private static final int [] body(int schedule[], int Eswap0, int Eswap1)
- {
- int left = 0;
- int right = 0;
- int t = 0;
-
- for(int j = 0; j < 25; j ++)
- {
- for(int i = 0; i < ITERATIONS * 2; i += 4)
- {
- left = D_ENCRYPT(left, right, i, Eswap0, Eswap1, schedule);
- right = D_ENCRYPT(right, left, i + 2, Eswap0, Eswap1, schedule);
- }
- t = left;
- left = right;
- right = t;
- }
-
- t = right;
-
- right = (left >>> 1) | (left << 31);
- left = (t >>> 1) | (t << 31);
-
- left &= 0xffffffff;
- right &= 0xffffffff;
-
- int results[] = new int[2];
-
- PERM_OP(right, left, 1, 0x55555555, results);
- right = results[0]; left = results[1];
-
- PERM_OP(left, right, 8, 0x00ff00ff, results);
- left = results[0]; right = results[1];
-
- PERM_OP(right, left, 2, 0x33333333, results);
- right = results[0]; left = results[1];
-
- PERM_OP(left, right, 16, 0x0000ffff, results);
- left = results[0]; right = results[1];
-
- PERM_OP(right, left, 4, 0x0f0f0f0f, results);
- right = results[0]; left = results[1];
-
- int out[] = new int[2];
-
- out[0] = left; out[1] = right;
-
- return(out);
- }
-
- public static final String crypt(String salt, String original)
- {
- while(salt.length() < 2)
- salt += "A";
-
- StringBuffer buffer = new StringBuffer(" ");
-
- char charZero = salt.charAt(0);
- char charOne = salt.charAt(1);
-
- buffer.setCharAt(0, charZero);
- buffer.setCharAt(1, charOne);
-
- int Eswap0 = con_salt[(int)charZero];
- int Eswap1 = con_salt[(int)charOne] << 4;
-
- byte key[] = new byte[8];
-
- for(int i = 0; i < key.length; i ++)
- key[i] = (byte)0;
-
- for(int i = 0; i < key.length && i < original.length(); i ++)
- {
- int iChar = (int)original.charAt(i);
-
- key[i] = (byte)(iChar << 1);
- }
-
- int schedule[] = des_set_key(key);
- int out[] = body(schedule, Eswap0, Eswap1);
-
- byte b[] = new byte[9];
-
- intToFourBytes(out[0], b, 0);
- intToFourBytes(out[1], b, 4);
- b[8] = 0;
-
- for(int i = 2, y = 0, u = 0x80; i < 13; i ++)
- {
- for(int j = 0, c = 0; j < 6; j ++)
- {
- c <<= 1;
-
- if(((int)b[y] & u) != 0)
- c |= 1;
-
- u >>>= 1;
-
- if(u == 0)
- {
- y++;
- u = 0x80;
- }
- buffer.setCharAt(i, (char)cov_2char[c]);
- }
- }
- return(buffer.toString());
- }
-
- public static void main(String args[])
- {
- if(args.length >= 2)
- {
- System.out.println
- (
- "[" + args[0] + "] [" + args[1] + "] => [" +
- Crypt.crypt(args[0], args[1]) + "]"
- );
- }
- }
-}
diff --git a/src/helma/util/CryptFile.java b/src/helma/util/CryptFile.java
deleted file mode 100644
index e33228c0..00000000
--- a/src/helma/util/CryptFile.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// CryptFile.java
-// Copyright (c) Hannes Wallnöfer 2001
-
-package helma.util;
-
-import java.util.*;
-import java.io.*;
-
-/**
- * This file authenticates against a passwd file
- */
-
-public class CryptFile {
-
- private Properties users;
- private CryptFile parentFile;
- private File file;
- private long lastRead = 0;
-
- public CryptFile (File file, CryptFile parentFile) {
- this.file = file;
- this.parentFile = parentFile;
- users = new Properties ();
- }
-
-
- public boolean authenticate (String username, String pw) {
- if (file.exists () && file.lastModified () > lastRead)
- readFile ();
- else if (!file.exists () && users.size () > 0)
- users.clear ();
- String realpw = users.getProperty (username);
- if (realpw != null) {
- try {
- // check if password matches
- // first we try with unix crypt algorithm
- String cryptpw = Crypt.crypt (realpw, pw);
- if (realpw.equals (cryptpw))
- return true;
- // then try MD5
- if (realpw.equals (MD5Encoder.encode (pw)))
- return true;
- } catch (Exception x) {
- return false;
- }
- } else {
- if (parentFile != null)
- return parentFile.authenticate (username, pw);
- }
- return false;
- }
-
- private synchronized void readFile () {
- BufferedReader reader = null;
- users = new Properties ();
- try {
- reader = new BufferedReader (new FileReader (file));
- String line = reader.readLine ();
- while (line != null) {
- StringTokenizer st = new StringTokenizer (line, ":");
- if (st.countTokens () > 1)
- users.put (st.nextToken (), st.nextToken ());
- line = reader.readLine ();
- }
- } catch (Exception ignore) {
- } finally {
- if (reader != null)
- try { reader.close (); } catch (Exception x) {}
- lastRead = System.currentTimeMillis ();
- }
- }
-
- public static void main (String args[]) {
- CryptFile cf = new CryptFile (new File ("passwd"), null);
- System.err.println (cf.authenticate ("hns", "asdf"));
- }
-
-}
diff --git a/src/helma/util/HtmlEncoder.java b/src/helma/util/HtmlEncoder.java
index 63d6f027..b54d7419 100644
--- a/src/helma/util/HtmlEncoder.java
+++ b/src/helma/util/HtmlEncoder.java
@@ -18,7 +18,6 @@ import java.text.*;
public final class HtmlEncoder {
- /*
static final Hashtable convertor = new Hashtable (128);
// conversion table
@@ -119,70 +118,70 @@ public final class HtmlEncoder {
convertor.put(new Integer(253), "ý");
convertor.put(new Integer(254), "þ");
convertor.put(new Integer(255), "ÿ");
- } */
+ }
/**
*
*/
- public final static String encode (String str) {
+ public final static String encode (String what) {
// try to make stringbuffer large enough from the start
- StringBuffer ret = new StringBuffer (Math.round (str.length()*1.4f));
- encode (str, ret);
+ StringBuffer ret = new StringBuffer (Math.round (what.length()*1.4f));
+ encode (what, ret);
return ret.toString();
}
/**
*
*/
- public final static void encode (String str, StringBuffer ret) {
- if (str == null)
+ public final static void encode (String what, StringBuffer ret) {
+ if (what == null || what.length() == 0) {
return;
-
- int l = str.length();
-
+ }
+
+ StringReader in = new StringReader (what);
+ int c;
boolean closeTag=false, readTag=false, tagOpen=false;
// the difference between swallowOneNewline and ignoreNewline is that swallowOneNewline is just effective once (for the next newline)
- boolean ignoreNewline = false;
+ boolean ignoreNewline = false;
boolean swallowOneNewline = false;
StringBuffer tag = new StringBuffer ();
-
- for (int i=0; i");
+ ret.append ('\n');
if (!tagOpen)
swallowOneNewline = false;
break;
@@ -197,28 +196,28 @@ public final class HtmlEncoder {
ret.append ('>');
break;
default:
- ret.append (c);
- // if (c < 160)
- // ret.append ((char) c);
- // else if (c >= 160 && c <= 255)
- // ret.append (convertor.get(new Integer(c)));
- // else {
- // ret.append ("");
- // ret.append (c);
- // ret.append (";");
- // }
- if (!tagOpen && !Character.isWhitespace (c))
+ if (c < 160)
+ ret.append ((char) c);
+ else if (c >= 160 && c <= 255)
+ ret.append (convertor.get(new Integer(c)));
+ else {
+ ret.append ("");
+ ret.append (c);
+ ret.append (";");
+ }
+ if (!tagOpen && !Character.isWhitespace ((char)c))
swallowOneNewline = false;
+ }
}
- }
+ } catch (IOException e) {}
}
/**
*
*/
- public final static String encodeFormValue (String str) {
- StringBuffer ret = new StringBuffer (Math.round (str.length()*1.2f));
- encodeAll (str, ret, false);
+ public final static String encodeFormValue (String what) {
+ StringBuffer ret = new StringBuffer (Math.round (what.length()*1.4f));
+ encodeAll (what, ret, false);
return ret.toString();
}
@@ -226,17 +225,17 @@ public final class HtmlEncoder {
/**
*
*/
- public final static String encodeAll (String str) {
- StringBuffer ret = new StringBuffer (Math.round (str.length()*1.2f));
- encodeAll (str, ret, true);
+ public final static String encodeAll (String what) {
+ StringBuffer ret = new StringBuffer (Math.round (what.length()*1.4f));
+ encodeAll (what, ret, true);
return ret.toString();
}
/**
*
*/
- public final static String encodeAll (String str, StringBuffer ret) {
- encodeAll (str, ret, true);
+ public final static String encodeAll (String what, StringBuffer ret) {
+ encodeAll (what, ret, true);
return ret.toString();
}
@@ -244,76 +243,115 @@ public final class HtmlEncoder {
/**
*
*/
- public final static void encodeAll (String str, StringBuffer ret, boolean encodeNewline) {
- if (str == null)
+ public final static void encodeAll (String what, StringBuffer ret, boolean encodeNewline) {
+ if (what == null || what.length() == 0) {
return;
+ }
- int l = str.length();
- for (int i=0; i':
+ case '>':
ret.append (">");
break;
- case '&':
+ case '&':
ret.append ("&");
break;
- case '"':
+ case '"':
ret.append (""");
break;
- case '\n':
- ret.append ('\n');
+ case '\n':
if (encodeNewline) {
ret.append (" ");
+ break;
}
- break;
- default:
- ret.append (c);
- // if (c < 160)
- // ret.append ((char) c);
- // else if (c >= 160 && c <= 255)
- // ret.append (convertor.get(new Integer(c)));
- // else {
- // ret.append ("");
- // ret.append (c);
- // ret.append (";");
- // }
+ default:
+ if (c < 160)
+ ret.append ((char) c);
+ else if (c >= 160 && c <= 255)
+ ret.append (convertor.get(new Integer(c)));
+ else {
+ ret.append ("");
+ ret.append (c);
+ ret.append (";");
+ }
+ }
}
+ } catch (IOException e) {}
+ }
+
+ public final static String encodeSoft (String what) {
+ StringBuffer ret = new StringBuffer (Math.round (what.length()*1.4f));
+ encodeSoft (what, ret);
+ return ret.toString();
+ }
+
+ public final static void encodeSoft (String what, StringBuffer ret) {
+ if (what == null || what.length() == 0) {
+ return;
}
+
+ StringReader in = new StringReader (what);
+ int c;
+ try {
+ while ((c = in.read()) != -1) {
+ switch (c) {
+ case 128: // Euro-Symbol. This is for missing Unicode support in TowerJ.
+ ret.append ("€");
+ break;
+ default:
+ if (c < 160)
+ ret.append ((char) c);
+ else if (c >= 160 && c <= 255)
+ ret.append (convertor.get(new Integer(c)));
+ else {
+ ret.append ("");
+ ret.append (c);
+ ret.append (";");
+ }
+ }
+ }
+ } catch (IOException e) {}
}
- public final static String encodeXml (String str) {
- StringBuffer ret = new StringBuffer (Math.round (str.length()*1.2f));
- encodeXml (str, ret);
+ public final static String encodeXml (String what) {
+ StringBuffer ret = new StringBuffer (Math.round (what.length()*1.4f));
+ encodeXml (what, ret);
return ret.toString();
}
- public final static void encodeXml (String str, StringBuffer ret) {
- if (str == null)
+ public final static void encodeXml (String what, StringBuffer ret) {
+ if (what == null || what.length() == 0) {
return;
+ }
- int l = str.length();
- for (int i=0; i':
+ case '>':
ret.append (">");
break;
- case '&':
+ case '&':
ret.append ("&");
break;
- default:
- ret.append (c);
+ default:
+ ret.append ((char) c);
+ }
}
- }
+ } catch (IOException e) {}
}
-} // end of class
+
+}
diff --git a/src/helma/util/Logger.java b/src/helma/util/Logger.java
index 933cd931..6a5e3ac6 100644
--- a/src/helma/util/Logger.java
+++ b/src/helma/util/Logger.java
@@ -6,353 +6,105 @@ package helma.util;
import java.io.*;
import java.util.*;
import java.text.*;
-import java.util.zip.GZIPOutputStream;
/**
* Utility class for asynchronous logging.
*/
-public final class Logger {
+public class Logger implements Runnable {
- // we use one static thread for all Loggers
- static Runner runner;
- // the list of active loggers
- static ArrayList loggers;
- // hash map of loggers
- static HashMap loggerMap;
+ private Thread logger;
- // buffer for log items
- private List entries;
-
- // fields used for logging to files
+ private Vector entries;
private String filename;
- private File logdir;
- private File logfile;
- private PrintWriter writer;
- // the canonical name for this logger
- String canonicalName;
-
- // used when logging to a PrintStream such as System.out
+ private String dirname;
+ private File dir;
+ private File currentFile;
+ private PrintWriter currentWriter;
+ private int fileindex = 0;
+ private DecimalFormat nformat;
+ private DateFormat dformat;
+ private long dateLastRendered;
+ private String dateCache;
private PrintStream out = null;
- // flag to tell runner thread if this log should be closed/discarded
- boolean closed = false;
-
- // fields for date rendering and caching
- static DateFormat dformat = new SimpleDateFormat ("[yyyy/MM/dd HH:mm] ");
- static long dateLastRendered;
- static String dateCache;
- // number format for log file rotation
- DecimalFormat nformat = new DecimalFormat ("000");
- DateFormat aformat = new SimpleDateFormat ("yyyy-MM-dd");
-
-
-
- /**
- * Create a logger for a PrintStream, such as System.out.
- */
public Logger (PrintStream out) {
+ dformat = DateFormat.getInstance ();
this.out = out;
- canonicalName = out.toString ();
-
- // create a synchronized list for log entries since different threads may
- // attempt to modify the list at the same time
- entries = Collections.synchronizedList (new LinkedList ());
-
- // register this instance with static logger list
- start (this);
+ entries = new Vector ();
+ logger = new Thread (this);
+ // logger.setPriority (Thread.MIN_PRIORITY+2);
+ logger.start ();
}
- /**
- * Create a file logger. The actual file names do have numbers appended and are
- * rotated every x bytes.
- */
- private Logger (String dirname, String filename) {
- this.filename = filename;
- logdir = new File (dirname);
- logfile = new File (logdir, filename+".log");
-
- try {
- canonicalName = logfile.getCanonicalPath ();
- } catch (IOException iox) {
- canonicalName = logfile.getAbsolutePath ();
- }
-
- if (!logdir.exists())
- logdir.mkdirs ();
-
- try {
- rotateLogFile ();
- } catch (IOException iox) {
- System.err.println ("Error creating log "+canonicalName+": "+iox);
- }
-
- // create a synchronized list for log entries since different threads may
- // attempt to modify the list at the same time
- entries = Collections.synchronizedList (new LinkedList ());
-
- // register this instance with static logger list
- start (this);
- }
-
-
- /**
- * Get a logger with a symbolic file name within a directory.
- */
- public static synchronized Logger getLogger (String dirname, String filename) {
+ public Logger (String dirname, String filename) throws IOException {
if (filename == null || dirname == null)
- throw new RuntimeException ("Logger can't use null as file or directory name");
- File file = new File (dirname, filename+".log");
- Logger log = null;
- if (loggerMap != null) try {
- log = (Logger) loggerMap.get (file.getCanonicalPath());
- } catch (IOException iox) {
- log = (Logger) loggerMap.get (file.getAbsolutePath());
- }
- if (log == null || log.isClosed ())
- log = new Logger (dirname, filename);
- return log;
+ throw new IOException ("Logger can't use null as file or directory name");
+ this.filename = filename;
+ this.dirname = dirname;
+ nformat = new DecimalFormat ("00000");
+ dformat = DateFormat.getInstance ();
+ dir = new File (dirname);
+ if (!dir.exists())
+ dir.mkdirs ();
+ currentFile = new File (dir, filename+nformat.format(++fileindex)+".log");
+ while (currentFile.exists())
+ currentFile = new File (dir, filename+nformat.format(++fileindex)+".log");
+ currentWriter = new PrintWriter (new FileWriter (currentFile), false);
+ entries = new Vector ();
+ logger = new Thread (this);
+ // logger.setPriority (Thread.MIN_PRIORITY+2);
+ logger.start ();
}
-
- /**
- * Append a message to the log.
- */
public void log (String msg) {
- // if we are closed, drop message without further notice
- if (closed)
- return;
// it's enough to render the date every 15 seconds
if (System.currentTimeMillis () - 15000 > dateLastRendered)
renderDate ();
- entries.add (dateCache + msg);
+ entries.addElement (dateCache + " " + msg);
}
- private static synchronized void renderDate () {
+ private synchronized void renderDate () {
dateLastRendered = System.currentTimeMillis ();
dateCache = dformat.format (new Date());
}
-
- /**
- * Return an object which identifies this logger.
- */
- public String getCanonicalName () {
- return canonicalName;
- }
-
-
- /**
- * Get the list of unwritten entries
- */
- public List getEntries () {
- return entries;
- }
-
- /**
- * This is called by the runner thread to perform actual output.
- */
- public void write () {
- if (entries.isEmpty ())
- return;
- try {
- if (logfile != null &&
- (logfile.length() > 10000000 || writer == null ||
- !logfile.exists() || !logfile.canWrite())) {
- // rotate log files each 10 megs of if we can't write to it
- rotateLogFile ();
- }
-
- int l = entries.size();
-
- // check if writing to printstream or file
- if (out != null) {
+ public void run () {
+ while (Thread.currentThread () == logger) {
+ try {
+ if (currentFile != null && currentFile.length() > 10000000) {
+ // rotate log files each 10 megs
+ swapFile ();
+ }
+
+ int l = entries.size();
for (int i=0; i 1000) {
- // more than 1000 entries queued plus exception - something
- // is definitely wrong with this logger. Write a message to std err and
- // discard queued log entries.
- System.err.println ("Error writing log file "+this+": "+x);
- System.err.println ("Discarding "+e+" log entries.");
- entries.clear ();
+ if (currentWriter != null)
+ currentWriter.flush ();
+ logger.sleep (1000l);
+
+ } catch (InterruptedException ir) {
+ Thread.currentThread().interrupt ();
}
}
}
- /**
- * Rotate log files, closing, renaming and gzipping the old file and
- * start a new one.
- */
- private void rotateLogFile () throws IOException {
- if (writer != null) try {
- writer.close();
- } catch (Exception ignore) {}
- if (logfile.exists()) {
- String today = aformat.format(new Date());
- int ct=0;
- File archive = null;
- while (archive==null || archive.exists()) {
- String archidx = ct>999 ? Integer.toString(ct) : nformat.format (++ct);
- String archname = filename+"-"+today+"-"+ archidx +".log.gz";
- archive = new File (logdir, archname);
- }
- if (logfile.renameTo (archive))
- (new GZipper(archive)).start();
- else
- System.err.println ("Error rotating log file "+canonicalName+". Old file will possibly be overwritten!");
+ private void swapFile () {
+ try {
+ currentWriter.close();
+ currentFile = new File (dir, filename+nformat.format(++fileindex)+".log");
+ currentWriter = new PrintWriter (new FileWriter (currentFile), false);
+ } catch (IOException iox) {
+ System.err.println ("Error swapping Log files: "+iox);
}
- writer = new PrintWriter (new FileWriter (logfile), false);
- }
-
- /**
- * Tell whether this log is closed.
- */
- public boolean isClosed () {
- return closed;
- }
-
- /**
- * Tells a log to close down. Only the flag is set, the actual closing is
- * done by the runner thread next time it comes around.
- */
- public void close () {
- this.closed = true;
- }
-
- /**
- * Actually closes the file writer of a log.
- */
- void closeFiles () {
- if (writer != null) try {
- writer.close ();
- } catch (Exception ignore) {}
- }
-
- /**
- * Return a string representation of this Logger
- */
- public String toString () {
- return "Logger["+canonicalName+"]";
- }
-
-
- /**
- * Add a log to the list of logs and
- * create and start the runner thread if necessary.
- */
- static synchronized void start (Logger log) {
- if (loggers == null)
- loggers = new ArrayList ();
- if (loggerMap == null)
- loggerMap = new HashMap ();
-
- loggers.add (log);
- loggerMap.put (log.canonicalName, log);
-
- if (runner == null || !runner.isAlive ()) {
- runner = new Runner ();
- runner.start ();
- }
- }
-
-
- /**
- * Return a list of all active Loggers
- */
- public static List getLoggers () {
- if (loggers == null)
- return null;
- return (List) loggers.clone ();
- }
-
- /**
- * The static runner class that loops through all loggers.
- */
- static class Runner extends Thread {
-
- public void run () {
- while (runner == this && !isInterrupted ()) {
- int nloggers = loggers.size();
- for (int i=nloggers-1; i>=0; i--) {
- try {
- Logger log = (Logger) loggers.get (i);
- log.write ();
- if (log.closed && log.entries.isEmpty()) {
- loggers.remove (log);
- log.closeFiles ();
- }
- } catch (Exception x) {
- System.err.println ("Error in Logger main loop: "+x);
- }
- }
- try {
- sleep (500);
- } catch (InterruptedException ix) {}
- }
- }
-
- }
-
- /**
- * a Thread class that zips up a file, filename will stay the same.
- */
- class GZipper extends Thread {
- File file, temp;
- public GZipper (File file) {
- this.file = file;
- this.temp = new File (file.getAbsolutePath()+".tmp");
- }
-
- public void run() {
- long start = System.currentTimeMillis();
- try {
- GZIPOutputStream zip = new GZIPOutputStream( new FileOutputStream(temp));
- BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
- byte[] b = new byte[1024];
- int len = 0;
- while( (len=in.read(b,0,1024))!=-1 ) {
- zip.write(b,0,len);
- }
- zip.close();
- in.close();
- file.delete();
- temp.renameTo(file);
- } catch ( Exception e ) {
- System.err.println (e.toString());
- }
- }
- }
-
-
-
-
- /**
- * test main method
- */
- public static void main (String[] args) throws IOException {
- Logger log = new Logger (".", "testlog");
- long start = System.currentTimeMillis ();
- for (int i=0; i<50000; i++)
- log.log ("test log entry "+i);
- log.log ("done: "+(System.currentTimeMillis () - start));
- System.err.println (System.currentTimeMillis () - start);
- log.close ();
- // System.exit (0);
}
}
diff --git a/src/helma/util/Logo.java b/src/helma/util/Logo.java
deleted file mode 100644
index 6464b8ea..00000000
--- a/src/helma/util/Logo.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package helma.util;
-
-import java.io.FileInputStream;
-
-/**
- * class with byte data of helma logo
- */
-
-public class Logo {
-
- public static final byte hop[] = {
- 71, 73,70,56,57,97,-82,0,35,0,-60,0,0,-1,-1,-1,-17,-17,-17,-33,-33,-33,-52,-52,-52,-67,
- -67,-67,-84,-84,-84,-103,-103,-103,-119,-119,-119,120,120,120,102,102,102,84,84,84,67,
- 67,67,51,51,51,33,33,33,18,18,18,0,0,0,-2,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,-7,4,4,20,0,-1,0,44,0,0,0,0,-82,0,
- 35,0,0,5,-1,32,32,-114,100,105,-98,104,-86,-82,108,-21,-66,112,44,-49,116,109,-33,120,
- -82,-45,-61,-79,52,-114,96,67,113,24,-20,-114,-56,-92,-78,21,32,32,22,-63,-121,116,74,
- 109,44,-118,-127,-91,118,-53,125,5,122,63,7,117,76,-106,58,-84,-40,-82,122,-83,28,24,
- -62,-27,-72,-4,113,78,20,-78,-20,-68,-34,21,40,36,24,98,115,-126,-126,14,12,8,4,120,123,
- -118,122,2,5,10,-127,-125,-111,-111,117,-120,-117,-106,92,5,-128,-110,-101,-100,-123,4,
- -105,-96,72,4,64,-100,-91,-110,103,70,-95,-86,55,9,-112,83,12,11,12,-111,86,11,-90,100,
- 14,9,47,4,4,2,57,77,-107,55,-69,-67,36,-65,-119,42,2,-69,54,-78,100,-97,4,-111,8,34,-74,
- 100,12,47,82,-48,36,-50,15,-97,-70,82,-37,54,-42,37,-39,-37,-75,11,40,8,82,54,-82,83,34,
- -25,-125,-51,-46,99,14,46,-30,37,-19,-58,44,-19,56,-12,36,-7,-47,15,-41,38,-56,-91,-101,
- 38,34,-63,-126,90,85,-96,76,-55,114,96,-116,-107,6,15,-84,-72,114,112,80,-99,-68,19,-55,
- 70,52,124,48,-128,-41,8,100,-34,0,16,72,-11,17,24,0,5,15,-88,-1,-91,64,118,-49,-60,-58,
- -114,-61,78,-90,28,33,-116,-90,55,49,9,58,-34,27,105,-94,35,9,117,15,114,1,-64,51,-64,
- 76,1,17,1,106,53,40,40,-91,-41,-80,0,6,-112,66,124,112,-128,4,-54,41,23,73,24,8,-60,0,
- 79,2,51,82,-114,2,-112,-91,64,68,-127,64,101,-121,34,116,96,100,-86,20,-110,34,32,78,
- 117,-48,-53,64,83,1,82,-86,126,-91,19,54,110,80,17,118,57,2,24,48,87,0,94,-66,116,-122,
- -99,-107,-110,86,-82,-108,68,64,-85,2,64,-112,10,-30,81,3,-48,-20,-90,-107,117,-111,64,
- 84,0,5,-60,-18,69,-96,96,65,-81,108,102,-62,-47,41,0,81,-78,-84,6,8,-60,-108,3,0,-82,
- -88,3,-42,15,122,-43,-6,-13,15,-76,-75,-112,67,-91,44,24,61,-103,-114,111,109,99,35,
- -58,126,80,46,64,94,118,-24,0,-120,65,32,-117,64,1,41,9,-82,70,-75,-115,91,-128,-13,
- -120,7,127,50,19,-39,-101,-10,108,-118,-28,-81,9,23,17,30,64,123,-124,-122,14,-111,
- -57,90,-94,22,52,-5,-2,-96,-111,-99,-1,9,127,-83,93,-113,61,17,-43,62,-40,116,-13,93,
- 85,2,-11,3,-50,-1,126,-5,8,-108,-51,23,-120,-28,67,-113,127,-38,16,56,2,80,34,52,-12,
- 73,81,81,5,32,-33,57,27,-126,35,-35,53,14,-112,72,85,9,27,-91,-10,81,95,-32,100,115,
- 20,56,27,5,112,-104,2,-7,124,-91,-46,8,-3,-44,-13,24,61,-32,-44,66,-115,-117,-76,-11,
- 102,79,126,-13,1,-28,99,113,15,-56,-56,88,62,67,-106,-96,-114,74,95,101,97,87,76,76,
- -43,-43,23,94,71,97,9,0,94,42,61,-63,20,125,35,4,-10,69,95,27,9,80,-44,3,71,125,-75,
- 84,96,83,44,5,-111,80,35,-96,116,-93,85,17,1,16,-29,-103,71,-31,100,103,83,120,2,-96,
- -90,8,103,118,24,-56,103,122,-94,-76,-90,67,50,45,101,-126,58,66,49,-96,104,108,-48,
- -127,-39,78,47,-41,81,-102,-101,111,85,57,-41,40,21,89,21,39,79,96,-67,-4,9,106,114,
- 101,-99,-45,-23,-127,37,-68,121,2,68,101,-119,122,-41,115,-82,94,-70,31,0,-127,-91,
- 18,24,93,-121,85,-59,-86,-89,-87,62,-112,-106,-109,99,72,-26,43,123,-77,33,-76,-98,
- 123,-58,77,118,17,-92,-59,-67,-93,30,-89,36,36,88,39,-87,-59,41,-38,35,-1,115,5,34,
- 55,2,-86,37,124,-89,-33,95,-90,30,-9,-55,126,-25,88,91,94,-114,72,90,103,-32,-75,-77,
- 33,37,34,-80,84,56,27,-51,121,-80,-31,23,100,-79,-8,-78,119,41,-120,-13,-127,-87,47,
- 52,16,61,-5,109,46,19,-10,-122,-39,124,125,32,112,90,55,38,-120,-13,93,84,-46,62,64,
- -92,44,4,51,-116,108,57,2,32,16,85,55,18,50,-116,-33,-63,22,94,56,70,-122,-56,-99,41,
- 101,91,104,-118,32,11,-119,44,-117,32,-58,81,61,48,20,15,9,13,13,-111,82,22,-39,40,
- -16,21,93,123,38,-71,39,108,127,121,123,-122,8,-39,32,112,79,59,6,-51,-124,44,115,
- 98,-4,-56,-40,-50,-67,108,36,108,111,-50,-40,76,-51,-111,67,-42,124,78,46,77,-62,43,
- 5,-108,62,7,-106,64,22,3,92,-107,-106,93,89,-90,-84,-27,97,12,-100,-106,-59,94,109,
- 18,-77,-13,-40,36,59,-102,82,42,127,-86,69,7,-35,-76,-54,-106,74,82,77,-107,-128,18,
- 90,-61,108,-107,-46,110,123,-38,-51,64,42,2,-120,-79,84,-96,34,-104,-99,69,-95,-45,2,
- -114,75,22,-122,-94,-32,22,60,-100,-113,49,103,12,-86,-22,-80,-21,125,42,48,40,-44,
- -7,-23,123,-53,32,0,3,-100,-63,101,3,-73,-92,-69,112,-64,-26,-88, -37,-30,-119,12,3,
- 28,-108,-45,14,-71,47,-32,122,-20,43,32,64,74,-19,-90,20,34,22,-16,-56,-65,-48,-120,
- -23,-60,15,66,-111,1,45,37,47,-3,10,-115,40,48,124,-13,85,40,80,0,-107,-45,119,-17,
- -123,19,-102,-44,94,-56,33,-47,123,111,-2,-9,-44,69,81,-54,-8,-37,-97,-17,-66,14,77,
- 60,-95,126,28,20,-111,-1,-2,-3,109,28,-96,0,32,66,16,49,64,-7,-8,11,-96,0,7,-56,-122,
- 16,0,0,59
- };
-
- /**
- * utitilty function to create byte array from file
- */
- public static void main ( String args[] ) throws Exception {
- FileInputStream fis = new FileInputStream ( args[0] );
- byte[] b = new byte[256];
- int linect=0, ct=0;
- System.out.print( "\n\n\n static byte[] image = {\n ");
- while ( ct>-1 ) {
- ct = fis.read(b);
- for ( int i=0; i30 ) {
- linect=0;
- System.out.print("\n ");
- }
- }
- }
- System.out.print( " };\n\n\n");
-
- }
-
-
-}
diff --git a/src/helma/util/MD5Encoder.java b/src/helma/util/MD5Encoder.java
deleted file mode 100644
index 32b296fd..00000000
--- a/src/helma/util/MD5Encoder.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package helma.util;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-
-public class MD5Encoder {
-
- private static MessageDigest md;
-
- /** used by commandline script to create admin username & password */
- public static void main ( String args[] ) throws Exception {
- if ( args.length < 2 ) {
- System.out.println( "\n\nUsage: helma.util.MD5Encoder ");
- System.out.println( "Output:");
- System.out.println( "adminUsername=");
- System.out.println( "adminPassword=\n");
- System.exit(0);
- }
- System.out.println( "adminUsername=" + encode(args[0]) );
- System.out.println( "adminPassword=" + encode(args[1]) );
- }
-
- public static String encode(String str) throws NoSuchAlgorithmException {
- md = MessageDigest.getInstance("MD5");
- byte[] b = md.digest(str.getBytes());
- StringBuffer buf = new StringBuffer();
- for ( int i=0; i -1)
- filename = fname + name.substring (ndot);
- else
- filename = fname;
- } else {
- filename = fname;
- }
- }
- File file = new File (base, filename);
- FileOutputStream fout = new FileOutputStream (file);
- fout.write (getContent ());
- fout.close ();
- return filename;
- } catch (Exception x) {
- return null;
- }
- }
-
- public String getName () {
- return name;
- }
-
-
-}
diff --git a/src/helma/util/MimePartDataSource.java b/src/helma/util/MimePartDataSource.java
deleted file mode 100644
index a120afe0..00000000
--- a/src/helma/util/MimePartDataSource.java
+++ /dev/null
@@ -1,45 +0,0 @@
-// MimePartDataSource.java
-// Copyright (c) Hannes Wallnöfer 1999-2000
-
-package helma.util;
-
-import javax.activation.*;
-import java.io.*;
-
-/**
- * Makes MimeParts usable as Datasources in the Java Activation Framework (JAF)
- */
-
-public class MimePartDataSource implements DataSource {
-
- private MimePart part;
- private String name;
-
- public MimePartDataSource (MimePart part) {
- this.part = part;
- this.name = part.getName ();
- }
-
- public MimePartDataSource (MimePart part, String name) {
- this.part = part;
- this.name = name;
- }
-
-
- public InputStream getInputStream() throws IOException {
- return new ByteArrayInputStream(part.getContent ());
- }
-
- public OutputStream getOutputStream () throws IOException {
- throw new IOException ("Can't write to MimePart object.");
- }
-
- public String getContentType() {
- return part.contentType;
- }
-
- public String getName () {
- return name;
- }
-
-}
diff --git a/src/helma/util/Updatable.java b/src/helma/util/Updatable.java
deleted file mode 100644
index fb51632a..00000000
--- a/src/helma/util/Updatable.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// Updatable.java
-// Copyright (c) Hannes Wallnöfer 2001
-
-package helma.util;
-
-
-/**
- * An interface of classes that can update themselves and know when to do so.
- */
-
-
-public interface Updatable {
-
- public boolean needsUpdate ();
-
- public void update ();
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/helma/util/Uploader.java b/src/helma/util/Uploader.java
index 6618d424..360d3211 100644
--- a/src/helma/util/Uploader.java
+++ b/src/helma/util/Uploader.java
@@ -3,7 +3,8 @@
package helma.util;
-import helma.util.mime.*;
+import helma.mime.*;
+import helma.objectmodel.*;
import java.io.*;
import java.util.*;
@@ -75,8 +76,9 @@ public class Uploader {
filename = filename.substring (sep+1);
}
if (filename != null) {
- MimePart part = new MimePart (filename, newb, type);
- parts.put (name, part);
+ Node node = new Node (filename);
+ node.setContent (newb, type);
+ parts.put (name, node);
} else {
parts.put (name, new String (newb));
}
diff --git a/src/helma/util/UrlEncoder.java b/src/helma/util/UrlEncoder.java
new file mode 100644
index 00000000..927f7671
--- /dev/null
+++ b/src/helma/util/UrlEncoder.java
@@ -0,0 +1,126 @@
+/*
+ * @(#)URLEncoder.java 1.12 98/07/01
+ *
+ * Copyright 1995-1998 by Sun Microsystems, Inc.,
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
+ * All rights reserved.
+ *
+ * This software is the confidential and proprietary information
+ * of Sun Microsystems, Inc. ("Confidential Information"). You
+ * shall not disclose such Confidential Information and shall use
+ * it only in accordance with the terms of the license agreement
+ * you entered into with Sun.
+ */
+
+// Repackaged by Hannes Wallnoefer because this is the only way to
+// encode space as %20 (no, subclassing doesn't work here).
+
+package helma.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.util.BitSet;
+
+/**
+ * The class contains a utility method for converting a
+ * String
into a MIME format called
+ * "x-www-form-urlencoded
" format.
+ *
+ * To convert a String
, each character is examined in turn:
+ *
+ * The ASCII characters 'a
' through 'z
',
+ * 'A
' through 'Z
', and '0
'
+ * through '9
' remain the same.
+ * All other characters are converted into the 3-character string
+ * "%xy
", where xy is the two-digit
+ * hexadecimal representation of the lower 8-bits of the character.
+ *
+ *
+ * @author Herb Jellinek
+ * @version 1.12, 07/01/98
+ * @since JDK1.0
+ */
+public class UrlEncoder {
+ static BitSet dontNeedEncoding;
+ static final int caseDiff = ('a' - 'A');
+
+ /* The list of characters that are not encoded have been determined by
+ referencing O'Reilly's "HTML: The Definitive Guide" (page 164). */
+
+ static {
+ dontNeedEncoding = new BitSet(256);
+ int i;
+ for (i = 'a'; i <= 'z'; i++) {
+ dontNeedEncoding.set(i);
+ }
+ for (i = 'A'; i <= 'Z'; i++) {
+ dontNeedEncoding.set(i);
+ }
+ for (i = '0'; i <= '9'; i++) {
+ dontNeedEncoding.set(i);
+ }
+ // dontNeedEncoding.set(' '); /* removed to encode space as %20 */
+ dontNeedEncoding.set('-');
+ dontNeedEncoding.set('_');
+ dontNeedEncoding.set('.');
+ dontNeedEncoding.set('*');
+ }
+
+ /**
+ * You can't call the constructor.
+ */
+ // private URLEncoder() { }
+
+ /**
+ * Translates a string into x-www-form-urlencoded
format.
+ *
+ * @param s String
to be translated.
+ * @return the translated String
.
+ * @since JDK1.0
+ */
+ public static String encode(String s) {
+ int maxBytesPerChar = 10;
+ ByteArrayOutputStream out = new ByteArrayOutputStream(s.length());
+ ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
+ OutputStreamWriter writer = new OutputStreamWriter(buf);
+
+ for (int i = 0; i < s.length(); i++) {
+ int c = (int)s.charAt(i);
+ if (dontNeedEncoding.get(c)) {
+ if (c == ' ') {
+ c = '+';
+ }
+ out.write(c);
+ } else {
+ // convert to external encoding before hex conversion
+ try {
+ writer.write(c);
+ writer.flush();
+ } catch(IOException e) {
+ buf.reset();
+ continue;
+ }
+ byte[] ba = buf.toByteArray();
+ for (int j = 0; j < ba.length; j++) {
+ out.write('%');
+ char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
+ // converting to use uppercase letter as part of
+ // the hex value if ch is a letter.
+ if (Character.isLetter(ch)) {
+ ch -= caseDiff;
+ }
+ out.write(ch);
+ ch = Character.forDigit(ba[j] & 0xF, 16);
+ if (Character.isLetter(ch)) {
+ ch -= caseDiff;
+ }
+ out.write(ch);
+ }
+ buf.reset();
+ }
+ }
+
+ return out.toString();
+ }
+}
diff --git a/src/helma/xmlrpc/Base64.java b/src/helma/xmlrpc/Base64.java
index 86cf8e5f..6d6380ed 100644
--- a/src/helma/xmlrpc/Base64.java
+++ b/src/helma/xmlrpc/Base64.java
@@ -1,286 +1,130 @@
-//////////////////////license & copyright header/////////////////////////
-// //
-// Base64 - encode/decode data using the Base64 encoding scheme //
-// //
-// Copyright (c) 1998 by Kevin Kelley //
-// //
-// This library 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.1 of the License, or (at your option) any later version. //
-// //
-// This library 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, or contact the author: //
-// //
-// Kevin Kelley - 30718 Rd. 28, La Junta, CO, //
-// 81050 USA. //
-// //
-////////////////////end license & copyright header///////////////////////
-
package helma.xmlrpc;
-import java.io.*; // needed only for main() method.
-
-
/**
-* Provides encoding of raw bytes to base64-encoded characters, and
-* decoding of base64 characters to raw bytes.
-*
-* @author Kevin Kelley (kelley@ruralnet.net)
-* @version 1.3
-* @date 06 August 1998
-* @modified 14 February 2000
-* @modified 22 September 2000
-*/
-public class Base64 {
+ * Provides encoding of raw bytes to base64-encoded characters, and
+ * decoding of base64 characters to raw bytes.
+ *
+ * @author Kevin Kelley (kelley@iguana.ruralnet.net)
+ * @version 1.0
+ * @date 06 August 1998
+ */
-/**
-* returns an array of base64-encoded characters to represent the
-* passed data array.
-*
-* @param data the array of bytes to encode
-* @return base64-coded character array.
-*/
-static public char[] encode(byte[] data)
+public class Base64
{
- char[] out = new char[((data.length + 2) / 3) * 4];
+ /**
+ * returns an array of base64-encoded characters to represent the
+ * passed data array.
+ *
+ * @param data the array of bytes to encode
+ * @return base64-coded character array.
+ */
+
+ static public char[] encode(byte[] data) {
+
+ char[] out = new char[((data.length + 2) / 3) * 4];
+ //
+ // 3 bytes encode to 4 chars. Output is always an even
+ // multiple of 4 characters.
+ //
+
+ for (int i = 0, index = 0; i < data.length; i += 3,
+ index += 4) {
+ boolean quad = false;
+ boolean trip = false;
+ int val = (0xFF & (int) data[i]);
+
+ val <<= 8;
+ if ((i + 1) < data.length) {
+ val |= (0xFF & (int) data[i + 1]);
+ trip = true;
+ }
+ val <<= 8;
+ if ((i + 2) < data.length) {
+ val |= (0xFF & (int) data[i + 2]);
+ quad = true;
+ }
+ out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
+ val >>= 6;
+ out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
+ val >>= 6;
+ out[index + 1] = alphabet[val & 0x3F];
+ val >>= 6;
+ out[index + 0] = alphabet[val & 0x3F];
+ }
+ return out;
+ }
+
+
+
+ /**
+ * Returns an array of bytes which were encoded in the passed
+ * character array.
+ *
+ * @param data the array of base64-encoded characters
+ * @return decoded data array
+ */
+ static public byte[] decode(byte[] data) {
+ int len = ((data.length + 3) / 4) * 3;
+ if (data.length > 0 && data[data.length - 1] == '=')
+ --len;
+ if (data.length > 1 && data[data.length - 2] == '=')
+ --len;
+ byte[] out = new byte[len];
+
+ int shift = 0; // # of excess bits stored in accum
+ int accum = 0; // excess bits
+ int index = 0;
+
+ for (int ix = 0; ix < data.length; ix++) {
+ int value = codes[data[ix] & 0xFF]; // ignore high byte of char
+ if (value >= 0) {
+ // skip over non-code
+ accum <<= 6; // bits shift up by 6 each time thru
+ shift += 6; // loop, with new bits being put in
+ accum |= value; // at the bottom.
+ if (shift >= 8) {
+ // whenever there are 8 or more shifted in,
+ shift -= 8; // write them out (from the top, leaving any
+ // excess at the bottom for next iteration.
+ out[index++] = (byte)((accum >> shift) & 0xff);
+ }
+ }
+ }
+
+ if (index != out.length) throw new RuntimeException("Error decoding BASE64 element: miscalculated data length!");
+
+ return out;
+ }
//
- // 3 bytes encode to 4 chars. Output is always an even
- // multiple of 4 characters.
+ // code characters for values 0..63
//
- for (int i=0, index=0; i>= 6;
- out[index+2] = alphabet[(trip? (val & 0x3F): 64)];
- val >>= 6;
- out[index+1] = alphabet[val & 0x3F];
- val >>= 6;
- out[index+0] = alphabet[val & 0x3F];
- }
- return out;
-}
+ static private char[] alphabet =
+
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
+ .toCharArray();
- /**
- * Decodes a BASE-64 encoded stream to recover the original
- * data. White space before and after will be trimmed away,
- * but no other manipulation of the input will be performed.
- *
- * As of version 1.2 this method will properly handle input
- * containing junk characters (newlines and the like) rather
- * than throwing an error. It does this by pre-parsing the
- * input and generating from that a count of VALID input
- * characters.
- **/
-static public byte[] decode(char[] data)
-{
- // as our input could contain non-BASE64 data (newlines,
- // whitespace of any sort, whatever) we must first adjust
- // our count of USABLE data so that...
- // (a) we don't misallocate the output array, and
- // (b) think that we miscalculated our data length
- // just because of extraneous throw-away junk
+ //
+ // lookup table for converting base64 characters to value in range 0..63
+ //
- int tempLen = data.length;
- for( int ix=0; ix 255) || codes[ data[ix] ] < 0 )
- --tempLen; // ignore non-valid chars and padding
- }
- // calculate required length:
- // -- 3 bytes for every 4 valid base64 chars
- // -- plus 2 bytes if there are 3 extra base64 chars,
- // or plus 1 byte if there are 2 extra.
+ static private byte[] codes = new byte[256];
+
+ static {
+ for (int i = 0; i < 256; i++)
+ codes[i] = -1;
+
+ for (int i = 'A'; i <= 'Z'; i++)
+ codes[i] = (byte)(i - 'A');
+
+ for (int i = 'a'; i <= 'z'; i++)
+ codes[i] = (byte)(26 + i - 'a');
- int len = (tempLen / 4) * 3;
- if ((tempLen % 4) == 3) len += 2;
- if ((tempLen % 4) == 2) len += 1;
+ for (int i = '0'; i <= '9'; i++)
+ codes[i] = (byte)(52 + i - '0');
- byte[] out = new byte[len];
-
-
-
- int shift = 0; // # of excess bits stored in accum
- int accum = 0; // excess bits
- int index = 0;
-
- // we now go through the entire array (NOT using the 'tempLen' value)
- for (int ix=0; ix255)? -1: codes[ data[ix] ];
-
- if ( value >= 0 ) // skip over non-code
- {
- accum <<= 6; // bits shift up by 6 each time thru
- shift += 6; // loop, with new bits being put in
- accum |= value; // at the bottom.
- if ( shift >= 8 ) // whenever there are 8 or more shifted in,
- {
- shift -= 8; // write them out (from the top, leaving any
- out[index++] = // excess at the bottom for next iteration.
- (byte) ((accum >> shift) & 0xff);
- }
- }
- // we will also have skipped processing a padding null byte ('=') here;
- // these are used ONLY for padding to an even length and do not legally
- // occur as encoded data. for this reason we can ignore the fact that
- // no index++ operation occurs in that special case: the out[] array is
- // initialized to all-zero bytes to start with and that works to our
- // advantage in this combination.
- }
-
- // if there is STILL something wrong we just have to throw up now!
- if( index != out.length)
- {
- throw new Error("Miscalculated data length (wrote " + index + " instead of " + out.length + ")");
- }
-
- return out;
-}
-
-
-//
-// code characters for values 0..63
-//
-static private char[] alphabet =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
- .toCharArray();
-
-//
-// lookup table for converting base64 characters to value in range 0..63
-//
-static private byte[] codes = new byte[256];
-static {
- for (int i=0; i<256; i++) codes[i] = -1;
- for (int i = 'A'; i <= 'Z'; i++) codes[i] = (byte)( i - 'A');
- for (int i = 'a'; i <= 'z'; i++) codes[i] = (byte)(26 + i - 'a');
- for (int i = '0'; i <= '9'; i++) codes[i] = (byte)(52 + i - '0');
- codes['+'] = 62;
- codes['/'] = 63;
-}
-
-
-
-
-///////////////////////////////////////////////////
-// remainder (main method and helper functions) is
-// for testing purposes only, feel free to clip it.
-///////////////////////////////////////////////////
-
-public static void main(String[] args)
-{
- boolean decode = false;
-
- if (args.length == 0) {
- System.out.println("usage: java Base64 [-d[ecode]] filename");
- System.exit(0);
- }
- for (int i=0; i 0) baos.write(buf, 0, count);
- }
- is.close();
- }
- catch (Exception e) { e.printStackTrace(); }
-
- return baos.toByteArray();
-}
-
-private static char[] readChars(File file)
-{
- CharArrayWriter caw = new CharArrayWriter();
- try
- {
- Reader fr = new FileReader(file);
- Reader in = new BufferedReader(fr);
- int count = 0;
- char[] buf = new char[16384];
- while ((count=in.read(buf)) != -1) {
- if (count > 0) caw.write(buf, 0, count);
- }
- in.close();
- }
- catch (Exception e) { e.printStackTrace(); }
-
- return caw.toCharArray();
-}
-
-private static void writeBytes(File file, byte[] data) {
- try {
- OutputStream fos = new FileOutputStream(file);
- OutputStream os = new BufferedOutputStream(fos);
- os.write(data);
- os.close();
- }
- catch (Exception e) { e.printStackTrace(); }
-}
-
-private static void writeChars(File file, char[] data) {
- try {
- Writer fos = new FileWriter(file);
- Writer os = new BufferedWriter(fos);
- os.write(data);
- os.close();
- }
- catch (Exception e) { e.printStackTrace(); }
-}
-///////////////////////////////////////////////////
-// end of test code.
-///////////////////////////////////////////////////
-
-}
diff --git a/src/helma/xmlrpc/test/Benchmark.java b/src/helma/xmlrpc/Benchmark.java
similarity index 98%
rename from src/helma/xmlrpc/test/Benchmark.java
rename to src/helma/xmlrpc/Benchmark.java
index f876c4c4..c64b3833 100644
--- a/src/helma/xmlrpc/test/Benchmark.java
+++ b/src/helma/xmlrpc/Benchmark.java
@@ -2,9 +2,8 @@
* Copyright 1999 Hannes Wallnoefer
*/
-package helma.xmlrpc.test;
+package helma.xmlrpc;
-import helma.xmlrpc.*;
import java.util.*;
import java.io.IOException;
diff --git a/src/helma/xmlrpc/WebServer.java b/src/helma/xmlrpc/WebServer.java
index f6bbd219..d99a9595 100644
--- a/src/helma/xmlrpc/WebServer.java
+++ b/src/helma/xmlrpc/WebServer.java
@@ -219,9 +219,6 @@ public class WebServer implements Runnable {
if (listener != null) {
Thread l = listener;
listener = null;
- try {
- serverSocket.close ();
- } catch (Exception ignore) {}
l.interrupt ();
}
}
@@ -399,7 +396,7 @@ class Connection implements Runnable {
private void parseAuth (String line) {
try {
- byte[] c = Base64.decode (line.substring (21).toCharArray ());
+ byte[] c = Base64.decode (line.substring (21).getBytes());
String str = new String (c);
int col = str.indexOf (":");
user = str.substring (0, col);
diff --git a/src/helma/xmlrpc/XmlRpc.java b/src/helma/xmlrpc/XmlRpc.java
index 2a745229..d1c72459 100644
--- a/src/helma/xmlrpc/XmlRpc.java
+++ b/src/helma/xmlrpc/XmlRpc.java
@@ -64,6 +64,7 @@ public abstract class XmlRpc extends HandlerBase {
static final int BASE64 = 5;
static final int STRUCT = 6;
static final int ARRAY = 7;
+ static final int NIL = 8;
// Error level + message
int errorLevel;
@@ -78,7 +79,7 @@ public abstract class XmlRpc extends HandlerBase {
// for debugging output
public static boolean debug = false;
- final static String types[] = {"String", "Integer", "Boolean", "Double", "Date", "Base64", "Struct", "Array"};
+ final static String types[] = {"String", "Integer", "Boolean", "Double", "Date", "Base64", "Struct", "Array", "Nil"};
// mapping between java encoding names and "real" names used in XML prolog.
// if you use an encoding not listed here send feedback to xmlrpc@helma.org
@@ -175,7 +176,7 @@ public abstract class XmlRpc extends HandlerBase {
long now = System.currentTimeMillis ();
if (parserClass == null) {
// try to get the name of the SAX driver from the System properties
- setDriver (System.getProperty ("sax.driver", "uk.co.wilson.xml.MinML"));
+ setDriver (System.getProperty ("sax.driver", "org.openxml.parser.XMLSAXParser"));
}
Parser parser = null;
@@ -240,7 +241,10 @@ public abstract class XmlRpc extends HandlerBase {
*/
void writeObject (Object what, XmlWriter writer) throws XmlRpcException {
writer.startElement ("value");
- if (what instanceof String) {
+ if (what == null) {
+ // try sending experimental element
+ writer.emptyElement ("nil");
+ } else if (what instanceof String) {
writer.chardata (what.toString ());
} else if (what instanceof Integer) {
writer.startElement ("int");
@@ -290,11 +294,8 @@ public abstract class XmlRpc extends HandlerBase {
}
}
writer.endElement ("struct");
- } else if (what == null) {
- throw new XmlRpcException (0, "null is not supported as parameter in XML-RPC.");
- } else {
+ } else
throw new XmlRpcException (0, "Java class not supported in XML-RPC: " + what.getClass ());
- }
writer.endElement ("value");
}
@@ -420,6 +421,8 @@ public abstract class XmlRpc extends HandlerBase {
currentValue.setType (STRUCT);
else if ("array".equals (name))
currentValue.setType (ARRAY);
+ else if ("nil".equals (name))
+ currentValue.setType (NIL);
}
@@ -501,7 +504,7 @@ public abstract class XmlRpc extends HandlerBase {
}
break;
case BASE64:
- value = Base64.decode (cdata.toCharArray ());
+ value = Base64.decode (cdata.getBytes());
break;
case STRING:
value = cdata;
@@ -590,10 +593,6 @@ public abstract class XmlRpc extends HandlerBase {
buf.append (text);
}
- public void write (char c) {
- buf.append (c);
- }
-
public String toString () {
return buf.toString ();
}
diff --git a/src/helma/xmlrpc/XmlRpcClient.java b/src/helma/xmlrpc/XmlRpcClient.java
index a2e47d93..1b1bf149 100644
--- a/src/helma/xmlrpc/XmlRpcClient.java
+++ b/src/helma/xmlrpc/XmlRpcClient.java
@@ -1,4 +1,4 @@
-/**
+/**
* Copyright 1999 Hannes Wallnoefer
* Implements a XML-RPC client. See http://www.xmlrpc.com/
*/
@@ -200,7 +200,7 @@ public class XmlRpcClient implements XmlRpcHandler {
runAsync (call.method, call.params, call.callback);
call = dequeue ();
}
- releaseWorker (this, true);
+ releaseWorker (this, false);
}
void runAsync (String method, Vector params, AsyncCallback callback) {
diff --git a/src/helma/xmlrpc/XmlRpcServer.java b/src/helma/xmlrpc/XmlRpcServer.java
index 8182049c..e8d52adb 100644
--- a/src/helma/xmlrpc/XmlRpcServer.java
+++ b/src/helma/xmlrpc/XmlRpcServer.java
@@ -263,11 +263,7 @@ class Invoker implements XmlRpcHandler {
catch (SecurityException s_e){
throw s_e;
}
-
- // our policy is to make all public methods callable except the ones defined in java.lang.Object
- if (method.getDeclaringClass () == Class.forName ("java.lang.Object"))
- throw new XmlRpcException (0, "Invoker can't call methods defined in java.lang.Object");
-
+
// invoke
Object returnValue = null;
try {
diff --git a/src/helma/xmlrpc/fesi/FesiRpcUtil.java b/src/helma/xmlrpc/fesi/FesiRpcUtil.java
index 94fc9ed8..e46b622a 100644
--- a/src/helma/xmlrpc/fesi/FesiRpcUtil.java
+++ b/src/helma/xmlrpc/fesi/FesiRpcUtil.java
@@ -5,8 +5,6 @@ package helma.xmlrpc.fesi;
import helma.xmlrpc.*;
-import helma.scripting.fesi.ESNode;
-import helma.objectmodel.INode;
import FESI.Exceptions.*;
import FESI.Data.*;
@@ -16,9 +14,7 @@ import java.util.*;
public class FesiRpcUtil {
- /**
- * convert a generic Java object to a JavaScript Object.
- */
+ // convert a generic Java object to a JavaScript Object.
public static ESValue convertJ2E (Object what, Evaluator evaluator) throws Exception {
if (what == null)
return ESNull.theNull;
@@ -26,7 +22,7 @@ public class FesiRpcUtil {
Vector v = (Vector) what;
ArrayPrototype retval = new ArrayPrototype (evaluator.getArrayPrototype (), evaluator);
int l = v.size ();
- for (int i=0; i 0 && args.length < 3) {
- url = args[0];
- XmlRpc.setKeepAlive (true);
- if (args.length == 2)
- XmlRpc.setDriver (args[1]);
- new AsyncBenchmark ();
- } else {
- System.err.println ("Usage: java helma.xmlrpc.Benchmark URL [SAXDriver]");
- }
- }
-
- class Callback implements AsyncCallback {
-
-
- int n;
-
- public Callback (Integer n) {
- this.n = Math.abs (n.intValue());
- }
-
- public synchronized void handleResult (Object result, URL url, String method) {
- if (n == ((Integer) result).intValue ())
- gCalls += 1;
- else
- gErrors += 1;
- if (gCalls + gErrors >= clients*loops)
- printStats ();
- }
-
- public synchronized void handleError (Exception exception, URL url, String method) {
- System.err.println (exception);
- exception.printStackTrace ();
- gErrors += 1;
- if (gCalls + gErrors >= clients*loops)
- printStats ();
- }
-
- public void printStats () {
- System.err.println ("");
- System.err.println (gCalls+" calls, "+gErrors+" errors in "+(System.currentTimeMillis()-start)+" millis");
- System.err.println ((1000*(gCalls+gErrors)/(System.currentTimeMillis()-start))+" calls per second");
- }
-
-}
-
-
-}
diff --git a/src/helma/xmlrpc/test/TestBase64.java b/src/helma/xmlrpc/test/TestBase64.java
deleted file mode 100644
index dc885d86..00000000
--- a/src/helma/xmlrpc/test/TestBase64.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Copyright 1999 Hannes Wallnoefer
- */
-
-package helma.xmlrpc.test;
-
-import helma.xmlrpc.*;
-import java.util.*;
-import java.io.IOException;
-
-public class TestBase64 implements Runnable {
-
- XmlRpcClient client;
- static String url;
- static int clients = 1; // 6;
- static int loops = 1; //00;
-
- int gCalls = 0, gErrors = 0;
-
- byte[] data;
-
- public TestBase64 () throws Exception {
- client = new XmlRpcClientLite (url);
-
- Vector args = new Vector ();
- // Some JITs (Symantec, IBM) have problems with several Threads
- // starting all at the same time.
- // This initial XML-RPC call seems to pacify them.
- args.addElement (new Integer (123));
- client.execute ("math.abs", args);
-
- data = new byte[20000];
- for (int j=0; j 0 && args.length < 3) {
- url = args[0];
- XmlRpc.setKeepAlive (true);
- // XmlRpc.setDebug (true);
- if (args.length == 2)
- XmlRpc.setDriver (args[1]);
- new TestBase64 ();
- } else {
- System.err.println ("Usage: java helma.xmlrpc.Benchmark URL [SAXDriver]");
- }
- }
-
-}