This commit was manufactured by cvs2svn to create tag
'v_1_2_feature_complete'.
This commit is contained in:
parent
84f281fb77
commit
e1033484c6
51 changed files with 2080 additions and 2145 deletions
|
@ -32,8 +32,6 @@ import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.text.*;
|
import java.text.*;
|
||||||
// import Acme.Serve.servlet.*;
|
|
||||||
// import Acme.Serve.servlet.http.*;
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.*;
|
import javax.servlet.http.*;
|
||||||
|
|
||||||
|
@ -257,7 +255,7 @@ public class Serve implements ServletContext, Runnable
|
||||||
{
|
{
|
||||||
servlet.init( new ServeConfig( (ServletContext) this ) );
|
servlet.init( new ServeConfig( (ServletContext) this ) );
|
||||||
registry.put( urlPat, servlet );
|
registry.put( urlPat, servlet );
|
||||||
servlets.put( servlet.getClass().getName(), servlet );
|
servlets.put( urlPat, servlet );
|
||||||
}
|
}
|
||||||
catch ( ServletException e )
|
catch ( ServletException e )
|
||||||
{
|
{
|
||||||
|
@ -268,12 +266,17 @@ public class Serve implements ServletContext, Runnable
|
||||||
public void removeServlet( String urlPat )
|
public void removeServlet( String urlPat )
|
||||||
{
|
{
|
||||||
registry.remove (urlPat);
|
registry.remove (urlPat);
|
||||||
|
servlets.remove (urlPat);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDefaultServlet (Servlet servlet) {
|
public void setDefaultServlet (Servlet servlet) {
|
||||||
defaultServlet = servlet;
|
defaultServlet = servlet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeDefaultServlet () {
|
||||||
|
defaultServlet = null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Register a standard set of Servlets. These will return
|
/// Register a standard set of Servlets. These will return
|
||||||
// files or directory listings, and run CGI programs, much like a
|
// files or directory listings, and run CGI programs, much like a
|
||||||
// standard HTTP server.
|
// standard HTTP server.
|
||||||
|
@ -655,8 +658,10 @@ class ServeConnection implements Runnable, HttpServletRequest, HttpServletRespon
|
||||||
|
|
||||||
// Decode %-sequences.
|
// Decode %-sequences.
|
||||||
reqUriPath = decode( reqUriPath );
|
reqUriPath = decode( reqUriPath );
|
||||||
if (reqQuery != null)
|
// do not decode query string, since we do that from
|
||||||
reqQuery = decode (reqQuery);
|
// helma servlet where we know more about encoding!
|
||||||
|
// if (reqQuery != null)
|
||||||
|
// reqQuery = decode (reqQuery);
|
||||||
Servlet servlet = (Servlet) serve.registry.get( reqUriPath );
|
Servlet servlet = (Servlet) serve.registry.get( reqUriPath );
|
||||||
// maybe the application name without slash? try with slash appended
|
// maybe the application name without slash? try with slash appended
|
||||||
if (servlet == null)
|
if (servlet == null)
|
||||||
|
@ -665,10 +670,10 @@ class ServeConnection implements Runnable, HttpServletRequest, HttpServletRespon
|
||||||
servlet = serve.defaultServlet;
|
servlet = serve.defaultServlet;
|
||||||
if ( servlet != null )
|
if ( servlet != null )
|
||||||
runServlet( (HttpServlet) servlet );
|
runServlet( (HttpServlet) servlet );
|
||||||
else if ( "/".equals( reqUriPath ))
|
/* else if ( "/".equals( reqUriPath ))
|
||||||
sendRedirect (serve.props.getProperty ("rootapp", "base"));
|
sendRedirect (serve.props.getProperty ("rootapp", "base"));
|
||||||
else if ( !reqUriPath.endsWith ("/"))
|
else if ( !reqUriPath.endsWith ("/"))
|
||||||
sendRedirect (reqUriPath+"/");
|
sendRedirect (reqUriPath+"/"); */
|
||||||
else // Not found
|
else // Not found
|
||||||
sendError (404, "Not Found",
|
sendError (404, "Not Found",
|
||||||
"<p>If you are looking for a specific app, try <tt>/appname</tt>.</p>"+
|
"<p>If you are looking for a specific app, try <tt>/appname</tt>.</p>"+
|
||||||
|
@ -1092,7 +1097,7 @@ class ServeConnection implements Runnable, HttpServletRequest, HttpServletRespon
|
||||||
// In this server, the entire path is regexp-matched against the
|
// In this server, the entire path is regexp-matched against the
|
||||||
// servlet pattern, so there's no good way to distinguish which
|
// servlet pattern, so there's no good way to distinguish which
|
||||||
// part refers to the servlet.
|
// part refers to the servlet.
|
||||||
return null;
|
return reqUriPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns extra path information translated to a real path. Returns
|
/// Returns extra path information translated to a real path. Returns
|
||||||
|
@ -1292,8 +1297,21 @@ class ServeConnection implements Runnable, HttpServletRequest, HttpServletRespon
|
||||||
// type has yet been assigned, it is implicitly set to text/plain.
|
// type has yet been assigned, it is implicitly set to text/plain.
|
||||||
public String getCharacterEncoding()
|
public String getCharacterEncoding()
|
||||||
{
|
{
|
||||||
// !!!
|
String contentType = getContentType ();
|
||||||
return null;
|
if (contentType == null)
|
||||||
|
return (null);
|
||||||
|
int start = contentType.indexOf("charset=");
|
||||||
|
if (start < 0)
|
||||||
|
return (null);
|
||||||
|
String encoding = contentType.substring(start + 8);
|
||||||
|
int end = encoding.indexOf(';');
|
||||||
|
if (end >= 0)
|
||||||
|
encoding = encoding.substring(0, end);
|
||||||
|
encoding = encoding.trim();
|
||||||
|
if ((encoding.length() > 2) && (encoding.startsWith("\""))
|
||||||
|
&& (encoding.endsWith("\"")))
|
||||||
|
encoding = encoding.substring(1, encoding.length() - 1);
|
||||||
|
return (encoding.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class ESWrapper extends ESObject {
|
||||||
private boolean asBean = false; // true if created as a bean
|
private boolean asBean = false; // true if created as a bean
|
||||||
|
|
||||||
// A marker object never returned as a valid property !
|
// A marker object never returned as a valid property !
|
||||||
private static ESObject noPropertyMarker = null;
|
private ESObject noPropertyMarker = null;
|
||||||
|
|
||||||
private Hashtable eventHandlers = null;
|
private Hashtable eventHandlers = null;
|
||||||
private Hashtable eventAdaptors = null;
|
private Hashtable eventAdaptors = null;
|
||||||
|
|
61
src/helma/framework/RequestBean.java
Normal file
61
src/helma/framework/RequestBean.java
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package helma.framework;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import helma.framework.core.Application;
|
||||||
|
|
||||||
|
public class RequestBean implements Serializable {
|
||||||
|
|
||||||
|
RequestTrans req;
|
||||||
|
|
||||||
|
public RequestBean(RequestTrans req) {
|
||||||
|
this.req = req;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get (String name) {
|
||||||
|
return req.get (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGet () {
|
||||||
|
return req.isGet ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPost () {
|
||||||
|
return req.isPost ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "[Request]";
|
||||||
|
}
|
||||||
|
|
||||||
|
// property related methods:
|
||||||
|
|
||||||
|
public String getaction () {
|
||||||
|
return req.action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map getdata () {
|
||||||
|
return req.getRequestData ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getruntime () {
|
||||||
|
return (System.currentTimeMillis() - req.startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getpassword () {
|
||||||
|
return req.getPassword ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getpath () {
|
||||||
|
return req.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getusername () {
|
||||||
|
return req.getUsername ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
138
src/helma/framework/ResponseBean.java
Normal file
138
src/helma/framework/ResponseBean.java
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
package helma.framework;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import helma.framework.core.Application;
|
||||||
|
|
||||||
|
public class ResponseBean implements Serializable {
|
||||||
|
|
||||||
|
ResponseTrans res;
|
||||||
|
|
||||||
|
public ResponseBean(ResponseTrans res) {
|
||||||
|
this.res = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encode (Object what) {
|
||||||
|
res.encode (what);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encodeXml (Object what) {
|
||||||
|
res.encodeXml (what);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void format (Object what) {
|
||||||
|
res.format (what);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushStringBuffer () {
|
||||||
|
res.pushStringBuffer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String popStringBuffer () {
|
||||||
|
return res.popStringBuffer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void redirect (String url) throws RedirectException {
|
||||||
|
res.redirect (url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset () {
|
||||||
|
res.reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCookie (String key, String value) {
|
||||||
|
res.setCookie (key, value, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCookie (String key, String value, int days) {
|
||||||
|
res.setCookie (key, value, days);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write (Object what) {
|
||||||
|
res.write (what);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeln (Object what) {
|
||||||
|
res.writeln (what);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeBinary (byte[] what) {
|
||||||
|
res.writeBinary (what);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "[Response]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// property-related methods:
|
||||||
|
|
||||||
|
public boolean getcache () {
|
||||||
|
return res.cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setcache (boolean cache) {
|
||||||
|
res.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getcharset () {
|
||||||
|
return res.charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setcharset (String charset) {
|
||||||
|
res.charset = charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getcontentType () {
|
||||||
|
return res.contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setcontentType (String contentType) {
|
||||||
|
res.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map getdata () {
|
||||||
|
return res.getResponseData ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String geterror () {
|
||||||
|
return res.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getmessage () {
|
||||||
|
return res.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setmessage (String message) {
|
||||||
|
res.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getrealm () {
|
||||||
|
return res.realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setrealm (String realm) {
|
||||||
|
res.realm = realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setskinpath (Object[] arr) {
|
||||||
|
res.setTranslatedSkinpath (arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getskinpath () {
|
||||||
|
return res.getTranslatedSkinpath ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getstatus () {
|
||||||
|
return res.status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setstatus (int status) {
|
||||||
|
res.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class ResponseTrans implements Externalizable {
|
||||||
public String contentType = "text/html";
|
public String contentType = "text/html";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the charset of the response.
|
* Set the charset (encoding) to use for the response.
|
||||||
*/
|
*/
|
||||||
public String charset;
|
public String charset;
|
||||||
|
|
||||||
|
@ -143,6 +143,15 @@ public class ResponseTrans implements Externalizable {
|
||||||
return b.toString ();
|
return b.toString ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of characters written to the response buffer so far.
|
||||||
|
*/
|
||||||
|
public int getBufferLength() {
|
||||||
|
if (buffer == null)
|
||||||
|
return 0;
|
||||||
|
return buffer.length ();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append a string to the response unchanged.
|
* Append a string to the response unchanged.
|
||||||
*/
|
*/
|
||||||
|
@ -174,6 +183,16 @@ public class ResponseTrans implements Externalizable {
|
||||||
buffer.append (c, start, length);
|
buffer.append (c, start, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert string somewhere in the response buffer. Caller has to make sure
|
||||||
|
* that buffer exists and its length is larger than offset. str may be null, in which
|
||||||
|
* case nothing happens.
|
||||||
|
*/
|
||||||
|
public void insert (int offset, String str) {
|
||||||
|
if (str != null)
|
||||||
|
buffer.insert (offset, str);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace special characters with entities, including <, > and ", thus allowing
|
* Replace special characters with entities, including <, > and ", thus allowing
|
||||||
* no HTML tags.
|
* no HTML tags.
|
||||||
|
|
|
@ -8,12 +8,10 @@ import helma.doc.DocException;
|
||||||
import helma.framework.*;
|
import helma.framework.*;
|
||||||
import helma.main.Server;
|
import helma.main.Server;
|
||||||
import helma.scripting.*;
|
import helma.scripting.*;
|
||||||
import helma.scripting.fesi.ESUser;
|
|
||||||
import helma.objectmodel.*;
|
import helma.objectmodel.*;
|
||||||
import helma.objectmodel.db.*;
|
import helma.objectmodel.db.*;
|
||||||
import helma.xmlrpc.*;
|
import helma.xmlrpc.*;
|
||||||
import helma.util.*;
|
import helma.util.*;
|
||||||
import com.sleepycat.db.DbException;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
@ -67,10 +65,9 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
|
|
||||||
boolean stopped = false;
|
boolean stopped = false;
|
||||||
boolean debug;
|
boolean debug;
|
||||||
public long starttime;
|
long starttime;
|
||||||
|
|
||||||
public Hashtable sessions;
|
Hashtable sessions;
|
||||||
public Hashtable activeUsers;
|
|
||||||
Hashtable dbMappings;
|
Hashtable dbMappings;
|
||||||
Hashtable dbSources;
|
Hashtable dbSources;
|
||||||
|
|
||||||
|
@ -87,7 +84,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
protected String templateExtension, scriptExtension, actionExtension, skinExtension;
|
protected String templateExtension, scriptExtension, actionExtension, skinExtension;
|
||||||
|
|
||||||
// A transient node that is shared among all evaluators
|
// A transient node that is shared among all evaluators
|
||||||
protected INode appnode;
|
protected INode cachenode;
|
||||||
protected volatile long requestCount = 0;
|
protected volatile long requestCount = 0;
|
||||||
protected volatile long xmlrpcCount = 0;
|
protected volatile long xmlrpcCount = 0;
|
||||||
protected volatile long errorCount = 0;
|
protected volatile long errorCount = 0;
|
||||||
|
@ -219,11 +216,10 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
skinExtension = ".skin";
|
skinExtension = ".skin";
|
||||||
|
|
||||||
sessions = new Hashtable ();
|
sessions = new Hashtable ();
|
||||||
activeUsers = new Hashtable ();
|
|
||||||
dbMappings = new Hashtable ();
|
dbMappings = new Hashtable ();
|
||||||
dbSources = new Hashtable ();
|
dbSources = new Hashtable ();
|
||||||
|
|
||||||
appnode = new TransientNode ("app");
|
cachenode = new TransientNode ("app");
|
||||||
xmlrpc = helma.main.Server.getXmlRpcServer ();
|
xmlrpc = helma.main.Server.getXmlRpcServer ();
|
||||||
xmlrpcAccess = new XmlRpcAccess (this);
|
xmlrpcAccess = new XmlRpcAccess (this);
|
||||||
}
|
}
|
||||||
|
@ -231,7 +227,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
/**
|
/**
|
||||||
* Get the application ready to run, initializing the evaluators and type manager.
|
* Get the application ready to run, initializing the evaluators and type manager.
|
||||||
*/
|
*/
|
||||||
public void init () throws DbException, ScriptingException {
|
public void init () throws DatabaseException, ScriptingException {
|
||||||
scriptingEngine = new helma.scripting.fesi.FesiScriptingEnvironment ();
|
scriptingEngine = new helma.scripting.fesi.FesiScriptingEnvironment ();
|
||||||
scriptingEngine.init (this, props);
|
scriptingEngine.init (this, props);
|
||||||
|
|
||||||
|
@ -263,8 +259,11 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
String usernameField = userMapping.getNameField ();
|
String usernameField = userMapping.getNameField ();
|
||||||
if (usernameField == null)
|
if (usernameField == null)
|
||||||
usernameField = "name";
|
usernameField = "name";
|
||||||
p.put ("_properties", "user."+usernameField);
|
p.put ("_version","1.2");
|
||||||
|
p.put ("_children", "collection(user)");
|
||||||
|
p.put ("_children.accessname", usernameField);
|
||||||
userRootMapping = new DbMapping (this, "__userroot__", p);
|
userRootMapping = new DbMapping (this, "__userroot__", p);
|
||||||
|
|
||||||
rewireDbMappings ();
|
rewireDbMappings ();
|
||||||
|
|
||||||
nmgr = new NodeManager (this, dbDir.getAbsolutePath (), props);
|
nmgr = new NodeManager (this, dbDir.getAbsolutePath (), props);
|
||||||
|
@ -317,7 +316,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
// shut down node manager and embedded db
|
// shut down node manager and embedded db
|
||||||
try {
|
try {
|
||||||
nmgr.shutdown ();
|
nmgr.shutdown ();
|
||||||
} catch (DbException dbx) {
|
} catch (DatabaseException dbx) {
|
||||||
System.err.println ("Error shutting down embedded db: "+dbx);
|
System.err.println ("Error shutting down embedded db: "+dbx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +399,8 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
requestCount += 1;
|
requestCount += 1;
|
||||||
|
|
||||||
// get user for this request's session
|
// get user for this request's session
|
||||||
User u = getUser (req.session);
|
Session session = checkSession (req.session);
|
||||||
|
session.touch();
|
||||||
|
|
||||||
ResponseTrans res = null;
|
ResponseTrans res = null;
|
||||||
RequestEvaluator ev = null;
|
RequestEvaluator ev = null;
|
||||||
|
@ -419,7 +419,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
// if attachRequest returns null this means we came too late
|
// if attachRequest returns null this means we came too late
|
||||||
// and the other request was finished in the meantime
|
// and the other request was finished in the meantime
|
||||||
ev = getEvaluator ();
|
ev = getEvaluator ();
|
||||||
res = ev.invoke (req, u);
|
res = ev.invoke (req, session);
|
||||||
}
|
}
|
||||||
} catch (ApplicationStoppedException stopped) {
|
} catch (ApplicationStoppedException stopped) {
|
||||||
// let the servlet know that this application has gone to heaven
|
// let the servlet know that this application has gone to heaven
|
||||||
|
@ -442,7 +442,7 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
res.waitForClose ();
|
res.waitForClose ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,8 +531,8 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
/**
|
/**
|
||||||
* Return a transient node that is shared by all evaluators of this application ("app node")
|
* Return a transient node that is shared by all evaluators of this application ("app node")
|
||||||
*/
|
*/
|
||||||
public INode getAppNode () {
|
public INode getCacheNode () {
|
||||||
return appnode;
|
return cachenode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -571,51 +571,127 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrurn a skin for a given object. The skin is found by determining the prototype
|
* Return 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.
|
* to use for the object, then looking up the skin for the prototype.
|
||||||
*/
|
*/
|
||||||
public Skin getSkin (Object object, String skinname, Object[] skinpath) {
|
public Skin getSkin (Object object, String skinname, Object[] skinpath) {
|
||||||
return skinmgr.getSkin (object, skinname, skinpath);
|
return skinmgr.getSkin (object, skinname, skinpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the user currently associated with a given Hop session ID. This may be
|
* Return the session currently associated with a given Hop session ID.
|
||||||
* a registered or an anonymous user.
|
* Create a new session if necessary.
|
||||||
*/
|
*/
|
||||||
public User getUser (String sessionID) {
|
public Session checkSession (String sessionID) {
|
||||||
if (sessionID == null)
|
Session session = getSession(sessionID);
|
||||||
return null;
|
if ( session==null ) {
|
||||||
|
session = new Session (sessionID, this);
|
||||||
User u = (User) sessions.get (sessionID);
|
sessions.put (sessionID, session);
|
||||||
if (u != null) {
|
|
||||||
u.touch ();
|
|
||||||
} else {
|
|
||||||
u = new User (sessionID, this);
|
|
||||||
sessions.put (sessionID, u);
|
|
||||||
}
|
}
|
||||||
return u;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the session from the sessions-table and logout the user.
|
||||||
|
*/
|
||||||
|
public void destroySession (String sessionID) {
|
||||||
|
logoutSession (getSession (sessionID));
|
||||||
|
sessions.remove (sessionID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the session from the sessions-table and logout the user.
|
||||||
|
*/
|
||||||
|
public void destroySession (Session session) {
|
||||||
|
logoutSession (session);
|
||||||
|
sessions.remove (session.getSessionID ());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the whole session map. We return a clone of the table to prevent
|
||||||
|
* actual changes from the table itself, which is managed by the application.
|
||||||
|
* It is safe and allowed to manipulate the session objects contained in the table, though.
|
||||||
|
*/
|
||||||
|
public Map getSessions () {
|
||||||
|
return (Map) sessions.clone ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of Helma nodes (HopObjects - the database object representing the user,
|
||||||
|
* not the session object) representing currently logged in users.
|
||||||
|
*/
|
||||||
|
public List getActiveUsers () {
|
||||||
|
ArrayList list = new ArrayList();
|
||||||
|
// used to keep track of already added users - we only return
|
||||||
|
// one object per user, and users may have multiple sessions
|
||||||
|
HashSet usernames = new HashSet ();
|
||||||
|
for (Enumeration e=sessions.elements(); e.hasMoreElements(); ) {
|
||||||
|
Session s = (Session) e.nextElement ();
|
||||||
|
if(s==null) {
|
||||||
|
continue;
|
||||||
|
} else if (s.isLoggedIn() && !usernames.contains (s.getUID ()) ) {
|
||||||
|
// returns a session if it is logged in and has not been
|
||||||
|
// returned before (so for each logged-in user we get one
|
||||||
|
// session object, even if this user is logged in several
|
||||||
|
// times (used to retrieve the active users list).
|
||||||
|
INode node = s.getUserNode ();
|
||||||
|
// we check again because user may have been logged out between the first check
|
||||||
|
if (node != null) {
|
||||||
|
usernames.add (s.getUID ());
|
||||||
|
list.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array of <code>SessionBean</code> objects currently associated with a given
|
||||||
|
* Helma user.
|
||||||
|
*/
|
||||||
|
public List getSessionsForUsername (String username) {
|
||||||
|
ArrayList list = new ArrayList();
|
||||||
|
if (username == null)
|
||||||
|
return list;
|
||||||
|
for (Enumeration e=sessions.elements(); e.hasMoreElements(); ) {
|
||||||
|
Session s = (Session) e.nextElement ();
|
||||||
|
if(s==null) {
|
||||||
|
continue;
|
||||||
|
} else if (username.equals (s.getUID ())) {
|
||||||
|
// append to list if session is logged in and fits the given username
|
||||||
|
list.add (new SessionBean (s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the session currently associated with a given Hop session ID.
|
||||||
|
*/
|
||||||
|
public Session getSession (String sessionID) {
|
||||||
|
if (sessionID == null)
|
||||||
|
return null;
|
||||||
|
return (Session) sessions.get (sessionID);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a user with the given user name and password.
|
* Register a user with the given user name and password.
|
||||||
*/
|
*/
|
||||||
public INode registerUser (String uname, String password) {
|
public INode registerUser (String uname, String password) {
|
||||||
// Register a user who already has a user object
|
|
||||||
// (i.e. who has been surfing around)
|
|
||||||
if (uname == null)
|
if (uname == null)
|
||||||
return null;
|
return null;
|
||||||
uname = uname.toLowerCase ().trim ();
|
uname = uname.toLowerCase ().trim ();
|
||||||
if ("".equals (uname))
|
if ("".equals (uname))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
INode unode = null;
|
INode unode = null;
|
||||||
try {
|
try {
|
||||||
INode users = getUserRoot ();
|
INode users = getUserRoot ();
|
||||||
unode = users.getNode (uname, false);
|
unode = users.getNode (uname, false);
|
||||||
if (unode != null)
|
if (unode != null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
unode = users.createNode (uname);
|
unode = users.createNode (uname);
|
||||||
unode.setPrototype ("user");
|
unode.setPrototype ("user");
|
||||||
unode.setDbMapping (userMapping);
|
unode.setDbMapping (userMapping);
|
||||||
|
@ -628,8 +704,6 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
unode.setName (uname);
|
unode.setName (uname);
|
||||||
unode.setString (usernameProp, uname);
|
unode.setString (usernameProp, uname);
|
||||||
unode.setString ("password", password);
|
unode.setString ("password", password);
|
||||||
// users.setNode (uname, unode);
|
|
||||||
// return users.getNode (uname, false);
|
|
||||||
return unode;
|
return unode;
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
logEvent ("Error registering User: "+x);
|
logEvent ("Error registering User: "+x);
|
||||||
|
@ -640,26 +714,23 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
/**
|
/**
|
||||||
* Log in a user given his or her user name and password.
|
* Log in a user given his or her user name and password.
|
||||||
*/
|
*/
|
||||||
public boolean loginUser (String uname, String password, ESUser u) {
|
public boolean loginSession (String uname, String password, Session session) {
|
||||||
// Check the name/password of a user who already has a user object
|
// Check the name/password of a user and log it in to the current session
|
||||||
// (i.e. who has been surfing around)
|
|
||||||
if (uname == null)
|
if (uname == null)
|
||||||
return false;
|
return false;
|
||||||
uname = uname.toLowerCase ().trim ();
|
uname = uname.toLowerCase ().trim ();
|
||||||
if ("".equals (uname))
|
if ("".equals (uname))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
INode users = getUserRoot ();
|
INode users = getUserRoot ();
|
||||||
INode unode = users.getNode (uname, false);
|
Node unode = (Node)users.getNode (uname, false);
|
||||||
String pw = unode.getString ("password", false);
|
String pw = unode.getString ("password", false);
|
||||||
if (pw != null && pw.equals (password)) {
|
if (pw != null && pw.equals (password)) {
|
||||||
// give the user his/her persistant node
|
// let the old user-object forget about this session
|
||||||
u.setNode (unode);
|
logoutSession(session);
|
||||||
activeUsers.put (unode.getName (), u.user);
|
session.login (unode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -667,18 +738,10 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log out a user from this application.
|
* Log out a session from this application.
|
||||||
*/
|
*/
|
||||||
public boolean logoutUser (ESUser u) {
|
public void logoutSession (Session session) {
|
||||||
if (u.user != null) {
|
session.logout();
|
||||||
String uid = u.user.uid;
|
|
||||||
if (uid != null)
|
|
||||||
activeUsers.remove (uid);
|
|
||||||
|
|
||||||
// switch back to the non-persistent user node as cache
|
|
||||||
u.setNode (null);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -726,13 +789,6 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
if (rootproto != null && rootproto.equals (getPrototypeName (p)))
|
if (rootproto != null && rootproto.equals (getPrototypeName (p)))
|
||||||
break;
|
break;
|
||||||
b.insert (0, divider);
|
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)));
|
b.insert (0, URLEncoder.encode (getElementName (p)));
|
||||||
p = getParentElement (p);
|
p = getParentElement (p);
|
||||||
|
|
||||||
|
@ -740,11 +796,6 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p == users) {
|
|
||||||
b.insert (0, divider);
|
|
||||||
b.insert (0, "users");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actionName != null)
|
if (actionName != null)
|
||||||
b.append (URLEncoder.encode (actionName));
|
b.append (URLEncoder.encode (actionName));
|
||||||
|
|
||||||
|
@ -958,29 +1009,25 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
int sessionTimeout = 30;
|
int sessionTimeout = 30;
|
||||||
try {
|
try {
|
||||||
sessionTimeout = Math.max (0, Integer.parseInt (props.getProperty ("sessionTimeout", "30")));
|
sessionTimeout = Math.max (0, Integer.parseInt (props.getProperty ("sessionTimeout", "30")));
|
||||||
} catch (Exception ignore) {}
|
} catch (Exception ignore) {
|
||||||
|
System.out.println(ignore.toString());
|
||||||
|
}
|
||||||
|
|
||||||
long now = System.currentTimeMillis ();
|
long now = System.currentTimeMillis ();
|
||||||
|
|
||||||
// check if we should clean up user sessions
|
// check if we should clean up user sessions
|
||||||
if (now - lastCleanup > cleanupSleep) try {
|
if (now - lastCleanup > cleanupSleep) try {
|
||||||
lastCleanup = now;
|
lastCleanup = now;
|
||||||
// logEvent ("Cleaning up "+name+": " + sessions.size () + " sessions active");
|
|
||||||
Hashtable cloned = (Hashtable) sessions.clone ();
|
Hashtable cloned = (Hashtable) sessions.clone ();
|
||||||
for (Enumeration e = cloned.elements (); e.hasMoreElements (); ) {
|
for (Enumeration e = cloned.elements (); e.hasMoreElements (); ) {
|
||||||
User u = (User) e.nextElement ();
|
Session session = (Session) e.nextElement ();
|
||||||
if (now - u.lastTouched () > sessionTimeout * 60000) {
|
if (now - session.lastTouched () > sessionTimeout * 60000) {
|
||||||
if (u.uid != null) {
|
// if (session.uid != null) {
|
||||||
try {
|
// FIXME onlogout()! try {eval.invokeFunction (u, "onLogout", new Object[0]);} catch (Exception ignore) {}
|
||||||
eval.invokeFunction (u, "onLogout", new Object[0]);
|
// }
|
||||||
} catch (Exception ignore) {}
|
destroySession(session);
|
||||||
activeUsers.remove (u.uid);
|
|
||||||
}
|
|
||||||
sessions.remove (u.getSessionID ());
|
|
||||||
u.setNode (null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// logEvent ("Cleaned up "+name+": " + sessions.size () + " sessions remaining");
|
|
||||||
} catch (Exception cx) {
|
} catch (Exception cx) {
|
||||||
logEvent ("Error cleaning up sessions: "+cx);
|
logEvent ("Error cleaning up sessions: "+cx);
|
||||||
cx.printStackTrace ();
|
cx.printStackTrace ();
|
||||||
|
@ -1127,9 +1174,9 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
return props.getProperty (propname, defvalue);
|
return props.getProperty (propname, defvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SystemProperties getProperties() {
|
public SystemProperties getProperties() {
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -1189,6 +1236,10 @@ public class Application extends UnicastRemoteObject implements IRemoteApp, IPat
|
||||||
return errorCount;
|
return errorCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getStarttime () {
|
||||||
|
return starttime;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Periodically called to log thread stats for this application
|
* Periodically called to log thread stats for this application
|
||||||
*/
|
*/
|
||||||
|
|
181
src/helma/framework/core/ApplicationBean.java
Normal file
181
src/helma/framework/core/ApplicationBean.java
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
package helma.framework.core;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import helma.objectmodel.INode;
|
||||||
|
|
||||||
|
public class ApplicationBean implements Serializable {
|
||||||
|
|
||||||
|
Application app;
|
||||||
|
|
||||||
|
public ApplicationBean(Application app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCache () {
|
||||||
|
app.clearCache ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log (String msg) {
|
||||||
|
app.logEvent (msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log (String logname, String msg) {
|
||||||
|
app.getLogger (logname).log (msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void debug (String msg) {
|
||||||
|
if (app.debug()) {
|
||||||
|
app.logEvent (msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void debug (String logname, String msg) {
|
||||||
|
if (app.debug()) {
|
||||||
|
app.getLogger (logname).log (msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int countSessions () {
|
||||||
|
return app.sessions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionBean getSession (String sessionID) {
|
||||||
|
if (sessionID==null)
|
||||||
|
return null;
|
||||||
|
Session session = app.getSession (sessionID.trim ());
|
||||||
|
if (session == null)
|
||||||
|
return null;
|
||||||
|
return new SessionBean (session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionBean createSession (String sessionID) {
|
||||||
|
if (sessionID==null)
|
||||||
|
return null;
|
||||||
|
Session session = session = app.checkSession (sessionID.trim ());
|
||||||
|
if (session == null)
|
||||||
|
return null;
|
||||||
|
return new SessionBean (session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionBean[] getSessions () {
|
||||||
|
SessionBean[] theArray = new SessionBean[app.sessions.size()];
|
||||||
|
int i=0;
|
||||||
|
for (Enumeration e=app.sessions.elements(); e.hasMoreElements(); ) {
|
||||||
|
SessionBean sb = new SessionBean ((Session) e.nextElement ());
|
||||||
|
theArray[i++] = sb;
|
||||||
|
}
|
||||||
|
return theArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public INode registerUser (String username, String password) {
|
||||||
|
if (username==null || password==null || "".equals (username.trim ()) || "".equals (password.trim ()) )
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return app.registerUser (username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public INode getUser (String username) {
|
||||||
|
if (username==null || "".equals (username.trim()) )
|
||||||
|
return null;
|
||||||
|
return app.getUserNode (username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public INode[] getActiveUsers () {
|
||||||
|
List activeUsers = app.getActiveUsers ();
|
||||||
|
return (INode[]) activeUsers.toArray (new INode[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionBean[] getSessionsForUser (INode usernode) {
|
||||||
|
if (usernode==null)
|
||||||
|
return new SessionBean[0];
|
||||||
|
else
|
||||||
|
return getSessionsForUser(usernode.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionBean[] getSessionsForUser (String username) {
|
||||||
|
if (username==null || "".equals (username.trim ()) )
|
||||||
|
return new SessionBean[0];
|
||||||
|
List userSessions = app.getSessionsForUsername (username);
|
||||||
|
return (SessionBean[]) userSessions.toArray (new SessionBean[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// getter methods for readonly properties of this application
|
||||||
|
|
||||||
|
public INode getdata() {
|
||||||
|
return app.getCacheNode ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getupSince () {
|
||||||
|
return new Date (app.starttime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getrequestCount () {
|
||||||
|
return app.getRequestCount ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getxmlrpcCount () {
|
||||||
|
return app.getXmlrpcCount ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long geterrorCount () {
|
||||||
|
return app.getErrorCount ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Application get__app__ () {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map getproperties () {
|
||||||
|
return app.getProperties ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getfreeThreads () {
|
||||||
|
return app.countFreeEvaluators ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getactiveThreads () {
|
||||||
|
return app.countActiveEvaluators ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getmaxThreads () {
|
||||||
|
return app.countEvaluators ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setmaxThreads (int n) {
|
||||||
|
// add one to the number to compensate for the internal scheduler.
|
||||||
|
app.setNumberOfEvaluators (n+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map getskinfiles () {
|
||||||
|
Map skinz = new Hashtable ();
|
||||||
|
for (Iterator it = app.getPrototypes().iterator(); it.hasNext(); ) {
|
||||||
|
Prototype p = (Prototype) it.next ();
|
||||||
|
Map proto = new Hashtable ();
|
||||||
|
for (Iterator it2 = p.skins.values().iterator(); it2.hasNext(); ) {
|
||||||
|
SkinFile sf = (SkinFile) it2.next ();
|
||||||
|
String name = sf.getName ();
|
||||||
|
Skin skin = sf.getSkin ();
|
||||||
|
proto.put (name, skin.getSource ());
|
||||||
|
}
|
||||||
|
skinz.put (p.getName (), proto);
|
||||||
|
}
|
||||||
|
return skinz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "[Application " + app.getName() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ public class RequestEvaluator implements Runnable {
|
||||||
// the method to be executed
|
// the method to be executed
|
||||||
String method;
|
String method;
|
||||||
|
|
||||||
// the user object associated with the current request
|
// the session object associated with the current request
|
||||||
User user;
|
Session session;
|
||||||
|
|
||||||
// arguments passed to the function
|
// arguments passed to the function
|
||||||
Object[] args;
|
Object[] args;
|
||||||
|
@ -113,17 +113,18 @@ public class RequestEvaluator implements Runnable {
|
||||||
|
|
||||||
HashMap globals = new HashMap ();
|
HashMap globals = new HashMap ();
|
||||||
globals.put ("root", root);
|
globals.put ("root", root);
|
||||||
globals.put ("user", user);
|
globals.put ("session", session);
|
||||||
globals.put ("req", req);
|
globals.put ("req", req);
|
||||||
globals.put ("res", res);
|
globals.put ("res", res);
|
||||||
globals.put ("path", requestPath);
|
globals.put ("path", requestPath);
|
||||||
globals.put ("app", app.getAppNode());
|
globals.put ("app", app);
|
||||||
|
req.startTime = System.currentTimeMillis ();
|
||||||
if (error != null)
|
if (error != null)
|
||||||
res.error = error;
|
res.error = error;
|
||||||
if (user.message != null) {
|
if (session.message != null) {
|
||||||
// bring over the message from a redirect
|
// bring over the message from a redirect
|
||||||
res.message = user.message;
|
res.message = session.message;
|
||||||
user.message = null;
|
session.message = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -224,13 +225,8 @@ public class RequestEvaluator implements Runnable {
|
||||||
try {
|
try {
|
||||||
localrtx.timer.beginEvent (txname+" execute");
|
localrtx.timer.beginEvent (txname+" execute");
|
||||||
|
|
||||||
int actionDot = action.lastIndexOf (".");
|
|
||||||
boolean isAction = actionDot == -1;
|
|
||||||
// set the req.action property, cutting off the _action suffix
|
// set the req.action property, cutting off the _action suffix
|
||||||
if (isAction)
|
req.action = action.substring (0, action.length()-7);
|
||||||
req.action = action.substring (0, action.length()-7);
|
|
||||||
else
|
|
||||||
req.action = action;
|
|
||||||
|
|
||||||
// try calling onRequest() function on object before
|
// try calling onRequest() function on object before
|
||||||
// calling the actual action
|
// calling the actual action
|
||||||
|
@ -243,48 +239,14 @@ public class RequestEvaluator implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// do the actual action invocation
|
// do the actual action invocation
|
||||||
if (isAction) {
|
app.scriptingEngine.invoke (currentElement, action, new Object[0], globals, this);
|
||||||
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 (txname+" execute");
|
||||||
} catch (RedirectException redirect) {
|
} 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 there is a message set, save it on the user object for the next request
|
||||||
if (res.message != null)
|
if (res.message != null)
|
||||||
user.message = res.message;
|
session.message = res.message;
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +322,7 @@ public class RequestEvaluator implements Runnable {
|
||||||
HashMap globals = new HashMap ();
|
HashMap globals = new HashMap ();
|
||||||
globals.put ("root", root);
|
globals.put ("root", root);
|
||||||
globals.put ("res", res);
|
globals.put ("res", res);
|
||||||
globals.put ("app", app.getAppNode());
|
globals.put ("app", app);
|
||||||
|
|
||||||
currentElement = root;
|
currentElement = root;
|
||||||
|
|
||||||
|
@ -419,7 +381,7 @@ public class RequestEvaluator implements Runnable {
|
||||||
HashMap globals = new HashMap ();
|
HashMap globals = new HashMap ();
|
||||||
globals.put ("root", root);
|
globals.put ("root", root);
|
||||||
globals.put ("res", res);
|
globals.put ("res", res);
|
||||||
globals.put ("app", app.getAppNode());
|
globals.put ("app", app);
|
||||||
|
|
||||||
app.scriptingEngine.invoke (thisObject, method, args, globals, this);
|
app.scriptingEngine.invoke (thisObject, method, args, globals, this);
|
||||||
commitTransaction ();
|
commitTransaction ();
|
||||||
|
@ -497,10 +459,10 @@ public class RequestEvaluator implements Runnable {
|
||||||
} catch (InterruptedException ir) {}
|
} catch (InterruptedException ir) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized ResponseTrans invoke (RequestTrans req, User user) throws Exception {
|
public synchronized ResponseTrans invoke (RequestTrans req, Session session) throws Exception {
|
||||||
this.reqtype = HTTP;
|
this.reqtype = HTTP;
|
||||||
this.req = req;
|
this.req = req;
|
||||||
this.user = user;
|
this.session = session;
|
||||||
this.res = new ResponseTrans ();
|
this.res = new ResponseTrans ();
|
||||||
|
|
||||||
app.activeRequests.put (req, this);
|
app.activeRequests.put (req, this);
|
||||||
|
@ -534,7 +496,7 @@ public class RequestEvaluator implements Runnable {
|
||||||
|
|
||||||
public synchronized Object invokeXmlRpc (String method, Object[] args) throws Exception {
|
public synchronized Object invokeXmlRpc (String method, Object[] args) throws Exception {
|
||||||
this.reqtype = XMLRPC;
|
this.reqtype = XMLRPC;
|
||||||
this.user = null;
|
this.session = null;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
this.res = new ResponseTrans ();
|
this.res = new ResponseTrans ();
|
||||||
|
@ -559,7 +521,7 @@ public class RequestEvaluator implements Runnable {
|
||||||
public synchronized Object invokeFunction (Object object, String functionName, Object[] args)
|
public synchronized Object invokeFunction (Object object, String functionName, Object[] args)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
reqtype = INTERNAL;
|
reqtype = INTERNAL;
|
||||||
user = null;
|
session = null;
|
||||||
thisObject = object;
|
thisObject = object;
|
||||||
method = functionName;
|
method = functionName;
|
||||||
this.args =args;
|
this.args =args;
|
||||||
|
@ -579,10 +541,10 @@ public class RequestEvaluator implements Runnable {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Object invokeFunction (User user, String functionName, Object[] args)
|
public synchronized Object invokeFunction (Session session, String functionName, Object[] args)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
reqtype = INTERNAL;
|
reqtype = INTERNAL;
|
||||||
this.user = user;
|
this.session = session;
|
||||||
thisObject = null;
|
thisObject = null;
|
||||||
method = functionName;
|
method = functionName;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
|
@ -650,30 +612,15 @@ public class RequestEvaluator implements Runnable {
|
||||||
public String getAction (Object obj, String action) {
|
public String getAction (Object obj, String action) {
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
return null;
|
return null;
|
||||||
// check if this is a public skin, i.e. something with an extension
|
String act = action == null ? "main_action" : action+"_action";
|
||||||
// like "home.html"
|
try {
|
||||||
if (action != null && action.indexOf (".") > -1) {
|
if (app.scriptingEngine.hasFunction (obj, act, this))
|
||||||
int dot = action.lastIndexOf (".");
|
return act;
|
||||||
String extension = action.substring (dot+1);
|
} catch (ScriptingException x) {
|
||||||
String contentType = app.skinExtensions.getProperty (extension);
|
return null;
|
||||||
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 null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
131
src/helma/framework/core/Session.java
Normal file
131
src/helma/framework/core/Session.java
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
// Session.java
|
||||||
|
|
||||||
|
package helma.framework.core;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import helma.objectmodel.*;
|
||||||
|
import helma.objectmodel.db.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This represents a session currently using the Hop application.
|
||||||
|
* This comprends 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Session 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 userHandle;
|
||||||
|
|
||||||
|
// the transient cache node that is exposed to javascript
|
||||||
|
// this stays the same across logins and logouts.
|
||||||
|
public TransientNode cacheNode;
|
||||||
|
|
||||||
|
long onSince, lastTouched;
|
||||||
|
|
||||||
|
// used to remember messages to the user between requests -
|
||||||
|
// used for redirects.
|
||||||
|
String message;
|
||||||
|
|
||||||
|
public Session (String sessionID, Application app) {
|
||||||
|
this.sessionID = sessionID;
|
||||||
|
this.app = app;
|
||||||
|
this.uid = null;
|
||||||
|
this.userHandle = null;
|
||||||
|
cacheNode = new TransientNode ("session");
|
||||||
|
onSince = System.currentTimeMillis ();
|
||||||
|
lastTouched = onSince;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attach the given user node to this session.
|
||||||
|
*/
|
||||||
|
public void login (INode usernode) {
|
||||||
|
if (usernode==null) {
|
||||||
|
userHandle = null;
|
||||||
|
uid = null;
|
||||||
|
} else {
|
||||||
|
userHandle = ((Node)usernode).getHandle();
|
||||||
|
uid = usernode.getElementName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove this sessions's user node.
|
||||||
|
*/
|
||||||
|
public void logout() {
|
||||||
|
userHandle = null;
|
||||||
|
uid = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoggedIn() {
|
||||||
|
if (userHandle!=null && uid!=null) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user Node from this Application's NodeManager.
|
||||||
|
*/
|
||||||
|
public INode getUserNode() {
|
||||||
|
if (userHandle!=null)
|
||||||
|
return userHandle.getNode (app.getWrappedNodeManager());
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the transient cache node.
|
||||||
|
*/
|
||||||
|
public INode getCacheNode () {
|
||||||
|
return cacheNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Application getApp () {
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSessionID () {
|
||||||
|
return sessionID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void touch () {
|
||||||
|
lastTouched = System.currentTimeMillis ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long lastTouched () {
|
||||||
|
return lastTouched;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long onSince () {
|
||||||
|
return onSince;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
if ( uid!=null )
|
||||||
|
return "[Session for user " + uid + "]";
|
||||||
|
else
|
||||||
|
return "[Anonymous Session]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
73
src/helma/framework/core/SessionBean.java
Normal file
73
src/helma/framework/core/SessionBean.java
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package helma.framework.core;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import helma.objectmodel.INode;
|
||||||
|
import helma.scripting.ScriptingEnvironment;
|
||||||
|
import helma.scripting.ScriptingException;
|
||||||
|
import helma.scripting.fesi.*;
|
||||||
|
|
||||||
|
public class SessionBean implements Serializable {
|
||||||
|
|
||||||
|
// the wrapped session object
|
||||||
|
Session session;
|
||||||
|
|
||||||
|
public SessionBean(Session session) {
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return session.toString ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean login (String username, String password) {
|
||||||
|
boolean success = session.getApp().loginSession (username, password, session);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logout () {
|
||||||
|
session.getApp().logoutSession (session);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void touch () {
|
||||||
|
session.touch ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date lastActive() {
|
||||||
|
return new Date (session.lastTouched ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date onSince() {
|
||||||
|
return new Date (session.onSince ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// property-related methods:
|
||||||
|
|
||||||
|
public INode getdata() {
|
||||||
|
return session.getCacheNode ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public INode getuser() {
|
||||||
|
return session.getUserNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String get_id () {
|
||||||
|
return session.getSessionID ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getcookie() {
|
||||||
|
return session.getSessionID ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getlastActive() {
|
||||||
|
return new Date (session.lastTouched ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getonSince() {
|
||||||
|
return new Date (session.onSince ());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -258,16 +258,15 @@ public class Skin {
|
||||||
Object handlerObject = null;
|
Object handlerObject = null;
|
||||||
|
|
||||||
Object[] arguments = new Object[1];
|
Object[] arguments = new Object[1];
|
||||||
arguments[0] = parameters;
|
// pass a clone of the parameter map so if the script changes it,
|
||||||
|
// we still keep the original version.
|
||||||
|
arguments[0] = parameters.clone ();
|
||||||
|
|
||||||
// flag to tell whether we found our invocation target object
|
// flag to tell whether we found our invocation target object
|
||||||
boolean objectFound = true;
|
boolean objectFound = true;
|
||||||
|
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
if ("currentuser".equalsIgnoreCase (handler)) {
|
if (thisObject != null) {
|
||||||
// as a special convention, we use "currentuser" to access macros in the current user object
|
|
||||||
handlerObject = reval.user.getNode ();
|
|
||||||
} else if (thisObject != null) {
|
|
||||||
// not a global macro - need to find handler object
|
// not a global macro - need to find handler object
|
||||||
// was called with this object - check it or its parents for matching prototype
|
// was called with this object - check it or its parents for matching prototype
|
||||||
if (!handler.equalsIgnoreCase ("this") && !handler.equalsIgnoreCase (app.getPrototypeName (thisObject))) {
|
if (!handler.equalsIgnoreCase ("this") && !handler.equalsIgnoreCase (app.getPrototypeName (thisObject))) {
|
||||||
|
@ -314,6 +313,8 @@ public class Skin {
|
||||||
// if so, the macro evaluates to the function. Otherwise,
|
// if so, the macro evaluates to the function. Otherwise,
|
||||||
// a property/field with the name is used, if defined.
|
// a property/field with the name is used, if defined.
|
||||||
Object v = null;
|
Object v = null;
|
||||||
|
// remember length of response buffer before calling macro
|
||||||
|
int oldLength = reval.res.getBufferLength ();
|
||||||
if (app.scriptingEngine.hasFunction (handlerObject, name+"_macro", reval)) {
|
if (app.scriptingEngine.hasFunction (handlerObject, name+"_macro", reval)) {
|
||||||
// System.err.println ("Getting macro from function");
|
// System.err.println ("Getting macro from function");
|
||||||
v = app.scriptingEngine.invoke (handlerObject, name+"_macro", arguments, null, reval);
|
v = app.scriptingEngine.invoke (handlerObject, name+"_macro", arguments, null, reval);
|
||||||
|
@ -321,8 +322,19 @@ public class Skin {
|
||||||
// System.err.println ("Getting macro from property");
|
// System.err.println ("Getting macro from property");
|
||||||
v = app.scriptingEngine.get (handlerObject, name, reval);
|
v = app.scriptingEngine.get (handlerObject, name, reval);
|
||||||
}
|
}
|
||||||
if (v != null)
|
// check if macro wrote out to response buffer
|
||||||
|
int newLength = reval.res.getBufferLength ();
|
||||||
|
if (newLength > oldLength) {
|
||||||
|
// insert prefix and append suffix
|
||||||
|
String prefix = (String) parameters.get ("prefix");
|
||||||
|
String suffix = (String) parameters.get ("suffix");
|
||||||
|
reval.res.insert (oldLength, prefix);
|
||||||
|
reval.res.write (suffix);
|
||||||
|
}
|
||||||
|
// if macro returned something append it to response
|
||||||
|
if (v != null) {
|
||||||
writeToResponse (v.toString (), reval.res);
|
writeToResponse (v.toString (), reval.res);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
String msg = "[HopMacro unhandled: "+getFullName()+"]";
|
String msg = "[HopMacro unhandled: "+getFullName()+"]";
|
||||||
reval.res.write (" "+msg+" ");
|
reval.res.write (" "+msg+" ");
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
// User.java
|
|
||||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
|
||||||
|
|
||||||
package helma.framework.core;
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
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;
|
|
||||||
long onSince, lastTouched;
|
|
||||||
|
|
||||||
// used to remember messages to the user between requests -
|
|
||||||
// used for redirects.
|
|
||||||
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);
|
|
||||||
sessionID = sid;
|
|
||||||
onSince = System.currentTimeMillis ();
|
|
||||||
lastTouched = onSince;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
public void setNode (INode n) {
|
|
||||||
// IServer.getLogger().log ("esn = "+esn);
|
|
||||||
if (n == null) {
|
|
||||||
nhandle = null;
|
|
||||||
uid = null;
|
|
||||||
} else {
|
|
||||||
uid = n.getElementName ();
|
|
||||||
nhandle = ((Node) n).getHandle ();
|
|
||||||
}
|
|
||||||
// System.err.println ("User.setNode: "+nhandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public INode getNode () {
|
|
||||||
if (nhandle == 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSessionID () {
|
|
||||||
return sessionID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void touch () {
|
|
||||||
lastTouched = System.currentTimeMillis ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long lastTouched () {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -108,11 +108,11 @@ public class ApplicationManager {
|
||||||
if (server.websrv == null) {
|
if (server.websrv == null) {
|
||||||
Naming.rebind ("//:"+port+"/"+appName, app);
|
Naming.rebind ("//:"+port+"/"+appName, app);
|
||||||
} else {
|
} else {
|
||||||
AcmeServletClient servlet = new AcmeServletClient (app);
|
boolean isRoot = "base".equalsIgnoreCase (appName);
|
||||||
if ("base".equalsIgnoreCase (appName))
|
EmbeddedServletClient servlet = new EmbeddedServletClient (appName, isRoot);
|
||||||
|
if (isRoot)
|
||||||
server.websrv.setDefaultServlet (servlet);
|
server.websrv.setDefaultServlet (servlet);
|
||||||
else {
|
else {
|
||||||
// server.websrv.addServlet ("/"+appName+"/", servlet);
|
|
||||||
server.websrv.addServlet ("/"+appName+"/*", servlet);
|
server.websrv.addServlet ("/"+appName+"/*", servlet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,14 +147,17 @@ public class ApplicationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get an enumeration of all currently running applications.
|
* Get an array containing all currently running applications.
|
||||||
*/
|
*/
|
||||||
public Object[] getApplications () {
|
public Object[] getApplications () {
|
||||||
return applications.values ().toArray ();
|
return applications.values ().toArray ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Application getApplication(String name) {
|
/**
|
||||||
return (Application)applications.get(name);
|
* Get an application by name.
|
||||||
}
|
*/
|
||||||
|
public Application getApplication(String name) {
|
||||||
|
return (Application)applications.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import helma.framework.*;
|
||||||
import helma.framework.core.*;
|
import helma.framework.core.*;
|
||||||
import helma.xmlrpc.*;
|
import helma.xmlrpc.*;
|
||||||
import helma.util.*;
|
import helma.util.*;
|
||||||
import com.sleepycat.db.*;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
49
src/helma/objectmodel/DatabaseException.java
Normal file
49
src/helma/objectmodel/DatabaseException.java
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// DatabaseException.java
|
||||||
|
|
||||||
|
package helma.objectmodel;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown on any kind of Database-Error
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class DatabaseException extends RuntimeException {
|
||||||
|
|
||||||
|
public DatabaseException (String msg) {
|
||||||
|
super (msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
35
src/helma/objectmodel/IDatabase.java
Normal file
35
src/helma/objectmodel/IDatabase.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// IDatabase.java
|
||||||
|
|
||||||
|
package helma.objectmodel;
|
||||||
|
|
||||||
|
import helma.objectmodel.db.IDGenerator;
|
||||||
|
import helma.objectmodel.INode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface that is implemented by Database wrappers
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface IDatabase {
|
||||||
|
|
||||||
|
// db-related
|
||||||
|
public void shutdown ();
|
||||||
|
|
||||||
|
// id-related
|
||||||
|
public String nextID() throws ObjectNotFoundException;
|
||||||
|
public IDGenerator getIDGenerator (ITransaction transaction) throws Exception;
|
||||||
|
public void saveIDGenerator (ITransaction transaction, IDGenerator idgen) throws Exception;
|
||||||
|
|
||||||
|
// node-related
|
||||||
|
public INode getNode (ITransaction transaction, String key) throws Exception;
|
||||||
|
public void saveNode (ITransaction transaction, String key, INode node) throws Exception;
|
||||||
|
public void deleteNode (ITransaction transaction, String key) throws Exception;
|
||||||
|
|
||||||
|
// transaction-related
|
||||||
|
public ITransaction beginTransaction ();
|
||||||
|
public void commitTransaction (ITransaction transaction) throws DatabaseException;
|
||||||
|
public void abortTransaction (ITransaction transaction) throws DatabaseException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
18
src/helma/objectmodel/ITransaction.java
Normal file
18
src/helma/objectmodel/ITransaction.java
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// ITransaction.java
|
||||||
|
|
||||||
|
package helma.objectmodel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is kept for databases that are able
|
||||||
|
* to run transactions. Transactions were used for the
|
||||||
|
* Berkeley database and might be used in other future
|
||||||
|
* databases, so we leave transactions in.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface ITransaction {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class DbMapping implements Updatable {
|
||||||
// prototype name of this mapping
|
// prototype name of this mapping
|
||||||
String typename;
|
String typename;
|
||||||
|
|
||||||
int version;
|
// int version;
|
||||||
|
|
||||||
// properties from where the mapping is read
|
// properties from where the mapping is read
|
||||||
SystemProperties props;
|
SystemProperties props;
|
||||||
|
@ -135,21 +135,21 @@ public class DbMapping implements Updatable {
|
||||||
public synchronized void update () {
|
public synchronized void update () {
|
||||||
|
|
||||||
// determin file format version of type.properties file
|
// determin file format version of type.properties file
|
||||||
String versionInfo = props.getProperty ("_version");
|
/* String versionInfo = props.getProperty ("_version");
|
||||||
if ("1.2".equals (versionInfo))
|
if ("1.2".equals (versionInfo))
|
||||||
version = 1;
|
version = 1;
|
||||||
else
|
else
|
||||||
version = 0;
|
version = 0; */
|
||||||
|
|
||||||
table = props.getProperty (version == 0 ? "_tablename" : "_table");
|
table = props.getProperty ("_table");
|
||||||
idgen = props.getProperty ("_idgen");
|
idgen = props.getProperty ("_idgen");
|
||||||
// see if there is a field which specifies the prototype of objects, if different prototypes
|
// see if there is a field which specifies the prototype of objects, if different prototypes
|
||||||
// can be stored in this table
|
// can be stored in this table
|
||||||
prototypeField = props.getProperty ("_prototypefield");
|
prototypeField = props.getProperty ("_prototypefield");
|
||||||
// see if this prototype extends (inherits from) any other prototype
|
// see if this prototype extends (inherits from) any other prototype
|
||||||
extendsProto = props.getProperty ("_extends");
|
extendsProto = props.getProperty ("_extends");
|
||||||
|
|
||||||
sourceName = props.getProperty (version == 0 ? "_datasource" : "_db");
|
sourceName = props.getProperty ("_db");
|
||||||
if (sourceName != null) {
|
if (sourceName != null) {
|
||||||
source = app.getDbSource (sourceName);
|
source = app.getDbSource (sourceName);
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
|
@ -207,7 +207,7 @@ public class DbMapping implements Updatable {
|
||||||
Relation rel = propertyToRelation (propName);
|
Relation rel = propertyToRelation (propName);
|
||||||
if (rel == null)
|
if (rel == null)
|
||||||
rel = new Relation (dbField, propName, this, props);
|
rel = new Relation (dbField, propName, this, props);
|
||||||
rel.update (dbField, props, version);
|
rel.update (dbField, props);
|
||||||
p2d.put (propName, rel);
|
p2d.put (propName, rel);
|
||||||
if (rel.columnName != null &&
|
if (rel.columnName != null &&
|
||||||
(rel.reftype == Relation.PRIMITIVE ||
|
(rel.reftype == Relation.PRIMITIVE ||
|
||||||
|
@ -223,60 +223,21 @@ public class DbMapping implements Updatable {
|
||||||
prop2db = p2d;
|
prop2db = p2d;
|
||||||
db2prop = d2p;
|
db2prop = d2p;
|
||||||
|
|
||||||
if (version == 1) {
|
String subnodeMapping = props.getProperty ("_children");
|
||||||
String subnodeMapping = props.getProperty ("_children");
|
if (subnodeMapping != null) {
|
||||||
if (subnodeMapping != null) {
|
try {
|
||||||
try {
|
// check if subnode relation already exists. If so, reuse it
|
||||||
// check if subnode relation already exists. If so, reuse it
|
if (subnodesRel == null)
|
||||||
if (subnodesRel == null)
|
subnodesRel = new Relation (subnodeMapping, "_children", this, props);
|
||||||
subnodesRel = new Relation (subnodeMapping, "_children", this, props);
|
subnodesRel.update (subnodeMapping, props);
|
||||||
subnodesRel.update (subnodeMapping, props, version);
|
if (subnodesRel.accessor != null)
|
||||||
if (subnodesRel.accessor != null)
|
propertiesRel = subnodesRel;
|
||||||
propertiesRel = subnodesRel;
|
} catch (Exception x) {
|
||||||
|
app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
|
||||||
} catch (Exception x) {
|
// subnodesRel = null;
|
||||||
app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
|
}
|
||||||
// subnodesRel = null;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
subnodesRel = null;
|
|
||||||
} else {
|
} else {
|
||||||
String subnodeMapping = props.getProperty ("_subnodes");
|
subnodesRel = propertiesRel = null;
|
||||||
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) {
|
if (groupbyMapping != null) {
|
||||||
|
|
|
@ -1,292 +0,0 @@
|
||||||
// DbWrapper.java
|
|
||||||
// Copyright (c) Hannes Wallnöfer 1999-2000
|
|
||||||
|
|
||||||
|
|
||||||
package helma.objectmodel.db;
|
|
||||||
|
|
||||||
import com.sleepycat.db.*;
|
|
||||||
import helma.objectmodel.ObjectNotFoundException;
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A wrapper around a Berkeley embedded database. Used to gracefully handle the case
|
|
||||||
* when the native library can not be loaded.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class DbWrapper {
|
|
||||||
|
|
||||||
private boolean loaded, useTransactions;
|
|
||||||
|
|
||||||
private Db db;
|
|
||||||
DbEnv dbenv;
|
|
||||||
final int checkpointPause = 600000; // min. 10 minutes between checkpoints
|
|
||||||
volatile long lastCheckpoint = 0;
|
|
||||||
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;
|
|
||||||
|
|
||||||
try {
|
|
||||||
dbBaseDir = new File (dbHome);
|
|
||||||
if (!dbBaseDir.exists())
|
|
||||||
dbBaseDir.mkdirs();
|
|
||||||
|
|
||||||
useTransactions = useTx;
|
|
||||||
|
|
||||||
int dbInitFlags = Db.DB_CREATE | Db.DB_THREAD | Db.DB_INIT_MPOOL;
|
|
||||||
if (useTransactions) {
|
|
||||||
dbInitFlags = dbInitFlags | Db.DB_INIT_TXN;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbenv = new DbEnv (0);
|
|
||||||
try {
|
|
||||||
dbenv.open (dbHome, dbInitFlags, 0); // for berkeley 3.0, add second parameter (null)
|
|
||||||
} catch (FileNotFoundException fnf) {
|
|
||||||
// we just created the dirs, so this shouldn't happen
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
dbenv.set_error_stream(System.err);
|
|
||||||
dbenv.set_errpfx("Sleepycat");
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println("Error in DbWrapper: "+e.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
db = new Db (dbenv, 0);
|
|
||||||
try {
|
|
||||||
db.upgrade (dbFilename, 0);
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
// nothing to upgrade, db doesn't exist
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
db.open (dbFilename, null, Db.DB_BTREE, Db.DB_CREATE, 0644);
|
|
||||||
} catch (FileNotFoundException fnf) {
|
|
||||||
// we just created the dirs, so this shouldn't happen
|
|
||||||
}
|
|
||||||
loaded = true;
|
|
||||||
|
|
||||||
} catch (NoClassDefFoundError noclass) {
|
|
||||||
nmgr.app.logEvent ("Warning: Using internal file based db as fallback.");
|
|
||||||
nmgr.app.logEvent ("Reason: "+noclass);
|
|
||||||
loaded = false;
|
|
||||||
} catch (UnsatisfiedLinkError nolib) {
|
|
||||||
nmgr.app.logEvent ("Warning: Using internal file based db as fallback.");
|
|
||||||
nmgr.app.logEvent ("Reason: "+nolib);
|
|
||||||
loaded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void shutdown () throws DbException {
|
|
||||||
if (loaded) {
|
|
||||||
db.close (0);
|
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DbTxn beginTransaction () throws DbException {
|
|
||||||
if (loaded && useTransactions)
|
|
||||||
return dbenv.txn_begin (null, 0);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void commitTransaction (DbTxn txn) throws DbException {
|
|
||||||
if (txn == null || !loaded || !useTransactions)
|
|
||||||
return;
|
|
||||||
txn.commit (0);
|
|
||||||
if (++txncount%100 == 0 && System.currentTimeMillis()-checkpointPause > lastCheckpoint) {
|
|
||||||
// checkpoint transaction logs in time interval specified by server.checkpointPause
|
|
||||||
// if there are more then 100 transactions to checkpoint.
|
|
||||||
checkpoint ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void abortTransaction (DbTxn txn) throws DbException {
|
|
||||||
if (txn == null || !loaded || !useTransactions)
|
|
||||||
return;
|
|
||||||
txn.abort ();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void checkpoint () throws DbException {
|
|
||||||
if (!loaded || !useTransactions || txncount == 0)
|
|
||||||
return;
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if (now - lastCheckpoint < checkpointPause)
|
|
||||||
return;
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDGenerator getIDGenerator (DbTxn txn, String kstr) throws Exception {
|
|
||||||
if (loaded)
|
|
||||||
return getIDGenFromDB (txn, kstr);
|
|
||||||
else
|
|
||||||
return getIDGenFromFile (kstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node getNode (DbTxn txn, String kstr) throws Exception {
|
|
||||||
if (loaded)
|
|
||||||
return getNodeFromDB (txn, kstr);
|
|
||||||
else
|
|
||||||
return getNodeFromFile (kstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save (DbTxn txn, String kstr, Object obj) throws Exception {
|
|
||||||
if (loaded)
|
|
||||||
saveToDB (txn, kstr, obj);
|
|
||||||
else
|
|
||||||
saveToFile (kstr, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete (DbTxn txn, String kstr) throws Exception {
|
|
||||||
if (loaded)
|
|
||||||
deleteFromDB (txn, kstr);
|
|
||||||
else
|
|
||||||
deleteFromFile (kstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private IDGenerator getIDGenFromDB (DbTxn txn, String kstr) throws Exception {
|
|
||||||
long now = System.currentTimeMillis ();
|
|
||||||
byte[] kbuf = kstr.getBytes ();
|
|
||||||
Dbt key = new Dbt (kbuf);
|
|
||||||
key.set_size (kbuf.length);
|
|
||||||
Dbt data = new Dbt ();
|
|
||||||
data.set_flags (Db.DB_DBT_MALLOC);
|
|
||||||
|
|
||||||
db.get (txn, key, data, 0);
|
|
||||||
|
|
||||||
byte[] b = data.get_data ();
|
|
||||||
if (b == null)
|
|
||||||
throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
|
|
||||||
|
|
||||||
IDGenerator idgen = null;
|
|
||||||
ByteArrayInputStream bin = new ByteArrayInputStream (b);
|
|
||||||
ObjectInputStream oin = new ObjectInputStream (bin);
|
|
||||||
idgen = (IDGenerator) oin.readObject ();
|
|
||||||
|
|
||||||
oin.close ();
|
|
||||||
return idgen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Node getNodeFromDB (DbTxn txn, String kstr) throws Exception {
|
|
||||||
long now = System.currentTimeMillis ();
|
|
||||||
byte[] kbuf = kstr.getBytes ();
|
|
||||||
Dbt key = new Dbt (kbuf);
|
|
||||||
key.set_size (kbuf.length);
|
|
||||||
Dbt data = new Dbt ();
|
|
||||||
data.set_flags (Db.DB_DBT_MALLOC);
|
|
||||||
|
|
||||||
db.get (txn, key, data, 0);
|
|
||||||
|
|
||||||
byte[] b = data.get_data ();
|
|
||||||
if (b == null)
|
|
||||||
throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
|
|
||||||
|
|
||||||
Node node = null;
|
|
||||||
ByteArrayInputStream bin = new ByteArrayInputStream (b);
|
|
||||||
ObjectInputStream oin = new ObjectInputStream (bin);
|
|
||||||
node = (Node) oin.readObject ();
|
|
||||||
oin.close ();
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void saveToDB (DbTxn txn, String kstr, Object obj) throws Exception {
|
|
||||||
long now = System.currentTimeMillis ();
|
|
||||||
byte kbuf[] = kstr.getBytes();
|
|
||||||
ByteArrayOutputStream bout = new ByteArrayOutputStream ();
|
|
||||||
ObjectOutputStream oout = new ObjectOutputStream (bout);
|
|
||||||
oout.writeObject (obj);
|
|
||||||
oout.close ();
|
|
||||||
byte vbuf[] = bout.toByteArray ();
|
|
||||||
|
|
||||||
Dbt key = new Dbt (kbuf);
|
|
||||||
key.set_size (kbuf.length);
|
|
||||||
Dbt value = new Dbt (vbuf);
|
|
||||||
value.set_size (vbuf.length);
|
|
||||||
|
|
||||||
db.put (txn, key, value, 0);
|
|
||||||
// nmgr.app.logEvent ("saved "+obj+", size = "+vbuf.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteFromDB (DbTxn txn, String kstr) throws Exception {
|
|
||||||
|
|
||||||
byte kbuf[] = kstr.getBytes();
|
|
||||||
|
|
||||||
Dbt key = new Dbt (kbuf);
|
|
||||||
key.set_size (kbuf.length);
|
|
||||||
|
|
||||||
db.del (txn, key, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// File based fallback methods
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private IDGenerator getIDGenFromFile (String kstr) throws Exception {
|
|
||||||
|
|
||||||
File f = new File (dbBaseDir, kstr);
|
|
||||||
|
|
||||||
if ( ! f.exists() )
|
|
||||||
throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
|
|
||||||
|
|
||||||
IDGenerator idgen = null;
|
|
||||||
FileInputStream bin = new FileInputStream (f);
|
|
||||||
ObjectInputStream oin = new ObjectInputStream (bin);
|
|
||||||
idgen = (IDGenerator) oin.readObject ();
|
|
||||||
|
|
||||||
oin.close ();
|
|
||||||
return idgen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Node getNodeFromFile (String kstr) throws Exception {
|
|
||||||
|
|
||||||
File f = new File (dbBaseDir, kstr);
|
|
||||||
|
|
||||||
if ( ! f.exists() )
|
|
||||||
throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
|
|
||||||
|
|
||||||
Node node = null;
|
|
||||||
FileInputStream bin = new FileInputStream (f);
|
|
||||||
ObjectInputStream oin = new ObjectInputStream (bin);
|
|
||||||
node = (Node) oin.readObject ();
|
|
||||||
oin.close ();
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void saveToFile (String kstr, Object obj) throws Exception {
|
|
||||||
|
|
||||||
File f = new File (dbBaseDir, kstr);
|
|
||||||
|
|
||||||
FileOutputStream bout = new FileOutputStream (f);
|
|
||||||
ObjectOutputStream oout = new ObjectOutputStream (bout);
|
|
||||||
oout.writeObject (obj);
|
|
||||||
oout.close ();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteFromFile (String kstr) throws Exception {
|
|
||||||
|
|
||||||
File f = new File (dbBaseDir, kstr);
|
|
||||||
f.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -58,7 +58,7 @@ public final class IDGenerator implements Serializable {
|
||||||
/**
|
/**
|
||||||
* Get the current counter value
|
* Get the current counter value
|
||||||
*/
|
*/
|
||||||
protected long getValue () {
|
public long getValue () {
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,20 @@ public final class Node implements INode, Serializable {
|
||||||
out.writeObject (prototype);
|
out.writeObject (prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used by Xml deserialization
|
||||||
|
*/
|
||||||
|
public void setPropMap (Hashtable propMap) {
|
||||||
|
this.propMap = propMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used by Xml deserialization
|
||||||
|
*/
|
||||||
|
public void setSubnodes (List subnodes) {
|
||||||
|
this.subnodes = subnodes;
|
||||||
|
}
|
||||||
|
|
||||||
private transient String prototype;
|
private transient String prototype;
|
||||||
|
|
||||||
private transient NodeHandle handle;
|
private transient NodeHandle handle;
|
||||||
|
@ -164,8 +178,9 @@ public final class Node implements INode, Serializable {
|
||||||
/**
|
/**
|
||||||
* Creates a new Node with the given name. Only used by NodeManager for "root nodes" and
|
* Creates a new Node with the given name. Only used by NodeManager for "root nodes" and
|
||||||
* not in a Transaction context, which is why we can immediately mark it as CLEAN.
|
* not in a Transaction context, which is why we can immediately mark it as CLEAN.
|
||||||
|
* ADD: used by wrapped database to re-create an existing Node.
|
||||||
*/
|
*/
|
||||||
protected Node (String name, String id, String prototype, WrappedNodeManager nmgr) {
|
public Node (String name, String id, String prototype, WrappedNodeManager nmgr) {
|
||||||
this.nmgr = nmgr;
|
this.nmgr = nmgr;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name == null || "".equals (name) ? id : name;
|
this.name = name == null || "".equals (name) ? id : name;
|
||||||
|
@ -176,6 +191,17 @@ public final class Node implements INode, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor used to create a Node with a given name from a wrapped database.
|
||||||
|
*/
|
||||||
|
public Node (String name, String id, String prototype, WrappedNodeManager nmgr, long created, long lastmodified) {
|
||||||
|
this (name,id,prototype,nmgr);
|
||||||
|
this.created = created;
|
||||||
|
this.lastmodified = lastmodified;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor used for virtual nodes.
|
* Constructor used for virtual nodes.
|
||||||
*/
|
*/
|
||||||
|
@ -459,6 +485,8 @@ public final class Node implements INode, Serializable {
|
||||||
} else {
|
} else {
|
||||||
anonymous = true;
|
anonymous = true;
|
||||||
}
|
}
|
||||||
|
} else if (p.contains (this) > -1) {
|
||||||
|
anonymous = true;
|
||||||
}
|
}
|
||||||
} catch (Exception ignore) {
|
} catch (Exception ignore) {
|
||||||
// just fall back to default method
|
// just fall back to default method
|
||||||
|
@ -577,6 +605,10 @@ public final class Node implements INode, Serializable {
|
||||||
parentHandle = parent == null ? null : parent.getHandle ();
|
parentHandle = parent == null ? null : parent.getHandle ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setParentHandle (NodeHandle parent) {
|
||||||
|
parentHandle = parent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This version of setParent additionally marks the node as anonymous or non-anonymous,
|
* This version of setParent additionally marks the node as anonymous or non-anonymous,
|
||||||
* depending on the string argument. This is the version called from the scripting framework,
|
* depending on the string argument. This is the version called from the scripting framework,
|
||||||
|
@ -1197,6 +1229,10 @@ public final class Node implements INode, Serializable {
|
||||||
return new Enum ();
|
return new Enum ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List getSubnodeList() {
|
||||||
|
return subnodes;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean ignoreSubnodeChange () {
|
private boolean ignoreSubnodeChange () {
|
||||||
// return true if a change in subnodes can be ignored because it is
|
// return true if a change in subnodes can be ignored because it is
|
||||||
// stored in the subnodes themselves.
|
// stored in the subnodes themselves.
|
||||||
|
@ -1233,7 +1269,9 @@ public final class Node implements INode, Serializable {
|
||||||
// return propMap == null ? new Vector ().elements () : propMap.elements ();
|
// return propMap == null ? new Vector ().elements () : propMap.elements ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Hashtable getPropMap() {
|
||||||
|
return propMap;
|
||||||
|
}
|
||||||
|
|
||||||
public IProperty get (String propname, boolean inherit) {
|
public IProperty get (String propname, boolean inherit) {
|
||||||
return getProperty (propname, inherit);
|
return getProperty (propname, inherit);
|
||||||
|
|
|
@ -6,7 +6,6 @@ package helma.objectmodel.db;
|
||||||
import helma.util.CacheMap;
|
import helma.util.CacheMap;
|
||||||
import helma.objectmodel.*;
|
import helma.objectmodel.*;
|
||||||
import helma.framework.core.Application;
|
import helma.framework.core.Application;
|
||||||
import com.sleepycat.db.*;
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -26,7 +25,7 @@ public final class NodeManager {
|
||||||
|
|
||||||
private Replicator replicator;
|
private Replicator replicator;
|
||||||
|
|
||||||
protected DbWrapper db;
|
protected IDatabase db;
|
||||||
|
|
||||||
protected IDGenerator idgen;
|
protected IDGenerator idgen;
|
||||||
|
|
||||||
|
@ -42,7 +41,7 @@ public final class NodeManager {
|
||||||
* Create a new NodeManager for Application app. An embedded database will be
|
* Create a new NodeManager for Application app. An embedded database will be
|
||||||
* created in dbHome if one doesn't already exist.
|
* created in dbHome if one doesn't already exist.
|
||||||
*/
|
*/
|
||||||
public NodeManager (Application app, String dbHome, Properties props) throws DbException {
|
public NodeManager (Application app, String dbHome, Properties props) throws DatabaseException {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
int cacheSize = Integer.parseInt (props.getProperty ("cachesize", "1000"));
|
int cacheSize = Integer.parseInt (props.getProperty ("cachesize", "1000"));
|
||||||
// Make actual cache size bigger, since we use it only up to the threshold
|
// Make actual cache size bigger, since we use it only up to the threshold
|
||||||
|
@ -68,7 +67,7 @@ public final class NodeManager {
|
||||||
idBaseValue = Math.max (1l, idBaseValue); // 0 and 1 are reserved for root nodes
|
idBaseValue = Math.max (1l, idBaseValue); // 0 and 1 are reserved for root nodes
|
||||||
} catch (NumberFormatException ignore) {}
|
} catch (NumberFormatException ignore) {}
|
||||||
|
|
||||||
db = new DbWrapper (dbHome, helma.main.Server.dbFilename, this, helma.main.Server.useTransactions);
|
db = new XmlDatabase (dbHome, helma.main.Server.dbFilename, this);
|
||||||
initDb ();
|
initDb ();
|
||||||
|
|
||||||
logSql = "true".equalsIgnoreCase(props.getProperty ("logsql"));
|
logSql = "true".equalsIgnoreCase(props.getProperty ("logsql"));
|
||||||
|
@ -77,44 +76,44 @@ public final class NodeManager {
|
||||||
/**
|
/**
|
||||||
* Method used to create the root node and id-generator, if they don't exist already.
|
* Method used to create the root node and id-generator, if they don't exist already.
|
||||||
*/
|
*/
|
||||||
public void initDb () throws DbException {
|
public void initDb () throws DatabaseException {
|
||||||
|
|
||||||
DbTxn txn = null;
|
ITransaction txn = null;
|
||||||
try {
|
try {
|
||||||
txn = db.beginTransaction ();
|
txn = db.beginTransaction ();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
idgen = db.getIDGenerator (txn, "idgen");
|
idgen = db.getIDGenerator (txn);
|
||||||
if (idgen.getValue() < idBaseValue) {
|
if (idgen.getValue() < idBaseValue) {
|
||||||
idgen.setValue (idBaseValue);
|
idgen.setValue (idBaseValue);
|
||||||
db.save (txn, "idgen", idgen);
|
db.saveIDGenerator (txn, idgen);
|
||||||
}
|
}
|
||||||
} catch (ObjectNotFoundException notfound) {
|
} catch (ObjectNotFoundException notfound) {
|
||||||
// will start with idBaseValue+1
|
// will start with idBaseValue+1
|
||||||
idgen = new IDGenerator (idBaseValue);
|
idgen = new IDGenerator (idBaseValue);
|
||||||
db.save (txn, "idgen", idgen);
|
db.saveIDGenerator (txn, idgen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we need to set the id generator to a base value
|
// check if we need to set the id generator to a base value
|
||||||
|
|
||||||
Node node = null;
|
Node node = null;
|
||||||
try {
|
try {
|
||||||
node = db.getNode (txn, "0");
|
node = (Node)db.getNode (txn, "0");
|
||||||
node.nmgr = safe;
|
node.nmgr = safe;
|
||||||
} catch (ObjectNotFoundException notfound) {
|
} catch (ObjectNotFoundException notfound) {
|
||||||
node = new Node ("root", "0", "root", safe);
|
node = new Node ("root", "0", "root", safe);
|
||||||
node.setDbMapping (app.getDbMapping ("root"));
|
node.setDbMapping (app.getDbMapping ("root"));
|
||||||
db.save (txn, node.getID (), node);
|
db.saveNode (txn, node.getID (), node);
|
||||||
registerNode (node); // register node with nodemanager cache
|
registerNode (node); // register node with nodemanager cache
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
node = db.getNode (txn, "1");
|
node = (Node)db.getNode (txn, "1");
|
||||||
node.nmgr = safe;
|
node.nmgr = safe;
|
||||||
} catch (ObjectNotFoundException notfound) {
|
} catch (ObjectNotFoundException notfound) {
|
||||||
node = new Node ("users", "1", null, safe);
|
node = new Node ("users", "1", null, safe);
|
||||||
node.setDbMapping (app.getDbMapping ("__userroot__"));
|
node.setDbMapping (app.getDbMapping ("__userroot__"));
|
||||||
db.save (txn, node.getID (), node);
|
db.saveNode (txn, node.getID (), node);
|
||||||
registerNode (node); // register node with nodemanager cache
|
registerNode (node); // register node with nodemanager cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +124,7 @@ public final class NodeManager {
|
||||||
try {
|
try {
|
||||||
db.abortTransaction (txn);
|
db.abortTransaction (txn);
|
||||||
} catch (Exception ignore) {}
|
} catch (Exception ignore) {}
|
||||||
throw (new DbException ("Error initializing db"));
|
throw (new DatabaseException ("Error initializing db"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +133,7 @@ public final class NodeManager {
|
||||||
* Shut down this node manager. This is called when the application using this
|
* Shut down this node manager. This is called when the application using this
|
||||||
* node manager is stopped.
|
* node manager is stopped.
|
||||||
*/
|
*/
|
||||||
public void shutdown () throws DbException {
|
public void shutdown () throws DatabaseException {
|
||||||
db.shutdown ();
|
db.shutdown ();
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
synchronized (cache) {
|
synchronized (cache) {
|
||||||
|
@ -360,7 +359,7 @@ public final class NodeManager {
|
||||||
* Insert a new node in the embedded database or a relational database table, depending
|
* Insert a new node in the embedded database or a relational database table, depending
|
||||||
* on its db mapping.
|
* on its db mapping.
|
||||||
*/
|
*/
|
||||||
public void insertNode (DbWrapper db, DbTxn txn, Node node) throws Exception {
|
public void insertNode (IDatabase db, ITransaction txn, Node node) throws Exception {
|
||||||
|
|
||||||
Transactor tx = (Transactor) Thread.currentThread ();
|
Transactor tx = (Transactor) Thread.currentThread ();
|
||||||
// tx.timer.beginEvent ("insertNode "+node);
|
// tx.timer.beginEvent ("insertNode "+node);
|
||||||
|
@ -368,7 +367,7 @@ public final class NodeManager {
|
||||||
DbMapping dbm = node.getDbMapping ();
|
DbMapping dbm = node.getDbMapping ();
|
||||||
|
|
||||||
if (dbm == null || !dbm.isRelational ()) {
|
if (dbm == null || !dbm.isRelational ()) {
|
||||||
db.save (txn, node.getID (), node);
|
db.saveNode (txn, node.getID (), node);
|
||||||
} else {
|
} else {
|
||||||
app.logEvent ("inserting relational node: "+node.getID ());
|
app.logEvent ("inserting relational node: "+node.getID ());
|
||||||
TableDataSet tds = null;
|
TableDataSet tds = null;
|
||||||
|
@ -438,7 +437,7 @@ public final class NodeManager {
|
||||||
* Updates a modified node in the embedded db or an external relational database, depending
|
* Updates a modified node in the embedded db or an external relational database, depending
|
||||||
* on its database mapping.
|
* on its database mapping.
|
||||||
*/
|
*/
|
||||||
public void updateNode (DbWrapper db, DbTxn txn, Node node) throws Exception {
|
public void updateNode (IDatabase db, ITransaction txn, Node node) throws Exception {
|
||||||
|
|
||||||
Transactor tx = (Transactor) Thread.currentThread ();
|
Transactor tx = (Transactor) Thread.currentThread ();
|
||||||
// tx.timer.beginEvent ("updateNode "+node);
|
// tx.timer.beginEvent ("updateNode "+node);
|
||||||
|
@ -446,7 +445,7 @@ public final class NodeManager {
|
||||||
DbMapping dbm = node.getDbMapping ();
|
DbMapping dbm = node.getDbMapping ();
|
||||||
|
|
||||||
if (dbm == null || !dbm.isRelational ()) {
|
if (dbm == null || !dbm.isRelational ()) {
|
||||||
db.save (txn, node.getID (), node);
|
db.saveNode (txn, node.getID (), node);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
TableDataSet tds = null;
|
TableDataSet tds = null;
|
||||||
|
@ -537,7 +536,7 @@ public final class NodeManager {
|
||||||
/**
|
/**
|
||||||
* Performs the actual deletion of a node from either the embedded or an external SQL database.
|
* 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 {
|
public void deleteNode (IDatabase db, ITransaction txn, Node node) throws Exception {
|
||||||
|
|
||||||
Transactor tx = (Transactor) Thread.currentThread ();
|
Transactor tx = (Transactor) Thread.currentThread ();
|
||||||
// tx.timer.beginEvent ("deleteNode "+node);
|
// tx.timer.beginEvent ("deleteNode "+node);
|
||||||
|
@ -545,7 +544,7 @@ public final class NodeManager {
|
||||||
DbMapping dbm = node.getDbMapping ();
|
DbMapping dbm = node.getDbMapping ();
|
||||||
|
|
||||||
if (dbm == null || !dbm.isRelational ()) {
|
if (dbm == null || !dbm.isRelational ()) {
|
||||||
db.delete (txn, node.getID ());
|
db.deleteNode (txn, node.getID ());
|
||||||
} else {
|
} else {
|
||||||
Statement st = null;
|
Statement st = null;
|
||||||
try {
|
try {
|
||||||
|
@ -865,14 +864,14 @@ public final class NodeManager {
|
||||||
// private getNode methods
|
// private getNode methods
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private Node getNodeByKey (DbTxn txn, DbKey key) throws Exception {
|
private Node getNodeByKey (ITransaction txn, DbKey key) throws Exception {
|
||||||
// Note: Key must be a DbKey, otherwise will not work for relational objects
|
// Note: Key must be a DbKey, otherwise will not work for relational objects
|
||||||
Node node = null;
|
Node node = null;
|
||||||
DbMapping dbm = app.getDbMapping (key.getStorageName ());
|
DbMapping dbm = app.getDbMapping (key.getStorageName ());
|
||||||
String kstr = key.getID ();
|
String kstr = key.getID ();
|
||||||
|
|
||||||
if (dbm == null || !dbm.isRelational ()) {
|
if (dbm == null || !dbm.isRelational ()) {
|
||||||
node = db.getNode (txn, kstr);
|
node = (Node)db.getNode (txn, kstr);
|
||||||
node.nmgr = safe;
|
node.nmgr = safe;
|
||||||
if (node != null && dbm != null)
|
if (node != null && dbm != null)
|
||||||
node.setDbMapping (dbm);
|
node.setDbMapping (dbm);
|
||||||
|
@ -905,7 +904,7 @@ public final class NodeManager {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node getNodeByRelation (DbTxn txn, Node home, String kstr, Relation rel) throws Exception {
|
private Node getNodeByRelation (ITransaction txn, Node home, String kstr, Relation rel) throws Exception {
|
||||||
Node node = null;
|
Node node = null;
|
||||||
|
|
||||||
if (rel.virtual) {
|
if (rel.virtual) {
|
||||||
|
@ -922,13 +921,13 @@ public final class NodeManager {
|
||||||
} else if (rel != null && rel.groupby != null) {
|
} else if (rel != null && rel.groupby != null) {
|
||||||
node = home.getGroupbySubnode (kstr, false);
|
node = home.getGroupbySubnode (kstr, false);
|
||||||
if (node == null && (rel.otherType == null || !rel.otherType.isRelational ())) {
|
if (node == null && (rel.otherType == null || !rel.otherType.isRelational ())) {
|
||||||
node = db.getNode (txn, kstr);
|
node = (Node)db.getNode (txn, kstr);
|
||||||
node.nmgr = safe;
|
node.nmgr = safe;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
} else if (rel == null || rel.otherType == null || !rel.otherType.isRelational ()) {
|
} else if (rel == null || rel.otherType == null || !rel.otherType.isRelational ()) {
|
||||||
node = db.getNode (txn, kstr);
|
node = (Node)db.getNode (txn, kstr);
|
||||||
node.nmgr = safe;
|
node.nmgr = safe;
|
||||||
node.setDbMapping (rel.otherType);
|
node.setDbMapping (rel.otherType);
|
||||||
return node;
|
return node;
|
||||||
|
|
|
@ -202,14 +202,25 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
||||||
unregisterNode ();
|
unregisterNode ();
|
||||||
if (type == JAVAOBJECT)
|
if (type == JAVAOBJECT)
|
||||||
this.jvalue = null;
|
this.jvalue = null;
|
||||||
|
|
||||||
// registerNode (value);
|
// registerNode (value);
|
||||||
type = NODE;
|
type = NODE;
|
||||||
|
|
||||||
nhandle = value.getHandle ();
|
nhandle = value.getHandle ();
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setNodeHandle (NodeHandle value) {
|
||||||
|
if (type == NODE)
|
||||||
|
unregisterNode ();
|
||||||
|
if (type == JAVAOBJECT)
|
||||||
|
this.jvalue = null;
|
||||||
|
// registerNode (value);
|
||||||
|
type = NODE;
|
||||||
|
nhandle = value;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
public void setJavaObjectValue (Object value) {
|
public void setJavaObjectValue (Object value) {
|
||||||
if (type == NODE)
|
if (type == NODE)
|
||||||
unregisterNode ();
|
unregisterNode ();
|
||||||
|
|
|
@ -89,213 +89,12 @@ public class Relation {
|
||||||
otherType = null;
|
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
|
// parse methods for new file format
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void update_v0 (String desc, Properties props) {
|
public void update (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 ();
|
Application app = ownType.getApplication ();
|
||||||
if (desc == null || "".equals (desc.trim ())) {
|
if (desc == null || "".equals (desc.trim ())) {
|
||||||
if (propName != null) {
|
if (propName != null) {
|
||||||
|
@ -344,7 +143,7 @@ public class Relation {
|
||||||
if (reftype != PRIMITIVE && reftype != INVALID) {
|
if (reftype != PRIMITIVE && reftype != INVALID) {
|
||||||
|
|
||||||
Vector newConstraints = new Vector ();
|
Vector newConstraints = new Vector ();
|
||||||
parseOptions_v1 (newConstraints, props);
|
parseOptions (newConstraints, props);
|
||||||
|
|
||||||
constraints = new Constraint[newConstraints.size()];
|
constraints = new Constraint[newConstraints.size()];
|
||||||
newConstraints.copyInto (constraints);
|
newConstraints.copyInto (constraints);
|
||||||
|
@ -352,7 +151,7 @@ public class Relation {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void parseOptions_v1 (Vector cnst, Properties props) {
|
protected void parseOptions (Vector cnst, Properties props) {
|
||||||
String loading = props.getProperty (propName+".loadmode");
|
String loading = props.getProperty (propName+".loadmode");
|
||||||
aggressiveLoading = loading != null && "aggressive".equalsIgnoreCase (loading.trim());
|
aggressiveLoading = loading != null && "aggressive".equalsIgnoreCase (loading.trim());
|
||||||
String caching = props.getProperty (propName+".cachemode");
|
String caching = props.getProperty (propName+".cachemode");
|
||||||
|
|
|
@ -9,7 +9,6 @@ import java.sql.*;
|
||||||
import helma.objectmodel.*;
|
import helma.objectmodel.*;
|
||||||
import helma.util.Timer;
|
import helma.util.Timer;
|
||||||
import helma.framework.TimeoutException;
|
import helma.framework.TimeoutException;
|
||||||
import com.sleepycat.db.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subclass of thread that keeps track of changed nodes and triggers
|
* A subclass of thread that keeps track of changed nodes and triggers
|
||||||
|
@ -30,7 +29,7 @@ public class Transactor extends Thread {
|
||||||
private volatile boolean killed;
|
private volatile boolean killed;
|
||||||
|
|
||||||
// Transaction for the embedded database
|
// Transaction for the embedded database
|
||||||
protected DbTxn txn;
|
protected ITransaction txn;
|
||||||
// Transactions for SQL data sources
|
// Transactions for SQL data sources
|
||||||
protected HashMap sqlCon;
|
protected HashMap sqlCon;
|
||||||
|
|
||||||
|
@ -108,7 +107,7 @@ public class Transactor extends Thread {
|
||||||
public synchronized void begin (String tnm) throws Exception {
|
public synchronized void begin (String tnm) throws Exception {
|
||||||
|
|
||||||
if (killed)
|
if (killed)
|
||||||
throw new DbException ("Transaction started on killed thread");
|
throw new DatabaseException ("Transaction started on killed thread");
|
||||||
|
|
||||||
if (active)
|
if (active)
|
||||||
abort ();
|
abort ();
|
||||||
|
@ -171,7 +170,7 @@ public class Transactor extends Thread {
|
||||||
cleannodes.clear ();
|
cleannodes.clear ();
|
||||||
|
|
||||||
if (nmgr.idgen.dirty) {
|
if (nmgr.idgen.dirty) {
|
||||||
nmgr.db.save (txn, "idgen", nmgr.idgen);
|
nmgr.db.saveIDGenerator (txn, nmgr.idgen);
|
||||||
nmgr.idgen.dirty = false;
|
nmgr.idgen.dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
95
src/helma/objectmodel/db/XmlDatabase.java
Normal file
95
src/helma/objectmodel/db/XmlDatabase.java
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package helma.objectmodel.db;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Date;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
import helma.objectmodel.*;
|
||||||
|
import helma.objectmodel.dom.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple XML-database
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class XmlDatabase implements IDatabase {
|
||||||
|
|
||||||
|
private String dbHome;
|
||||||
|
private File dbBaseDir;
|
||||||
|
private NodeManager nmgr;
|
||||||
|
private IDGenerator idgen;
|
||||||
|
// character encoding to use when writing files.
|
||||||
|
// use standard encoding by default.
|
||||||
|
private String encoding = null;
|
||||||
|
|
||||||
|
public XmlDatabase (String dbHome, String dbFilename, NodeManager nmgr) throws DatabaseException {
|
||||||
|
this.dbHome = dbHome;
|
||||||
|
this.nmgr = nmgr;
|
||||||
|
dbBaseDir = new File (dbHome);
|
||||||
|
if (!dbBaseDir.exists() && !dbBaseDir.mkdirs() )
|
||||||
|
throw new RuntimeException("Couldn't create DB-directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown () { }
|
||||||
|
public ITransaction beginTransaction () throws DatabaseException { return null; }
|
||||||
|
public void commitTransaction (ITransaction txn) throws DatabaseException { }
|
||||||
|
public void abortTransaction (ITransaction txn) throws DatabaseException { }
|
||||||
|
|
||||||
|
public String nextID() throws ObjectNotFoundException {
|
||||||
|
if (idgen==null) {
|
||||||
|
getIDGenerator(null);
|
||||||
|
}
|
||||||
|
return idgen.newID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDGenerator getIDGenerator (ITransaction txn) throws ObjectNotFoundException {
|
||||||
|
File file = new File (dbBaseDir, "idgen.xml");
|
||||||
|
this.idgen = IDGenParser.getIDGenerator(file);
|
||||||
|
return idgen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveIDGenerator (ITransaction txn, IDGenerator idgen) throws Exception {
|
||||||
|
File file = new File (dbBaseDir, "idgen.xml");
|
||||||
|
IDGenParser.saveIDGenerator(idgen,file);
|
||||||
|
this.idgen = idgen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public INode getNode (ITransaction txn, String kstr) throws Exception {
|
||||||
|
File f = new File (dbBaseDir, kstr+".xml");
|
||||||
|
if ( ! f.exists() )
|
||||||
|
throw new ObjectNotFoundException ("Object not found for key "+kstr+".");
|
||||||
|
try {
|
||||||
|
XmlReader reader = new XmlReader (nmgr);
|
||||||
|
Node node = (Node)reader.read (f, null);
|
||||||
|
return node;
|
||||||
|
} catch ( RuntimeException x ) {
|
||||||
|
nmgr.app.logEvent("error reading node from XmlDatbase: " + x.toString() );
|
||||||
|
throw new ObjectNotFoundException(x.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveNode (ITransaction txn, String kstr, INode node) throws Exception {
|
||||||
|
XmlWriter writer = null;
|
||||||
|
File file = new File (dbBaseDir,kstr+".xml");
|
||||||
|
if (encoding != null)
|
||||||
|
writer = new XmlWriter (file, encoding);
|
||||||
|
else
|
||||||
|
writer = new XmlWriter (file);
|
||||||
|
writer.setMaxLevels(1);
|
||||||
|
boolean result = writer.write((Node)node);
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteNode (ITransaction txn, String kstr) throws Exception {
|
||||||
|
File f = new File (dbBaseDir, kstr+".xml");
|
||||||
|
f.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEncoding (String enc) {
|
||||||
|
this.encoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEncoding () {
|
||||||
|
return encoding;
|
||||||
|
}
|
||||||
|
}
|
37
src/helma/objectmodel/dom/IDGenParser.java
Normal file
37
src/helma/objectmodel/dom/IDGenParser.java
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package helma.objectmodel.dom;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Date;
|
||||||
|
import org.w3c.dom.*;
|
||||||
|
|
||||||
|
import helma.objectmodel.ObjectNotFoundException;
|
||||||
|
import helma.objectmodel.db.IDGenerator;
|
||||||
|
|
||||||
|
public class IDGenParser {
|
||||||
|
|
||||||
|
public static IDGenerator getIDGenerator (File file) throws ObjectNotFoundException {
|
||||||
|
if ( ! file.exists() )
|
||||||
|
throw new ObjectNotFoundException ("IDGenerator not found in idgen.xml");
|
||||||
|
try {
|
||||||
|
Document document = XmlUtil.parse(new FileInputStream (file));
|
||||||
|
org.w3c.dom.Element tmp = (Element)document.getDocumentElement().getElementsByTagName("counter").item(0);
|
||||||
|
return new IDGenerator( Long.parseLong (XmlUtil.getTextContent(tmp)) );
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ObjectNotFoundException(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IDGenerator saveIDGenerator (IDGenerator idgen, File file) throws Exception {
|
||||||
|
OutputStreamWriter out = new OutputStreamWriter (new FileOutputStream (file));
|
||||||
|
out.write ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||||
|
out.write ("<!-- printed by helma object publisher -->\n");
|
||||||
|
out.write ("<!-- created " + (new Date()).toString() + " -->\n" );
|
||||||
|
out.write ("<xmlroot>\n");
|
||||||
|
out.write (" <counter>" + idgen.getValue() + "</counter>\n");
|
||||||
|
out.write ("</xmlroot>\n");
|
||||||
|
out.close ();
|
||||||
|
return idgen;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package helma.objectmodel.dom;
|
||||||
|
|
||||||
public interface XmlConstants {
|
public interface XmlConstants {
|
||||||
|
|
||||||
public final String NAMESPACE = "http://www.helma.org/";
|
public final String NAMESPACE = "http://www.helma.org/docs/guide/features/database";
|
||||||
public final String DATEFORMAT = "dd.MM.yyyy HH:mm:ss z";
|
public final String DATEFORMAT = "dd.MM.yyyy HH:mm:ss z";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,8 @@ public class XmlConverter implements XmlConstants {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: handle CDATA!
|
||||||
|
|
||||||
// it's some kind of element (property or child)
|
// it's some kind of element (property or child)
|
||||||
if ( childNode.getNodeType()==org.w3c.dom.Node.ELEMENT_NODE ) {
|
if ( childNode.getNodeType()==org.w3c.dom.Node.ELEMENT_NODE ) {
|
||||||
|
|
||||||
|
|
|
@ -1,91 +1,95 @@
|
||||||
package helma.objectmodel.dom;
|
package helma.objectmodel.dom;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.File;
|
||||||
import java.net.*;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.*;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.xml.parsers.*;
|
|
||||||
import org.w3c.dom.*;
|
import org.w3c.dom.*;
|
||||||
|
|
||||||
import helma.objectmodel.*;
|
import helma.objectmodel.INode;
|
||||||
|
import helma.objectmodel.db.DbKey;
|
||||||
|
import helma.objectmodel.db.ExternalizableVector;
|
||||||
|
import helma.objectmodel.db.Node;
|
||||||
|
import helma.objectmodel.db.NodeHandle;
|
||||||
|
import helma.objectmodel.db.NodeManager;
|
||||||
|
import helma.objectmodel.db.Property;
|
||||||
|
|
||||||
public class XmlReader implements XmlConstants {
|
public class XmlReader implements XmlConstants {
|
||||||
|
|
||||||
private int offset = 0;
|
|
||||||
private HashMap convertedNodes;
|
private HashMap convertedNodes;
|
||||||
|
private NodeManager nmgr = null;
|
||||||
|
|
||||||
public XmlReader() {
|
public XmlReader () {
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlReader (NodeManager nmgr) {
|
||||||
|
this.nmgr = nmgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public INode read( String desc ) {
|
/**
|
||||||
return read(desc, new TransientNode() );
|
* main entry to read an xml-file.
|
||||||
}
|
*/
|
||||||
|
public INode read (File file, INode helmaNode) throws RuntimeException {
|
||||||
public INode read( String desc, INode helmaNode ) throws RuntimeException {
|
|
||||||
try {
|
try {
|
||||||
return read( new File(desc), helmaNode );
|
return read (new FileInputStream(file), helmaNode);
|
||||||
} catch ( FileNotFoundException notfound ) {
|
} catch (FileNotFoundException notfound) {
|
||||||
throw new RuntimeException( "couldn't find xml-file: " + desc );
|
System.err.println ("couldn't find xml-file: " + file.getAbsolutePath ());
|
||||||
} catch ( IOException ioerror ) {
|
|
||||||
throw new RuntimeException( "couldn't read xml: " + desc );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public INode read( File file, INode helmaNode ) throws RuntimeException, FileNotFoundException {
|
|
||||||
return read( new FileInputStream(file), helmaNode );
|
|
||||||
}
|
|
||||||
|
|
||||||
public INode read( InputStream in, INode helmaNode ) throws RuntimeException {
|
|
||||||
Document document = XmlUtil.parse(in);
|
|
||||||
if ( document!=null && document.getDocumentElement()!=null ) {
|
|
||||||
Node tmp = document.getDocumentElement().getFirstChild();
|
|
||||||
Element workelement = null;
|
|
||||||
while( tmp!=null ) {
|
|
||||||
tmp = tmp.getNextSibling();
|
|
||||||
if ( tmp.getNodeType()==Node.ELEMENT_NODE ) {
|
|
||||||
workelement = (Element) tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return startConversion( helmaNode, workelement );
|
|
||||||
} else {
|
|
||||||
return helmaNode;
|
return helmaNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INode startConversion( INode helmaNode, Element element ) {
|
/**
|
||||||
convertedNodes = new HashMap();
|
* read an InputStream with xml-content.
|
||||||
INode convertedNode = convert(helmaNode, element );
|
*/
|
||||||
convertedNodes = null;
|
public INode read (InputStream in, INode helmaNode) throws RuntimeException {
|
||||||
return convertedNode;
|
if (helmaNode==null && nmgr==null)
|
||||||
|
throw new RuntimeException ("can't create a new Node without a NodeManager");
|
||||||
|
Document document = XmlUtil.parse (in);
|
||||||
|
Element element = XmlUtil.getFirstElement(document);
|
||||||
|
if (element==null)
|
||||||
|
throw new RuntimeException ("corrupted xml-file");
|
||||||
|
|
||||||
|
if (helmaNode==null) {
|
||||||
|
return convert (element);
|
||||||
|
} else {
|
||||||
|
convertedNodes = new HashMap ();
|
||||||
|
INode convertedNode = convert (element, helmaNode);
|
||||||
|
convertedNodes = null;
|
||||||
|
return convertedNode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public INode convert( INode helmaNode, Element element ) {
|
/**
|
||||||
offset++;
|
* convert children of an Element to a given helmaNode
|
||||||
String idref = element.getAttributeNS(NAMESPACE, "idref");
|
*/
|
||||||
String key = idref + "-" + element.getAttributeNS(NAMESPACE, "prototyperef");
|
public INode convert (Element element, INode helmaNode) {
|
||||||
|
String idref = element.getAttribute("idref");
|
||||||
|
String key = idref + "-" + element.getAttribute("prototyperef");
|
||||||
if( idref!=null && !idref.equals("") ) {
|
if( idref!=null && !idref.equals("") ) {
|
||||||
if( convertedNodes.containsKey(key) ) {
|
if( convertedNodes.containsKey(key) ) {
|
||||||
offset--;
|
|
||||||
return (INode)convertedNodes.get(key);
|
return (INode)convertedNodes.get(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
key = element.getAttributeNS(NAMESPACE, "id") + "-" + element.getAttributeNS(NAMESPACE, "prototype");
|
key = element.getAttribute("id") + "-" + element.getAttribute("prototype");
|
||||||
convertedNodes.put( key, helmaNode );
|
convertedNodes.put( key, helmaNode );
|
||||||
|
String prototype = element.getAttribute("prototype");
|
||||||
// FIXME: import id on persistent nodes
|
|
||||||
String prototype = element.getAttributeNS(NAMESPACE, "prototype");
|
|
||||||
if( !prototype.equals("") && !prototype.equals("hopobject") ) {
|
if( !prototype.equals("") && !prototype.equals("hopobject") ) {
|
||||||
helmaNode.setPrototype( prototype );
|
helmaNode.setPrototype( prototype );
|
||||||
}
|
}
|
||||||
children(helmaNode, element);
|
children(helmaNode, element);
|
||||||
offset--;
|
|
||||||
return helmaNode;
|
return helmaNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// used by convert(Element,INode)
|
||||||
private INode children( INode helmaNode, Element element ) {
|
private INode children( INode helmaNode, Element element ) {
|
||||||
NodeList list = element.getChildNodes();
|
NodeList list = element.getChildNodes();
|
||||||
int len = list.getLength();
|
int len = list.getLength();
|
||||||
|
@ -94,16 +98,23 @@ public class XmlReader implements XmlConstants {
|
||||||
try {
|
try {
|
||||||
childElement = (Element)list.item(i);
|
childElement = (Element)list.item(i);
|
||||||
} catch( ClassCastException e ) {
|
} catch( ClassCastException e ) {
|
||||||
continue;
|
continue; // ignore CDATA, comments etc
|
||||||
}
|
}
|
||||||
INode workNode = null;
|
INode workNode = null;
|
||||||
|
|
||||||
if ( childElement.getTagName().equals("hop:child") ) {
|
if ( childElement.getTagName().equals("hop:child") ) {
|
||||||
convert( helmaNode.createNode(null), childElement );
|
|
||||||
} else if ( !"".equals(childElement.getAttributeNS(NAMESPACE,"id")) || !"".equals(childElement.getAttributeNS(NAMESPACE,"idref")) ) {
|
convert (childElement, helmaNode.createNode(null));
|
||||||
// we've got an object!
|
|
||||||
helmaNode.setNode( childElement.getTagName(), convert( helmaNode.createNode(childElement.getTagName()), childElement ) );
|
} else if ( !"".equals(childElement.getAttribute("id")) || !"".equals(childElement.getAttribute("idref")) ) {
|
||||||
|
|
||||||
|
String childTagName = childElement.getTagName();
|
||||||
|
INode newNode = convert (childElement, helmaNode.createNode (childTagName));
|
||||||
|
helmaNode.setNode (childTagName, newNode);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
String type = childElement.getAttribute("hop:type");
|
|
||||||
|
String type = childElement.getAttribute("type");
|
||||||
String key = childElement.getTagName();
|
String key = childElement.getTagName();
|
||||||
String content = XmlUtil.getTextContent(childElement);
|
String content = XmlUtil.getTextContent(childElement);
|
||||||
if ( type.equals("boolean") ) {
|
if ( type.equals("boolean") ) {
|
||||||
|
@ -132,26 +143,101 @@ public class XmlReader implements XmlConstants {
|
||||||
return helmaNode;
|
return helmaNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** for testing */
|
|
||||||
public static void main ( String args[] ) throws Exception {
|
/**
|
||||||
try {
|
* This is a basic de-serialization method for XML-2-Node conversion.
|
||||||
XmlReader x = new XmlReader ();
|
* It reads a Node from a database-like file and should return a Node
|
||||||
INode node = x.read("test.xml");
|
* that matches exactly the one dumped to that file before.
|
||||||
} catch ( Exception e ) {
|
* It only supports persistent-capable Nodes (from objectmodel.db-package).
|
||||||
System.out.println("exception " + e.toString() );
|
*/
|
||||||
throw new RuntimeException(e.toString());
|
public helma.objectmodel.db.Node convert (Element element) {
|
||||||
|
// FIXME: this method should use Element.getAttributeNS():
|
||||||
|
// FIXME: do we need the name value or is it retrieved through mappings anyway?
|
||||||
|
String name = element.getAttribute("name");
|
||||||
|
// String name = null;
|
||||||
|
String id = element.getAttribute("id");
|
||||||
|
String prototype = element.getAttribute("prototype");
|
||||||
|
if ( "".equals(prototype) )
|
||||||
|
prototype = "hopobject";
|
||||||
|
helma.objectmodel.db.Node helmaNode = null;
|
||||||
|
try {
|
||||||
|
long created = Long.parseLong (element.getAttribute ("created"));
|
||||||
|
long lastmodified = Long.parseLong (element.getAttribute ("lastModified"));
|
||||||
|
helmaNode = new helma.objectmodel.db.Node (name,id,prototype,nmgr.safe,created,lastmodified);
|
||||||
|
} catch ( NumberFormatException e ) {
|
||||||
|
helmaNode = new helma.objectmodel.db.Node (name,id,prototype,nmgr.safe);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// now loop through all child elements and retrieve properties/subnodes for this node.
|
||||||
|
NodeList list = element.getChildNodes();
|
||||||
|
int len = list.getLength();
|
||||||
|
Hashtable propMap = new Hashtable();
|
||||||
|
List subnodes = new ExternalizableVector();
|
||||||
|
for ( int i=0; i<len; i++ ) {
|
||||||
|
|
||||||
/** for testing */
|
Element childElement;
|
||||||
void debug(Object msg) {
|
try {
|
||||||
for ( int i=0; i<offset; i++ ) {
|
childElement = (Element)list.item(i);
|
||||||
System.out.print(" ");
|
} catch( ClassCastException e ) {
|
||||||
|
continue; // ignore CDATA, comments etc
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( childElement.getTagName().equals("hop:child") ) {
|
||||||
|
// add a new NodeHandle, presume all IDs in this objectcache are unique,
|
||||||
|
// a prerequisite for a simple internal database.
|
||||||
|
subnodes.add (new NodeHandle (new DbKey(null,childElement.getAttribute("idref") ) ) );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( childElement.getTagName().equals("hop:parent") ) {
|
||||||
|
// add a NodeHandle to parent object
|
||||||
|
helmaNode.setParentHandle (new NodeHandle (new DbKey(null,childElement.getAttribute("idref") ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we come until here, childelement is a property value
|
||||||
|
Property prop = new Property (childElement.getTagName(), helmaNode);
|
||||||
|
if ( !"".equals(childElement.getAttribute("id")) || !"".equals(childElement.getAttribute("idref")) ) {
|
||||||
|
// we've got an object!
|
||||||
|
String idref = childElement.getAttribute("idref");
|
||||||
|
prop.setNodeHandle (new NodeHandle(new DbKey(null,idref)));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
String type = childElement.getAttribute("type");
|
||||||
|
String content = XmlUtil.getTextContent(childElement);
|
||||||
|
if ( type.equals("boolean") ) {
|
||||||
|
if ( content.equals("true") ) {
|
||||||
|
prop.setBooleanValue(true);
|
||||||
|
} else {
|
||||||
|
prop.setBooleanValue(false);
|
||||||
|
}
|
||||||
|
} else if ( type.equals("date") ) {
|
||||||
|
SimpleDateFormat format = new SimpleDateFormat ( DATEFORMAT );
|
||||||
|
try {
|
||||||
|
Date date = format.parse(content);
|
||||||
|
prop.setDateValue (date);
|
||||||
|
} catch ( ParseException e ) {
|
||||||
|
prop.setStringValue (content);
|
||||||
|
}
|
||||||
|
} else if ( type.equals("float") ) {
|
||||||
|
prop.setFloatValue ((new Double(content)).doubleValue());
|
||||||
|
} else if ( type.equals("integer") ) {
|
||||||
|
prop.setIntegerValue ((new Long(content)).longValue());
|
||||||
|
} else {
|
||||||
|
prop.setStringValue (content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
propMap.put (childElement.getTagName(), prop);
|
||||||
}
|
}
|
||||||
System.out.println(msg.toString());
|
if ( propMap.size()>0 )
|
||||||
|
helmaNode.setPropMap (propMap);
|
||||||
|
else
|
||||||
|
helmaNode.setPropMap (null);
|
||||||
|
if ( subnodes.size()>0 )
|
||||||
|
helmaNode.setSubnodes (subnodes);
|
||||||
|
else
|
||||||
|
helmaNode.setSubnodes (null);
|
||||||
|
return helmaNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
@ -54,6 +55,24 @@ public class XmlUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get first "real" element (ie not the document-rootelement, but the next one
|
||||||
|
*/
|
||||||
|
public static Element getFirstElement (Document document) {
|
||||||
|
Element workelement = null;
|
||||||
|
if ( document.getDocumentElement()!=null ) {
|
||||||
|
org.w3c.dom.Node tmp = document.getDocumentElement().getFirstChild();
|
||||||
|
while( tmp!=null ) {
|
||||||
|
tmp = tmp.getNextSibling();
|
||||||
|
if ( tmp.getNodeType()==org.w3c.dom.Node.ELEMENT_NODE ) {
|
||||||
|
workelement = (Element) tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return workelement;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the text content of an element
|
* return the text content of an element
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,65 +1,97 @@
|
||||||
package helma.objectmodel.dom;
|
package helma.objectmodel.dom;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.File;
|
||||||
import java.net.*;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.Date;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
import helma.objectmodel.*;
|
import helma.objectmodel.*;
|
||||||
|
import helma.objectmodel.INode;
|
||||||
|
import helma.objectmodel.IProperty;
|
||||||
|
import helma.objectmodel.TransientNode;
|
||||||
|
import helma.objectmodel.db.Node;
|
||||||
|
import helma.objectmodel.db.DbMapping;
|
||||||
import helma.util.HtmlEncoder;
|
import helma.util.HtmlEncoder;
|
||||||
|
|
||||||
public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
|
|
||||||
private final static String LINESEPARATOR = System.getProperty("line.separator");
|
private final static String LINESEPARATOR = System.getProperty("line.separator");
|
||||||
|
|
||||||
private Vector convertedNodes;
|
private Vector convertedNodes;
|
||||||
private int maxLevels = 3;
|
private int maxLevels = 3;
|
||||||
|
|
||||||
private String indent = " ";
|
private String indent = " ";
|
||||||
private StringBuffer prefix = new StringBuffer();
|
private StringBuffer prefix = new StringBuffer();
|
||||||
|
|
||||||
private static int fileid;
|
private static int fileid;
|
||||||
|
private SimpleDateFormat format = new SimpleDateFormat ( DATEFORMAT );
|
||||||
|
|
||||||
|
private boolean dbmode = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create ids that can be used for temporary files.
|
* create ids that can be used for temporary files.
|
||||||
*/
|
*/
|
||||||
public static int generateID() {
|
public static int generateID() {
|
||||||
return fileid++;
|
return fileid++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* empty constructor, will use System.out as outputstream.
|
* empty constructor, will use System.out as outputstream.
|
||||||
*/
|
*/
|
||||||
public XmlWriter () {
|
public XmlWriter () {
|
||||||
super(System.out);
|
super(System.out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmlWriter (OutputStream out) {
|
public XmlWriter (OutputStream out) {
|
||||||
super(out);
|
super(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmlWriter (String desc) throws FileNotFoundException {
|
public XmlWriter (OutputStream out, String enc) throws UnsupportedEncodingException {
|
||||||
|
super(out, enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlWriter (String desc) throws FileNotFoundException {
|
||||||
super (new FileOutputStream (desc));
|
super (new FileOutputStream (desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmlWriter (File file) throws FileNotFoundException {
|
public XmlWriter (String desc, String enc) throws FileNotFoundException, UnsupportedEncodingException {
|
||||||
|
super (new FileOutputStream (desc), enc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlWriter (File file) throws FileNotFoundException {
|
||||||
super (new FileOutputStream (file));
|
super (new FileOutputStream (file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public XmlWriter (File file, String enc) throws FileNotFoundException, UnsupportedEncodingException {
|
||||||
|
super (new FileOutputStream (file), enc);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* by default writing only descends 50 levels into the node tree to prevent
|
* by default writing only descends 50 levels into the node tree to prevent
|
||||||
* infite loops. number can be changed here.
|
* infite loops. number can be changed here.
|
||||||
*/
|
*/
|
||||||
public void setMaxLevels (int levels) {
|
public void setMaxLevels (int levels) {
|
||||||
maxLevels = levels;
|
maxLevels = levels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDatabaseMode (boolean dbmode) {
|
||||||
|
this.dbmode = dbmode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the number of space chars
|
* set the number of space chars
|
||||||
*/
|
*/
|
||||||
public void setIndent (int ct) {
|
public void setIndent (int ct) {
|
||||||
StringBuffer tmp = new StringBuffer ();
|
StringBuffer tmp = new StringBuffer ();
|
||||||
for ( int i=0; i<ct; i++ ) {
|
for ( int i=0; i<ct; i++ ) {
|
||||||
tmp.append(" ");
|
tmp.append(" ");
|
||||||
}
|
}
|
||||||
indent = tmp.toString();
|
indent = tmp.toString();
|
||||||
|
@ -70,9 +102,10 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
* creates document header too and initializes
|
* creates document header too and initializes
|
||||||
* the cache of already converted nodes.
|
* the cache of already converted nodes.
|
||||||
*/
|
*/
|
||||||
public boolean write( INode node ) throws IOException {
|
public boolean write( INode node ) throws IOException {
|
||||||
convertedNodes = new Vector();
|
convertedNodes = new Vector();
|
||||||
writeln ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
String encoding = getEncoding();
|
||||||
|
writeln ("<?xml version=\"1.0\" encoding=\""+encoding+"\"?>");
|
||||||
writeln ("<!-- printed by helma object publisher -->");
|
writeln ("<!-- printed by helma object publisher -->");
|
||||||
writeln ("<!-- created " + (new Date()).toString() + " -->" );
|
writeln ("<!-- created " + (new Date()).toString() + " -->" );
|
||||||
write ("<xmlroot xmlns:hop=\"");
|
write ("<xmlroot xmlns:hop=\"");
|
||||||
|
@ -86,17 +119,26 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* write a hopobject and print all its properties and children.
|
* write a hopobject and print all its properties and children.
|
||||||
* if node has already been fully printed, just make a reference here.
|
* references are made here if a node already has been fully printed
|
||||||
|
* or if this is the last level that's going to be dumped
|
||||||
*/
|
*/
|
||||||
public void write (INode node, String name, int level) throws IOException {
|
public void write (INode node, String name, int level) throws IOException {
|
||||||
if ( ++level>maxLevels )
|
if (node==null)
|
||||||
return;
|
return;
|
||||||
prefix.append(indent);
|
prefix.append(indent);
|
||||||
if ( convertedNodes.contains(node) ) {
|
if ( ++level>maxLevels ) {
|
||||||
writeReferenceTag (node, name);
|
writeReferenceTag (node, name);
|
||||||
} else {
|
prefix = prefix.delete( prefix.length()-indent.length(), Integer.MAX_VALUE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( convertedNodes.contains(node) ) {
|
||||||
|
writeReferenceTag (node, name);
|
||||||
|
} else {
|
||||||
convertedNodes.addElement (node);
|
convertedNodes.addElement (node);
|
||||||
writeTagOpen (node,name);
|
writeTagOpen (node,name);
|
||||||
|
if ( node.getParent()!=null ) {
|
||||||
|
writeReferenceTag (node.getParent(),"hop:parent");
|
||||||
|
}
|
||||||
writeProperties (node,level);
|
writeProperties (node,level);
|
||||||
writeChildren (node,level);
|
writeChildren (node,level);
|
||||||
writeTagClose (node,name);
|
writeTagClose (node,name);
|
||||||
|
@ -104,61 +146,72 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
prefix = prefix.delete( prefix.length()-indent.length(), Integer.MAX_VALUE );
|
prefix = prefix.delete( prefix.length()-indent.length(), Integer.MAX_VALUE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* loop through properties and print them with their property-name
|
* loop through properties and print them with their property-name
|
||||||
* as elementname
|
* as elementname
|
||||||
*/
|
*/
|
||||||
private void writeProperties (INode node, int level) throws IOException {
|
private void writeProperties (INode node, int level) throws IOException {
|
||||||
Enumeration e = node.properties();
|
Enumeration e = null;
|
||||||
while ( e.hasMoreElements() ) {
|
if ( dbmode==true && node instanceof helma.objectmodel.db.Node ) {
|
||||||
|
// a newly constructed db.Node doesn't have a propMap,
|
||||||
|
// but returns an enumeration of all it's db-mapped properties
|
||||||
|
Hashtable props = ((Node)node).getPropMap();
|
||||||
|
if (props==null)
|
||||||
|
return;
|
||||||
|
e = props.keys();
|
||||||
|
} else {
|
||||||
|
e = node.properties();
|
||||||
|
}
|
||||||
|
while ( e.hasMoreElements() ) {
|
||||||
String key = (String)e.nextElement();
|
String key = (String)e.nextElement();
|
||||||
IProperty prop = node.get(key,false);
|
IProperty prop = node.get(key,false);
|
||||||
if ( prop!=null ) {
|
if ( prop!=null ) {
|
||||||
int type = prop.getType();
|
int type = prop.getType();
|
||||||
if( type==IProperty.NODE ) {
|
if( type==IProperty.NODE ) {
|
||||||
write (node.getNode(key,false), key, level);
|
write (node.getNode(key,false), key, level);
|
||||||
} else {
|
} else {
|
||||||
writeProperty (node.get(key,false));
|
writeProperty (node.get(key,false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeNullProperty (String key) throws IOException {
|
public void writeNullProperty (String key) throws IOException {
|
||||||
write (prefix.toString());
|
write (prefix.toString());
|
||||||
write (indent);
|
write (indent);
|
||||||
write ("<");
|
write ("<");
|
||||||
write (key);
|
write (key);
|
||||||
write (" hop:type=\"null\"/>");
|
write (" type=\"null\"/>");
|
||||||
write (LINESEPARATOR);
|
write (LINESEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* write a single property, set attribute type according to type,
|
* write a single property, set attribute type according to type,
|
||||||
* apply xml-encoding.
|
* apply xml-encoding.
|
||||||
*/
|
*/
|
||||||
public void writeProperty (IProperty property) throws IOException {
|
public void writeProperty (IProperty property) throws IOException {
|
||||||
write (prefix.toString());
|
write (prefix.toString());
|
||||||
write (indent);
|
write (indent);
|
||||||
write ("<");
|
write ("<");
|
||||||
write (property.getName());
|
write (property.getName());
|
||||||
switch (property.getType()) {
|
switch (property.getType()) {
|
||||||
case IProperty.BOOLEAN:
|
case IProperty.BOOLEAN:
|
||||||
write (" hop:type=\"boolean\"");
|
write (" type=\"boolean\"");
|
||||||
break;
|
break;
|
||||||
case IProperty.FLOAT:
|
case IProperty.FLOAT:
|
||||||
write (" hop:type=\"float\"");
|
write (" type=\"float\"");
|
||||||
break;
|
break;
|
||||||
case IProperty.INTEGER:
|
case IProperty.INTEGER:
|
||||||
write (" hop:type=\"integer\"");
|
write (" type=\"integer\"");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ( property.getType()==IProperty.DATE ) {
|
if ( property.getType()==IProperty.DATE ) {
|
||||||
write (" hop:type=\"date\"");
|
write (" type=\"date\"");
|
||||||
SimpleDateFormat format = new SimpleDateFormat ( DATEFORMAT );
|
|
||||||
write (">");
|
write (">");
|
||||||
write ( format.format (property.getDateValue()) );
|
write ( format.format (property.getDateValue()) );
|
||||||
} else {
|
} else {
|
||||||
write (">");
|
write (">");
|
||||||
write ( HtmlEncoder.encodeXml (property.getStringValue()) );
|
write ( HtmlEncoder.encodeXml (property.getStringValue()) );
|
||||||
}
|
}
|
||||||
|
@ -171,9 +224,15 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
/**
|
/**
|
||||||
* loop through the children-array and print them as <hop:child>
|
* loop through the children-array and print them as <hop:child>
|
||||||
*/
|
*/
|
||||||
private void writeChildren (INode node, int level) throws IOException {
|
private void writeChildren (INode node, int level) throws IOException {
|
||||||
|
if ( dbmode==true && node instanceof helma.objectmodel.db.Node ) {
|
||||||
|
Node dbNode = (Node)node;
|
||||||
|
DbMapping smap = dbNode.getDbMapping() == null ? null : dbNode.getDbMapping().getSubnodeMapping ();
|
||||||
|
if (smap != null && smap.isRelational ())
|
||||||
|
return;
|
||||||
|
}
|
||||||
Enumeration e = node.getSubnodes();
|
Enumeration e = node.getSubnodes();
|
||||||
while (e.hasMoreElements()) {
|
while (e.hasMoreElements()) {
|
||||||
INode nextNode = (INode)e.nextElement();
|
INode nextNode = (INode)e.nextElement();
|
||||||
write (nextNode, "hop:child", level);
|
write (nextNode, "hop:child", level);
|
||||||
}
|
}
|
||||||
|
@ -183,16 +242,22 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
* write an opening tag for a node. Include id and prototype, use a
|
* write an opening tag for a node. Include id and prototype, use a
|
||||||
* name if parameter is non-empty.
|
* name if parameter is non-empty.
|
||||||
*/
|
*/
|
||||||
public void writeTagOpen (INode node, String name) throws IOException {
|
public void writeTagOpen (INode node, String name) throws IOException {
|
||||||
write (prefix.toString());
|
write (prefix.toString());
|
||||||
write ("<");
|
write ("<");
|
||||||
write ( (name==null)?"hopobject" : name);
|
write ( (name==null)?"hopobject" : name);
|
||||||
write (" hop:id=\"");
|
write (" id=\"");
|
||||||
write (getNodeIdentifier(node));
|
write (getNodeIdentifier(node));
|
||||||
write ("\" hop:prototype=\"");
|
write ("\" name=\"");
|
||||||
|
write (node.getName());
|
||||||
|
write ("\" prototype=\"");
|
||||||
write (getNodePrototype(node));
|
write (getNodePrototype(node));
|
||||||
write ("\"");
|
write ("\" created=\"");
|
||||||
write (">");
|
write (Long.toString(node.created()));
|
||||||
|
write ("\" lastModified=\"");
|
||||||
|
write (Long.toString(node.lastModified()));
|
||||||
|
//FIXME: do we need anonymous-property?
|
||||||
|
write ("\">");
|
||||||
write (LINESEPARATOR);
|
write (LINESEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +265,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
* write a closing tag for a node
|
* write a closing tag for a node
|
||||||
* e.g. </root>
|
* e.g. </root>
|
||||||
*/
|
*/
|
||||||
public void writeTagClose (INode node, String name) throws IOException {
|
public void writeTagClose (INode node, String name) throws IOException {
|
||||||
write (prefix.toString());
|
write (prefix.toString());
|
||||||
write ("</");
|
write ("</");
|
||||||
write ( (name==null)?"hopobject" : name);
|
write ( (name==null)?"hopobject" : name);
|
||||||
|
@ -210,16 +275,16 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* write a tag holding a reference to an element that has
|
* write a tag holding a reference to an element that has
|
||||||
* been dumped before.
|
* been written out before.
|
||||||
* e.g. <parent hop:idref="t35" hop:prototyperef="hopobject"/>
|
* e.g. <parent idref="35" prototyperef="hopobject"/>
|
||||||
*/
|
*/
|
||||||
public void writeReferenceTag (INode node, String name) throws IOException {
|
public void writeReferenceTag (INode node, String name) throws IOException {
|
||||||
write (prefix.toString());
|
write (prefix.toString());
|
||||||
write ("<");
|
write ("<");
|
||||||
write ( (name==null)?"hopobject" : name);
|
write ( (name==null)?"hopobject" : name);
|
||||||
write ( " hop:idref=\"");
|
write ( " idref=\"");
|
||||||
write (getNodeIdentifier(node));
|
write (getNodeIdentifier(node));
|
||||||
write ("\" hop:prototyperef=\"");
|
write ("\" prototyperef=\"");
|
||||||
write (getNodePrototype(node));
|
write (getNodePrototype(node));
|
||||||
write ("\"");
|
write ("\"");
|
||||||
write ("/>");
|
write ("/>");
|
||||||
|
@ -229,10 +294,10 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
/**
|
/**
|
||||||
* retrieve prototype-string of a node, defaults to "hopobject"
|
* retrieve prototype-string of a node, defaults to "hopobject"
|
||||||
*/
|
*/
|
||||||
private String getNodePrototype( INode node ) {
|
private String getNodePrototype( INode node ) {
|
||||||
if ( node.getPrototype()==null || "".equals(node.getPrototype()) ) {
|
if ( node.getPrototype()==null || "".equals(node.getPrototype()) ) {
|
||||||
return "hopobject";
|
return "hopobject";
|
||||||
} else {
|
} else {
|
||||||
return node.getPrototype();
|
return node.getPrototype();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,12 +305,12 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
/**
|
/**
|
||||||
* TransientNode produces a different ID each time we call the getID()-method
|
* 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.
|
* this is a workaround and uses hashCode if INode stands for a TransientNode.
|
||||||
*/
|
*/
|
||||||
private String getNodeIdentifier( INode node ) {
|
private String getNodeIdentifier( INode node ) {
|
||||||
try {
|
try {
|
||||||
TransientNode tmp = (TransientNode)node;
|
TransientNode tmp = (TransientNode)node;
|
||||||
return Integer.toString( tmp.hashCode() );
|
return Integer.toString( tmp.hashCode() );
|
||||||
} catch ( ClassCastException e ) {
|
} catch ( ClassCastException e ) {
|
||||||
return node.getID();
|
return node.getID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,7 +318,7 @@ public class XmlWriter extends OutputStreamWriter implements XmlConstants {
|
||||||
public void writeln(String str) throws IOException {
|
public void writeln(String str) throws IOException {
|
||||||
write (str);
|
write (str);
|
||||||
write (LINESEPARATOR);
|
write (LINESEPARATOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,149 +0,0 @@
|
||||||
// ESAppNode.java
|
|
||||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
|
||||||
|
|
||||||
package helma.scripting.fesi;
|
|
||||||
|
|
||||||
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
|
|
||||||
* space as well as access to some app related runtime information.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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();
|
|
||||||
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("setMaxThreads", new AppSetNumberOfEvaluators ("setMaxThreads", evaluator, fp));
|
|
||||||
putHiddenProperty("clearCache", new AppClearCache ("clearCache", evaluator, fp));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides getProperty to return some app-specific properties
|
|
||||||
*/
|
|
||||||
public ESValue getProperty (String propname, int hash) throws EcmaScriptException {
|
|
||||||
if ("requestCount".equals (propname)) {
|
|
||||||
return new ESNumber (app.getRequestCount ());
|
|
||||||
}
|
|
||||||
if ("xmlrpcCount".equals (propname)) {
|
|
||||||
return new ESNumber (app.getXmlrpcCount ());
|
|
||||||
}
|
|
||||||
if ("errorCount".equals (propname)) {
|
|
||||||
return new ESNumber (app.getErrorCount ());
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
return super.getProperty (propname, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class AppCountEvaluators extends BuiltinFunctionObject {
|
|
||||||
AppCountEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 0);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
return new ESNumber (app.countEvaluators ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppCountFreeEvaluators extends BuiltinFunctionObject {
|
|
||||||
AppCountFreeEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 0);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
return new ESNumber (app.countFreeEvaluators ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppCountActiveEvaluators extends BuiltinFunctionObject {
|
|
||||||
AppCountActiveEvaluators (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 ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppCountMaxActiveEvaluators extends BuiltinFunctionObject {
|
|
||||||
AppCountMaxActiveEvaluators (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 ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppCountThreads extends BuiltinFunctionObject {
|
|
||||||
AppCountThreads (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 0);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
return new ESNumber (app.countThreads ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppSetNumberOfEvaluators extends BuiltinFunctionObject {
|
|
||||||
AppSetNumberOfEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
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 ());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
59
src/helma/scripting/fesi/ESBeanWrapper.java
Normal file
59
src/helma/scripting/fesi/ESBeanWrapper.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package helma.scripting.fesi;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import helma.objectmodel.INode;
|
||||||
|
|
||||||
|
import FESI.Interpreter.Evaluator;
|
||||||
|
import FESI.Exceptions.EcmaScriptException;
|
||||||
|
import FESI.Data.ESNull;
|
||||||
|
import FESI.Data.ESValue;
|
||||||
|
import FESI.Data.ESWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap a Java Bean for use in EcmaScript.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ESBeanWrapper extends ESWrapper {
|
||||||
|
|
||||||
|
FesiEvaluator eval;
|
||||||
|
|
||||||
|
public ESBeanWrapper (Object object, FesiEvaluator eval) {
|
||||||
|
super (object, eval.getEvaluator(),true);
|
||||||
|
this.eval = eval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap getProperty, return ESNode if INode would be returned.
|
||||||
|
*/
|
||||||
|
public ESValue getProperty(String propertyName, int hash)
|
||||||
|
throws EcmaScriptException {
|
||||||
|
try {
|
||||||
|
ESValue val = super.getProperty (propertyName, hash);
|
||||||
|
if (val instanceof ESWrapper && ((ESWrapper)val).getJavaObject() instanceof INode) {
|
||||||
|
return eval.getNodeWrapper( (INode) ((ESWrapper)val).getJavaObject() );
|
||||||
|
} else if (val instanceof ESWrapper && ((ESWrapper)val).getJavaObject() instanceof Map) {
|
||||||
|
return new ESMapWrapper(eval, (Map) ((ESWrapper)val).getJavaObject() );
|
||||||
|
} else {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
} catch (Exception rte) {
|
||||||
|
return ESNull.theNull;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putProperty(String propertyName, ESValue propertyValue, int hash)
|
||||||
|
throws EcmaScriptException {
|
||||||
|
try {
|
||||||
|
super.putProperty (propertyName, propertyValue, hash);
|
||||||
|
} catch (Exception rte) {
|
||||||
|
// create a nice error message
|
||||||
|
throw new EcmaScriptException("can't set property " + propertyName +
|
||||||
|
" to this value on " + getJavaObject().toString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,8 @@ public class ESMapWrapper extends ESWrapper {
|
||||||
return new ESString ((String) val);
|
return new ESString ((String) val);
|
||||||
else if (val instanceof INode)
|
else if (val instanceof INode)
|
||||||
return fesi.getNodeWrapper ((INode) val);
|
return fesi.getNodeWrapper ((INode) val);
|
||||||
|
else if (val instanceof Map)
|
||||||
|
return new ESMapWrapper (fesi, (Map)val);
|
||||||
else if (val instanceof ESValue)
|
else if (val instanceof ESValue)
|
||||||
return (ESValue) val;
|
return (ESValue) val;
|
||||||
return ESLoader.normalizeValue(val, evaluator);
|
return ESLoader.normalizeValue(val, evaluator);
|
||||||
|
|
|
@ -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. <p>
|
|
||||||
* 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 ());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class FesiActionAdapter {
|
||||||
Application app;
|
Application app;
|
||||||
String sourceName;
|
String sourceName;
|
||||||
// this is the parsed function which can be easily applied to RequestEvaluator objects
|
// this is the parsed function which can be easily applied to RequestEvaluator objects
|
||||||
TypeUpdater pfunc;
|
TypeUpdater pfunc, pfuncAsString;
|
||||||
|
|
||||||
public FesiActionAdapter (ActionFile action) {
|
public FesiActionAdapter (ActionFile action) {
|
||||||
prototype = action.getPrototype ();
|
prototype = action.getPrototype ();
|
||||||
|
@ -40,45 +40,34 @@ public class FesiActionAdapter {
|
||||||
String functionName = action.getFunctionName ();
|
String functionName = action.getFunctionName ();
|
||||||
sourceName = action.toString ();
|
sourceName = action.toString ();
|
||||||
try {
|
try {
|
||||||
pfunc = parseFunction (functionName, "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", content);
|
pfunc = parseFunction (functionName,
|
||||||
|
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
||||||
|
content);
|
||||||
} catch (Throwable x) {
|
} catch (Throwable x) {
|
||||||
String message = x.getMessage ();
|
String message = x.getMessage ();
|
||||||
pfunc = new ErrorFeedback (functionName, message);
|
pfunc = new ErrorFeedback (functionName, message);
|
||||||
}
|
}
|
||||||
|
// check if this is a template and we need to generate an "_as_string" variant
|
||||||
|
if (action instanceof Template) {
|
||||||
|
try {
|
||||||
|
pfuncAsString = parseFunction (functionName+"_as_string",
|
||||||
|
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
||||||
|
"res.pushStringBuffer(); "+content+"\r\nreturn res.popStringBuffer();\r\n");
|
||||||
|
} catch (Throwable x) {
|
||||||
|
String message = x.getMessage ();
|
||||||
|
pfunc = new ErrorFeedback (functionName+"_as_string", message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pfuncAsString = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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) {}
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* 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());
|
|
||||||
}
|
|
||||||
} catch (Exception ignore) {}
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
|
|
||||||
public synchronized void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
|
public synchronized void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
|
||||||
if (pfunc != null)
|
if (pfunc != null)
|
||||||
pfunc.updateEvaluator (fesi);
|
pfunc.updateEvaluator (fesi);
|
||||||
|
if (pfuncAsString != null)
|
||||||
|
pfuncAsString.updateEvaluator (fesi);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TypeUpdater parseFunction (String funcname, String params, String body) throws EcmaScriptException {
|
protected TypeUpdater parseFunction (String funcname, String params, String body) throws EcmaScriptException {
|
||||||
|
|
|
@ -22,14 +22,14 @@ import Acme.LruHashtable;
|
||||||
* This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter.
|
* This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class FesiEvaluator {
|
public final class FesiEvaluator {
|
||||||
|
|
||||||
// the application we're running in
|
// the application we're running in
|
||||||
public Application app;
|
public Application app;
|
||||||
|
|
||||||
// The FESI evaluator
|
// The FESI evaluator
|
||||||
Evaluator evaluator;
|
Evaluator evaluator;
|
||||||
|
|
||||||
// the global object
|
// the global object
|
||||||
GlobalObject global;
|
GlobalObject global;
|
||||||
|
|
||||||
|
@ -50,8 +50,13 @@ public class FesiEvaluator {
|
||||||
"helma.scripting.fesi.extensions.ImageExtension",
|
"helma.scripting.fesi.extensions.ImageExtension",
|
||||||
"helma.scripting.fesi.extensions.FtpExtension",
|
"helma.scripting.fesi.extensions.FtpExtension",
|
||||||
"FESI.Extensions.JavaAccess",
|
"FESI.Extensions.JavaAccess",
|
||||||
|
"helma.scripting.fesi.extensions.DomExtension",
|
||||||
"FESI.Extensions.OptionalRegExp"};
|
"FESI.Extensions.OptionalRegExp"};
|
||||||
|
|
||||||
|
// remember global variables from last invokation to be able to
|
||||||
|
// do lazy cleanup
|
||||||
|
Map lastGlobals = null;
|
||||||
|
|
||||||
public FesiEvaluator (Application app, RequestEvaluator reval) {
|
public FesiEvaluator (Application app, RequestEvaluator reval) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.reval = reval;
|
this.reval = reval;
|
||||||
|
@ -73,7 +78,7 @@ public class FesiEvaluator {
|
||||||
// fake a cache member like the one found in ESNodes
|
// fake a cache member like the one found in ESNodes
|
||||||
global.putHiddenProperty ("cache", new ESNode (new TransientNode ("cache"), this));
|
global.putHiddenProperty ("cache", new ESNode (new TransientNode ("cache"), this));
|
||||||
global.putHiddenProperty ("undefined", ESUndefined.theUndefined);
|
global.putHiddenProperty ("undefined", ESUndefined.theUndefined);
|
||||||
ESAppNode appnode = new ESAppNode (app.getAppNode (), this);
|
ESBeanWrapper appnode = new ESBeanWrapper (new ApplicationBean (app), this);
|
||||||
global.putHiddenProperty ("app", appnode);
|
global.putHiddenProperty ("app", appnode);
|
||||||
initialize();
|
initialize();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -145,12 +150,13 @@ public class FesiEvaluator {
|
||||||
else
|
else
|
||||||
evaluateString (prototype, ff.getContent ());
|
evaluateString (prototype, ff.getContent ());
|
||||||
}
|
}
|
||||||
/* for (Iterator it = prototype.templates.values().iterator(); it.hasNext(); ) {
|
for (Iterator it = prototype.templates.values().iterator(); it.hasNext(); ) {
|
||||||
Template tmp = (Template) it.next ();
|
Template tmp = (Template) it.next ();
|
||||||
try {
|
try {
|
||||||
tmp.updateRequestEvaluator (reval);
|
FesiActionAdapter adp = new FesiActionAdapter (tmp);
|
||||||
|
adp.updateEvaluator (this);
|
||||||
} catch (EcmaScriptException ignore) {}
|
} catch (EcmaScriptException ignore) {}
|
||||||
} */
|
}
|
||||||
for (Iterator it = prototype.actions.values().iterator(); it.hasNext(); ) {
|
for (Iterator it = prototype.actions.values().iterator(); it.hasNext(); ) {
|
||||||
ActionFile act = (ActionFile) it.next ();
|
ActionFile act = (ActionFile) it.next ();
|
||||||
try {
|
try {
|
||||||
|
@ -204,7 +210,7 @@ public class FesiEvaluator {
|
||||||
esv[i] = ESLoader.normalizeValue (args[i], evaluator);
|
esv[i] = ESLoader.normalizeValue (args[i], evaluator);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globals != null) {
|
if (globals != null && globals != lastGlobals) {
|
||||||
// remember all global variables before invocation
|
// remember all global variables before invocation
|
||||||
Set tmpGlobal = new HashSet ();
|
Set tmpGlobal = new HashSet ();
|
||||||
for (Enumeration en = global.getAllProperties(); en.hasMoreElements(); ) {
|
for (Enumeration en = global.getAllProperties(); en.hasMoreElements(); ) {
|
||||||
|
@ -221,13 +227,10 @@ public class FesiEvaluator {
|
||||||
// comfortable to EcmaScript coders, i.e. we use a lot of custom wrappers
|
// comfortable to EcmaScript coders, i.e. we use a lot of custom wrappers
|
||||||
// that expose properties and functions in a special way instead of just going
|
// that expose properties and functions in a special way instead of just going
|
||||||
// with the standard java object wrappers.
|
// with the standard java object wrappers.
|
||||||
if (v instanceof RequestTrans)
|
|
||||||
((RequestTrans) v).data = new ESMapWrapper (this, ((RequestTrans) v).getRequestData ());
|
if (v instanceof Map) {
|
||||||
else if (v instanceof ResponseTrans)
|
|
||||||
((ResponseTrans) v).data = new ESMapWrapper (this, ((ResponseTrans) v).getResponseData ());
|
|
||||||
if (v instanceof Map)
|
|
||||||
sv = new ESMapWrapper (this, (Map) v);
|
sv = new ESMapWrapper (this, (Map) v);
|
||||||
else if ("path".equals (k)) {
|
} else if ("path".equals (k)) {
|
||||||
ArrayPrototype parr = new ArrayPrototype (evaluator.getArrayPrototype(), evaluator);
|
ArrayPrototype parr = new ArrayPrototype (evaluator.getArrayPrototype(), evaluator);
|
||||||
List path = (List) v;
|
List path = (List) v;
|
||||||
// register path elements with their prototype
|
// register path elements with their prototype
|
||||||
|
@ -240,15 +243,21 @@ public class FesiEvaluator {
|
||||||
parr.putHiddenProperty (protoname, wrappedElement);
|
parr.putHiddenProperty (protoname, wrappedElement);
|
||||||
}
|
}
|
||||||
sv = parr;
|
sv = parr;
|
||||||
} else if ("user".equals (k)) {
|
} else if ("req".equals (k)) {
|
||||||
sv = getNodeWrapper ((User) v);
|
sv = new ESBeanWrapper (new RequestBean ((RequestTrans) v), this);
|
||||||
|
} else if ("res".equals (k)) {
|
||||||
|
sv = new ESBeanWrapper (new ResponseBean ((ResponseTrans) v), this);
|
||||||
|
} else if ("session".equals (k)) {
|
||||||
|
sv = new ESBeanWrapper (new SessionBean ((Session)v), this);
|
||||||
} else if ("app".equals (k)) {
|
} else if ("app".equals (k)) {
|
||||||
sv = new ESAppNode ((INode) v, this);
|
sv = new ESBeanWrapper (new ApplicationBean ((Application)v), this);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
sv = ESLoader.normalizeValue (v, evaluator);
|
sv = ESLoader.normalizeValue (v, evaluator);
|
||||||
|
}
|
||||||
global.putHiddenProperty (k, sv);
|
global.putHiddenProperty (k, sv);
|
||||||
}
|
}
|
||||||
|
// remember the globals set on this evaluator
|
||||||
|
// lastGlobals = globals;
|
||||||
}
|
}
|
||||||
evaluator.thread = Thread.currentThread ();
|
evaluator.thread = Thread.currentThread ();
|
||||||
ESValue retval = eso.doIndirectCall (evaluator, eso, functionName, esv);
|
ESValue retval = eso.doIndirectCall (evaluator, eso, functionName, esv);
|
||||||
|
@ -262,8 +271,10 @@ public class FesiEvaluator {
|
||||||
String msg = x.getMessage ();
|
String msg = x.getMessage ();
|
||||||
if (msg == null || msg.length() < 10)
|
if (msg == null || msg.length() < 10)
|
||||||
msg = x.toString ();
|
msg = x.toString ();
|
||||||
System.err.println ("INVOKE-ERROR: "+msg);
|
if (app.debug ()) {
|
||||||
x.printStackTrace ();
|
System.err.println ("Error in Script: "+msg);
|
||||||
|
x.printStackTrace ();
|
||||||
|
}
|
||||||
throw new ScriptingException (msg);
|
throw new ScriptingException (msg);
|
||||||
} finally {
|
} finally {
|
||||||
// remove global variables that have been added during invocation.
|
// remove global variables that have been added during invocation.
|
||||||
|
@ -274,8 +285,10 @@ public class FesiEvaluator {
|
||||||
if (globalVariables != null) {
|
if (globalVariables != null) {
|
||||||
for (Enumeration en = global.getAllProperties(); en.hasMoreElements(); ) {
|
for (Enumeration en = global.getAllProperties(); en.hasMoreElements(); ) {
|
||||||
String g = en.nextElement ().toString ();
|
String g = en.nextElement ().toString ();
|
||||||
if (!globalVariables.contains (g)) try {
|
try {
|
||||||
global.deleteProperty (g, g.hashCode());
|
if (!globalVariables.contains (g) &&
|
||||||
|
!(global.getProperty (g, g.hashCode()) instanceof BuiltinFunctionObject))
|
||||||
|
global.deleteProperty (g, g.hashCode());
|
||||||
} catch (Exception x) {
|
} catch (Exception x) {
|
||||||
System.err.println ("Error resetting global property: "+g);
|
System.err.println ("Error resetting global property: "+g);
|
||||||
}
|
}
|
||||||
|
@ -420,7 +433,7 @@ public class FesiEvaluator {
|
||||||
* Get a script wrapper for an implemntation of helma.objectmodel.INode
|
* Get a script wrapper for an implemntation of helma.objectmodel.INode
|
||||||
*/
|
*/
|
||||||
public ESNode getNodeWrapper (INode n) {
|
public ESNode getNodeWrapper (INode n) {
|
||||||
|
// FIXME: should this return ESNull.theNull?
|
||||||
if (n == null)
|
if (n == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -443,12 +456,7 @@ public class FesiEvaluator {
|
||||||
if (op == null)
|
if (op == null)
|
||||||
op = getPrototype("hopobject");
|
op = getPrototype("hopobject");
|
||||||
|
|
||||||
|
esn = new ESNode (op, evaluator, n, this);
|
||||||
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);
|
wrappercache.put (n, esn);
|
||||||
// app.logEvent ("Wrapper for "+n+" created");
|
// app.logEvent ("Wrapper for "+n+" created");
|
||||||
|
@ -466,28 +474,6 @@ public class FesiEvaluator {
|
||||||
wrappercache.put (n, 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.
|
* Return the RequestEvaluator owning and driving this FESI evaluator.
|
||||||
*/
|
*/
|
||||||
|
@ -527,39 +513,13 @@ public class FesiEvaluator {
|
||||||
|
|
||||||
public synchronized void updateEvaluator (Prototype prototype, Reader reader, EvaluationSource source) {
|
public synchronized void updateEvaluator (Prototype prototype, Reader reader, EvaluationSource source) {
|
||||||
|
|
||||||
// HashMap priorProps = null;
|
|
||||||
// HashSet newProps = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
ObjectPrototype op = getPrototype (prototype.getName());
|
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
|
// do the update, evaluating the file
|
||||||
evaluator.evaluate(reader, op, source, false);
|
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) {
|
} catch (Throwable e) {
|
||||||
app.logEvent ("Error parsing function file "+source+": "+e);
|
app.logEvent ("Error parsing function file "+source+": "+e);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -568,18 +528,6 @@ public class FesiEvaluator {
|
||||||
reader.close();
|
reader.close();
|
||||||
} catch (IOException ignore) {}
|
} 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);
|
|
||||||
} */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import FESI.Exceptions.*;
|
||||||
/**
|
/**
|
||||||
* This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter.
|
* This is the implementation of ScriptingEnvironment for the FESI EcmaScript interpreter.
|
||||||
*/
|
*/
|
||||||
public class FesiScriptingEnvironment implements ScriptingEnvironment {
|
public final class FesiScriptingEnvironment implements ScriptingEnvironment {
|
||||||
|
|
||||||
Application app;
|
Application app;
|
||||||
Properties props;
|
Properties props;
|
||||||
|
@ -74,7 +74,7 @@ public class FesiScriptingEnvironment implements ScriptingEnvironment {
|
||||||
return evaluators.values();
|
return evaluators.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
FesiEvaluator getEvaluator (RequestEvaluator reval) {
|
private FesiEvaluator getEvaluator (RequestEvaluator reval) {
|
||||||
FesiEvaluator fesi = (FesiEvaluator) evaluators.get (reval);
|
FesiEvaluator fesi = (FesiEvaluator) evaluators.get (reval);
|
||||||
if (fesi == null) {
|
if (fesi == null) {
|
||||||
fesi = new FesiEvaluator (app, reval);
|
fesi = new FesiEvaluator (app, reval);
|
||||||
|
|
|
@ -20,7 +20,7 @@ import org.xml.sax.InputSource;
|
||||||
/**
|
/**
|
||||||
* This is the basic Extension for FESI interpreters used in Helma. It sets up
|
* This is the basic Extension for FESI interpreters used in Helma. It sets up
|
||||||
* varios constructors, global functions and properties on the HopObject prototype
|
* varios constructors, global functions and properties on the HopObject prototype
|
||||||
* (Node objects), the user prototype, the global prototype etc.
|
* (Node objects), the global prototype, the session object etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class HopExtension {
|
public class HopExtension {
|
||||||
|
@ -61,8 +61,8 @@ public class HopExtension {
|
||||||
ObjectPrototype esObjectPrototype = new ObjectPrototype (op, evaluator);
|
ObjectPrototype esObjectPrototype = new ObjectPrototype (op, evaluator);
|
||||||
// the Node prototype
|
// the Node prototype
|
||||||
ObjectPrototype esNodePrototype = new ObjectPrototype(op, evaluator);
|
ObjectPrototype esNodePrototype = new ObjectPrototype(op, evaluator);
|
||||||
// the User prototype
|
// the Session prototype
|
||||||
ObjectPrototype esUserPrototype = new ObjectPrototype (esNodePrototype, evaluator);
|
ObjectPrototype esSessionPrototype = new ObjectPrototype (esNodePrototype, evaluator);
|
||||||
// the Node constructor
|
// the Node constructor
|
||||||
ESObject node = new NodeConstructor ("Node", fp, fesi);
|
ESObject node = new NodeConstructor ("Node", fp, fesi);
|
||||||
|
|
||||||
|
@ -97,12 +97,6 @@ public class HopExtension {
|
||||||
go.putHiddenProperty("HopObject", node); // HopObject is the new name for node.
|
go.putHiddenProperty("HopObject", node); // HopObject is the new name for node.
|
||||||
go.putHiddenProperty("getProperty", new GlobalGetProperty ("getProperty", evaluator, fp));
|
go.putHiddenProperty("getProperty", new GlobalGetProperty ("getProperty", evaluator, fp));
|
||||||
go.putHiddenProperty("token", new GlobalGetProperty ("token", evaluator, fp));
|
go.putHiddenProperty("token", new GlobalGetProperty ("token", evaluator, fp));
|
||||||
go.putHiddenProperty("getUser", new GlobalGetUser ("getUser", evaluator, fp));
|
|
||||||
go.putHiddenProperty("getUserBySession", new GlobalGetUserBySession ("getUserBySession", evaluator, fp));
|
|
||||||
go.putHiddenProperty("getAllUsers", new GlobalGetAllUsers ("getAllUsers", evaluator, fp));
|
|
||||||
go.putHiddenProperty("getActiveUsers", new GlobalGetActiveUsers ("getActiveUsers", evaluator, fp));
|
|
||||||
go.putHiddenProperty("countActiveUsers", new GlobalCountActiveUsers ("countActiveUsers", evaluator, fp));
|
|
||||||
go.putHiddenProperty("isActive", new GlobalIsActive ("isActive", evaluator, fp));
|
|
||||||
go.putHiddenProperty("getAge", new GlobalGetAge ("getAge", evaluator, fp));
|
go.putHiddenProperty("getAge", new GlobalGetAge ("getAge", evaluator, fp));
|
||||||
go.putHiddenProperty("getURL", new GlobalGetURL ("getURL", evaluator, fp));
|
go.putHiddenProperty("getURL", new GlobalGetURL ("getURL", evaluator, fp));
|
||||||
go.putHiddenProperty("encode", new GlobalEncode ("encode", evaluator, fp));
|
go.putHiddenProperty("encode", new GlobalEncode ("encode", evaluator, fp));
|
||||||
|
@ -120,20 +114,11 @@ public class HopExtension {
|
||||||
go.putHiddenProperty("authenticate", new GlobalAuthenticate ("authenticate", evaluator, fp));
|
go.putHiddenProperty("authenticate", new GlobalAuthenticate ("authenticate", evaluator, fp));
|
||||||
go.deleteProperty("exit", "exit".hashCode());
|
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));
|
|
||||||
|
|
||||||
// register object prototypes with FesiEvaluator
|
// register object prototypes with FesiEvaluator
|
||||||
fesi.putPrototype ("global", go);
|
fesi.putPrototype ("global", go);
|
||||||
fesi.putPrototype ("hopobject", esNodePrototype);
|
fesi.putPrototype ("hopobject", esNodePrototype);
|
||||||
fesi.putPrototype ("__javaobject__", esObjectPrototype);
|
fesi.putPrototype ("__javaobject__", esObjectPrototype);
|
||||||
fesi.putPrototype ("user", esUserPrototype);
|
// fesi.putPrototype ("session", esSessionPrototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
class NodeAdd extends BuiltinFunctionObject {
|
class NodeAdd extends BuiltinFunctionObject {
|
||||||
|
@ -415,92 +400,6 @@ public class HopExtension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserLogin extends BuiltinFunctionObject {
|
|
||||||
UserLogin (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
if (arguments.length < 2)
|
|
||||||
return ESBoolean.makeBoolean(false);
|
|
||||||
ESUser u = (ESUser) thisObject;
|
|
||||||
if (u.user == null)
|
|
||||||
throw new EcmaScriptException ("login() can only be called for user objects that are online at the moment!");
|
|
||||||
boolean success = app.loginUser (arguments[0].toString (), arguments[1].toString (), u);
|
|
||||||
try {
|
|
||||||
u.doIndirectCall (this.evaluator, u, "onLogin", new ESValue[0]);
|
|
||||||
} catch (Exception nosuch) {}
|
|
||||||
return ESBoolean.makeBoolean (success);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserRegister extends BuiltinFunctionObject {
|
|
||||||
UserRegister (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 2);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
if (arguments.length < 2)
|
|
||||||
return ESBoolean.makeBoolean(false);
|
|
||||||
INode unode = app.registerUser (arguments[0].toString (), arguments[1].toString ());
|
|
||||||
if (unode == null)
|
|
||||||
return ESNull.theNull;
|
|
||||||
else
|
|
||||||
return fesi.getNodeWrapper (unode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserLogout extends BuiltinFunctionObject {
|
|
||||||
UserLogout (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
ESUser u = (ESUser) thisObject;
|
|
||||||
if (u.user == null)
|
|
||||||
return ESBoolean.makeBoolean (true);
|
|
||||||
try {
|
|
||||||
u.doIndirectCall (this.evaluator, u, "onLogout", new ESValue[0]);
|
|
||||||
} catch (Exception nosuch) {}
|
|
||||||
return ESBoolean.makeBoolean (app.logoutUser (u));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserOnSince extends BuiltinFunctionObject {
|
|
||||||
UserOnSince (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
ESUser u = (ESUser) thisObject;
|
|
||||||
if (u.user == null)
|
|
||||||
throw new EcmaScriptException ("onSince() can only be called for users that are online at the moment!");
|
|
||||||
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.onSince ()));
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserLastActive extends BuiltinFunctionObject {
|
|
||||||
UserLastActive (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
ESUser u = (ESUser) thisObject;
|
|
||||||
if (u.user == null)
|
|
||||||
throw new EcmaScriptException ("lastActive() can only be called for users that are online at the moment!");
|
|
||||||
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.lastTouched ()));
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UserTouch extends BuiltinFunctionObject {
|
|
||||||
UserTouch (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
ESUser u = (ESUser) thisObject;
|
|
||||||
if (u.user != null)
|
|
||||||
u.user.touch ();
|
|
||||||
return ESNull.theNull;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlobalGetProperty extends BuiltinFunctionObject {
|
class GlobalGetProperty extends BuiltinFunctionObject {
|
||||||
GlobalGetProperty (String name, Evaluator evaluator, FunctionPrototype fp) {
|
GlobalGetProperty (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||||
super (fp, evaluator, name, 1);
|
super (fp, evaluator, name, 1);
|
||||||
|
@ -625,109 +524,6 @@ public class HopExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GlobalGetUser extends BuiltinFunctionObject {
|
|
||||||
GlobalGetUser (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
INode user = null;
|
|
||||||
if (arguments.length > 0) {
|
|
||||||
String uname = arguments[0].toString ().trim ();
|
|
||||||
user = app.getUserNode (uname);
|
|
||||||
}
|
|
||||||
if (user == null)
|
|
||||||
return ESNull.theNull;
|
|
||||||
return fesi.getNodeWrapper (user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlobalGetUserBySession extends BuiltinFunctionObject {
|
|
||||||
GlobalGetUserBySession (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
User user = null;
|
|
||||||
if (arguments.length > 0) {
|
|
||||||
String sid = arguments[0].toString ().trim ();
|
|
||||||
user = app.getUser (sid);
|
|
||||||
}
|
|
||||||
if (user == null || user.getUID() == null)
|
|
||||||
return ESNull.theNull;
|
|
||||||
user.touch ();
|
|
||||||
return fesi.getNodeWrapper (user.getNode ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class GlobalGetAllUsers extends BuiltinFunctionObject {
|
|
||||||
GlobalGetAllUsers (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
INode users = app.getUserRoot ();
|
|
||||||
ESObject ap = this.evaluator.getArrayPrototype();
|
|
||||||
ArrayPrototype theArray = new ArrayPrototype(ap, this.evaluator);
|
|
||||||
int i=0;
|
|
||||||
for (Enumeration e=users.properties (); e.hasMoreElements (); ) {
|
|
||||||
String propname = (String) e.nextElement ();
|
|
||||||
theArray.putProperty (i++, new ESString (propname));
|
|
||||||
}
|
|
||||||
return theArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlobalGetActiveUsers extends BuiltinFunctionObject {
|
|
||||||
GlobalGetActiveUsers (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
Hashtable sessions = (Hashtable) app.sessions.clone ();
|
|
||||||
ESObject ap = this.evaluator.getArrayPrototype();
|
|
||||||
ArrayPrototype theArray = new ArrayPrototype (ap, this.evaluator);
|
|
||||||
theArray.setSize (sessions.size ());
|
|
||||||
int i=0;
|
|
||||||
// Hashtable visited = new Hashtable ();
|
|
||||||
for (Enumeration e=sessions.elements(); e.hasMoreElements(); ) {
|
|
||||||
User u = (User) e.nextElement ();
|
|
||||||
// Note: we previously sorted out duplicate users - now we simply enumerate all active sessions.
|
|
||||||
// if (u.uid == null || !visited.containsKey (u.uid)) {
|
|
||||||
theArray.setElementAt (fesi.getNodeWrapper (u), i++);
|
|
||||||
// if (u.uid != null) visited.put (u.uid, u);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
return theArray;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlobalCountActiveUsers extends BuiltinFunctionObject {
|
|
||||||
GlobalCountActiveUsers (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
return new ESNumber (app.sessions.size ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlobalIsActive extends BuiltinFunctionObject {
|
|
||||||
GlobalIsActive (String name, Evaluator evaluator, FunctionPrototype fp) {
|
|
||||||
super (fp, evaluator, name, 1);
|
|
||||||
}
|
|
||||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
|
||||||
if (arguments.length < 1)
|
|
||||||
return ESBoolean.makeBoolean (false);
|
|
||||||
String username = null;
|
|
||||||
boolean active = false;
|
|
||||||
if (arguments[0] instanceof ESUser) {
|
|
||||||
ESUser esu = (ESUser) arguments[0];
|
|
||||||
active = (esu.user != null);
|
|
||||||
} else {
|
|
||||||
active = app.activeUsers.contains (arguments[0].toString ());
|
|
||||||
}
|
|
||||||
return ESBoolean.makeBoolean (active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlobalGetAge extends BuiltinFunctionObject {
|
class GlobalGetAge extends BuiltinFunctionObject {
|
||||||
GlobalGetAge (String name, Evaluator evaluator, FunctionPrototype fp) {
|
GlobalGetAge (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||||
super (fp, evaluator, name, 1);
|
super (fp, evaluator, name, 1);
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class DomExtension extends Extension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class XmlSave extends BuiltinFunctionObject {
|
class XmlSave extends BuiltinFunctionObject {
|
||||||
XmlSave(String name, Evaluator evaluator, FunctionPrototype fp) {
|
XmlSave(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||||
super(fp, evaluator, name, 1);
|
super(fp, evaluator, name, 1);
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ public class DomExtension extends Extension {
|
||||||
try {
|
try {
|
||||||
File tmpFile = new File(arguments[0].toString()+".tmp."+XmlWriter.generateID());
|
File tmpFile = new File(arguments[0].toString()+".tmp."+XmlWriter.generateID());
|
||||||
XmlWriter writer = new XmlWriter (tmpFile);
|
XmlWriter writer = new XmlWriter (tmpFile);
|
||||||
|
writer.setDatabaseMode(false);
|
||||||
boolean result = writer.write(node);
|
boolean result = writer.write(node);
|
||||||
writer.close();
|
writer.close();
|
||||||
File finalFile = new File(arguments[0].toString());
|
File finalFile = new File(arguments[0].toString());
|
||||||
|
@ -81,6 +82,10 @@ public class DomExtension extends Extension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Xml.create() is used to get a string containing the xml-content.
|
||||||
|
* Useful if Xml-content should be made public through the web.
|
||||||
|
*/
|
||||||
class XmlCreate extends BuiltinFunctionObject {
|
class XmlCreate extends BuiltinFunctionObject {
|
||||||
XmlCreate(String name, Evaluator evaluator, FunctionPrototype fp) {
|
XmlCreate(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||||
super(fp, evaluator, name, 1);
|
super(fp, evaluator, name, 1);
|
||||||
|
@ -98,6 +103,7 @@ public class DomExtension extends Extension {
|
||||||
try {
|
try {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
XmlWriter writer = new XmlWriter (out);
|
XmlWriter writer = new XmlWriter (out);
|
||||||
|
writer.setDatabaseMode(false);
|
||||||
boolean result = writer.write(node);
|
boolean result = writer.write(node);
|
||||||
writer.flush();
|
writer.flush();
|
||||||
return new ESString (out.toString());
|
return new ESString (out.toString());
|
||||||
|
@ -123,7 +129,7 @@ public class DomExtension extends Extension {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
XmlReader reader = new XmlReader ();
|
XmlReader reader = new XmlReader ();
|
||||||
INode result = reader.read (arguments[0].toString(),node);
|
INode result = reader.read (new File(arguments[0].toString()),node);
|
||||||
return this.evaluator.reval.getNodeWrapper (result);
|
return this.evaluator.reval.getNodeWrapper (result);
|
||||||
} catch ( NoClassDefFoundError e ) {
|
} catch ( NoClassDefFoundError e ) {
|
||||||
throw new EcmaScriptException ("Can't load dom-capable xml parser.");
|
throw new EcmaScriptException ("Can't load dom-capable xml parser.");
|
||||||
|
|
|
@ -9,7 +9,6 @@ import javax.mail.internet.*;
|
||||||
import javax.activation.*;
|
import javax.activation.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import helma.framework.core.*;
|
|
||||||
import helma.util.*;
|
import helma.util.*;
|
||||||
import FESI.Data.*;
|
import FESI.Data.*;
|
||||||
import FESI.Interpreter.*;
|
import FESI.Interpreter.*;
|
||||||
|
|
|
@ -21,13 +21,22 @@ import helma.util.*;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public abstract class AbstractServletClient extends HttpServlet {
|
public abstract class AbstractServletClient extends HttpServlet {
|
||||||
|
|
||||||
|
// host on which Helma app is running
|
||||||
String host = null;
|
String host = null;
|
||||||
|
// port of Helma RMI server
|
||||||
int port = 0;
|
int port = 0;
|
||||||
int uploadLimit; // limit to HTTP uploads in kB
|
// limit to HTTP uploads in kB
|
||||||
|
int uploadLimit;
|
||||||
|
// RMI url of Helma app
|
||||||
String hopUrl;
|
String hopUrl;
|
||||||
|
// cookie domain to use
|
||||||
String cookieDomain;
|
String cookieDomain;
|
||||||
|
// default encoding for requests
|
||||||
|
String defaultEncoding;
|
||||||
|
// allow caching of responses
|
||||||
boolean caching;
|
boolean caching;
|
||||||
|
// enable debug output
|
||||||
boolean debug;
|
boolean debug;
|
||||||
|
|
||||||
static final byte HTTP_GET = 0;
|
static final byte HTTP_GET = 0;
|
||||||
|
@ -35,7 +44,7 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
|
|
||||||
public void init (ServletConfig init) throws ServletException {
|
public void init (ServletConfig init) throws ServletException {
|
||||||
super.init (init);
|
super.init (init);
|
||||||
|
|
||||||
host = init.getInitParameter ("host");
|
host = init.getInitParameter ("host");
|
||||||
if (host == null) host = "localhost";
|
if (host == null) host = "localhost";
|
||||||
|
|
||||||
|
@ -49,6 +58,8 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
|
|
||||||
hopUrl = "//" + host + ":" + port + "/";
|
hopUrl = "//" + host + ":" + port + "/";
|
||||||
|
|
||||||
|
defaultEncoding = init.getInitParameter ("charset");
|
||||||
|
|
||||||
debug = ("true".equalsIgnoreCase (init.getInitParameter ("debug")));
|
debug = ("true".equalsIgnoreCase (init.getInitParameter ("debug")));
|
||||||
|
|
||||||
caching = ! ("false".equalsIgnoreCase (init.getInitParameter ("caching")));
|
caching = ! ("false".equalsIgnoreCase (init.getInitParameter ("caching")));
|
||||||
|
@ -88,13 +99,15 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// read and set http parameters
|
// read and set http parameters
|
||||||
for (Enumeration e = request.getParameterNames(); e.hasMoreElements(); ) {
|
Map parameters = parseParameters (request);
|
||||||
String nextKey = (String)e.nextElement();
|
for (Iterator i=parameters.entrySet().iterator(); i.hasNext(); ) {
|
||||||
String[] paramValues = request.getParameterValues(nextKey);
|
Map.Entry entry = (Map.Entry) i.next ();
|
||||||
if (paramValues != null) {
|
String key = (String) entry.getKey ();
|
||||||
reqtrans.set (nextKey, paramValues[0]); // set to single string value
|
String[] values = (String[]) entry.getValue ();
|
||||||
if (paramValues.length > 1)
|
if (values != null && values.length > 0) {
|
||||||
reqtrans.set (nextKey+"_array", paramValues); // set string array
|
reqtrans.set (key, values[0]); // set to single string value
|
||||||
|
if (values.length > 1)
|
||||||
|
reqtrans.set (key+"_array", values); // set string array
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,13 +115,13 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
String contentType = request.getContentType();
|
String contentType = request.getContentType();
|
||||||
if (contentType != null && contentType.indexOf("multipart/form-data")==0) {
|
if (contentType != null && contentType.indexOf("multipart/form-data")==0) {
|
||||||
// File Upload
|
// File Upload
|
||||||
Uploader up;
|
|
||||||
try {
|
try {
|
||||||
if ((up = getUpload (request)) != null) {
|
FileUpload upload = getUpload (request);
|
||||||
Hashtable upload = up.getParts ();
|
if (upload != null) {
|
||||||
for (Enumeration e = upload.keys(); e.hasMoreElements(); ) {
|
Hashtable parts = upload.getParts ();
|
||||||
|
for (Enumeration e = parts.keys(); e.hasMoreElements(); ) {
|
||||||
String nextKey = (String) e.nextElement ();
|
String nextKey = (String) e.nextElement ();
|
||||||
Object nextPart = upload.get (nextKey);
|
Object nextPart = parts.get (nextKey);
|
||||||
reqtrans.set (nextKey, nextPart);
|
reqtrans.set (nextKey, nextPart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,6 +239,13 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
res.setHeader( "WWW-Authenticate", "Basic realm=\"" + trans.realm + "\"" );
|
res.setHeader( "WWW-Authenticate", "Basic realm=\"" + trans.realm + "\"" );
|
||||||
if (trans.status > 0)
|
if (trans.status > 0)
|
||||||
res.setStatus (trans.status);
|
res.setStatus (trans.status);
|
||||||
|
// if we don't know which charset to use for parsing HTTP params,
|
||||||
|
// take the one from the response. This usually works because
|
||||||
|
// browsers send parrameters in the same encoding as the page
|
||||||
|
// containing the form has. Problem is we can do this only per servlet,
|
||||||
|
// not per session or even per page, which would produce too much overhead
|
||||||
|
if (defaultEncoding == null)
|
||||||
|
defaultEncoding = trans.charset;
|
||||||
res.setContentLength (trans.getContentLength ());
|
res.setContentLength (trans.getContentLength ());
|
||||||
res.setContentType (trans.getContentType ());
|
res.setContentType (trans.getContentType ());
|
||||||
try {
|
try {
|
||||||
|
@ -245,10 +265,10 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Uploader getUpload (HttpServletRequest request) throws Exception {
|
public FileUpload getUpload (HttpServletRequest request) throws Exception {
|
||||||
int contentLength = request.getContentLength ();
|
int contentLength = request.getContentLength ();
|
||||||
BufferedInputStream in = new BufferedInputStream (request.getInputStream ());
|
BufferedInputStream in = new BufferedInputStream (request.getInputStream ());
|
||||||
Uploader up = null;
|
FileUpload upload = null;
|
||||||
try {
|
try {
|
||||||
if (contentLength > uploadLimit*1024) {
|
if (contentLength > uploadLimit*1024) {
|
||||||
// consume all input to make Apache happy
|
// consume all input to make Apache happy
|
||||||
|
@ -259,42 +279,165 @@ public abstract class AbstractServletClient extends HttpServlet {
|
||||||
throw new RuntimeException ("Upload exceeds limit of "+uploadLimit+" kb.");
|
throw new RuntimeException ("Upload exceeds limit of "+uploadLimit+" kb.");
|
||||||
}
|
}
|
||||||
String contentType = request.getContentType ();
|
String contentType = request.getContentType ();
|
||||||
up = new Uploader(uploadLimit);
|
upload = new FileUpload(uploadLimit);
|
||||||
up.load (in, contentType, contentLength);
|
upload.load (in, contentType, contentLength);
|
||||||
} finally {
|
} finally {
|
||||||
try { in.close (); } catch (Exception ignore) {}
|
try {
|
||||||
|
in.close ();
|
||||||
|
} catch (Exception ignore) {}
|
||||||
}
|
}
|
||||||
return up;
|
return upload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Object getUploadPart(Uploader up, String name) {
|
public Object getUploadPart(FileUpload upload, String name) {
|
||||||
return up.getParts().get(name);
|
return upload.getParts().get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put name value pair in map.
|
||||||
|
*
|
||||||
|
* @param b the character value byte
|
||||||
|
*
|
||||||
|
* Put name and value pair in map. When name already exist, add value
|
||||||
|
* to array of values.
|
||||||
|
*/
|
||||||
|
private static void putMapEntry( Map map, String name, String value) {
|
||||||
|
String[] newValues = null;
|
||||||
|
String[] oldValues = (String[]) map.get(name);
|
||||||
|
if (oldValues == null) {
|
||||||
|
newValues = new String[1];
|
||||||
|
newValues[0] = value;
|
||||||
|
} else {
|
||||||
|
newValues = new String[oldValues.length + 1];
|
||||||
|
System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
|
||||||
|
newValues[oldValues.length] = value;
|
||||||
|
}
|
||||||
|
map.put(name, newValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected Map parseParameters (HttpServletRequest request) {
|
||||||
|
|
||||||
|
String encoding = request.getCharacterEncoding ();
|
||||||
|
if (encoding == null)
|
||||||
|
// no encoding from request, use standard one
|
||||||
|
encoding = defaultEncoding;
|
||||||
|
if (encoding == null)
|
||||||
|
encoding = "ISO-8859-1";
|
||||||
|
|
||||||
|
HashMap parameters = new HashMap ();
|
||||||
|
// Parse any query string parameters from the request
|
||||||
|
try {
|
||||||
|
parseParameters (parameters, request.getQueryString().getBytes(), encoding);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse any posted parameters in the input stream
|
||||||
|
if ("POST".equals(request.getMethod()) &&
|
||||||
|
"application/x-www-form-urlencoded".equals(request.getContentType())) {
|
||||||
|
try {
|
||||||
|
int max = request.getContentLength();
|
||||||
|
int len = 0;
|
||||||
|
byte buf[] = new byte[max];
|
||||||
|
ServletInputStream is = request.getInputStream();
|
||||||
|
while (len < max) {
|
||||||
|
int next = is.read(buf, len, max - len);
|
||||||
|
if (next < 0 ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len += next;
|
||||||
|
}
|
||||||
|
// is.close();
|
||||||
|
parseParameters(parameters, buf, encoding);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append request parameters from the specified String to the specified
|
||||||
|
* Map. It is presumed that the specified Map is not accessed from any
|
||||||
|
* other thread, so no synchronization is performed.
|
||||||
|
* <p>
|
||||||
|
* <strong>IMPLEMENTATION NOTE</strong>: URL decoding is performed
|
||||||
|
* individually on the parsed name and value elements, rather than on
|
||||||
|
* the entire query string ahead of time, to properly deal with the case
|
||||||
|
* where the name or value includes an encoded "=" or "&" character
|
||||||
|
* that would otherwise be interpreted as a delimiter.
|
||||||
|
*
|
||||||
|
* NOTE: byte array data is modified by this method. Caller beware.
|
||||||
|
*
|
||||||
|
* @param map Map that accumulates the resulting parameters
|
||||||
|
* @param data Input string containing request parameters
|
||||||
|
* @param encoding Encoding to use for converting hex
|
||||||
|
*
|
||||||
|
* @exception UnsupportedEncodingException if the data is malformed
|
||||||
|
*/
|
||||||
|
public static void parseParameters (Map map, byte[] data, String encoding)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
|
|
||||||
|
if (data != null && data.length > 0) {
|
||||||
|
int pos = 0;
|
||||||
|
int ix = 0;
|
||||||
|
int ox = 0;
|
||||||
|
String key = null;
|
||||||
|
String value = null;
|
||||||
|
while (ix < data.length) {
|
||||||
|
byte c = data[ix++];
|
||||||
|
switch ((char) c) {
|
||||||
|
case '&':
|
||||||
|
value = new String(data, 0, ox, encoding);
|
||||||
|
if (key != null) {
|
||||||
|
putMapEntry(map, key, value);
|
||||||
|
key = null;
|
||||||
|
}
|
||||||
|
ox = 0;
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
key = new String(data, 0, ox, encoding);
|
||||||
|
ox = 0;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
data[ox++] = (byte)' ';
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4)
|
||||||
|
+ convertHexDigit(data[ix++]));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
data[ox++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//The last value does not end in '&'. So save it now.
|
||||||
|
if (key != null) {
|
||||||
|
value = new String(data, 0, ox, encoding);
|
||||||
|
putMapEntry(map, key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a byte character value to hexidecimal digit value.
|
||||||
|
*
|
||||||
|
* @param b the character value byte
|
||||||
|
*/
|
||||||
|
private static byte convertHexDigit( byte b ) {
|
||||||
|
if ((b >= '0') && (b <= '9')) return (byte)(b - '0');
|
||||||
|
if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10);
|
||||||
|
if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public String getServletInfo(){
|
public String getServletInfo(){
|
||||||
return new String("Hop Servlet Client");
|
return new String("Helma Servlet Client");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,271 +0,0 @@
|
||||||
// AcmeServletClient.java
|
|
||||||
// Copyright (c) Hannes Wallnoefer, 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.util.*;
|
|
||||||
import helma.framework.*;
|
|
||||||
import helma.framework.core.Application;
|
|
||||||
import helma.util.Uploader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 {
|
|
||||||
|
|
||||||
private int uploadLimit; // limit to HTTP uploads in kB
|
|
||||||
private Hashtable apps;
|
|
||||||
private Application app;
|
|
||||||
private String cookieDomain;
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init (ServletConfig config) throws ServletException {
|
|
||||||
super.init (config);
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void execute (HttpServletRequest request, HttpServletResponse response, byte method) {
|
|
||||||
String protocol = request.getProtocol ();
|
|
||||||
Cookie[] cookies = request.getCookies();
|
|
||||||
try {
|
|
||||||
RequestTrans reqtrans = new RequestTrans (method);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 (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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
} catch (Exception x) {
|
|
||||||
x.printStackTrace ();
|
|
||||||
try {
|
|
||||||
response.setContentType ("text/html");
|
|
||||||
Writer out = response.getWriter ();
|
|
||||||
if (debug)
|
|
||||||
out.write ("<b>Error:</b><br>" +x);
|
|
||||||
else
|
|
||||||
out.write ("This server is temporarily unavailable. Please check back later.");
|
|
||||||
out.flush ();
|
|
||||||
} catch (Exception io_e) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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.getRedirect () != null) {
|
|
||||||
try {
|
|
||||||
res.sendRedirect(trans.getRedirect ());
|
|
||||||
} catch(Exception io_e) {}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (!trans.cache) {
|
|
||||||
// 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) { System.out.println ("Error in writeResponse: "+io_e); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void redirectResponse (HttpServletRequest request, HttpServletResponse res, ResponseTrans trans, String url) {
|
|
||||||
try {
|
|
||||||
res.sendRedirect(url);
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println ("Exception in redirect: " + e + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Uploader getUpload (HttpServletRequest request) throws Exception {
|
|
||||||
return getUpload (500, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Uploader getUpload (int maxKbytes, HttpServletRequest request) throws Exception {
|
|
||||||
int contentLength = request.getContentLength ();
|
|
||||||
BufferedInputStream in = new BufferedInputStream (request.getInputStream ());
|
|
||||||
Uploader up = null;
|
|
||||||
if (contentLength > maxKbytes*1024) {
|
|
||||||
throw new RuntimeException ("Upload exceeds limit of "+maxKbytes+" kb.");
|
|
||||||
}
|
|
||||||
String contentType = request.getContentType ();
|
|
||||||
up = new Uploader(maxKbytes);
|
|
||||||
up.load (in, contentType, contentLength);
|
|
||||||
return up;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Object getUploadPart(Uploader up, String name) {
|
|
||||||
return up.getParts().get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getServletInfo (){
|
|
||||||
return new String("Hop 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] == '/')) {
|
|
||||||
st++;
|
|
||||||
}
|
|
||||||
while ((st < len) && (val[len - 1] <= ' ' || val[len - 1] == '/')) {
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
return ((st > 0) || (len < val.length)) ? new String (val, st, len-st) : str;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
78
src/helma/servlet/EmbeddedServletClient.java
Normal file
78
src/helma/servlet/EmbeddedServletClient.java
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
// EmbeddedServletClient.java
|
||||||
|
// Copyright (c) Hannes Wallnöfer, 2002
|
||||||
|
|
||||||
|
package helma.servlet;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import helma.framework.*;
|
||||||
|
import helma.framework.core.Application;
|
||||||
|
import helma.main.*;
|
||||||
|
import helma.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Servlet client that runs a Helma application for the embedded
|
||||||
|
* web server
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class EmbeddedServletClient extends AbstractServletClient {
|
||||||
|
|
||||||
|
private Application app = null;
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
// tells us whether the application is mounted as root or by its name
|
||||||
|
// depending on this we know whether we have to transform the request path
|
||||||
|
boolean root;
|
||||||
|
|
||||||
|
public EmbeddedServletClient (String appName, boolean isRoot) {
|
||||||
|
this.appName = appName;
|
||||||
|
this.root = isRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IRemoteApp getApp (String appID) {
|
||||||
|
if (app == null)
|
||||||
|
app = Server.getServer().getApplication (appName);
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void invalidateApp (String appID) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
String getAppID (String path) {
|
||||||
|
return appName;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getRequestPath (String path) {
|
||||||
|
if (path == null)
|
||||||
|
return "";
|
||||||
|
if (root)
|
||||||
|
return trim (path);
|
||||||
|
int appInPath = path.indexOf (appName);
|
||||||
|
if (appInPath > 0)
|
||||||
|
return trim (path.substring (appInPath+appName.length()));
|
||||||
|
else
|
||||||
|
return trim (path);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -70,17 +70,17 @@ public class MultiServletClient extends AbstractServletClient {
|
||||||
int len = val.length;
|
int len = val.length;
|
||||||
int st = 0;
|
int st = 0;
|
||||||
|
|
||||||
// advance to start of path
|
// advance to start of path, eating up any slashes
|
||||||
while ((st < len) && (val[st] <= ' ' || val[st] == '/'))
|
while ((st < len) && (val[st] <= ' ' || val[st] == '/'))
|
||||||
st++;
|
st++;
|
||||||
|
|
||||||
// eat characters of first path element
|
// advance until slash ending the first path element
|
||||||
while (st < len && val[st] != '/')
|
while (st < len && val[st] != '/')
|
||||||
st++;
|
st++;
|
||||||
if (st < len && val[st] == '/')
|
if (st < len && val[st] == '/')
|
||||||
st++;
|
st++;
|
||||||
|
|
||||||
// eat away noise at end of path
|
// eat away spaces and slashes at end of path
|
||||||
while ((st < len) && (val[len - 1] <= ' ' || val[len - 1] == '/'))
|
while ((st < len) && (val[len - 1] <= ' ' || val[len - 1] == '/'))
|
||||||
len--;
|
len--;
|
||||||
|
|
||||||
|
|
|
@ -1,44 +1,36 @@
|
||||||
// ServletClient.java
|
// ServletClient.java
|
||||||
// Copyright (c) Hannes Wallnöfer, Raphael Spannocchi 1998-2000
|
// Copyright (c) Hannes Wallnöfer, Raphael Spannocchi 1998-2002
|
||||||
|
|
||||||
/* Portierung von helma.asp.AspClient auf Servlets */
|
|
||||||
/* Author: Raphael Spannocchi Datum: 27.11.1998 */
|
|
||||||
|
|
||||||
package helma.servlet;
|
package helma.servlet;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.*;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.rmi.Naming;
|
import java.rmi.Naming;
|
||||||
import java.rmi.RemoteException;
|
import java.rmi.RemoteException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import helma.framework.*;
|
import helma.framework.*;
|
||||||
import helma.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the HOP servlet adapter. This class communicates with just
|
* This is the standard Helma servlet adapter. This class represents a servlet
|
||||||
* one Hop application.
|
* that is dedicated to one Helma application over RMI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ServletClient extends AbstractServletClient {
|
public class ServletClient extends AbstractServletClient {
|
||||||
|
|
||||||
private IRemoteApp app = null;
|
private IRemoteApp app = null;
|
||||||
private String appName;
|
private String appName = null;
|
||||||
|
|
||||||
public void init (ServletConfig init) throws ServletException {
|
public void init (ServletConfig init) throws ServletException {
|
||||||
super.init (init);
|
super.init (init);
|
||||||
|
|
||||||
appName = init.getInitParameter ("application");
|
appName = init.getInitParameter ("application");
|
||||||
if (appName == null)
|
|
||||||
appName = "base";
|
|
||||||
|
|
||||||
super.init (init);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IRemoteApp getApp (String appID) throws Exception {
|
IRemoteApp getApp (String appID) throws Exception {
|
||||||
if (app != null)
|
if (app != null)
|
||||||
return app;
|
return app;
|
||||||
|
if (appName == null)
|
||||||
|
throw new ServletException ("Helma application name not specified for helma.servlet.ServletClient");
|
||||||
app = (IRemoteApp) Naming.lookup (hopUrl + appName);
|
app = (IRemoteApp) Naming.lookup (hopUrl + appName);
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
@ -76,7 +68,7 @@ public class ServletClient extends AbstractServletClient {
|
||||||
// for testing
|
// for testing
|
||||||
public static void main (String args[]) {
|
public static void main (String args[]) {
|
||||||
AbstractServletClient client = new ServletClient ();
|
AbstractServletClient client = new ServletClient ();
|
||||||
String path = "///appname/do/it/for/me///";
|
String path = "///appname/some/random/path///";
|
||||||
System.out.println (client.getAppID (path));
|
System.out.println (client.getAppID (path));
|
||||||
System.out.println (client.getRequestPath (path));
|
System.out.println (client.getRequestPath (path));
|
||||||
}
|
}
|
||||||
|
@ -85,20 +77,3 @@ public class ServletClient extends AbstractServletClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,16 +4,15 @@
|
||||||
package helma.servlet;
|
package helma.servlet;
|
||||||
|
|
||||||
import javax.servlet.*;
|
import javax.servlet.*;
|
||||||
import javax.servlet.http.*;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import helma.framework.*;
|
import helma.framework.*;
|
||||||
import helma.framework.core.Application;
|
import helma.framework.core.Application;
|
||||||
import helma.objectmodel.*;
|
|
||||||
import helma.util.*;
|
import helma.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a standalone Hop servlet client, running a Hop application by itself.
|
* Standalone servlet client that runs a Helma application all by itself
|
||||||
|
* in embedded mode without relying on helma.main.Server.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public final class StandaloneServletClient extends AbstractServletClient {
|
public final class StandaloneServletClient extends AbstractServletClient {
|
||||||
|
@ -22,7 +21,7 @@ public final class StandaloneServletClient extends AbstractServletClient {
|
||||||
private String appName;
|
private String appName;
|
||||||
private String serverProps;
|
private String serverProps;
|
||||||
|
|
||||||
|
|
||||||
public void init (ServletConfig init) throws ServletException {
|
public void init (ServletConfig init) throws ServletException {
|
||||||
super.init (init);
|
super.init (init);
|
||||||
appName = init.getInitParameter ("application");
|
appName = init.getInitParameter ("application");
|
||||||
|
@ -105,13 +104,11 @@ public final class StandaloneServletClient extends AbstractServletClient {
|
||||||
// for testing
|
// for testing
|
||||||
public static void main (String args[]) {
|
public static void main (String args[]) {
|
||||||
AbstractServletClient client = new ServletClient ();
|
AbstractServletClient client = new ServletClient ();
|
||||||
String path = "///appname/do/it/for/me///";
|
String path = "///appname/some/random/path///";
|
||||||
System.out.println (client.getAppID (path));
|
System.out.println (client.getAppID (path));
|
||||||
System.out.println (client.getRequestPath (path));
|
System.out.println (client.getRequestPath (path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Uploader.java
|
// FileUpload.java
|
||||||
// Copyright (c) Hannes Wallnöfer 1996-2000
|
// Copyright (c) Hannes Wallnöfer 1996-2000
|
||||||
|
|
||||||
package helma.util;
|
package helma.util;
|
||||||
|
@ -8,19 +8,19 @@ import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for file uploads via HTTP POST.
|
* Utility class for MIME file uploads via HTTP POST.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Uploader {
|
public class FileUpload {
|
||||||
|
|
||||||
public Hashtable parts;
|
public Hashtable parts;
|
||||||
int maxKbytes;
|
int maxKbytes;
|
||||||
|
|
||||||
public Uploader () {
|
public FileUpload () {
|
||||||
maxKbytes = 500;
|
maxKbytes = 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uploader (int max) {
|
public FileUpload (int max) {
|
||||||
maxKbytes = max;
|
maxKbytes = max;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,109 +17,146 @@ import java.text.*;
|
||||||
|
|
||||||
public final class HtmlEncoder {
|
public final class HtmlEncoder {
|
||||||
|
|
||||||
|
// transformation table for characters 128 to 255. These actually fall into two
|
||||||
|
// groups, put together for efficiency: "Windows" chacacters 128-159 such as
|
||||||
|
// "smart quotes", which are encoded to valid Unicode entities, and
|
||||||
|
// valid ISO-8859 caracters 160-255, which are encoded to the symbolic HTML
|
||||||
|
// entity. Everything >= 256 is encoded to a numeric entity.
|
||||||
|
//
|
||||||
|
// for mor on HTML entities see http://www.pemberley.com/janeinfo/latin1.html and
|
||||||
|
// ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT
|
||||||
|
//
|
||||||
|
static final String[] transform = {
|
||||||
|
"€", // 128
|
||||||
|
"", // empty string means character is undefined in unicode
|
||||||
|
"‚",
|
||||||
|
"ƒ",
|
||||||
|
"„",
|
||||||
|
"…",
|
||||||
|
"†",
|
||||||
|
"‡",
|
||||||
|
"ˆ",
|
||||||
|
"‰",
|
||||||
|
"Š",
|
||||||
|
"‹",
|
||||||
|
"Œ",
|
||||||
|
"",
|
||||||
|
"Ž",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"‘",
|
||||||
|
"’",
|
||||||
|
"“",
|
||||||
|
"”",
|
||||||
|
"•",
|
||||||
|
"–",
|
||||||
|
"—",
|
||||||
|
"˜",
|
||||||
|
"™",
|
||||||
|
"š",
|
||||||
|
"›",
|
||||||
|
"œ",
|
||||||
|
"",
|
||||||
|
"ž",
|
||||||
|
"Ÿ", // 159
|
||||||
|
" ", // 160
|
||||||
|
"¡",
|
||||||
|
"¢",
|
||||||
|
"£",
|
||||||
|
"¤",
|
||||||
|
"¥",
|
||||||
|
"¦",
|
||||||
|
"§",
|
||||||
|
"¨",
|
||||||
|
"©",
|
||||||
|
"ª",
|
||||||
|
"«",
|
||||||
|
"¬",
|
||||||
|
"­",
|
||||||
|
"®",
|
||||||
|
"¯",
|
||||||
|
"°",
|
||||||
|
"±",
|
||||||
|
"²",
|
||||||
|
"³",
|
||||||
|
"´",
|
||||||
|
"µ",
|
||||||
|
"¶",
|
||||||
|
"·",
|
||||||
|
"¸",
|
||||||
|
"¹",
|
||||||
|
"º",
|
||||||
|
"»",
|
||||||
|
"¼",
|
||||||
|
"½",
|
||||||
|
"¾",
|
||||||
|
"¿",
|
||||||
|
"À",
|
||||||
|
"Á",
|
||||||
|
"Â",
|
||||||
|
"Ã",
|
||||||
|
"Ä",
|
||||||
|
"Å",
|
||||||
|
"Æ",
|
||||||
|
"Ç",
|
||||||
|
"È",
|
||||||
|
"É",
|
||||||
|
"Ê",
|
||||||
|
"Ë",
|
||||||
|
"Ì",
|
||||||
|
"Í",
|
||||||
|
"Î",
|
||||||
|
"Ï",
|
||||||
|
"Ð",
|
||||||
|
"Ñ",
|
||||||
|
"Ò",
|
||||||
|
"Ó",
|
||||||
|
"Ô",
|
||||||
|
"Õ",
|
||||||
|
"Ö",
|
||||||
|
"×",
|
||||||
|
"Ø",
|
||||||
|
"Ù",
|
||||||
|
"Ú",
|
||||||
|
"Û",
|
||||||
|
"Ü",
|
||||||
|
"Ý",
|
||||||
|
"Þ",
|
||||||
|
"ß",
|
||||||
|
"à",
|
||||||
|
"á",
|
||||||
|
"â",
|
||||||
|
"ã",
|
||||||
|
"ä",
|
||||||
|
"å",
|
||||||
|
"æ",
|
||||||
|
"ç",
|
||||||
|
"è",
|
||||||
|
"é",
|
||||||
|
"ê",
|
||||||
|
"ë",
|
||||||
|
"ì",
|
||||||
|
"í",
|
||||||
|
"î",
|
||||||
|
"ï",
|
||||||
|
"ð",
|
||||||
|
"ñ",
|
||||||
|
"ò",
|
||||||
|
"ó",
|
||||||
|
"ô",
|
||||||
|
"õ",
|
||||||
|
"ö",
|
||||||
|
"÷",
|
||||||
|
"ø",
|
||||||
|
"ù",
|
||||||
|
"ú",
|
||||||
|
"û",
|
||||||
|
"ü",
|
||||||
|
"ý",
|
||||||
|
"þ",
|
||||||
|
"ÿ" // 255
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
static final Hashtable convertor = new Hashtable (128);
|
|
||||||
|
|
||||||
// conversion table
|
|
||||||
static {
|
|
||||||
convertor.put(new Integer(160), " ");
|
|
||||||
convertor.put(new Integer(161), "¡");
|
|
||||||
convertor.put(new Integer(162), "¢");
|
|
||||||
convertor.put(new Integer(163), "£");
|
|
||||||
convertor.put(new Integer(164), "¤");
|
|
||||||
convertor.put(new Integer(165), "¥");
|
|
||||||
convertor.put(new Integer(166), "¦");
|
|
||||||
convertor.put(new Integer(167), "§");
|
|
||||||
convertor.put(new Integer(168), "¨");
|
|
||||||
convertor.put(new Integer(169), "©");
|
|
||||||
convertor.put(new Integer(170), "ª");
|
|
||||||
convertor.put(new Integer(171), "«");
|
|
||||||
convertor.put(new Integer(172), "¬");
|
|
||||||
convertor.put(new Integer(173), "­");
|
|
||||||
convertor.put(new Integer(174), "®");
|
|
||||||
convertor.put(new Integer(175), "¯");
|
|
||||||
convertor.put(new Integer(176), "°");
|
|
||||||
convertor.put(new Integer(177), "±");
|
|
||||||
convertor.put(new Integer(178), "²");
|
|
||||||
convertor.put(new Integer(179), "³");
|
|
||||||
convertor.put(new Integer(180), "´");
|
|
||||||
convertor.put(new Integer(181), "µ");
|
|
||||||
convertor.put(new Integer(182), "¶");
|
|
||||||
convertor.put(new Integer(183), "·");
|
|
||||||
convertor.put(new Integer(184), "¸");
|
|
||||||
convertor.put(new Integer(185), "¹");
|
|
||||||
convertor.put(new Integer(186), "º");
|
|
||||||
convertor.put(new Integer(187), "»");
|
|
||||||
convertor.put(new Integer(188), "¼");
|
|
||||||
convertor.put(new Integer(189), "½");
|
|
||||||
convertor.put(new Integer(190), "¾");
|
|
||||||
convertor.put(new Integer(191), "¿");
|
|
||||||
convertor.put(new Integer(192), "À");
|
|
||||||
convertor.put(new Integer(193), "Á");
|
|
||||||
convertor.put(new Integer(194), "Â");
|
|
||||||
convertor.put(new Integer(195), "Ã");
|
|
||||||
convertor.put(new Integer(196), "Ä");
|
|
||||||
convertor.put(new Integer(197), "Å");
|
|
||||||
convertor.put(new Integer(198), "Æ");
|
|
||||||
convertor.put(new Integer(199), "Ç");
|
|
||||||
convertor.put(new Integer(200), "È");
|
|
||||||
convertor.put(new Integer(201), "É");
|
|
||||||
convertor.put(new Integer(202), "Ê");
|
|
||||||
convertor.put(new Integer(203), "Ë");
|
|
||||||
convertor.put(new Integer(204), "Ì");
|
|
||||||
convertor.put(new Integer(205), "Í");
|
|
||||||
convertor.put(new Integer(206), "Î");
|
|
||||||
convertor.put(new Integer(207), "Ï");
|
|
||||||
convertor.put(new Integer(208), "Ð");
|
|
||||||
convertor.put(new Integer(209), "Ñ");
|
|
||||||
convertor.put(new Integer(210), "Ò");
|
|
||||||
convertor.put(new Integer(211), "Ó");
|
|
||||||
convertor.put(new Integer(212), "Ô");
|
|
||||||
convertor.put(new Integer(213), "Õ");
|
|
||||||
convertor.put(new Integer(214), "Ö");
|
|
||||||
convertor.put(new Integer(215), "×");
|
|
||||||
convertor.put(new Integer(216), "Ø");
|
|
||||||
convertor.put(new Integer(217), "Ù");
|
|
||||||
convertor.put(new Integer(218), "Ú");
|
|
||||||
convertor.put(new Integer(219), "Û");
|
|
||||||
convertor.put(new Integer(220), "Ü");
|
|
||||||
convertor.put(new Integer(221), "Ý");
|
|
||||||
convertor.put(new Integer(222), "Þ");
|
|
||||||
convertor.put(new Integer(223), "ß");
|
|
||||||
convertor.put(new Integer(224), "à");
|
|
||||||
convertor.put(new Integer(225), "á");
|
|
||||||
convertor.put(new Integer(226), "â");
|
|
||||||
convertor.put(new Integer(227), "ã");
|
|
||||||
convertor.put(new Integer(228), "ä");
|
|
||||||
convertor.put(new Integer(229), "å");
|
|
||||||
convertor.put(new Integer(230), "æ");
|
|
||||||
convertor.put(new Integer(231), "ç");
|
|
||||||
convertor.put(new Integer(232), "è");
|
|
||||||
convertor.put(new Integer(233), "é");
|
|
||||||
convertor.put(new Integer(234), "ê");
|
|
||||||
convertor.put(new Integer(235), "ë");
|
|
||||||
convertor.put(new Integer(236), "ì");
|
|
||||||
convertor.put(new Integer(237), "í");
|
|
||||||
convertor.put(new Integer(238), "î");
|
|
||||||
convertor.put(new Integer(239), "ï");
|
|
||||||
convertor.put(new Integer(240), "ð");
|
|
||||||
convertor.put(new Integer(241), "ñ");
|
|
||||||
convertor.put(new Integer(242), "ò");
|
|
||||||
convertor.put(new Integer(243), "ó");
|
|
||||||
convertor.put(new Integer(244), "ô");
|
|
||||||
convertor.put(new Integer(245), "õ");
|
|
||||||
convertor.put(new Integer(246), "ö");
|
|
||||||
convertor.put(new Integer(247), "÷");
|
|
||||||
convertor.put(new Integer(248), "ø");
|
|
||||||
convertor.put(new Integer(249), "ù");
|
|
||||||
convertor.put(new Integer(250), "ú");
|
|
||||||
convertor.put(new Integer(251), "û");
|
|
||||||
convertor.put(new Integer(252), "ü");
|
|
||||||
convertor.put(new Integer(253), "ý");
|
|
||||||
convertor.put(new Integer(254), "þ");
|
|
||||||
convertor.put(new Integer(255), "ÿ");
|
|
||||||
} */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -182,7 +219,7 @@ public final class HtmlEncoder {
|
||||||
case '\n':
|
case '\n':
|
||||||
ret.append ('\n');
|
ret.append ('\n');
|
||||||
if (!ignoreNewline && !swallowOneNewline)
|
if (!ignoreNewline && !swallowOneNewline)
|
||||||
ret.append ("<br>");
|
ret.append ("<br />");
|
||||||
if (!tagOpen)
|
if (!tagOpen)
|
||||||
swallowOneNewline = false;
|
swallowOneNewline = false;
|
||||||
break;
|
break;
|
||||||
|
@ -197,16 +234,16 @@ public final class HtmlEncoder {
|
||||||
ret.append ('>');
|
ret.append ('>');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret.append (c);
|
// ret.append (c);
|
||||||
// if (c < 160)
|
if (c < 128)
|
||||||
// ret.append ((char) c);
|
ret.append (c);
|
||||||
// else if (c >= 160 && c <= 255)
|
else if (c >= 128 && c < 256)
|
||||||
// ret.append (convertor.get(new Integer(c)));
|
ret.append (transform[c-128]);
|
||||||
// else {
|
else {
|
||||||
// ret.append ("&#");
|
ret.append ("&#");
|
||||||
// ret.append (c);
|
ret.append ((int) c);
|
||||||
// ret.append (";");
|
ret.append (";");
|
||||||
// }
|
}
|
||||||
if (!tagOpen && !Character.isWhitespace (c))
|
if (!tagOpen && !Character.isWhitespace (c))
|
||||||
swallowOneNewline = false;
|
swallowOneNewline = false;
|
||||||
}
|
}
|
||||||
|
@ -267,20 +304,20 @@ public final class HtmlEncoder {
|
||||||
case '\n':
|
case '\n':
|
||||||
ret.append ('\n');
|
ret.append ('\n');
|
||||||
if (encodeNewline) {
|
if (encodeNewline) {
|
||||||
ret.append ("<br>");
|
ret.append ("<br />");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret.append (c);
|
// ret.append (c);
|
||||||
// if (c < 160)
|
if (c < 128)
|
||||||
// ret.append ((char) c);
|
ret.append (c);
|
||||||
// else if (c >= 160 && c <= 255)
|
else if (c >= 128 && c < 256)
|
||||||
// ret.append (convertor.get(new Integer(c)));
|
ret.append (transform[c-128]);
|
||||||
// else {
|
else {
|
||||||
// ret.append ("&#");
|
ret.append ("&#");
|
||||||
// ret.append (c);
|
ret.append ((int) c);
|
||||||
// ret.append (";");
|
ret.append (";");
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,5 +352,26 @@ public final class HtmlEncoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test method
|
||||||
|
public static String printCharRange (int from, int to) {
|
||||||
|
StringBuffer response = new StringBuffer();
|
||||||
|
for (int i=from;i<to;i++) {
|
||||||
|
response.append (i);
|
||||||
|
response.append (" ");
|
||||||
|
response.append ((char) i);
|
||||||
|
response.append (" ");
|
||||||
|
if (i < 128)
|
||||||
|
response.append ((char) i);
|
||||||
|
else if (i >= 128 && i < 256)
|
||||||
|
response.append (transform[i-128]);
|
||||||
|
else {
|
||||||
|
response.append ("&#");
|
||||||
|
response.append (i);
|
||||||
|
response.append (";");
|
||||||
|
}
|
||||||
|
response.append ("\r\n");
|
||||||
|
}
|
||||||
|
return response.toString();
|
||||||
|
}
|
||||||
|
|
||||||
} // end of class
|
} // end of class
|
||||||
|
|
|
@ -141,6 +141,12 @@ public final class SystemProperties extends Properties {
|
||||||
return props.keys();
|
return props.keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set keySet () {
|
||||||
|
if (System.currentTimeMillis () - lastcheck > cacheTime)
|
||||||
|
checkFile ();
|
||||||
|
return props.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
public Enumeration elements () {
|
public Enumeration elements () {
|
||||||
if (System.currentTimeMillis () - lastcheck > cacheTime)
|
if (System.currentTimeMillis () - lastcheck > cacheTime)
|
||||||
checkFile ();
|
checkFile ();
|
||||||
|
|
Loading…
Add table
Reference in a new issue