This commit was manufactured by cvs2svn to create tag
'Pre1_2001_02_27_stable'.
This commit is contained in:
parent
84f281fb77
commit
8bf0f8dee6
140 changed files with 7090 additions and 13818 deletions
|
@ -179,7 +179,7 @@ public class FileServlet extends HttpServlet
|
|||
|
||||
protected void serveFile( HttpServletRequest req, HttpServletResponse res, boolean headOnly, String path, String filename, File file ) throws IOException
|
||||
{
|
||||
// log( "getting " + path );
|
||||
log( "getting " + path );
|
||||
if ( ! file.canRead() )
|
||||
{
|
||||
res.sendError( HttpServletResponse.SC_FORBIDDEN );
|
||||
|
|
|
@ -147,8 +147,6 @@ public class Serve implements ServletContext, Runnable
|
|||
private int port;
|
||||
private PrintStream logStream;
|
||||
Acme.WildcardDictionary registry;
|
||||
// the servlet to use if no other matches the request
|
||||
Servlet defaultServlet;
|
||||
Properties props;
|
||||
|
||||
/// Constructor.
|
||||
|
@ -270,10 +268,6 @@ public class Serve implements ServletContext, Runnable
|
|||
registry.remove (urlPat);
|
||||
}
|
||||
|
||||
public void setDefaultServlet (Servlet servlet) {
|
||||
defaultServlet = servlet;
|
||||
}
|
||||
|
||||
/// Register a standard set of Servlets. These will return
|
||||
// files or directory listings, and run CGI programs, much like a
|
||||
// standard HTTP server.
|
||||
|
@ -457,7 +451,8 @@ public class Serve implements ServletContext, Runnable
|
|||
// Same as the CGI variable SERVER_SOFTWARE.
|
||||
public String getServerInfo()
|
||||
{
|
||||
return ServeUtils.serverName + " " + helma.main.Server.version + " (" + ServeUtils.serverUrl + ")";
|
||||
return ServeUtils.serverName + " " + ServeUtils.serverVersion +
|
||||
" (" + ServeUtils.serverUrl + ")";
|
||||
}
|
||||
|
||||
/// Returns the value of the named attribute of the network service, or
|
||||
|
@ -658,11 +653,6 @@ class ServeConnection implements Runnable, HttpServletRequest, HttpServletRespon
|
|||
if (reqQuery != null)
|
||||
reqQuery = decode (reqQuery);
|
||||
Servlet servlet = (Servlet) serve.registry.get( reqUriPath );
|
||||
// maybe the application name without slash? try with slash appended
|
||||
if (servlet == null)
|
||||
servlet = (Servlet) serve.registry.get (reqUriPath+"//");
|
||||
if (servlet == null)
|
||||
servlet = serve.defaultServlet;
|
||||
if ( servlet != null )
|
||||
runServlet( (HttpServlet) servlet );
|
||||
else if ( "/".equals( reqUriPath ))
|
||||
|
@ -687,7 +677,7 @@ class ServeConnection implements Runnable, HttpServletRequest, HttpServletRespon
|
|||
setStatus( SC_OK );
|
||||
setDateHeader( "Date", System.currentTimeMillis() );
|
||||
setHeader(
|
||||
"Server", ServeUtils.serverName + "/" + helma.main.Server.version );
|
||||
"Server", ServeUtils.serverName + "/" + ServeUtils.serverVersion );
|
||||
setHeader( "Connection", "close" );
|
||||
try
|
||||
{
|
||||
|
|
|
@ -42,9 +42,8 @@ public class ServeUtils
|
|||
{
|
||||
|
||||
// Server identification.
|
||||
public static final String serverName = "Helma";
|
||||
// we're using the server version from helma.main.Server class.
|
||||
// public static final String serverVersion = "1.2 p1";
|
||||
public static final String serverName = "Hop";
|
||||
public static final String serverVersion = "1.1 p1";
|
||||
public static final String serverUrl = "http://helma.org/";
|
||||
|
||||
/// Write a standard-format HTML address for this server.
|
||||
|
@ -53,7 +52,7 @@ public class ServeUtils
|
|||
PrintStream p = new PrintStream( o );
|
||||
p.println(
|
||||
"<ADDRESS><A HREF=\"" + serverUrl + "\">" +
|
||||
serverName + " " + helma.main.Server.version + "</A></ADDRESS>" );
|
||||
serverName + " " + serverVersion + "</A></ADDRESS>" );
|
||||
}
|
||||
|
||||
|
||||
|
@ -92,4 +91,3 @@ public class ServeUtils
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -260,11 +260,8 @@ public abstract class ESLoader extends ESObject {
|
|||
return (ESArrayWrapper) obj; // An array wrapper received externally
|
||||
} else if (obj.getClass().isArray()) {
|
||||
return new ESArrayWrapper(obj, evaluator);
|
||||
} // else if (obj instanceof helma.framework.IPathElement) { // Hannes Wallnoefer, 13. Aug 2001
|
||||
// return evaluator.reval.getElementWrapper ((helma.framework.IPathElement) obj);
|
||||
// }
|
||||
// return new ESWrapper(obj, evaluator);
|
||||
return evaluator.reval.getObjectWrapper (obj);
|
||||
}
|
||||
return new ESWrapper(obj, evaluator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -338,7 +335,6 @@ public abstract class ESLoader extends ESObject {
|
|||
* Check that each object in the paremeter array can be converted
|
||||
* to the type specified by the target array and convert them if needed.
|
||||
* <P>Even if the parameters are compatible with an EcmaScript value,
|
||||
|
||||
* some may have to be converted to an intermediate type. For example
|
||||
* an EcmaScript string of 1 character long is compatible with a Java
|
||||
* Character, but some conversion is needed. Arrays need a similar
|
||||
|
@ -386,7 +382,6 @@ public abstract class ESLoader extends ESObject {
|
|||
if (targetClass.isPrimitive()) { // or: Object.class.isAssignableFrom(targetClass)
|
||||
accepted = false;
|
||||
debugInfo = " rejected (null cannot be assigned to primitive)";
|
||||
|
||||
} else {
|
||||
accepted = true;
|
||||
debugInfo = " accepted (null to Object)";
|
||||
|
|
|
@ -105,16 +105,6 @@ public abstract class ESObject extends ESValue {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allow the prototype to be set, added 2001-04-05 by Hannes Wallnöfer
|
||||
*
|
||||
* @param prototype The new prototype object
|
||||
*/
|
||||
public void setPrototype(ESObject prototype) {
|
||||
this.prototype = prototype;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the name of the class of objects ([[class]]), as used in the default toString
|
||||
* method of objects (15.2.4.2)
|
||||
|
|
|
@ -338,10 +338,9 @@ public class ESWrapper extends ESObject {
|
|||
return noPropertyMarker;
|
||||
}
|
||||
int modifiers = fld.getModifiers();
|
||||
// ALLOW ACCESS TO STATIC FIELDS. HW, 2001-11-27
|
||||
// if ((theObject == null) != Modifier.isStatic(modifiers)) {
|
||||
// throw new EcmaScriptException("Field mode (static) not correct for "+ propertyName);
|
||||
// }
|
||||
if ((theObject == null) != Modifier.isStatic(modifiers)) {
|
||||
throw new EcmaScriptException("Field mode (static) not correct for "+ propertyName);
|
||||
}
|
||||
if (!Modifier.isPublic(modifiers)) {
|
||||
throw new EcmaScriptException("Field "+ propertyName + " not public");
|
||||
}
|
||||
|
|
|
@ -15,11 +15,3 @@ Changes to standard FESI distribution (1.1.4) for Hop
|
|||
ESNumber.
|
||||
- Made EcmaScriptFunctionVisitor recognise thisObj - Functions are now assigned
|
||||
to the current thisObject.
|
||||
- Added setPrototype() method to FESI.Data.ESObject to be able to manipulate
|
||||
the prototype after the object was created.
|
||||
- Changed FESI.Interpreter.EcmaScriptEvaluateVisitor to use .equals instead of
|
||||
== in equal method for helma.framework.core.ESNode objects, since different
|
||||
wrappers may wrap the same object.
|
||||
- Added RequestEvaluator reval field to FESI.Interpreter.Evaluator in order to
|
||||
let ESLoader crate wrappers with correct prototype for path element objects.
|
||||
|
||||
|
|
|
@ -248,13 +248,6 @@ public class EcmaScriptEvaluateVisitor
|
|||
return b1==b2;
|
||||
}
|
||||
|
||||
// ESNode wrappers must be checked with equals() because
|
||||
// it's possible that different wrappers wrap the same node!
|
||||
if (v1 instanceof helma.scripting.fesi.ESNode ||
|
||||
v1 instanceof helma.scripting.fesi.ESGenericObject) {
|
||||
return v1.equals (v2);
|
||||
}
|
||||
|
||||
return v1 == v2;
|
||||
}
|
||||
|
||||
|
@ -1363,5 +1356,3 @@ public class EcmaScriptEvaluateVisitor
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -44,8 +44,6 @@ public class Evaluator {
|
|||
|
||||
// used to stop thread, 06.12.99 Hannes Wallnoefer
|
||||
public volatile Thread thread;
|
||||
// used to retrieve wrappers with correct Prototype for path elements in ESLoader
|
||||
public helma.scripting.fesi.FesiEvaluator reval;
|
||||
|
||||
private static String eol = System.getProperty("line.separator", "\n");
|
||||
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
import helma.framework.IPathElement;
|
||||
import helma.main.Server;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class DocApplication extends DocElement implements IPathElement {
|
||||
|
||||
private DocPrototype[] prototypes;
|
||||
|
||||
/** read all prototypes
|
||||
* @param name application to be documented
|
||||
* @param appDir directory of this application */
|
||||
public DocApplication(String name, String appDir) throws DocException {
|
||||
super( name, appDir, APPLICATION );
|
||||
checkCommentFile();
|
||||
readPrototypes();
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return ( "Application " + name );
|
||||
}
|
||||
|
||||
/** return number of prototypes */
|
||||
public int countPrototypes() {
|
||||
return prototypes.length;
|
||||
}
|
||||
|
||||
/** return a single prototype */
|
||||
public DocPrototype getDocPrototype(String name) {
|
||||
for ( int i=0; i<prototypes.length; i++ ) {
|
||||
if ( prototypes[i].getName().equalsIgnoreCase(name) )
|
||||
return prototypes[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** return array of prototypes */
|
||||
public DocPrototype[] listPrototypes() {
|
||||
return prototypes;
|
||||
}
|
||||
|
||||
public DocFunction[] listFunctions() {
|
||||
return listFunctions(-1);
|
||||
}
|
||||
|
||||
public DocFunction[] listFunctions(int type) {
|
||||
Vector funcVec = new Vector();
|
||||
for ( int i=0; i<prototypes.length; i++ ) {
|
||||
DocFunction[] tmp = prototypes[i].listFunctions();
|
||||
for ( int j=0; j<tmp.length; j++ ) {
|
||||
if ( type==-1 || tmp[j].getType()==type )
|
||||
funcVec.addElement(tmp[j]);
|
||||
}
|
||||
}
|
||||
DocFunction[] funcArr = (DocFunction[])funcVec.toArray(new DocFunction[funcVec.size()]);
|
||||
Arrays.sort(funcArr,new DocComparator(DocComparator.BY_NAME,this));
|
||||
return funcArr;
|
||||
}
|
||||
|
||||
/** read prototypes, create them and make them parse their functions */
|
||||
private void readPrototypes() {
|
||||
File d = new File ( location );
|
||||
String pt[] = d.list();
|
||||
Vector ptVec = new Vector();
|
||||
for ( int i=0; i<pt.length; i++ ) {
|
||||
File f = new File ( d.getAbsolutePath(), pt[i] );
|
||||
if ( f.isDirectory() && DocRun.prototypeAllowed(pt[i]) ) {
|
||||
try {
|
||||
DocPrototype p = new DocPrototype(pt[i],f.getAbsolutePath(),this);
|
||||
ptVec.addElement(p);
|
||||
//break;
|
||||
} catch ( DocException e ) {
|
||||
DocRun.log( "couldn't read prototype " + pt[i] + ": " + e.getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
prototypes = (DocPrototype[])ptVec.toArray(new DocPrototype[ptVec.size()]);
|
||||
Arrays.sort(prototypes,new DocComparator(this));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ( "[DocApplication " + name + "]" );
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
// from helma.framework.IPathElement
|
||||
////////////////////////////////////
|
||||
|
||||
public String getElementName() {
|
||||
return "api";
|
||||
}
|
||||
|
||||
public IPathElement getChildElement(String name) {
|
||||
for( int i=0; i<prototypes.length; i++ ) {
|
||||
if ( prototypes[i].getElementName().equals(name) ) {
|
||||
return prototypes[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IPathElement getParentElement() {
|
||||
Server s = helma.main.Server.getServer();
|
||||
return s.getChildElement(this.name);
|
||||
}
|
||||
|
||||
public java.lang.String getPrototype() {
|
||||
return "docapplication";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
public class DocComparator implements Comparator {
|
||||
|
||||
public static final int BY_TYPE = 0;
|
||||
public static final int BY_NAME = 1;
|
||||
|
||||
int mode;
|
||||
DocElement docEl;
|
||||
|
||||
public DocComparator(int mode, DocElement docEl) {
|
||||
this.mode = mode;
|
||||
this.docEl = docEl;
|
||||
}
|
||||
|
||||
public DocComparator(DocElement docEl) {
|
||||
this.mode = 0;
|
||||
this.docEl = docEl;
|
||||
}
|
||||
|
||||
public int compare(Object obj1, Object obj2) {
|
||||
DocElement e1 = (DocElement)obj1;
|
||||
DocElement e2 = (DocElement)obj2;
|
||||
if ( mode==BY_TYPE && e1.getType()>e2.getType() )
|
||||
return 1;
|
||||
else if ( mode==BY_TYPE && e1.getType()<e2.getType() )
|
||||
return -1;
|
||||
else {
|
||||
return e1.name.compareTo(e2.name);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
DocElement el = (DocElement)obj;
|
||||
if ( el.name.equals(docEl.name) && el.getType()==docEl.getType() ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public abstract class DocElement {
|
||||
|
||||
// identifiers of this element
|
||||
String name;
|
||||
int type;
|
||||
String location;
|
||||
|
||||
// comment-content
|
||||
DocTag tags[];
|
||||
String comment;
|
||||
|
||||
public static final int DOCROOT = 0;
|
||||
public static final int APPLICATION = 1;
|
||||
public static final int PROTOTYPE = 2;
|
||||
public static final int METHOD = 3;
|
||||
public static final int ACTION = 4;
|
||||
public static final int TEMPLATE = 5;
|
||||
public static final int FUNCTION = 6;
|
||||
public static final int MACRO = 7;
|
||||
public static final int SKIN = 8;
|
||||
public static final int PROPERTY = 9; // to be implemented
|
||||
|
||||
public static final String[] typeNames = {"DocRoot","Application","Prototype","Method","Action","Template","Function","Macro","Skin","Property"};
|
||||
|
||||
/** a default file that is read as comment for applications and prototypes if found in their directories */
|
||||
public static final String DOCFILENAME = "doc.html";
|
||||
|
||||
public DocElement(String name, String location, int type) throws DocException {
|
||||
if ( (new File(location)).exists()==false )
|
||||
throw new DocException( name + " not found in " + location );
|
||||
this.name = name;
|
||||
this.location = location;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public DocElement(String name, File location, int type) throws DocException {
|
||||
if ( location.exists()==false )
|
||||
throw new DocException( name + " not found in " + location.toString() );
|
||||
this.name = name;
|
||||
this.location = location.getAbsolutePath();
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/** @return the name of the element */
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
abstract public String getFullName();
|
||||
|
||||
/** @return absolute path to location of element (directory for apps and prototypes, file for methods) */
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public boolean isApplication() { return (type==APPLICATION)?true:false; }
|
||||
public boolean isPrototype() { return (type==PROTOTYPE)?true:false; }
|
||||
public boolean isMethod() { if ( type>=METHOD && type<=SKIN ) return true; else return false; }
|
||||
public boolean isAction() { return (type==ACTION)?true:false; }
|
||||
public boolean isTemplate() { return (type==TEMPLATE)?true:false; }
|
||||
public boolean isFunction() { return (type==FUNCTION)?true:false; }
|
||||
public boolean isMacro() { return (type==MACRO)?true:false; }
|
||||
public boolean isSkin() { return (type==SKIN)?true:false; }
|
||||
|
||||
public int getType() { return type; }
|
||||
public String getTypeName() { return typeNames[type]; }
|
||||
|
||||
public String getDocFileName() { return (typeNames[type] + "_" + name).toLowerCase() + ".html"; }
|
||||
|
||||
/** @return the text of the comment */
|
||||
public String getComment() { return (comment!=null)?comment:""; }
|
||||
|
||||
public int countTags() { return countTags(-1); }
|
||||
public int countTags(int kind) {
|
||||
int ct=0;
|
||||
for ( int i=0; i<tags.length; i++ ) {
|
||||
if ( kind==-1 || tags[i].getKind()==kind ) {
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
return ct;
|
||||
}
|
||||
|
||||
public DocTag[] listTags() { return tags; }
|
||||
/** @return an array of tags that should get a special format
|
||||
* expects a -1 if it should retrieve all tags! */
|
||||
public DocTag[] listTags(int kind) {
|
||||
Vector vec = new Vector();
|
||||
for ( int i=0; i<tags.length; i++ ) {
|
||||
if ( kind==-1 || tags[i].getKind()==kind ) {
|
||||
vec.addElement(tags[i]);
|
||||
}
|
||||
}
|
||||
DocTag[] dt = (DocTag[])vec.toArray(new DocTag[vec.size()]);
|
||||
return dt;
|
||||
}
|
||||
|
||||
/** parse rawComment, render DocTags */
|
||||
void parseComment(String rawComment) {
|
||||
try {
|
||||
// get rid of java comment tags (delimiter "/**")
|
||||
int beg = rawComment.indexOf("/*");
|
||||
beg = ( beg<0 ) ? beg=0 : beg+3;
|
||||
int end = rawComment.indexOf("*/");
|
||||
end = ( end<0 ) ? rawComment.length()-1 : end;
|
||||
end = ( end<0 ) ? 0 : end;
|
||||
rawComment = rawComment.substring(beg,end).trim();
|
||||
// separate comment from tags:
|
||||
StringBuffer commentBuf = new StringBuffer();
|
||||
StringBuffer tagBuf = new StringBuffer();
|
||||
boolean switched = false;
|
||||
StringTokenizer tok = new StringTokenizer(rawComment,"\n");
|
||||
while(tok.hasMoreTokens() ) {
|
||||
String line = tok.nextToken().trim();
|
||||
if ( line.startsWith("*") )
|
||||
line = line.substring(1).trim();
|
||||
if ( line.length()==0 ) continue;
|
||||
if ( line.startsWith("@") && switched==false )
|
||||
switched=true;
|
||||
if ( switched==true )
|
||||
tagBuf.append(line + "\n" );
|
||||
else
|
||||
commentBuf.append(line + "\n" );
|
||||
}
|
||||
comment = commentBuf.toString();
|
||||
// now create taglist:
|
||||
tok = new StringTokenizer(tagBuf.toString(),"@");
|
||||
tags = new DocTag[tok.countTokens()];
|
||||
int i = 0;
|
||||
while(tok.hasMoreTokens() ) {
|
||||
tags[i++] = new DocTag(tok.nextToken().trim());
|
||||
}
|
||||
} catch ( DocException e ) {
|
||||
DocRun.log("parse error in " + location + ": " + e.getMessage() );
|
||||
}
|
||||
}
|
||||
|
||||
/** read properties file (app.props || type.props), format of comments has to be discussed! */
|
||||
static Properties readPropertiesFile(String filename) throws DocException {
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(new FileInputStream(filename));
|
||||
} catch ( IOException e ) {
|
||||
DocRun.log("couldn't read file: " + e.getMessage() );
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
void checkCommentFile() throws DocException {
|
||||
File f = new File (location, DOCFILENAME );
|
||||
if ( f.exists() ) {
|
||||
String rawComment = readAFile(f.getAbsolutePath());
|
||||
parseComment(rawComment);
|
||||
} else {
|
||||
comment = "";
|
||||
tags = new DocTag[0];
|
||||
}
|
||||
}
|
||||
|
||||
/** read a complete file into a string */
|
||||
public static String readAFile(String str) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new FileReader(new File(str)));
|
||||
String line = in.readLine();
|
||||
while(line!=null) {
|
||||
buf.append(line+"\n");
|
||||
line = in.readLine();
|
||||
}
|
||||
return ( buf.toString() );
|
||||
} catch ( IOException e ) {
|
||||
return ("");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
public class DocException extends Exception {
|
||||
|
||||
String str;
|
||||
|
||||
public DocException (String str) {
|
||||
super (str);
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
import helma.framework.IPathElement;
|
||||
import java.io.*;
|
||||
|
||||
public class DocFunction extends DocElement implements IPathElement {
|
||||
|
||||
public static final String[] typeSuffix = {"_action","_as_string","","_macro",""};
|
||||
|
||||
private DocPrototype prototype;
|
||||
private String source;
|
||||
|
||||
public DocFunction( String name, String location, int type, DocPrototype prototype, String rawComment ) throws DocException {
|
||||
super(name,location, type);
|
||||
this.prototype = prototype;
|
||||
parseComment(rawComment);
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
switch(type) {
|
||||
case ACTION: return ( "Action " + name );
|
||||
case TEMPLATE: return ( "Template " + name );
|
||||
case FUNCTION: return ( "Function " + name );
|
||||
case MACRO: return ( "Macro " + name );
|
||||
case SKIN: return ( "Skin " + name );
|
||||
}
|
||||
return ( "Method " + name );
|
||||
}
|
||||
|
||||
public DocPrototype getDocPrototype() { return prototype; }
|
||||
|
||||
public void readSource(String sourceFile, int beginLine, int beginColumn, int endLine, int endColumn ) {
|
||||
StringBuffer buf = new StringBuffer ();
|
||||
int ct=0;
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new FileReader(sourceFile));
|
||||
String line="";
|
||||
while ( line!=null ) {
|
||||
line = in.readLine();
|
||||
if ( line==null ) break;
|
||||
ct++;
|
||||
if ( ct==beginLine )
|
||||
buf.append(line.substring(beginColumn-1, line.length())+"\n");
|
||||
else if ( ct>beginLine && ct<endLine )
|
||||
buf.append(line+"\n");
|
||||
else if ( ct==endLine )
|
||||
buf.append(line.substring(0,endColumn));
|
||||
}
|
||||
} catch ( FileNotFoundException e ) {
|
||||
} catch ( StringIndexOutOfBoundsException e ) {
|
||||
} catch ( IOException e ) {
|
||||
DocRun.log(e.getMessage());
|
||||
}
|
||||
source = buf.toString();
|
||||
}
|
||||
|
||||
public void readSource(String sourceFile) {
|
||||
StringBuffer buf = new StringBuffer ();
|
||||
try {
|
||||
BufferedReader in = new BufferedReader(new FileReader(sourceFile));
|
||||
String line="";
|
||||
while ( line!=null ) {
|
||||
line = in.readLine();
|
||||
if ( line==null ) break;
|
||||
buf.append(line+"\n");
|
||||
}
|
||||
} catch ( FileNotFoundException e ) {
|
||||
} catch ( IOException e ) {
|
||||
DocRun.log(e.getMessage());
|
||||
}
|
||||
source = buf.toString();
|
||||
}
|
||||
|
||||
public void setSource(String source) { this.source = source; }
|
||||
public String getSource() { return (source!=null)?source:""; }
|
||||
|
||||
public String toString() {
|
||||
return ( "[DocFunction " + getTypeName() + " " + name + "]" );
|
||||
}
|
||||
|
||||
////////////////////////////////////
|
||||
// from helma.framework.IPathElement
|
||||
////////////////////////////////////
|
||||
|
||||
public String getElementName() {
|
||||
return getTypeName().toLowerCase()+"_"+name;
|
||||
}
|
||||
|
||||
public IPathElement getChildElement(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public IPathElement getParentElement() {
|
||||
return prototype;
|
||||
}
|
||||
|
||||
public java.lang.String getPrototype() {
|
||||
return "docfunction";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,328 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import helma.util.*;
|
||||
|
||||
public class DocHtmlWriter extends PrintWriter {
|
||||
|
||||
public static DocApplication app;
|
||||
|
||||
public static final int APPLICATION = 0;
|
||||
public static final int PROTOTYPE = 1;
|
||||
public static final int INDEX = 2;
|
||||
public static final int METHOD = 3;
|
||||
|
||||
public DocHtmlWriter(String filename) throws FileNotFoundException {
|
||||
super(new FileOutputStream(filename));
|
||||
}
|
||||
|
||||
public void printHeader( String title ) { printHeader(title,false); }
|
||||
|
||||
/** print header, slightly different for frameset file **/
|
||||
public void printHeader( String title, boolean frameset ) {
|
||||
if ( frameset==true )
|
||||
print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\"\"http://www.w3.org/TR/REC-html40/frameset.dtd\">");
|
||||
else
|
||||
print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">");
|
||||
print("<HTML><HEAD>");
|
||||
print("<!-- Generated by helmadoc on " + (new Date()).toString() + " -->");
|
||||
println("<TITLE>" + title + "</TITLE>");
|
||||
if ( frameset==true )
|
||||
print("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"stylesheet.css\" TITLE=Style>");
|
||||
println("</HEAD>");
|
||||
}
|
||||
|
||||
|
||||
public void printFrameSet() {
|
||||
println ("<FRAMESET cols=\"20%,80%\">");
|
||||
println ("<FRAME src=\"app-frame.html\" name=appFrame>");
|
||||
println ("<FRAME src=\"app.html\" name=prototypeFrame>");
|
||||
println ("</FRAMESET><NOFRAMES>sorry, your browser doesn't understand frames!</NOFRAMES></HTML>");
|
||||
}
|
||||
|
||||
/** print app title for left frame */
|
||||
public void printAppIndexTitle(String title) {
|
||||
print("<table border=0 width=\"100%\"><tr><td nowrap>");
|
||||
print("<FONT size=+1 ID=FrameTitleFont><b>");
|
||||
print("Application " + title + "</b></font></td></tr></table>" );
|
||||
}
|
||||
|
||||
/** print prototype list for left frame */
|
||||
public void printAppIndexList(DocElement[] pt) {
|
||||
print("<TABLE BORDER=0 WIDTH=\"100%\"><TR><TD NOWRAP>");
|
||||
print("<P><FONT size=+1 ID=FrameHeadingFont>Prototypes</FONT><BR><BR>");
|
||||
for ( int i=0; i<pt.length; i++ ) {
|
||||
print ("<FONT ID=FrameItemFont><A HREF=\"" + pt[i].getDocFileName() + "\" TARGET=prototypeFrame>" + pt[i].getName() + "</A></FONT><BR>");
|
||||
}
|
||||
print ("</TD></TR></TABLE>");
|
||||
}
|
||||
|
||||
/** navigation on top of the page **/
|
||||
public void printNavBar(String name, DocPrototype pt, int page ) {
|
||||
String urlPrefix = ( page==METHOD ) ? "../" : "";
|
||||
print("<!-- ========== START OF NAVBAR ========== -->");
|
||||
print("<A NAME=navbar_top><!-- --></A>");
|
||||
print("<TABLE BORDER=0 WIDTH=100% CELLPADDING=1 CELLSPACING=0>");
|
||||
print("<TR><TD COLSPAN=2 BGCOLOR=#EEEEFF ID=NavBarCell1>");
|
||||
print("<A NAME=navbar_top_firstrow><!-- --></A>");
|
||||
|
||||
print("<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=3>");
|
||||
print("<TR ALIGN=center VALIGN=top>");
|
||||
if ( page==APPLICATION )
|
||||
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1Rev><FONT ID=NavBarFont1Rev><B>Application</B></FONT> </TD>");
|
||||
else
|
||||
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1><A HREF=\"" + urlPrefix + "app.html\"><FONT ID=NavBarFont1><B>Application</B></FONT></A> </TD>");
|
||||
if ( page==PROTOTYPE )
|
||||
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1Rev> <FONT ID=NavBarFont1Rev><B>Prototype</B></FONT> </TD>");
|
||||
else if ( page==METHOD )
|
||||
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1> <a href=\"" + urlPrefix + "prototype_" + pt.getName() + ".html\"><FONT ID=NavBarFont1><B>Prototype</B></A></FONT> </TD>");
|
||||
else
|
||||
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1> <FONT ID=NavBarFont1><B>Prototype</B></FONT> </TD>");
|
||||
if ( page==INDEX )
|
||||
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1Rev><FONT ID=NavBarFont1><B>Index</B></FONT> </TD>");
|
||||
else
|
||||
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1><A HREF=\"" + urlPrefix + "index-1.html\"><FONT ID=NavBarFont1><B>Index</B></FONT></A> </TD>");
|
||||
print("</TR></TABLE>");
|
||||
|
||||
print("</TD><TD ALIGN=right VALIGN=top ROWSPAN=3><EM><b>Application " + name + "</b><br><font size=-1></font></EM>");
|
||||
print("</TD></TR>");
|
||||
if ( pt!=null && page!=METHOD ) {
|
||||
print("<TR><TD VALIGN=top ID=NavBarCell3><FONT SIZE=-2>");
|
||||
print("<a href=\"#Actions\">ACTIONS</a> | ");
|
||||
print("<a href=\"#Templates\">TEMPLATES</a> | ");
|
||||
print("<a href=\"#Functions\">FUNCTIONS</a> | ");
|
||||
print("<a href=\"#Macros\">MACROS</a> | ");
|
||||
print("<a href=\"#Skins\">SKINS</a> ");
|
||||
print("</TD></TR>");
|
||||
}
|
||||
|
||||
print("</TABLE>");
|
||||
print("<!-- =========== END OF NAVBAR =========== -->");
|
||||
}
|
||||
|
||||
public void printElementTitle(DocElement docEl) {
|
||||
print("<HR><H2>" + docEl.getName() + "<BR>");
|
||||
print(docEl.getFullName() + "</H2>");
|
||||
print("<HR>");
|
||||
}
|
||||
|
||||
public void printComment(DocElement docEl) {
|
||||
if( docEl.getComment().length()>0 || docEl.countTags()>0 ) {
|
||||
print("<DL><DT>" + docEl.getComment() + "</DT>");
|
||||
print("<DT>");
|
||||
for ( int i=0; i<DocTag.TYPE_COUNT; i++ ) {
|
||||
if ( docEl.countTags(i)>0 ) {
|
||||
print("<DT><b>" + DocTag.kindDesc[i] + "</b><DT>");
|
||||
DocTag[] dt = docEl.listTags(i);
|
||||
for ( int j=0; j<dt.length; j++ ) {
|
||||
print("<DD>" + renderTag(dt[j],j) + "</DD>");
|
||||
}
|
||||
}
|
||||
}
|
||||
print("</DL>");
|
||||
}
|
||||
}
|
||||
|
||||
private String renderFunctionName(DocFunction func) {
|
||||
StringBuffer buf = new StringBuffer ();
|
||||
buf.append("<CODE><B>");
|
||||
if ( DocRun.getOption("-f").equals("true") )
|
||||
buf.append("<a href=\"" + func.getDocPrototype().getName().toLowerCase()+"/"+func.getDocFileName() + "\">" );
|
||||
if ( func.isMacro() ) {
|
||||
buf.append( func.getDocPrototype().getName()+"."+func.getName().substring(0,func.getName().length()-6) );
|
||||
} else {
|
||||
buf.append(func.getName().trim());
|
||||
if( func.isTemplate() || func.isFunction() ) {
|
||||
buf.append("(");
|
||||
int ct = func.countTags(DocTag.ARG);
|
||||
for ( int i=0; i<ct; i++ ) {
|
||||
buf.append("arg"+i);
|
||||
if ( i<ct-1 )
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append(")");
|
||||
}
|
||||
}
|
||||
buf.append("</a></B></CODE>");
|
||||
if ( func.isFunction() || func.isMacro() )
|
||||
buf.append(" <small><i>in " + (new File(func.getLocation())).getName() + "</i></small>" );
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String renderTag(DocTag tag) {
|
||||
return renderTag(tag,0);
|
||||
}
|
||||
|
||||
private String renderTag(DocTag tag, int i) {
|
||||
int kind = tag.getKind();
|
||||
String text = tag.getText();
|
||||
String name = tag.getName();
|
||||
switch (kind) {
|
||||
case DocTag.ARG:
|
||||
return( "<b>Argument " + i + ":</b> " + text );
|
||||
case DocTag.PARAM:
|
||||
return( "<b>Parameter " + name + "</b> " + text );
|
||||
case DocTag.RETURNS:
|
||||
case DocTag.AUTHOR:
|
||||
case DocTag.VERSION:
|
||||
case DocTag.RELEASE:
|
||||
return( text );
|
||||
case DocTag.SEE:
|
||||
if ( text.startsWith("http://") ) {
|
||||
StringTokenizer tok = new StringTokenizer (text.trim()," ");
|
||||
String url = (tok.countTokens()>1)?tok.nextToken():text;
|
||||
return( "<a href=\"" + url + "\">" + ((tok.countTokens()>0)?text.substring(url.length(),text.length()):text) + "</a>" );
|
||||
} else {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
StringTokenizer tok = new StringTokenizer (text.trim(),".");
|
||||
if ( tok.countTokens()==0 ) return text;
|
||||
DocPrototype dp = app.getDocPrototype( tok.nextToken() );
|
||||
if ( dp==null ) return text;
|
||||
buf.append("<a href=\"" );
|
||||
DocFunction df = null;
|
||||
if ( tok.countTokens()>0 )
|
||||
df = dp.getFunction( tok.nextToken() );
|
||||
if ( df==null )
|
||||
buf.append( link(dp) + "\">" + dp.getName() );
|
||||
else
|
||||
buf.append( link(df) + "\">" + dp.getName() + "." + df.getName() );
|
||||
return(buf.toString()+"</a>");
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
public void printListHeader(String title) {
|
||||
print("<A NAME=\"" + title + "\"><!-- --></A>");
|
||||
print("<TABLE BORDER=1 CELLPADDING=3 CELLSPACING=0 WIDTH=100%>");
|
||||
print("<TR BGCOLOR=#CCCCFF ID=TableHeadingColor><TD COLSPAN=2><FONT SIZE=+2><B>" + title + "</B></FONT></TD></TR>");
|
||||
}
|
||||
|
||||
public void printPrototypeList(DocPrototype[] dl, String title) {
|
||||
if ( dl.length==0 ) return;
|
||||
printListHeader(title);
|
||||
for ( int i=0; i<dl.length; i++ ) {
|
||||
print("<TR BGCOLOR=white ID=TableRowColor><TD ALIGN=right VALIGN=top WIDTH=1%><FONT SIZE=-1>");
|
||||
print("<a name=\"" + dl[i].getName() + "\"><!-- --></a>");
|
||||
print("<CODE> " + dl[i].getTypeName() + "</CODE></FONT></TD>");
|
||||
print("<TD><CODE><B><A HREF=\"" + dl[i].getDocFileName() + "\">" + dl[i].getName() + "</A></B></CODE>");
|
||||
print("<BR> " + dl[i].getComment() + "<br>" );
|
||||
print("</TD></TR>");
|
||||
}
|
||||
print("</TABLE><BR>");
|
||||
}
|
||||
|
||||
public void printFunctionList(DocFunction[] dl, String title) {
|
||||
if ( dl.length==0 ) return;
|
||||
printListHeader(title);
|
||||
for ( int i=0; i<dl.length; i++ ) {
|
||||
print("<TR BGCOLOR=white ID=TableRowColor>");
|
||||
print("<TD ALIGN=right VALIGN=top WIDTH=50><FONT SIZE=-1>");
|
||||
print("<a name=\"" + dl[i].getName() + "\"><!-- --></a>");
|
||||
print("<CODE> " + dl[i].getTypeName() + "</CODE></FONT></TD>");
|
||||
print("<TD><DL><DT>" + renderFunctionName(dl[i]) );
|
||||
print("<DT>");
|
||||
printComment(dl[i]);
|
||||
print("</DL></TD></TR>");
|
||||
}
|
||||
print("</TABLE><BR>");
|
||||
}
|
||||
|
||||
public void printFunctionIndex(DocFunction[] dl) {
|
||||
if ( dl.length==0 ) return;
|
||||
String curChar = " ";
|
||||
print("<DL>");
|
||||
for ( int i=0; i<dl.length; i++ ) {
|
||||
String name = dl[i].getName();
|
||||
if ( !name.toLowerCase().startsWith(curChar) ) {
|
||||
print ( "</DL><h2>" + name.substring(0,1).toUpperCase() + "</h2><dl>");
|
||||
curChar = name.substring(0,1).toLowerCase();
|
||||
}
|
||||
print("<DT><a href=\"" + link(dl[i]) + "\">" + dl[i].getName() + "</a> - " + dl[i].getTypeName() + " in <a href=\"" + link(dl[i].getDocPrototype()) + "\">" + dl[i].getDocPrototype().getName() + "</a>" );
|
||||
}
|
||||
print("</DL>");
|
||||
}
|
||||
|
||||
public void printInheritance(DocPrototype pt) {
|
||||
if ( pt.getName().equalsIgnoreCase("hopobject") )
|
||||
return;
|
||||
DocApplication app = pt.getApplication();
|
||||
DocPrototype hopobject = (DocPrototype)app.getDocPrototype("hopobject");
|
||||
if ( hopobject==null || hopobject.countFunctions()==0 )
|
||||
return;
|
||||
print("<TABLE BORDER=1 CELLPADDING=3 CELLSPACING=0 WIDTH=100%>");
|
||||
print("<TR BGCOLOR=\"#EEEEFF\" CLASS=TableSubHeadingColor>");
|
||||
print("<TD><B>Methods inherited from Prototype <a href=\"" + link(hopobject) + "\">hopobject</A></B></TD>");
|
||||
print("</TR>");
|
||||
print("<TR BGCOLOR=\"white\" CLASS=TableRowColor><TD><code>");
|
||||
DocFunction[] df = hopobject.listFunctions();
|
||||
|
||||
int lastType = -1;
|
||||
StringBuffer buf1 = new StringBuffer();
|
||||
StringBuffer buf2 = new StringBuffer();
|
||||
|
||||
for ( int i=0; i<df.length; i++ ) {
|
||||
if ( df[i].getType()!=lastType && i>0 && buf2.length()>0 ) {
|
||||
buf1.append("<b>" + DocElement.typeNames[lastType] + ":</b> <code>" );
|
||||
buf1.append( buf2.toString().substring(0, buf2.toString().length()-2) );
|
||||
buf1.append("</code><br>");
|
||||
buf2 = new StringBuffer();
|
||||
}
|
||||
lastType = df[i].getType();
|
||||
buf2.append ( "<a href=\"" + link(df[i]) + "\">" + df[i].getName() + "</a>, " );
|
||||
}
|
||||
if ( buf2.length()>0 ) {
|
||||
buf1.append("<b>" + DocElement.typeNames[lastType] + ":</b> <code>" );
|
||||
buf1.append( buf2.toString().substring(0, buf2.toString().length()-2) );
|
||||
buf1.append("</code><br>");
|
||||
}
|
||||
print ( buf1.toString() );
|
||||
print("</TR></TABLE>");
|
||||
}
|
||||
|
||||
public void printFunction(DocFunction func) {
|
||||
print( "<br><br><small><i>in " + func.getDocPrototype().getName() + "/" + (new File(func.getLocation())).getName() + ":</i></small>" );
|
||||
print( "<br><pre>");
|
||||
print( HtmlEncoder.encodeAll(func.getSource()) );
|
||||
print( "</pre>" );
|
||||
}
|
||||
|
||||
public void printStyleSheet() {
|
||||
println( "/* Javadoc style sheet */");
|
||||
println( "/* Define colors, fonts and other style attributes here to override the defaults */");
|
||||
println( "* Page background color */");
|
||||
println( "body { background-color: #FFFFFF }");
|
||||
println( "/* Table colors */");
|
||||
println( "#TableHeadingColor { background: #CCCCFF } /* Dark mauve */");
|
||||
println( "#TableSubHeadingColor { background: #EEEEFF } /* Light mauve */");
|
||||
println( "#TableRowColor { background: #FFFFFF } /* White */");
|
||||
println( "/* Font used in left-hand frame lists */");
|
||||
println( "#FrameTitleFont { font-size: normal; font-family: normal }");
|
||||
println( "#FrameHeadingFont { font-size: normal; font-family: normal }");
|
||||
println( "#FrameItemFont { font-size: normal; font-family: normal }");
|
||||
println( "/* Example of smaller, sans-serif font in frames */");
|
||||
println( "/* #FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */");
|
||||
println( "/* Navigation bar fonts and colors */");
|
||||
println( "#NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */");
|
||||
println( "#NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */");
|
||||
println( "#NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;}");
|
||||
println( "#NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;}");
|
||||
println( "#NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}");
|
||||
println( "#NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;}");
|
||||
}
|
||||
|
||||
public String link(DocElement docEl) {
|
||||
if ( docEl.isPrototype() ) {
|
||||
return "prototype_" + docEl.getName() + ".html";
|
||||
} else if ( docEl.isMethod() ) {
|
||||
DocFunction df = (DocFunction)docEl;
|
||||
return "prototype_" + df.getDocPrototype().getName() + ".html#" + df.getName();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,221 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
import helma.framework.IPathElement;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import FESI.Parser.*;
|
||||
|
||||
|
||||
public class DocPrototype extends DocElement implements IPathElement {
|
||||
|
||||
DocFunction[] functions;
|
||||
DocApplication app;
|
||||
|
||||
public DocPrototype( String name, String location, DocApplication app ) throws DocException {
|
||||
super( name, location, PROTOTYPE );
|
||||
this.app = app;
|
||||
if ( name.equals("hopobject")==false && name.equals("global")==false )
|
||||
readPropertiesFile( new File(location,"type.properties").getAbsolutePath());
|
||||
checkCommentFile();
|
||||
readFunctions();
|
||||
}
|
||||
|
||||
public String getFullName() { return ( "Prototype " + name ); }
|
||||
|
||||
/** return number of functions */
|
||||
public int countFunctions() { return functions.length; }
|
||||
|
||||
/** return array of functions of a special type */
|
||||
public int countFunctions(int type) {
|
||||
int ct = 0;
|
||||
for ( int i=0; i<functions.length; i++ ) {
|
||||
if ( functions[i].getType()==type ) {
|
||||
ct++;
|
||||
}
|
||||
}
|
||||
return ct;
|
||||
}
|
||||
|
||||
/** return a single function */
|
||||
public DocFunction getFunction(String name) {
|
||||
for ( int i=0; i<functions.length; i++ ) {
|
||||
if ( functions[i].getName().equals(name) )
|
||||
return functions[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** return array of functions */
|
||||
public DocFunction[] listFunctions() {
|
||||
return functions;
|
||||
}
|
||||
|
||||
/** return array of functions of a special type */
|
||||
public DocFunction[] listFunctions(int type) {
|
||||
Vector funcVec = new Vector();
|
||||
for ( int i=0; i<functions.length; i++ ) {
|
||||
if ( functions[i].getType()==type ) {
|
||||
funcVec.addElement(functions[i]);
|
||||
}
|
||||
}
|
||||
return (DocFunction[])funcVec.toArray(new DocFunction[funcVec.size()]);;
|
||||
}
|
||||
|
||||
|
||||
/** return the application */
|
||||
public DocApplication getApplication() { return app; }
|
||||
|
||||
|
||||
/** create the function list & read all valid files */
|
||||
private void readFunctions() {
|
||||
DocRun.debug("parsing Prototype " + name + " using " + location );
|
||||
String files[] = (new File(location)).list();
|
||||
Vector funcVec = new Vector();;
|
||||
for ( int i=0; i<files.length; i++ ) {
|
||||
DocRun.debug("reading " + files[i] );
|
||||
try {
|
||||
if ( files[i].endsWith(DocRun.actionExtension) ) {
|
||||
readAction(new File(location,files[i]).getAbsolutePath(),funcVec);
|
||||
} else if ( files[i].endsWith(DocRun.scriptExtension) ) {
|
||||
readFunctionFile(new File(location,files[i]).getAbsolutePath(),funcVec);
|
||||
} else if ( files[i].endsWith(DocRun.templateExtension) ) {
|
||||
readTemplate(new File(location,files[i]).getAbsolutePath(),funcVec);
|
||||
} else if ( files[i].endsWith(DocRun.skinExtension) ) {
|
||||
readSkin(new File(location,files[i]).getAbsolutePath(),funcVec);
|
||||
}
|
||||
} catch ( DocException e ) {
|
||||
DocRun.log ( "couldn't read function " + name + "." + files[i] + ": " + e.getMessage() );
|
||||
}
|
||||
}
|
||||
functions = (DocFunction[])funcVec.toArray(new DocFunction[funcVec.size()]);
|
||||
DocRun.debug( name + " has " + functions.length + " functions" );
|
||||
Arrays.sort(functions,new DocComparator(this));
|
||||
}
|
||||
|
||||
private void readAction(String f, Vector funcVec) throws DocException {
|
||||
EcmaScriptTokenManager mgr = createTokenManager(new File(f));
|
||||
Token tok = mgr.getNextToken();
|
||||
DocFunction func = new DocFunction( fileToFuncName(f), f, DocElement.ACTION, this, getCommentFromToken(tok) );
|
||||
func.readSource(f);
|
||||
funcVec.addElement( func );
|
||||
}
|
||||
|
||||
private void readFunctionFile(String f, Vector funcVec) throws DocException {
|
||||
EcmaScriptTokenManager mgr = createTokenManager(new File(f));
|
||||
Token tok = mgr.getNextToken();
|
||||
while( tok.kind!=0 ) {
|
||||
if( tok.kind == EcmaScriptConstants.FUNCTION ) {
|
||||
int beginLine = tok.beginLine;
|
||||
int beginColumn = tok.beginColumn;
|
||||
String funcName = mgr.getNextToken().toString();
|
||||
DocFunction func;
|
||||
if ( funcName.endsWith("_macro") )
|
||||
func = new DocFunction( funcName, f, DocElement.MACRO, this, getCommentFromToken(tok) );
|
||||
else
|
||||
func = new DocFunction( funcName, f, DocElement.FUNCTION, this, getCommentFromToken(tok) );
|
||||
funcVec.addElement(func);
|
||||
|
||||
tok = mgr.getNextToken();
|
||||
int endLine=0, endColumn=0;
|
||||
while( tok.kind!=0 && tok.kind!=EcmaScriptConstants.FUNCTION ) {
|
||||
endLine = tok.endLine;
|
||||
endColumn = tok.endColumn;
|
||||
tok = mgr.getNextToken();
|
||||
}
|
||||
func.readSource(f,beginLine,beginColumn,endLine,endColumn);
|
||||
//DocRun.log("going from " + beginLine +"." + beginColumn + " to " + endLine + "." + endColumn );
|
||||
//DocRun.log("============================here starts a new one");
|
||||
}
|
||||
if ( tok.kind!=0 && tok.kind!=EcmaScriptConstants.FUNCTION )
|
||||
tok = mgr.getNextToken();
|
||||
}
|
||||
}
|
||||
|
||||
private void readTemplate(String f, Vector funcVec) throws DocException {
|
||||
String content = readAFile(f);
|
||||
// get the first scripting zone and tokenize it
|
||||
DocFunction func;
|
||||
try {
|
||||
StringReader str = new StringReader( content.substring(content.indexOf("<%")+2,content.indexOf("%>")) );
|
||||
EcmaScriptTokenManager mgr = new EcmaScriptTokenManager(new ASCII_CharStream(str,1,1),0);
|
||||
Token tok = mgr.getNextToken();
|
||||
func = new DocFunction( fileToFuncName(f), f, DocElement.TEMPLATE, this, getCommentFromToken(tok) );
|
||||
} catch ( IndexOutOfBoundsException e ) {
|
||||
func = new DocFunction( fileToFuncName(f), f, DocElement.TEMPLATE, this, "" );
|
||||
}
|
||||
func.setSource(content);
|
||||
funcVec.addElement(func);
|
||||
}
|
||||
|
||||
private void readSkin(String f, Vector funcVec) throws DocException {
|
||||
// can't be commented yet
|
||||
// simply add them
|
||||
DocFunction func = new DocFunction(fileToFuncName(f),f,DocElement.SKIN, this,"");
|
||||
func.readSource(f);
|
||||
funcVec.addElement(func);
|
||||
}
|
||||
|
||||
|
||||
/** create token manager for a file */
|
||||
private EcmaScriptTokenManager createTokenManager(File f) {
|
||||
try {
|
||||
ASCII_CharStream is = new ASCII_CharStream(new FileReader(f), 1, 1);
|
||||
EcmaScriptTokenManager mgr = new EcmaScriptTokenManager(is,0);
|
||||
return mgr;
|
||||
} catch ( FileNotFoundException shouldnotappear ) { }
|
||||
return null;
|
||||
}
|
||||
|
||||
/** connect all available specialTokens */
|
||||
private String getCommentFromToken(Token tok) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
while( tok.specialToken!=null ) {
|
||||
buf.append(tok.specialToken.toString() );
|
||||
tok = tok.specialToken;
|
||||
}
|
||||
return ( buf.toString().trim() );
|
||||
}
|
||||
|
||||
private String fileToFuncName(String f) {
|
||||
return fileToFuncName(new File(f));
|
||||
}
|
||||
|
||||
private String fileToFuncName(File f) {
|
||||
String tmp = f.getName();
|
||||
return tmp.substring(0,tmp.indexOf("."));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ( "[DocPrototype " + name + "]" );
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
// from helma.framework.IPathElement
|
||||
////////////////////////////////////
|
||||
|
||||
public String getElementName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public IPathElement getChildElement(String name) {
|
||||
for ( int i=0; i<functions.length; i++ ) {
|
||||
if ( name.equals( functions[i].getTypeName().toLowerCase()+"_"+functions[i].getName() ) )
|
||||
return functions[i];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// return getFunction(name);
|
||||
// }
|
||||
|
||||
public IPathElement getParentElement() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public java.lang.String getPrototype() {
|
||||
return "docprototype";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import helma.util.SystemProperties;
|
||||
|
||||
/**
|
||||
* Description of the Class
|
||||
*
|
||||
*@author Stefan Pollach
|
||||
*@created August 20, 2001
|
||||
*/
|
||||
public class DocRun {
|
||||
|
||||
/**
|
||||
* Description of the Field
|
||||
*/
|
||||
public static String propfile;
|
||||
/**
|
||||
* Description of the Field
|
||||
*/
|
||||
public static SystemProperties sysProps, dbProps;
|
||||
/**
|
||||
* Description of the Field
|
||||
*/
|
||||
public static String actionExtension = ".hac";
|
||||
/**
|
||||
* Description of the Field
|
||||
*/
|
||||
public static String scriptExtension = ".js";
|
||||
/**
|
||||
* Description of the Field
|
||||
*/
|
||||
public static String templateExtension = ".hsp";
|
||||
/**
|
||||
* Description of the Field
|
||||
*/
|
||||
public static String skinExtension = ".skin";
|
||||
|
||||
/**
|
||||
* Description of the Field
|
||||
*/
|
||||
public static String hopHomeDir;
|
||||
|
||||
public static Hashtable options = new Hashtable();
|
||||
|
||||
String appName;
|
||||
DocApplication app;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for the DocRun object
|
||||
*
|
||||
*@param appDir Description of Parameter
|
||||
*@exception DocException Description of Exception
|
||||
*/
|
||||
public DocRun(String appDir) throws DocException {
|
||||
File d = new File(appDir);
|
||||
if (!d.exists()) {
|
||||
throw new DocException(d.toString() + " doesn't exist");
|
||||
}
|
||||
if (!d.isDirectory()) {
|
||||
throw new DocException(d.toString() + " is not a directory");
|
||||
}
|
||||
log("parsing application " + d.getName() + " located in " + d.getAbsolutePath());
|
||||
log("writing output to " + getOption("-d", new File(hopHomeDir, "/appdocs/" + d.getName()).getAbsolutePath()));
|
||||
app = new DocApplication(d.getName(), d.getAbsolutePath());
|
||||
DocWriter.start(getOption("-d", new File(hopHomeDir, "/appdocs/" + d.getName()).getAbsolutePath()), app);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the option attribute of the DocRun class
|
||||
*
|
||||
*@param name Description of Parameter
|
||||
*@return The option value
|
||||
*/
|
||||
public static String getOption(String name) {
|
||||
return getOption(name, "");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the option attribute of the DocRun class
|
||||
*
|
||||
*@param name Description of Parameter
|
||||
*@param def Description of Parameter
|
||||
*@return The option value
|
||||
*/
|
||||
public static String getOption(String name, String def) {
|
||||
if (options.containsKey(name)) {
|
||||
return (String) options.get(name);
|
||||
} else {
|
||||
return (def);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Description of the Method
|
||||
*
|
||||
*@param args Description of Parameter
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
boolean usageError = false;
|
||||
// parse options from command line
|
||||
options = new Hashtable();
|
||||
StringBuffer buf = new StringBuffer();
|
||||
String name = "";
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i].startsWith("-")) {
|
||||
if (i > 0) {
|
||||
if (buf.toString().length() == 0) {
|
||||
usageError = true;
|
||||
} else {
|
||||
options.put(name, buf.toString());
|
||||
}
|
||||
}
|
||||
name = args[i];
|
||||
buf = new StringBuffer();
|
||||
} else {
|
||||
buf.append(((buf.toString().length() > 0) ? " " : "") + args[i]);
|
||||
}
|
||||
}
|
||||
options.put(name, buf.toString());
|
||||
// include last option
|
||||
// now check parameter
|
||||
if (options.containsKey("-h")) {
|
||||
hopHomeDir = (String) options.get("-h");
|
||||
} else {
|
||||
hopHomeDir = System.getProperty("user.dir");
|
||||
}
|
||||
readHopProperties(hopHomeDir);
|
||||
String parAppDir = "";
|
||||
if (options.containsKey("-a")) {
|
||||
parAppDir = (String) options.get("-a");
|
||||
} else {
|
||||
usageError = true;
|
||||
}
|
||||
if (usageError == true) {
|
||||
help();
|
||||
System.exit(0);
|
||||
}
|
||||
try {
|
||||
new DocRun(parAppDir);
|
||||
} catch (DocException e) {
|
||||
System.out.println("doc error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Description of the Method
|
||||
*/
|
||||
public static void help() {
|
||||
System.out.println("usage: java helma.doc.DocApplication -a appdir [-f] [-h hopdir] [-d docdir] [-i ignore]");
|
||||
System.out.println(" -a appdir Specify source directory");
|
||||
System.out.println(" -h hopdir Specify hop home directory");
|
||||
System.out.println(" -d docdir Specify destination directory");
|
||||
System.out.println(" -f true Link functions to source code");
|
||||
System.out.println(" -i ignore Specify prototypes to ignore (like: \"-i CVS mistsack\")");
|
||||
System.out.println(" -debug");
|
||||
System.out.println("\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Description of the Method
|
||||
*
|
||||
*@param name Description of Parameter
|
||||
*@return Description of the Returned Value
|
||||
*/
|
||||
public static boolean prototypeAllowed(String name) {
|
||||
String ig = " " + getOption("-i").toLowerCase() + " ";
|
||||
if (ig.equals("")) {
|
||||
return true;
|
||||
}
|
||||
name = name.toLowerCase();
|
||||
if (ig.indexOf(" " + name + " ") > -1) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* reads server.properties, apps.properties and db.properties from
|
||||
* hop-home-directory TBD: should be cleaned up to work exactly like the
|
||||
* helma server
|
||||
*
|
||||
*@param hopHomeDir Description of Parameter
|
||||
*/
|
||||
public static void readHopProperties(String hopHomeDir) {
|
||||
propfile = new File(hopHomeDir, "server.properties").getAbsolutePath();
|
||||
sysProps = new SystemProperties(propfile);
|
||||
dbProps = new SystemProperties(new File(hopHomeDir, "db.properties").getAbsolutePath());
|
||||
actionExtension = sysProps.getProperty("actionExtension", ".hac");
|
||||
scriptExtension = sysProps.getProperty("scriptExtension", ".js");
|
||||
templateExtension = sysProps.getProperty("templateExtension", ".hsp");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Description of the Method
|
||||
*
|
||||
*@param msg Description of Parameter
|
||||
*/
|
||||
public static void debug(String msg) {
|
||||
if (options.containsKey("-debug")) {
|
||||
System.out.println(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Description of the Method
|
||||
*
|
||||
*@param msg Description of Parameter
|
||||
*/
|
||||
public static void log(String msg) {
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class DocTag {
|
||||
|
||||
public static final int ARG = 0;
|
||||
public static final int PARAM = 1;
|
||||
public static final int RETURNS = 2;
|
||||
public static final int AUTHOR = 3;
|
||||
public static final int VERSION = 4;
|
||||
public static final int RELEASE = 5;
|
||||
public static final int SEE = 6;
|
||||
|
||||
/** number of different tag-types **/
|
||||
public static final int TYPE_COUNT = 7;
|
||||
|
||||
/** constants are used as array indices! **/
|
||||
public static final String[] kindNames = {"arg","param","return","author","version","release","see"};
|
||||
public static final String[] kindDesc = {"Arguments","Parameter","Returns","Author","Version","Release","See also"};
|
||||
|
||||
private String name;
|
||||
private int kind;
|
||||
private String text;
|
||||
|
||||
public DocTag( String rawTag ) throws DocException {
|
||||
//DocRun.log(rawTag);
|
||||
try {
|
||||
StringTokenizer tok = new StringTokenizer(rawTag);
|
||||
String kindstr = tok.nextToken().toLowerCase();
|
||||
for ( int i=0; i<kindNames.length; i++ ) {
|
||||
if ( kindstr.startsWith(kindNames[i]) ) {
|
||||
kind = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if ( kind==PARAM ) {
|
||||
name = tok.nextToken();
|
||||
}
|
||||
while ( tok.hasMoreTokens() ) {
|
||||
buf.append( tok.nextToken() + " " );
|
||||
}
|
||||
text = buf.toString();
|
||||
} catch ( Exception e ) { }
|
||||
}
|
||||
|
||||
public String getName() { return (name!=null && !name.equals("null"))?name:""; }
|
||||
public int getKind() { return kind; }
|
||||
public String getText() { return (text!=null && !text.equals("null"))?text:""; }
|
||||
|
||||
public String toString() {
|
||||
return "[" + ((name!=null)?name+" ":"" ) + text + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
package helma.doc;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class DocWriter extends DocHtmlWriter {
|
||||
|
||||
public static String docDir;
|
||||
|
||||
public DocWriter( String filename ) throws FileNotFoundException {
|
||||
super( new File(docDir,filename).getAbsolutePath() );
|
||||
DocRun.log("creating " + filename );
|
||||
}
|
||||
|
||||
public static void start( String parDocDir, DocApplication parApp ) {
|
||||
app = parApp;
|
||||
docDir = parDocDir;
|
||||
if ( !(new File(parDocDir).exists()) ) {
|
||||
DocRun.log("creating directory " + parDocDir );
|
||||
(new File(parDocDir)).mkdirs();
|
||||
}
|
||||
printStyleSheet(app);
|
||||
printFrameSet(app);
|
||||
printAppDoc(app);
|
||||
printAppIndex(app);
|
||||
printPrototypes(app);
|
||||
printFunctionIndex(app);
|
||||
if ( DocRun.getOption("-f").equals("true") )
|
||||
printFunctions(app);
|
||||
}
|
||||
|
||||
/** print index-1.html .. alphabetical list of all functions */
|
||||
public static void printFunctionIndex(DocApplication app) {
|
||||
try {
|
||||
DocWriter dw = new DocWriter("index-1.html");
|
||||
dw.printHeader("Application " + app.getName() );
|
||||
dw.printNavBar(app.getName(), null, INDEX );
|
||||
DocFunction[] df = app.listFunctions();
|
||||
Arrays.sort(df,new DocComparator(1,df[0]));
|
||||
dw.printFunctionIndex(df);
|
||||
dw.close();
|
||||
} catch ( FileNotFoundException e ) { DocRun.log( e.getMessage() ); }
|
||||
}
|
||||
|
||||
/** print stylesheet.css */
|
||||
public static void printStyleSheet(DocApplication app) {
|
||||
try {
|
||||
DocWriter dw = new DocWriter("stylesheet.css");
|
||||
dw.printStyleSheet();
|
||||
dw.close();
|
||||
} catch ( FileNotFoundException e ) { DocRun.log( e.getMessage() ); }
|
||||
}
|
||||
|
||||
/** print index.html */
|
||||
public static void printFrameSet(DocApplication app) {
|
||||
try {
|
||||
DocWriter dw = new DocWriter("index.html");
|
||||
dw.printHeader("Application " + app.getName() );
|
||||
dw.printFrameSet();
|
||||
dw.close();
|
||||
} catch ( FileNotFoundException e ) { DocRun.log( e.getMessage() ); }
|
||||
}
|
||||
|
||||
/** print app.html, list of prototypes */
|
||||
public static void printAppDoc(DocApplication app) {
|
||||
try {
|
||||
DocWriter dw = new DocWriter("app.html");
|
||||
dw.printHeader("Application " + app.getName() );
|
||||
dw.printNavBar(app.getName(), null, APPLICATION );
|
||||
dw.printElementTitle(app);
|
||||
dw.printComment(app);
|
||||
dw.printPrototypeList(app.listPrototypes(),"Prototypes");
|
||||
dw.close();
|
||||
} catch ( FileNotFoundException e ) { DocRun.log( e.getMessage() ); }
|
||||
}
|
||||
|
||||
/** print app-frame.html, content of left frame */
|
||||
public static void printAppIndex(DocApplication app) {
|
||||
try {
|
||||
DocWriter dw = new DocWriter("app-frame.html");
|
||||
dw.printHeader("Application " + app.getName() );
|
||||
dw.printAppIndexTitle(app.getName());
|
||||
dw.printAppIndexList((DocPrototype[])app.listPrototypes());
|
||||
dw.close();
|
||||
} catch ( FileNotFoundException e ) { DocRun.log( e.getMessage() ); }
|
||||
}
|
||||
|
||||
/** print all prototype-files, lists of functions */
|
||||
public static void printPrototypes(DocApplication app) {
|
||||
DocPrototype[] pt = app.listPrototypes();
|
||||
for ( int i=0; i<pt.length; i++ ) {
|
||||
try {
|
||||
DocWriter dw = new DocWriter( pt[i].getDocFileName());
|
||||
dw.printHeader("Application " + app.getName() + " / Prototype " + pt[i].getName());
|
||||
dw.printNavBar(app.getName(), pt[i], PROTOTYPE );
|
||||
dw.printElementTitle(pt[i]);
|
||||
dw.printComment(pt[i]);
|
||||
dw.printFunctionList(pt[i].listFunctions(DocElement.ACTION), "Actions");
|
||||
dw.printFunctionList(pt[i].listFunctions(DocElement.TEMPLATE), "Templates");
|
||||
dw.printFunctionList(pt[i].listFunctions(DocElement.FUNCTION), "Functions");
|
||||
dw.printFunctionList(pt[i].listFunctions(DocElement.MACRO), "Macros");
|
||||
dw.printFunctionList(pt[i].listFunctions(DocElement.SKIN), "Skins");
|
||||
dw.printInheritance(pt[i]);
|
||||
dw.close();
|
||||
} catch ( FileNotFoundException e ) { DocRun.log( e.getMessage() ); }
|
||||
}
|
||||
}
|
||||
|
||||
/** print all function sources */
|
||||
public static void printFunctions(DocApplication app) {
|
||||
DocFunction[] df = app.listFunctions();
|
||||
for ( int i=0;i<df.length; i++ ) {
|
||||
try {
|
||||
File d = new File ( docDir, df[i].getDocPrototype().getName().toLowerCase() );
|
||||
if ( !d.exists() )
|
||||
d.mkdir();
|
||||
DocWriter dw = new DocWriter( df[i].getDocPrototype().getName().toLowerCase() + "/" + df[i].getDocFileName() );
|
||||
dw.printHeader( app.getName() + "." + df[i].getDocPrototype().getName() + "." + df[i].getName() );
|
||||
dw.printNavBar( app.getName(), df[i].getDocPrototype(), DocHtmlWriter.METHOD);
|
||||
dw.printFunction( df[i] );
|
||||
dw.close();
|
||||
} catch ( FileNotFoundException e ) { DocRun.log( e.getMessage() ); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
// IPathElement.java
|
||||
// Copyright (c) Hannes Wallnöfer 2001
|
||||
|
||||
package helma.framework;
|
||||
|
||||
|
||||
/**
|
||||
* Interface that objects need to implement to build a Helma URL tree. Apart from methods
|
||||
* to retrieve the identifier and its child and parent elements, this interface defines a method
|
||||
* that determines which prototype to use to add scripts and skins to an object. <p>
|
||||
*
|
||||
* Please note that this interface is still work in progress. You should expect it to get some
|
||||
* additional methods that allow for looping through child elements, for example, or retrieving the
|
||||
* parent element. <p>
|
||||
*
|
||||
*/
|
||||
|
||||
public interface IPathElement {
|
||||
|
||||
/**
|
||||
* Return the name to be used to get this element from its parent
|
||||
*/
|
||||
public String getElementName ();
|
||||
|
||||
/**
|
||||
* Retrieve a child element of this object by name.
|
||||
*/
|
||||
public IPathElement getChildElement (String name);
|
||||
|
||||
/**
|
||||
* Return the parent element of this object.
|
||||
*/
|
||||
public IPathElement getParentElement ();
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the prototype to be used for this object. This will
|
||||
* determine which scripts, actions and skins can be called on it
|
||||
* within the Helma scripting and rendering framework.
|
||||
*/
|
||||
public String getPrototype ();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
package helma.framework;
|
||||
|
||||
import java.rmi.*;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* RMI interface for an application. Currently only execute is used and supported.
|
||||
|
@ -14,6 +13,8 @@ public interface IRemoteApp extends Remote {
|
|||
|
||||
public ResponseTrans execute (RequestTrans param) throws RemoteException;
|
||||
|
||||
public ResponseTrans get (String path, String sessionID) throws RemoteException;
|
||||
|
||||
public void ping () throws RemoteException;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
// IReplicatedApp.java
|
||||
// Copyright (c) Hannes Wallnöfer 2001
|
||||
|
||||
package helma.framework;
|
||||
|
||||
import java.rmi.*;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* RMI interface for an application that is able to replicate it's node cache.
|
||||
*/
|
||||
|
||||
public interface IReplicatedApp extends Remote {
|
||||
|
||||
public void replicateCache (Vector add, Vector delete) throws RemoteException;
|
||||
|
||||
}
|
|
@ -3,13 +3,14 @@
|
|||
|
||||
package helma.framework;
|
||||
|
||||
import FESI.Exceptions.EcmaScriptException;
|
||||
|
||||
/**
|
||||
* RedirectException is thrown internally when a response is redirected to a
|
||||
* new URL.
|
||||
*/
|
||||
|
||||
public class RedirectException extends RuntimeException {
|
||||
public class RedirectException extends EcmaScriptException {
|
||||
|
||||
String url;
|
||||
|
||||
|
@ -19,15 +20,15 @@ public class RedirectException extends RuntimeException {
|
|||
}
|
||||
|
||||
public String getMessage () {
|
||||
return url;
|
||||
return url;
|
||||
}
|
||||
|
||||
public void printStackTrace(java.io.PrintStream s) {
|
||||
// do nothing
|
||||
|
||||
}
|
||||
|
||||
public void printStackTrace(java.io.PrintWriter w) {
|
||||
// do nothing
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,64 +6,40 @@ package helma.framework;
|
|||
import java.io.*;
|
||||
import java.util.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.xmlrpc.Base64;
|
||||
|
||||
/**
|
||||
* A Transmitter for a request from the servlet client. Objects of this
|
||||
* class are directly exposed to JavaScript as global property req.
|
||||
*/
|
||||
|
||||
public class RequestTrans implements Externalizable {
|
||||
public class RequestTrans implements Serializable {
|
||||
|
||||
// the uri path of the request
|
||||
public String path;
|
||||
// the request's session id
|
||||
public String session;
|
||||
// the map of form and cookie data
|
||||
private Map values;
|
||||
// the request method - 0 for GET, 1 for POST
|
||||
private byte httpMethod = 0;
|
||||
private Hashtable values;
|
||||
|
||||
// this is used to hold the EcmaScript form data object
|
||||
public transient Object data;
|
||||
// when was execution started on this request?
|
||||
public transient long startTime;
|
||||
|
||||
// the name of the action being invoked
|
||||
public transient String action;
|
||||
|
||||
private transient String httpUsername;
|
||||
private transient String httpPassword;
|
||||
|
||||
static final long serialVersionUID = 5398880083482000580L;
|
||||
|
||||
/**
|
||||
* Create a new Request transmitter with an empty data map.
|
||||
*/
|
||||
public RequestTrans () {
|
||||
httpMethod = 0;
|
||||
values = new HashMap ();
|
||||
super ();
|
||||
values = new Hashtable ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new request transmitter with the given data map.
|
||||
*/
|
||||
public RequestTrans (byte method) {
|
||||
httpMethod = method;
|
||||
values = new HashMap ();
|
||||
public RequestTrans (Hashtable values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a parameter value in this request transmitter.
|
||||
*/
|
||||
public void set (String name, Object value) {
|
||||
values.put (name, value);
|
||||
}
|
||||
|
||||
public Enumeration keys () {
|
||||
return values.keys ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value from the requests map by key.
|
||||
*/
|
||||
public Object get (String name) {
|
||||
try {
|
||||
return values.get (name);
|
||||
|
@ -72,17 +48,10 @@ public class RequestTrans implements Externalizable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data map for this request transmitter.
|
||||
*/
|
||||
public Map getRequestData () {
|
||||
public Hashtable getReqData () {
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash code is computed from the session id if available. This is used to
|
||||
* detect multiple identic requests.
|
||||
*/
|
||||
public int hashCode () {
|
||||
return session == null ? super.hashCode () : session.hashCode ();
|
||||
}
|
||||
|
@ -97,80 +66,10 @@ public class RequestTrans implements Externalizable {
|
|||
RequestTrans other = (RequestTrans) what;
|
||||
return (session.equals (other.session) &&
|
||||
path.equalsIgnoreCase (other.path) &&
|
||||
values.equals (other.getRequestData ()));
|
||||
values.equals (other.getReqData ()));
|
||||
} catch (Exception x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this object represents a HTTP GET Request.
|
||||
*/
|
||||
public boolean isGet () {
|
||||
return httpMethod == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this object represents a HTTP GET Request.
|
||||
*/
|
||||
public boolean isPost () {
|
||||
return httpMethod == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom externalization code for quicker serialization.
|
||||
*/
|
||||
public void readExternal (ObjectInput s) throws ClassNotFoundException, IOException {
|
||||
path = s.readUTF ();
|
||||
session = s.readUTF ();
|
||||
values = (Map) s.readObject ();
|
||||
httpMethod = s.readByte ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom externalization code for quicker serialization.
|
||||
*/
|
||||
public void writeExternal (ObjectOutput s) throws IOException {
|
||||
s.writeUTF (path);
|
||||
s.writeUTF (session);
|
||||
s.writeObject (values);
|
||||
s.writeByte (httpMethod);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
if ( httpUsername!=null )
|
||||
return httpUsername;
|
||||
String auth = (String)get("authorization");
|
||||
if ( auth==null || "".equals(auth) ) {
|
||||
return null;
|
||||
}
|
||||
decodeHttpAuth(auth);
|
||||
return httpUsername;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
if ( httpPassword!=null )
|
||||
return httpPassword;
|
||||
String auth = (String)get("authorization");
|
||||
if ( auth==null || "".equals(auth) ) {
|
||||
return null;
|
||||
}
|
||||
decodeHttpAuth(auth);
|
||||
return httpPassword;
|
||||
}
|
||||
|
||||
private void decodeHttpAuth(String auth) {
|
||||
if ( auth==null )
|
||||
return;
|
||||
StringTokenizer tok;
|
||||
if( auth.startsWith("Basic ") )
|
||||
tok = new StringTokenizer ( new String( Base64.decode((auth.substring(6)).toCharArray()) ), ":" );
|
||||
else
|
||||
tok = new StringTokenizer ( new String( Base64.decode(auth.toCharArray()) ), ":" );
|
||||
try { httpUsername = tok.nextToken(); }
|
||||
catch ( NoSuchElementException e ) { httpUsername = null; }
|
||||
try { httpPassword = tok.nextToken(); }
|
||||
catch ( NoSuchElementException e ) { httpPassword = null; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,112 +13,47 @@ import helma.util.*;
|
|||
* class are directly exposed to JavaScript as global property res.
|
||||
*/
|
||||
|
||||
public class ResponseTrans implements Externalizable {
|
||||
public class ResponseTrans implements Serializable {
|
||||
|
||||
/**
|
||||
* Set the MIME content type of the response.
|
||||
*/
|
||||
public String contentType = "text/html";
|
||||
|
||||
/**
|
||||
* Set the charset of the response.
|
||||
*/
|
||||
public String charset;
|
||||
|
||||
/**
|
||||
* used to allow or disable client side caching
|
||||
*/
|
||||
public boolean cache = true;
|
||||
|
||||
/**
|
||||
* Used for HTTP response code, if 0 code 200 OK will be used.
|
||||
*/
|
||||
public int status = 0;
|
||||
|
||||
/**
|
||||
* Used for HTTP authentication
|
||||
*/
|
||||
public String realm;
|
||||
|
||||
// name of the skin to be rendered after completion, if any
|
||||
public transient String skin = null;
|
||||
|
||||
// the actual response
|
||||
private byte[] response = null;
|
||||
|
||||
// contains the redirect URL
|
||||
private String redir = null;
|
||||
public String redirect = null;
|
||||
|
||||
// cookies
|
||||
String cookieKeys[];
|
||||
String cookieValues[];
|
||||
int cookieDays[];
|
||||
public String cookieKeys[];
|
||||
public String cookieValues[];
|
||||
public int cookieDays[];
|
||||
int nCookies = 0;
|
||||
|
||||
// used to allow or disable client side caching
|
||||
public boolean cache = true;
|
||||
|
||||
// the buffer used to build the response
|
||||
private transient StringBuffer buffer = null;
|
||||
// these are used to implement the _as_string variants for Hop templates.
|
||||
private transient Stack buffers;
|
||||
|
||||
// the path used to resolve skin names
|
||||
private transient Object skinpath = null;
|
||||
// the processed skinpath as array of Nodes or directory names
|
||||
private transient Object[] translatedSkinpath = null;
|
||||
|
||||
static final long serialVersionUID = -8627370766119740844L;
|
||||
|
||||
/**
|
||||
* the buffers used to build the single body parts -
|
||||
* transient, response must be constructed before this is serialized
|
||||
*/
|
||||
// the buffers used to build the single body parts -
|
||||
// transient, response must be constructed before this is serialized
|
||||
public transient String title, head, body, message, error;
|
||||
|
||||
/**
|
||||
* JavaScript object to make the values Map accessible to
|
||||
* script code as res.data
|
||||
*/
|
||||
public transient Object data;
|
||||
|
||||
// the map of form and cookie data
|
||||
private transient Map values;
|
||||
// name of the skin to be rendered after completion, if any
|
||||
public transient String mainSkin = null;
|
||||
|
||||
|
||||
public ResponseTrans () {
|
||||
super ();
|
||||
title = head = body = message = error = null;
|
||||
values = new HashMap ();
|
||||
title = head = body = message = error = "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a value from the responses map by key.
|
||||
*/
|
||||
public Object get (String name) {
|
||||
try {
|
||||
return values.get (name);
|
||||
} catch (Exception x) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data map for this response transmitter.
|
||||
*/
|
||||
public Map getResponseData () {
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the response object to its initial empty state.
|
||||
*/
|
||||
public void reset () {
|
||||
if (buffer != null)
|
||||
buffer.setLength (0);
|
||||
response = null;
|
||||
redir = null;
|
||||
skin = null;
|
||||
title = head = body = message = error = null;
|
||||
values.clear ();
|
||||
redirect = null;
|
||||
mainSkin = null;
|
||||
title = head = body = message = error = "";
|
||||
}
|
||||
|
||||
|
||||
|
@ -154,26 +89,6 @@ public class ResponseTrans implements Externalizable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function that appends a <br> to whatever is written
|
||||
*/
|
||||
public void writeln (Object what) {
|
||||
if (buffer == null)
|
||||
buffer = new StringBuffer (512);
|
||||
if (what != null)
|
||||
buffer.append (what.toString ());
|
||||
buffer.append ("<br />\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a part from a char array to the response buffer.
|
||||
*/
|
||||
public void writeCharArray (char[] c, int start, int length) {
|
||||
if (buffer == null)
|
||||
buffer = new StringBuffer (512);
|
||||
buffer.append (c, start, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace special characters with entities, including <, > and ", thus allowing
|
||||
* no HTML tags.
|
||||
|
@ -212,18 +127,6 @@ public class ResponseTrans implements Externalizable {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode HTML entities, but leave newlines alone. This is for the content of textarea forms.
|
||||
*/
|
||||
public void encodeForm (Object what) {
|
||||
if (what != null) {
|
||||
if (buffer == null)
|
||||
buffer = new StringBuffer (512);
|
||||
HtmlEncoder.encodeAll (what.toString (), buffer, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void append (String what) {
|
||||
if (what != null) {
|
||||
if (buffer == null)
|
||||
|
@ -233,51 +136,23 @@ public class ResponseTrans implements Externalizable {
|
|||
}
|
||||
|
||||
public void redirect (String url) throws RedirectException {
|
||||
redir = url;
|
||||
redirect = url;
|
||||
throw new RedirectException (url);
|
||||
}
|
||||
|
||||
public String getRedirect () {
|
||||
return redir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow to directly set the byte array for the response. Calling this more than once will
|
||||
* overwrite the previous output. We take a generic object as parameter to be able to
|
||||
* generate a better error message, but it must be byte[].
|
||||
*/
|
||||
public void writeBinary (byte[] what) {
|
||||
response = what;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This has to be called after writing to this response has finished and before it is shipped back to the
|
||||
* web server. Transforms the string buffer into a char array to minimize size.
|
||||
*/
|
||||
public synchronized void close (String cset) throws UnsupportedEncodingException {
|
||||
// only use default charset if not explicitly set for this response.
|
||||
if (charset == null)
|
||||
charset = cset;
|
||||
|
||||
boolean error = false;
|
||||
if (response == null) {
|
||||
if (buffer != null) {
|
||||
try {
|
||||
response = buffer.toString ().getBytes (charset);
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
error = true;
|
||||
response = buffer.toString ().getBytes ();
|
||||
}
|
||||
buffer = null; // make sure this is done only once, even with more requsts attached
|
||||
} else {
|
||||
response = new byte[0];
|
||||
}
|
||||
public synchronized void close () {
|
||||
if (buffer != null) {
|
||||
response = buffer.toString ().getBytes ();
|
||||
buffer = null; // make sure this is done only once, even with more requsts attached
|
||||
} else {
|
||||
response = new byte[0];
|
||||
}
|
||||
notifyAll ();
|
||||
// if there was a problem with the encoding, let the app know
|
||||
if (error)
|
||||
throw new UnsupportedEncodingException (charset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -302,26 +177,7 @@ public class ResponseTrans implements Externalizable {
|
|||
}
|
||||
|
||||
public String getContentType () {
|
||||
if (charset != null)
|
||||
return contentType+"; charset="+charset;
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setSkinpath (Object obj) {
|
||||
this.skinpath = obj;
|
||||
this.translatedSkinpath = null;
|
||||
}
|
||||
|
||||
public Object getSkinpath () {
|
||||
return skinpath;
|
||||
}
|
||||
|
||||
public void setTranslatedSkinpath (Object[] arr) {
|
||||
this.translatedSkinpath = arr;
|
||||
}
|
||||
|
||||
public Object[] getTranslatedSkinpath () {
|
||||
return translatedSkinpath;
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public synchronized void setCookie (String key, String value) {
|
||||
|
@ -371,31 +227,6 @@ public class ResponseTrans implements Externalizable {
|
|||
return cookieValues[i];
|
||||
}
|
||||
|
||||
public void readExternal (ObjectInput s) throws ClassNotFoundException, IOException {
|
||||
contentType = (String) s.readObject ();
|
||||
response = (byte[]) s.readObject ();
|
||||
redir = (String) s.readObject ();
|
||||
cookieKeys = (String[]) s.readObject ();
|
||||
cookieValues = (String[]) s.readObject ();
|
||||
cookieDays = (int[]) s.readObject ();
|
||||
nCookies = s.readInt ();
|
||||
cache = s.readBoolean ();
|
||||
status = s.readInt ();
|
||||
realm = (String) s.readObject ();
|
||||
}
|
||||
|
||||
public void writeExternal (ObjectOutput s) throws IOException {
|
||||
s.writeObject (contentType);
|
||||
s.writeObject (response);
|
||||
s.writeObject (redir);
|
||||
s.writeObject (cookieKeys);
|
||||
s.writeObject (cookieValues);
|
||||
s.writeObject (cookieDays);
|
||||
s.writeInt (nCookies);
|
||||
s.writeBoolean (cache);
|
||||
s.writeInt (status);
|
||||
s.writeObject (realm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
// ActionFile.java
|
||||
// Action.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.scripting.fesi;
|
||||
package helma.framework.core;
|
||||
|
||||
import helma.scripting.*;
|
||||
import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.util.Updatable;
|
||||
import helma.objectmodel.IServer;
|
||||
import FESI.Data.*;
|
||||
import FESI.Parser.*;
|
||||
import FESI.AST.ASTFormalParameterList;
|
||||
|
@ -21,64 +18,90 @@ import FESI.Exceptions.*;
|
|||
|
||||
|
||||
/**
|
||||
* An class that updates fesi interpreters with actionfiles and templates.
|
||||
* An Action is a JavaScript function that is exposed as a URI. It is
|
||||
* usually represented by a file with extension .hac (hop action file)
|
||||
* that contains the pure JavaScript body of the function.
|
||||
*/
|
||||
|
||||
|
||||
public class FesiActionAdapter {
|
||||
public class Action {
|
||||
|
||||
String name;
|
||||
String functionName;
|
||||
Prototype prototype;
|
||||
Application app;
|
||||
String sourceName;
|
||||
File file;
|
||||
long lastmod;
|
||||
|
||||
// this is the parsed function which can be easily applied to RequestEvaluator objects
|
||||
TypeUpdater pfunc;
|
||||
|
||||
public FesiActionAdapter (ActionFile action) {
|
||||
prototype = action.getPrototype ();
|
||||
app = action.getApplication ();
|
||||
String content = action.getContent ();
|
||||
String functionName = action.getFunctionName ();
|
||||
sourceName = action.toString ();
|
||||
try {
|
||||
pfunc = parseFunction (functionName, "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", content);
|
||||
} catch (Throwable x) {
|
||||
String message = x.getMessage ();
|
||||
pfunc = new ErrorFeedback (functionName, message);
|
||||
}
|
||||
|
||||
public Action (File file, String name, Prototype proto) {
|
||||
this.prototype = proto;
|
||||
this.app = proto.app;
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
update (file);
|
||||
}
|
||||
|
||||
/* protected void update (FesiEvaluator fesi) throws Exception {
|
||||
// app.logEvent ("Reading text template " + name);
|
||||
|
||||
FesiScriptingEnvironment scriptEnv = (FesiScriptingEnvironment) app.getScriptingEnvironment ();
|
||||
Iterator evals = scriptEnv.getEvaluators().iterator();
|
||||
while (evals.hasNext ()) {
|
||||
try {
|
||||
FesiEvaluator fesi = (FesiEvaluator) evals.next ();
|
||||
updateEvaluator (fesi);
|
||||
} catch (Exception ignore) {}
|
||||
public void update (File f) {
|
||||
|
||||
this.file = f;
|
||||
long fmod = file.lastModified ();
|
||||
if (lastmod == fmod)
|
||||
return;
|
||||
|
||||
try {
|
||||
FileReader reader = new FileReader (file);
|
||||
char cbuf[] = new char[(int) file.length ()];
|
||||
reader.read (cbuf);
|
||||
reader.close ();
|
||||
String content = new String (cbuf);
|
||||
update (content);
|
||||
} catch (Exception filex) {
|
||||
IServer.getLogger().log ("*** Error reading action file "+file+": "+filex);
|
||||
}
|
||||
} */
|
||||
lastmod = fmod;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void update (String content) throws Exception {
|
||||
// IServer.getLogger().log ("Reading text template " + name);
|
||||
|
||||
functionName = name+"_hop_action";
|
||||
|
||||
try {
|
||||
pfunc = parseFunction (functionName, "arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10", content);
|
||||
} catch (Exception x) {
|
||||
String message = x.getMessage ();
|
||||
pfunc = new ErrorFeedback (functionName, message);
|
||||
}
|
||||
|
||||
/* protected void remove () {
|
||||
Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
|
||||
while (evals.hasNext ()) {
|
||||
try {
|
||||
RequestEvaluator reval = (RequestEvaluator) evals.next ();
|
||||
ObjectPrototype op = reval.getPrototype (prototype.getName());
|
||||
functionName = name+"_action";
|
||||
ESValue esv = (ESValue) op.getProperty (functionName, functionName.hashCode());
|
||||
if (esv instanceof ConstructedFunctionObject || esv instanceof ThrowException) {
|
||||
op.deleteProperty (functionName, functionName.hashCode());
|
||||
}
|
||||
updateRequestEvaluator (reval);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
|
||||
public synchronized void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
|
||||
public String getName () {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getFunctionName () {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
|
||||
public synchronized void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
|
||||
if (pfunc != null)
|
||||
pfunc.updateEvaluator (fesi);
|
||||
pfunc.updateRequestEvaluator (reval);
|
||||
}
|
||||
|
||||
protected TypeUpdater parseFunction (String funcname, String params, String body) throws EcmaScriptException {
|
||||
|
@ -122,10 +145,10 @@ public class FesiActionAdapter {
|
|||
sl = (ASTStatementList) parser.StatementList();
|
||||
is.close();
|
||||
} catch (ParseException x) {
|
||||
app.logEvent ("Error parsing file "+app.getName()+":"+sourceName+": "+x);
|
||||
IServer.getLogger().log ("Error parsing file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+x);
|
||||
throw new EcmaScriptParseException (x, new StringEvaluationSource(fulltext, null));
|
||||
} catch (Exception x) {
|
||||
app.logEvent ("Error parsing file "+app.getName()+":"+sourceName+": "+x);
|
||||
IServer.getLogger().log ("Error parsing file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+x);
|
||||
throw new RuntimeException (x.getMessage ());
|
||||
}
|
||||
|
||||
|
@ -150,15 +173,15 @@ public class FesiActionAdapter {
|
|||
this.functionName = functionName;
|
||||
}
|
||||
|
||||
public void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
|
||||
public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
|
||||
|
||||
ObjectPrototype op = fesi.getPrototype (prototype.getName());
|
||||
ObjectPrototype op = reval.getPrototype (prototype.getName());
|
||||
|
||||
EcmaScriptVariableVisitor vdvisitor = fesi.evaluator.getVarDeclarationVisitor();
|
||||
EcmaScriptVariableVisitor vdvisitor = reval.evaluator.getVarDeclarationVisitor();
|
||||
Vector vnames = vdvisitor.processVariableDeclarations(sl, fes);
|
||||
|
||||
FunctionPrototype fp = ConstructedFunctionObject.makeNewConstructedFunction (
|
||||
fesi.evaluator, functionName, fes,
|
||||
reval.evaluator, functionName, fes,
|
||||
fullFunctionText, fpl.getArguments(), vnames, sl);
|
||||
op.putHiddenProperty (functionName, fp);
|
||||
}
|
||||
|
@ -174,12 +197,12 @@ public class FesiActionAdapter {
|
|||
errorMessage = msg;
|
||||
}
|
||||
|
||||
public void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException {
|
||||
public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
|
||||
|
||||
ObjectPrototype op = fesi.getPrototype (prototype.getName ());
|
||||
ObjectPrototype op = reval.getPrototype (prototype.getName ());
|
||||
|
||||
FunctionPrototype fp = (FunctionPrototype) fesi.evaluator.getFunctionPrototype ();
|
||||
FunctionPrototype func = new ThrowException (functionName, fesi.evaluator, fp, errorMessage);
|
||||
FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype ();
|
||||
FunctionPrototype func = new ThrowException (functionName, reval.evaluator, fp, errorMessage);
|
||||
op.putHiddenProperty (functionName, func);
|
||||
|
||||
}
|
||||
|
@ -200,8 +223,38 @@ public class FesiActionAdapter {
|
|||
}
|
||||
|
||||
interface TypeUpdater {
|
||||
public void updateEvaluator (FesiEvaluator fesi) throws EcmaScriptException;
|
||||
public void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,14 +1,12 @@
|
|||
// ESAppNode.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.scripting.fesi;
|
||||
package helma.framework.core;
|
||||
|
||||
import helma.framework.core.*;
|
||||
import helma.objectmodel.*;
|
||||
import FESI.Exceptions.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Interpreter.Evaluator;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* ESApp represents the app node of an application, providing an app-wide transient shared
|
||||
|
@ -20,18 +18,17 @@ public class ESAppNode extends ESNode {
|
|||
private Application app;
|
||||
private DatePrototype createtime;
|
||||
|
||||
public ESAppNode (INode node, FesiEvaluator eval) throws EcmaScriptException {
|
||||
super (eval.getPrototype("hopobject"), eval.getEvaluator(), node, eval);
|
||||
app = eval.getApplication();
|
||||
createtime = new DatePrototype (evaluator, node.created());
|
||||
FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
|
||||
public ESAppNode (INode node, RequestEvaluator eval) throws EcmaScriptException {
|
||||
super (eval.esNodePrototype, eval.evaluator, node, eval);
|
||||
app = eval.app;
|
||||
createtime = new DatePrototype (eval.evaluator, node.created());
|
||||
FunctionPrototype fp = (FunctionPrototype) eval.evaluator.getFunctionPrototype();
|
||||
putHiddenProperty("getThreads", new AppCountThreads ("getThreads", evaluator, fp));
|
||||
putHiddenProperty("getMaxThreads", new AppCountEvaluators ("getMaxThreads", evaluator, fp));
|
||||
putHiddenProperty("getFreeThreads", new AppCountFreeEvaluators ("getFreeThreads", evaluator, fp));
|
||||
putHiddenProperty("getActiveThreads", new AppCountActiveEvaluators ("getActiveThreads", evaluator, fp));
|
||||
putHiddenProperty("getMaxActiveThreads", new AppCountMaxActiveEvaluators ("getMaxActiveThreads", evaluator, fp));
|
||||
putHiddenProperty("getActiveThreads", new AppCountBusyEvaluators ("getActiveThreads", evaluator, fp));
|
||||
putHiddenProperty("getMaxActiveThreads", new AppCountMaxBusyEvaluators ("getMaxActiveThreads", evaluator, fp));
|
||||
putHiddenProperty("setMaxThreads", new AppSetNumberOfEvaluators ("setMaxThreads", evaluator, fp));
|
||||
putHiddenProperty("clearCache", new AppClearCache ("clearCache", evaluator, fp));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,32 +36,17 @@ public class ESAppNode extends ESNode {
|
|||
*/
|
||||
public ESValue getProperty (String propname, int hash) throws EcmaScriptException {
|
||||
if ("requestCount".equals (propname)) {
|
||||
return new ESNumber (app.getRequestCount ());
|
||||
return new ESNumber (app.requestCount);
|
||||
}
|
||||
if ("xmlrpcCount".equals (propname)) {
|
||||
return new ESNumber (app.getXmlrpcCount ());
|
||||
return new ESNumber (app.xmlrpcCount);
|
||||
}
|
||||
if ("errorCount".equals (propname)) {
|
||||
return new ESNumber (app.getErrorCount ());
|
||||
return new ESNumber (app.errorCount);
|
||||
}
|
||||
if ("upSince".equals (propname)) {
|
||||
return createtime;
|
||||
}
|
||||
if ("skinfiles".equals (propname)) {
|
||||
ESObject skinz = new ObjectPrototype (null, evaluator);
|
||||
for (Iterator it = app.getPrototypes().iterator(); it.hasNext(); ) {
|
||||
Prototype p = (Prototype) it.next ();
|
||||
ESObject proto = new ObjectPrototype (null, evaluator);
|
||||
for (Iterator it2 = p.skins.values().iterator(); it2.hasNext(); ) {
|
||||
SkinFile sf = (SkinFile) it2.next ();
|
||||
String name = sf.getName ();
|
||||
Skin skin = sf.getSkin ();
|
||||
proto.putProperty (name, new ESString (skin.getSource ()), name.hashCode ());
|
||||
}
|
||||
skinz.putProperty (p.getName (), proto, p.getName ().hashCode ());
|
||||
}
|
||||
return skinz;
|
||||
}
|
||||
if ("__app__".equals (propname)) {
|
||||
return new ESWrapper (app, evaluator);
|
||||
}
|
||||
|
@ -77,7 +59,7 @@ public class ESAppNode extends ESNode {
|
|||
super (fp, evaluator, name, 0);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESNumber (app.countEvaluators ());
|
||||
return new ESNumber (app.allThreads.size()-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,25 +68,25 @@ public class ESAppNode extends ESNode {
|
|||
super (fp, evaluator, name, 0);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESNumber (app.countFreeEvaluators ());
|
||||
return new ESNumber (app.freeThreads.size());
|
||||
}
|
||||
}
|
||||
|
||||
class AppCountActiveEvaluators extends BuiltinFunctionObject {
|
||||
AppCountActiveEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
class AppCountBusyEvaluators extends BuiltinFunctionObject {
|
||||
AppCountBusyEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 0);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESNumber (app.countActiveEvaluators ());
|
||||
return new ESNumber (app.allThreads.size() - app.freeThreads.size() -1);
|
||||
}
|
||||
}
|
||||
|
||||
class AppCountMaxActiveEvaluators extends BuiltinFunctionObject {
|
||||
AppCountMaxActiveEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
class AppCountMaxBusyEvaluators extends BuiltinFunctionObject {
|
||||
AppCountMaxBusyEvaluators (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 0);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESNumber (app.countMaxActiveEvaluators ());
|
||||
return new ESNumber (app.typemgr.countRegisteredRequestEvaluators () -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,7 +95,7 @@ public class ESAppNode extends ESNode {
|
|||
super (fp, evaluator, name, 0);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESNumber (app.countThreads ());
|
||||
return new ESNumber (app.threadgroup.activeCount() -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,25 +107,59 @@ public class ESAppNode extends ESNode {
|
|||
RequestEvaluator ev = new RequestEvaluator (app);
|
||||
if (arguments.length != 1)
|
||||
return ESBoolean.makeBoolean (false);
|
||||
// add one to the number to compensate for the internal scheduler.
|
||||
return ESBoolean.makeBoolean (app.setNumberOfEvaluators (1 + arguments[0].toInt32()));
|
||||
}
|
||||
}
|
||||
|
||||
class AppClearCache extends BuiltinFunctionObject {
|
||||
AppClearCache (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
app.clearCache ();
|
||||
return ESBoolean.makeBoolean (true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString () {
|
||||
return ("AppNode "+node.getElementName ());
|
||||
return ("AppNode "+node.getNameOrID ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -2,11 +2,9 @@
|
|||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
|
||||
package helma.scripting.fesi;
|
||||
package helma.framework.core;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.util.*;
|
||||
import FESI.Interpreter.*;
|
||||
import FESI.Exceptions.*;
|
||||
|
@ -24,106 +22,158 @@ import java.util.*;
|
|||
public class ESNode extends ObjectPrototype {
|
||||
|
||||
INode node;
|
||||
|
||||
// the cache node - persistent nodes have a transient property as a commodity to
|
||||
// store temporary stuff.
|
||||
INode cache;
|
||||
// the ecmascript wrapper for the cache.
|
||||
ESNode cacheWrapper;
|
||||
|
||||
// The handle of the wrapped Node. Makes ESNodes comparable without accessing the wrapped node.
|
||||
NodeHandle handle;
|
||||
// The ID of the wrapped Node. Makes ESNodes comparable without accessing the wrapped node.
|
||||
String nodeID;
|
||||
DbMapping dbmap;
|
||||
ESObject cacheWrapper;
|
||||
Throwable lastError = null;
|
||||
FesiEvaluator eval;
|
||||
RequestEvaluator eval;
|
||||
|
||||
/**
|
||||
* Constructor used to create transient cache nodes
|
||||
*/
|
||||
public ESNode (INode node, FesiEvaluator eval) {
|
||||
super (eval.getPrototype("hopobject"), eval.getEvaluator());
|
||||
this.eval = eval;
|
||||
this.node = node;
|
||||
cache = null;
|
||||
cacheWrapper = null;
|
||||
// used to create cache nodes
|
||||
protected ESNode (INode node, RequestEvaluator eval) {
|
||||
super (eval.esNodePrototype, eval.evaluator);
|
||||
this.eval = eval;
|
||||
this.node = node;
|
||||
cache = null;
|
||||
|
||||
// this is a transient node, set node handle to null
|
||||
handle = null;
|
||||
cacheWrapper = null;
|
||||
nodeID = node.getID ();
|
||||
dbmap = node.getDbMapping ();
|
||||
}
|
||||
|
||||
public ESNode (ESObject prototype, Evaluator evaluator, Object obj, FesiEvaluator eval) {
|
||||
super (prototype, evaluator);
|
||||
// eval.app.logEvent ("in ESNode constructor: "+o.getClass ());
|
||||
this.eval = eval;
|
||||
if (obj == null)
|
||||
node = new TransientNode (null);
|
||||
else if (obj instanceof ESWrapper)
|
||||
node = (INode) ((ESWrapper) obj).getJavaObject ();
|
||||
else if (obj instanceof INode)
|
||||
node = (INode) obj;
|
||||
else
|
||||
node = new TransientNode (obj.toString ());
|
||||
// set node handle to wrapped node
|
||||
if (node instanceof Node)
|
||||
handle = ((Node) node).getHandle ();
|
||||
else
|
||||
handle = null;
|
||||
public ESNode (ESObject prototype, Evaluator evaluator, Object obj, RequestEvaluator eval) {
|
||||
super (prototype, evaluator);
|
||||
// IServer.getLogger().log ("in ESNode constructor: "+o.getClass ());
|
||||
this.eval = eval;
|
||||
if (obj == null)
|
||||
node = new Node ();
|
||||
else if (obj instanceof ESWrapper)
|
||||
node = (INode) ((ESWrapper) obj).getJavaObject ();
|
||||
else if (obj instanceof INode)
|
||||
node = (INode) obj;
|
||||
else
|
||||
node = new Node (obj.toString ());
|
||||
// set nodeID to id of wrapped node
|
||||
nodeID = node.getID ();
|
||||
dbmap = node.getDbMapping ();
|
||||
|
||||
// cache Node is initialized on demend when it is needed
|
||||
cache = null;
|
||||
cacheWrapper = null;
|
||||
// get transient cache Node
|
||||
cache = node.getCacheNode ();
|
||||
cacheWrapper = new ESNode (cache, eval);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node has been invalidated. If so, it has to be re-fetched
|
||||
* from the db via the app's node manager.
|
||||
*/
|
||||
protected void checkNode () {
|
||||
private void checkNode () {
|
||||
if (node.getState () == INode.INVALID) try {
|
||||
node = handle.getNode (eval.app.getWrappedNodeManager ());
|
||||
setNode (eval.app.nmgr.getNode (node.getID (), node.getDbMapping ()));
|
||||
} catch (Exception nx) {}
|
||||
}
|
||||
|
||||
public INode getNode () {
|
||||
checkNode ();
|
||||
return node;
|
||||
public INode getNode () {
|
||||
checkNode ();
|
||||
return node;
|
||||
}
|
||||
|
||||
public void setNode (INode node) {
|
||||
if (node != null) {
|
||||
this.node = node;
|
||||
nodeID = node.getID ();
|
||||
dbmap = node.getDbMapping ();
|
||||
eval.objectcache.put (node, this);
|
||||
// get transient cache Node
|
||||
cache = node.getCacheNode ();
|
||||
cacheWrapper = new ESNode (cache, eval);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPrototype (String protoName) {
|
||||
checkNode ();
|
||||
node.setPrototype (protoName);
|
||||
checkNode ();
|
||||
node.setPrototype (protoName);
|
||||
}
|
||||
|
||||
public String getPrototypeName () {
|
||||
return node.getPrototype ();
|
||||
return node.getPrototype ();
|
||||
}
|
||||
|
||||
public String getESClassName () {
|
||||
return "HopObject";
|
||||
return "HopObject";
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
if (node == null)
|
||||
return "<null>";
|
||||
return node.toString ();
|
||||
if (node == null)
|
||||
return "<null>";
|
||||
return node.toString ();
|
||||
}
|
||||
|
||||
public String toDetailString () {
|
||||
return "ES:[Object: builtin " + this.getClass().getName() + ":" +
|
||||
((node == null) ? "null" : node.toString()) + "]";
|
||||
return "ES:[Object: builtin " + this.getClass().getName() + ":" +
|
||||
((node == null) ? "null" : node.toString()) + "]";
|
||||
}
|
||||
|
||||
protected void setError (Throwable e) {
|
||||
lastError = e;
|
||||
lastError = e;
|
||||
}
|
||||
|
||||
|
||||
public boolean setContent (ESValue what[]) {
|
||||
checkNode ();
|
||||
if (what.length > 0) {
|
||||
if (what[0] instanceof ESString) {
|
||||
node.setContent (what[0].toString ());
|
||||
return true;
|
||||
}
|
||||
if (what[0] instanceof ESWrapper) {
|
||||
Object o = ((ESWrapper) what[0]).toJavaObject ();
|
||||
if (o instanceof INode) {
|
||||
try {
|
||||
INode p = (INode) o;
|
||||
node.setContent (p.getContent (), p.getContentType ());
|
||||
return true;
|
||||
} catch (Exception x) {
|
||||
IServer.getLogger().log ("error in ESNode.setContent: "+x);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (what[0] instanceof ESNode) {
|
||||
INode i = ((ESNode) what[0]).getNode ();
|
||||
try {
|
||||
node.setContent (i.getContent (), i.getContentType ());
|
||||
return true;
|
||||
} catch (Exception x) {
|
||||
IServer.getLogger().log ("error in ESNode.setContent: "+x);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object getContent () {
|
||||
checkNode ();
|
||||
if (node.getContentLength () == 0)
|
||||
return null;
|
||||
String contentType = node.getContentType ();
|
||||
if (contentType != null && contentType.startsWith ("text/")) {
|
||||
return node.getText ();
|
||||
} else {
|
||||
return node.getContent ();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean add (ESValue what[]) {
|
||||
checkNode ();
|
||||
for (int i=0; i<what.length; i++)
|
||||
if (what[i] instanceof ESNode) {
|
||||
ESNode esn = (ESNode) what[i];
|
||||
INode added = node.addNode (esn.getNode ());
|
||||
// only rewrap if a transient node was addet to a persistent one.
|
||||
if (esn.getNode () instanceof helma.objectmodel.Node &&
|
||||
!(node instanceof helma.objectmodel.Node))
|
||||
esn.rewrap (added);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -153,25 +203,61 @@ public class ESNode extends ObjectPrototype {
|
|||
throw new EcmaScriptException ("Can ony add Node objects as subnodes");
|
||||
ESNode esn = (ESNode) what[1];
|
||||
INode added = node.addNode (esn.getNode (), (int) what[0].toInt32 ());
|
||||
// only rewrap if a transient node was addet to a persistent one.
|
||||
if (esn.getNode () instanceof helma.objectmodel.Node &&
|
||||
!(node instanceof helma.objectmodel.Node))
|
||||
esn.rewrap (added);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is necessary to remap ESNodes to their new peers
|
||||
* when they go from transient to persistent state.
|
||||
*/
|
||||
protected void rewrap (INode newnode) {
|
||||
// IServer.getLogger().log ("rewrapping "+this+" from "+node+" to "+newnode);
|
||||
if (newnode == null)
|
||||
throw new RuntimeException ("Non-consistent check-in detected in rewrap ()");
|
||||
INode oldnode = node;
|
||||
if (oldnode == newnode) {
|
||||
// IServer.getLogger().log ("loop detected or new peers unchanged in rewrap");
|
||||
return;
|
||||
}
|
||||
// set node and nodeID to new node
|
||||
node = newnode;
|
||||
nodeID = node.getID ();
|
||||
dbmap = node.getDbMapping ();
|
||||
|
||||
int l = oldnode.numberOfNodes ();
|
||||
for (int i=0; i<l; i++) {
|
||||
INode next = oldnode.getSubnodeAt (i);
|
||||
ESNode esn = eval.getNodeWrapperFromCache (next);
|
||||
// IServer.getLogger().log ("rewrapping node: "+next+" -> "+esn);
|
||||
if (esn != null) {
|
||||
esn.rewrap (newnode.getSubnodeAt (i));
|
||||
}
|
||||
}
|
||||
for (Enumeration e=oldnode.properties (); e.hasMoreElements (); ) {
|
||||
IProperty p = oldnode.get ((String) e.nextElement (), false);
|
||||
if (p != null && p.getType () == IProperty.NODE) {
|
||||
INode next = p.getNodeValue ();
|
||||
ESNode esn = eval.getNodeWrapperFromCache (next);
|
||||
if (esn != null) {
|
||||
esn.rewrap (newnode.getNode (p.getName (), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove node itself or one or more subnodes.
|
||||
* Remove one or more subnodes.
|
||||
*/
|
||||
public boolean remove (ESValue args[]) {
|
||||
checkNode ();
|
||||
// semantics: if called without arguments, remove self.
|
||||
// otherwise, remove given subnodes.
|
||||
if (args.length == 0) {
|
||||
return node.remove ();
|
||||
} else {
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (args[i] instanceof ESNode) {
|
||||
ESNode esn = (ESNode) args[i];
|
||||
node.removeNode (esn.getNode ());
|
||||
}
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (args[i] instanceof ESNode) {
|
||||
ESNode esn = (ESNode) args[i];
|
||||
node.removeNode (esn.getNode ());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -230,8 +316,9 @@ public class ESNode extends ObjectPrototype {
|
|||
|
||||
public void putProperty(String propertyName, ESValue propertyValue, int hash) throws EcmaScriptException {
|
||||
checkNode ();
|
||||
// eval.app.logEvent ("put property called: "+propertyName+", "+propertyValue.getClass());
|
||||
if ("cache".equalsIgnoreCase (propertyName))
|
||||
// IServer.getLogger().log ("put property called: "+propertyName+", "+propertyValue.getClass());
|
||||
if ("lastmodified".equalsIgnoreCase (propertyName) || "created".equalsIgnoreCase (propertyName) ||
|
||||
"contentlength".equalsIgnoreCase (propertyName) || "cache".equalsIgnoreCase (propertyName))
|
||||
throw new EcmaScriptException ("Can't modify read-only property \""+propertyName+"\".");
|
||||
|
||||
if ("subnodeRelation".equalsIgnoreCase (propertyName)) {
|
||||
|
@ -239,15 +326,9 @@ public class ESNode extends ObjectPrototype {
|
|||
return;
|
||||
}
|
||||
|
||||
// check if the property is write protected, i.e. the type.property file describes it as [readonly]
|
||||
DbMapping dbm = node.getDbMapping ();
|
||||
if (dbm != null) {
|
||||
Relation rel = dbm.getPropertyRelation (propertyName);
|
||||
if (rel != null && rel.isReadonly ())
|
||||
return;
|
||||
}
|
||||
|
||||
if (propertyValue instanceof ESNull || propertyValue instanceof ESUndefined)
|
||||
if ("contenttype".equalsIgnoreCase (propertyName))
|
||||
node.setContentType (propertyValue.toString ());
|
||||
else if (propertyValue instanceof ESNull)
|
||||
node.unset (propertyName);
|
||||
else if (propertyValue instanceof ESString)
|
||||
node.setString (propertyName, propertyValue.toString ());
|
||||
|
@ -261,9 +342,14 @@ public class ESNode extends ObjectPrototype {
|
|||
// long now = System.currentTimeMillis ();
|
||||
ESNode esn = (ESNode) propertyValue;
|
||||
node.setNode (propertyName, esn.getNode ());
|
||||
// eval.app.logEvent ("*** spent "+(System.currentTimeMillis () - now)+" ms to set property "+propertyName);
|
||||
if (esn.getNode () instanceof helma.objectmodel.Node &&
|
||||
!(node instanceof helma.objectmodel.Node)) {
|
||||
INode newnode = node.getNode (propertyName, false);
|
||||
esn.rewrap (newnode);
|
||||
}
|
||||
// IServer.getLogger().log ("*** spent "+(System.currentTimeMillis () - now)+" ms to set property "+propertyName);
|
||||
} else {
|
||||
// eval.app.logEvent ("got "+propertyValue.getClass ());
|
||||
// IServer.getLogger().log ("got "+propertyValue.getClass ());
|
||||
// A persistent node can't store anything other than the types above, so throw an exception
|
||||
// throw new EcmaScriptException ("Can't set a JavaScript Object or Array as property of "+node);
|
||||
node.setJavaObject (propertyName, propertyValue.toJavaObject ());
|
||||
|
@ -271,25 +357,25 @@ public class ESNode extends ObjectPrototype {
|
|||
}
|
||||
|
||||
public boolean deleteProperty(String propertyName, int hash) throws EcmaScriptException {
|
||||
checkNode ();
|
||||
// eval.app.logEvent ("delete property called: "+propertyName);
|
||||
if (node.get (propertyName, false) != null) {
|
||||
node.unset (propertyName);
|
||||
return true;
|
||||
}
|
||||
checkNode ();
|
||||
// IServer.getLogger().log ("delete property called: "+propertyName);
|
||||
if (node.get (propertyName, false) != null) {
|
||||
node.unset (propertyName);
|
||||
return true;
|
||||
}
|
||||
return super.deleteProperty (propertyName, hash);
|
||||
}
|
||||
|
||||
public ESValue getProperty (int i) throws EcmaScriptException {
|
||||
checkNode ();
|
||||
INode n = node.getSubnodeAt (i);
|
||||
checkNode ();
|
||||
INode n = node.getSubnodeAt (i);
|
||||
if (n == null)
|
||||
return ESNull.theNull;
|
||||
return eval.getNodeWrapper (n);
|
||||
return eval.getNodeWrapper (n);
|
||||
}
|
||||
|
||||
public void putProperty(int index, ESValue propertyValue) throws EcmaScriptException {
|
||||
checkNode ();
|
||||
checkNode ();
|
||||
if (propertyValue instanceof ESNode) {
|
||||
ESNode n = (ESNode) propertyValue;
|
||||
node.addNode (n.getNode (), index);
|
||||
|
@ -298,55 +384,29 @@ public class ESNode extends ObjectPrototype {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a property from the node object or the underlying EcmaScript prototype.
|
||||
* Normally we would first check the node object and then the prototype, but since
|
||||
* node properties are potentially expensive to look up because they require database
|
||||
* queries, we do the prototype lookup first. This usually doesn't cause any confusion
|
||||
* because generally things are divided cleanly between prototype and object - the
|
||||
* first holds the functions, the latter the mapped data properties.
|
||||
*/
|
||||
public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException {
|
||||
checkNode ();
|
||||
// eval.app.logEvent ("get property called: "+propertyName);
|
||||
checkNode ();
|
||||
// IServer.getLogger().log ("get property called: "+propertyName);
|
||||
ESValue retval = super.getProperty (propertyName, hash);
|
||||
if (! (retval instanceof ESUndefined))
|
||||
return retval;
|
||||
return getNodeProperty (propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a property only from the node itself, not the underlying EcmaScript prototype object.
|
||||
* This is called directly when we call get(x) on a hopobject, since we don't want to return
|
||||
* the prototype functions in that case.
|
||||
*/
|
||||
public ESValue getNodeProperty (String propertyName) throws EcmaScriptException {
|
||||
if ("cache".equalsIgnoreCase (propertyName) && cache != null)
|
||||
return cacheWrapper;
|
||||
if ("created".equalsIgnoreCase (propertyName))
|
||||
return new DatePrototype (evaluator, node.created ());
|
||||
if ("lastmodified".equalsIgnoreCase (propertyName))
|
||||
return new DatePrototype (evaluator, node.lastModified ());
|
||||
if ("contenttype".equalsIgnoreCase (propertyName))
|
||||
return new ESString (node.getContentType ());
|
||||
if ("contentlength".equalsIgnoreCase (propertyName))
|
||||
return new ESNumber (node.getContentLength ());
|
||||
|
||||
// persistent or persistent capable nodes have a cache property that's a transient node.
|
||||
// it it hasn't requested before, initialize it now
|
||||
if ("cache".equalsIgnoreCase (propertyName) && node instanceof Node) {
|
||||
cache = node.getCacheNode ();
|
||||
if (cacheWrapper == null)
|
||||
cacheWrapper = new ESNode (cache, eval);
|
||||
else
|
||||
cacheWrapper.node = cache;
|
||||
return cacheWrapper;
|
||||
}
|
||||
if ("subnodeRelation".equalsIgnoreCase (propertyName)) {
|
||||
String rel = node.getSubnodeRelation ();
|
||||
return rel == null ? (ESValue) ESNull.theNull : new ESString (rel);
|
||||
}
|
||||
|
||||
if ("_id".equals (propertyName))
|
||||
return new ESString (node.getID ());
|
||||
if ("_parent".equals (propertyName)) {
|
||||
INode n = node.getParent ();
|
||||
if (n != null)
|
||||
return eval.getNodeWrapper (n);
|
||||
else
|
||||
return ESNull.theNull;
|
||||
}
|
||||
|
||||
// this is not very nice, but as a hack we return the id of a node as node.__id__
|
||||
if (propertyName.startsWith ("__") && propertyName.endsWith ("__"))
|
||||
return getInternalProperty (propertyName);
|
||||
|
@ -388,14 +448,9 @@ public class ESNode extends ObjectPrototype {
|
|||
return ESNull.theNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some internal properties defined for every Node object. These are most commonly
|
||||
* used for debugging Helma applications.
|
||||
*/
|
||||
private ESValue getInternalProperty (String propertyName) throws EcmaScriptException {
|
||||
if ("__id__".equalsIgnoreCase (propertyName)) {
|
||||
if ("__id__".equalsIgnoreCase (propertyName))
|
||||
return new ESString (node.getID ());
|
||||
}
|
||||
if ("__prototype__".equalsIgnoreCase (propertyName)) {
|
||||
String p = node.getPrototype ();
|
||||
if (p == null)
|
||||
|
@ -418,27 +473,16 @@ public class ESNode extends ObjectPrototype {
|
|||
if ("__hash__".equals (propertyName))
|
||||
return new ESString (""+node.hashCode ());
|
||||
if ("__node__".equals (propertyName))
|
||||
return new ESWrapper (node, evaluator);
|
||||
if ("__created__".equalsIgnoreCase (propertyName))
|
||||
return new DatePrototype (evaluator, node.created ());
|
||||
if ("__lastmodified__".equalsIgnoreCase (propertyName))
|
||||
return new DatePrototype (evaluator, node.lastModified ());
|
||||
|
||||
return ESLoader.normalizeObject (node, evaluator);
|
||||
return ESNull.theNull;
|
||||
}
|
||||
|
||||
public boolean clearCache () {
|
||||
checkNode ();
|
||||
node.clearCacheNode ();
|
||||
return true;
|
||||
}
|
||||
|
||||
public Enumeration getAllProperties () {
|
||||
return getProperties ();
|
||||
}
|
||||
|
||||
public Enumeration getProperties () {
|
||||
checkNode ();
|
||||
checkNode ();
|
||||
return node.properties ();
|
||||
}
|
||||
|
||||
|
@ -458,10 +502,6 @@ public class ESNode extends ObjectPrototype {
|
|||
lastError = null;
|
||||
}
|
||||
|
||||
public Object toJavaObject () {
|
||||
return getNode ();
|
||||
}
|
||||
|
||||
/**
|
||||
* An ESNode equals another object if it is an ESNode that wraps the same INode
|
||||
* or the wrapped INode itself. FIXME: doesen't check dbmapping/type!
|
||||
|
@ -473,19 +513,62 @@ public class ESNode extends ObjectPrototype {
|
|||
return true;
|
||||
if (what instanceof ESNode) {
|
||||
ESNode other = (ESNode) what;
|
||||
if (handle != null)
|
||||
return handle.equals (other.handle);
|
||||
else
|
||||
return (node == other.node);
|
||||
return (other.nodeID.equals (nodeID) && other.dbmap == dbmap);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public ESValue getDefaultValue(int hint) throws EcmaScriptException {
|
||||
return new ESString (this.toString());
|
||||
}
|
||||
|
||||
} // class ESNode
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
126
src/helma/framework/core/ESRequestData.java
Normal file
126
src/helma/framework/core/ESRequestData.java
Normal file
|
@ -0,0 +1,126 @@
|
|||
// ESRequestData.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
|
||||
package helma.framework.core;
|
||||
|
||||
import FESI.Data.*;
|
||||
import FESI.Exceptions.*;
|
||||
import FESI.Interpreter.Evaluator;
|
||||
import java.util.*;
|
||||
import helma.objectmodel.INode;
|
||||
|
||||
|
||||
/**
|
||||
* An EcmaScript object that makes stuff in a hashtable accessible as its properties
|
||||
*/
|
||||
|
||||
public class ESRequestData extends ESWrapper {
|
||||
|
||||
private Hashtable data;
|
||||
private RequestEvaluator reval;
|
||||
|
||||
public ESRequestData (RequestEvaluator reval) {
|
||||
super (new Object(), reval.evaluator);
|
||||
this.reval = reval;
|
||||
}
|
||||
|
||||
public void setData (Hashtable data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to make the object read-only
|
||||
*/
|
||||
public void putProperty(String propertyName, ESValue propertyValue, int hash) throws EcmaScriptException {
|
||||
throw new EcmaScriptException ("Can't set property, object is read-only");
|
||||
}
|
||||
|
||||
public boolean deleteProperty(String propertyName, int hash) throws EcmaScriptException {
|
||||
throw new EcmaScriptException ("Can't delete property, object is read-only");
|
||||
}
|
||||
|
||||
public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException {
|
||||
if (data == null)
|
||||
return ESNull.theNull;
|
||||
|
||||
Object val = data.get (propertyName);
|
||||
|
||||
if (val == null)
|
||||
return ESNull.theNull;
|
||||
|
||||
if (val instanceof String)
|
||||
return new ESString ((String) val);
|
||||
else if (val instanceof INode)
|
||||
return reval.getNodeWrapper ((INode) val);
|
||||
|
||||
return ESLoader.normalizeValue(val, evaluator);
|
||||
}
|
||||
|
||||
|
||||
public Enumeration getAllProperties () {
|
||||
return getProperties ();
|
||||
}
|
||||
|
||||
public Enumeration getProperties () {
|
||||
if (data == null)
|
||||
return new Hashtable().keys();
|
||||
return data.keys();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
125
src/helma/framework/core/ESUser.java
Normal file
125
src/helma/framework/core/ESUser.java
Normal file
|
@ -0,0 +1,125 @@
|
|||
// ESUser.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.framework.core;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import FESI.Interpreter.*;
|
||||
import FESI.Exceptions.*;
|
||||
import FESI.Data.*;
|
||||
|
||||
/**
|
||||
* The ESUser is a special kind of Node object that represents a user of
|
||||
* a HOP application. The actual user session data are kept in class User.
|
||||
* If the user is logged in as a registered member, the wrapped node represents
|
||||
* the user object in the database, while for anonymous surfers the node object
|
||||
* is just a transient node. <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, RequestEvaluator eval) {
|
||||
super (eval.esUserPrototype, eval.evaluator, node, eval);
|
||||
user = (User) eval.app.activeUsers.get (node.getNameOrID ());
|
||||
if (user == null)
|
||||
user = (User) eval.app.sessions.get (node.getNameOrID ());
|
||||
if (user != null) {
|
||||
cache = user.cache;
|
||||
cacheWrapper = new ESNode (cache, eval);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides getProperty to return the uid (which is not a regular property)
|
||||
*/
|
||||
public ESValue getProperty (String propname, int hash) throws EcmaScriptException {
|
||||
if ("uid".equals (propname)) {
|
||||
if (user == null || user.uid == null)
|
||||
return ESNull.theNull;
|
||||
else
|
||||
return new ESString (user.uid);
|
||||
}
|
||||
if ("sessionID".equals (propname)) {
|
||||
return new ESString (user.getSessionID ());
|
||||
}
|
||||
return super.getProperty (propname, hash);
|
||||
}
|
||||
|
||||
|
||||
public void setUser (User user) {
|
||||
if (this.user != user) {
|
||||
this.user = user;
|
||||
cache = user.cache;
|
||||
}
|
||||
cacheWrapper = new ESNode (cache, eval);
|
||||
}
|
||||
|
||||
public void setNode (INode node) {
|
||||
if (node != null) {
|
||||
this.node = node;
|
||||
nodeID = node.getID ();
|
||||
dbmap = node.getDbMapping ();
|
||||
eval.objectcache.put (node, this);
|
||||
// we don't take over the transient cache from the node,
|
||||
// because we always use the one from the user object.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString () {
|
||||
return ("UserObject "+node.getNameOrID ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
120
src/helma/framework/core/FunctionFile.java
Normal file
120
src/helma/framework/core/FunctionFile.java
Normal file
|
@ -0,0 +1,120 @@
|
|||
// FunctionFile.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.framework.core;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import helma.objectmodel.IServer;
|
||||
import FESI.Data.ObjectPrototype;
|
||||
import FESI.Exceptions.EcmaScriptException;
|
||||
import FESI.Interpreter.*;
|
||||
|
||||
|
||||
/**
|
||||
* This represents a File containing JavaScript functions for a given Object.
|
||||
*/
|
||||
|
||||
|
||||
public class FunctionFile {
|
||||
|
||||
String name;
|
||||
Prototype prototype;
|
||||
Application app;
|
||||
File file;
|
||||
long lastmod;
|
||||
|
||||
public FunctionFile (File file, String name, Prototype proto) {
|
||||
this.prototype = proto;
|
||||
this.app = proto.app;
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
update (file);
|
||||
}
|
||||
|
||||
|
||||
public void update (File f) {
|
||||
|
||||
this.file = f;
|
||||
|
||||
long fmod = file.lastModified ();
|
||||
if (lastmod == fmod)
|
||||
return;
|
||||
|
||||
lastmod = fmod;
|
||||
// app.typemgr.readFunctionFile (file, prototype.getName ());
|
||||
Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
|
||||
while (evals.hasNext ()) {
|
||||
try {
|
||||
RequestEvaluator reval = (RequestEvaluator) evals.next ();
|
||||
updateRequestEvaluator (reval);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public synchronized void updateRequestEvaluator (RequestEvaluator reval) {
|
||||
|
||||
EvaluationSource es = new FileEvaluationSource(file.getPath(), null);
|
||||
FileReader fr = null;
|
||||
|
||||
try {
|
||||
fr = new FileReader(file);
|
||||
ObjectPrototype op = reval.getPrototype (prototype.getName());
|
||||
reval.evaluator.evaluate(fr, op, es, false);
|
||||
} catch (IOException e) {
|
||||
IServer.getLogger().log ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
|
||||
} catch (EcmaScriptException e) {
|
||||
IServer.getLogger().log ("Error parsing function file "+app.getName()+":"+prototype.getName()+"/"+file.getName()+": "+e);
|
||||
} finally {
|
||||
if (fr!=null) {
|
||||
try {
|
||||
fr.close();
|
||||
} catch (IOException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,13 +1,10 @@
|
|||
// HopExtension.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.scripting.fesi;
|
||||
package helma.framework.core;
|
||||
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.util.*;
|
||||
import helma.framework.IPathElement;
|
||||
import FESI.Interpreter.*;
|
||||
import FESI.Exceptions.*;
|
||||
import FESI.Extensions.*;
|
||||
|
@ -18,33 +15,32 @@ import java.text.*;
|
|||
import org.xml.sax.InputSource;
|
||||
|
||||
/**
|
||||
* This is the basic Extension for FESI interpreters used in Helma. It sets up
|
||||
* varios constructors, global functions and properties on the HopObject prototype
|
||||
* (Node objects), the user prototype, the global prototype etc.
|
||||
* This is the basic Extension for FESI interpreters used in HOP. It sets up
|
||||
* varios constructors, global functions and properties etc.
|
||||
*/
|
||||
|
||||
public class HopExtension {
|
||||
|
||||
protected Application app;
|
||||
protected FesiEvaluator fesi;
|
||||
|
||||
public HopExtension (Application app) {
|
||||
this.app = app;
|
||||
public HopExtension () {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called by the evaluator after the extension is loaded.
|
||||
*/
|
||||
public void initializeExtension (FesiEvaluator fesi) throws EcmaScriptException {
|
||||
this.fesi = fesi;
|
||||
Evaluator evaluator = fesi.getEvaluator ();
|
||||
public void initializeExtension (RequestEvaluator reval) throws EcmaScriptException {
|
||||
|
||||
this.app = reval.app;
|
||||
Evaluator evaluator = reval.evaluator;
|
||||
GlobalObject go = evaluator.getGlobalObject();
|
||||
FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
|
||||
|
||||
ESObject op = evaluator.getObjectPrototype();
|
||||
|
||||
// The editor functions for String, Boolean and Number are deprecated!
|
||||
////////// The editor functions for String, Boolean and Number are deprecated!
|
||||
ESObject sp = evaluator.getStringPrototype ();
|
||||
sp.putHiddenProperty ("editor", new StringEditor ("editor", evaluator, fp));
|
||||
ESObject np = evaluator.getNumberPrototype ();
|
||||
|
@ -55,85 +51,94 @@ public class HopExtension {
|
|||
ESObject dp = evaluator.getDatePrototype ();
|
||||
dp.putHiddenProperty ("format", new DatePrototypeFormat ("format", evaluator, fp));
|
||||
|
||||
sp.putHiddenProperty ("trim", new StringTrim ("trim", evaluator, fp));
|
||||
reval.esNodePrototype = new ObjectPrototype(op, evaluator); // the Node prototype
|
||||
|
||||
// generic (Java wrapper) object prototype
|
||||
ObjectPrototype esObjectPrototype = new ObjectPrototype (op, evaluator);
|
||||
// the Node prototype
|
||||
ObjectPrototype esNodePrototype = new ObjectPrototype(op, evaluator);
|
||||
// the User prototype
|
||||
ObjectPrototype esUserPrototype = new ObjectPrototype (esNodePrototype, evaluator);
|
||||
// the Node constructor
|
||||
ESObject node = new NodeConstructor ("Node", fp, fesi);
|
||||
reval.esUserPrototype = new ObjectPrototype (reval.esNodePrototype, evaluator); // the User prototype
|
||||
|
||||
ESObject node = new NodeConstructor ("Node", fp, reval); // the Node constructor
|
||||
|
||||
// register the default methods of Node objects in the Node prototype
|
||||
esNodePrototype.putHiddenProperty ("add", new NodeAdd ("add", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("addAt", new NodeAddAt ("addAt", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("remove", new NodeRemove ("remove", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("link", new NodeLink ("link", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("list", new NodeList ("list", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("set", new NodeSet ("set", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("get", new NodeGet ("get", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("count", new NodeCount ("count", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("contains", new NodeContains ("contains", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("size", new NodeCount ("size", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("editor", new NodeEditor ("editor", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("path", new NodeHref ("path", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp));
|
||||
esNodePrototype.putHiddenProperty ("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false));
|
||||
esNodePrototype.putHiddenProperty ("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true));
|
||||
esNodePrototype.putHiddenProperty ("clearCache", new NodeClearCache ("clearCache", evaluator, fp));
|
||||
|
||||
// default methods for generic Java wrapper object prototype.
|
||||
// This is a small subset of the methods in esNodePrototype.
|
||||
esObjectPrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
|
||||
esObjectPrototype.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false));
|
||||
esObjectPrototype.putHiddenProperty("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true));
|
||||
reval.esNodePrototype.putHiddenProperty ("add", new NodeAdd ("add", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("addAt", new NodeAddAt ("addAt", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("remove", new NodeRemove ("remove", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("link", new NodeLink ("link", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("list", new NodeList ("list", evaluator, fp, reval));
|
||||
reval.esNodePrototype.putHiddenProperty ("set", new NodeSet ("set", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("get", new NodeGet ("get", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("count", new NodeCount ("count", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("contains", new NodeContains ("contains", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("size", new NodeCount ("size", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("editor", new NodeEditor ("editor", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("chooser", new NodeChooser ("chooser", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("multiChooser", new MultiNodeChooser ("multiChooser", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("getContent", new NodeGetContent ("getContent", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("setContent", new NodeSetContent ("setContent", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("path", new NodePath ("path", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp));
|
||||
reval.esNodePrototype.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, reval, false, false));
|
||||
reval.esNodePrototype.putHiddenProperty("renderSkin_as_string", new RenderSkin ("renderSkin_as_string", evaluator, fp, reval, false, true));
|
||||
|
||||
// methods that give access to properties and global user lists
|
||||
go.putHiddenProperty("Node", node); // register the constructor for a plain Node object.
|
||||
go.putHiddenProperty("HopObject", node); // HopObject is the new name for node.
|
||||
go.putHiddenProperty("getProperty", new GlobalGetProperty ("getProperty", evaluator, fp));
|
||||
go.putHiddenProperty("token", new GlobalGetProperty ("token", evaluator, fp));
|
||||
go.putHiddenProperty("getUser", new GlobalGetUser ("getUser", evaluator, fp));
|
||||
go.putHiddenProperty("getUserBySession", new GlobalGetUserBySession ("getUserBySession", evaluator, fp));
|
||||
go.putHiddenProperty("getAllUsers", new GlobalGetAllUsers ("getAllUsers", evaluator, fp));
|
||||
go.putHiddenProperty("getActiveUsers", new GlobalGetActiveUsers ("getActiveUsers", evaluator, fp));
|
||||
go.putHiddenProperty("countActiveUsers", new GlobalCountActiveUsers ("countActiveUsers", evaluator, fp));
|
||||
go.putHiddenProperty("getUser", new GlobalGetUser ("getUser", evaluator, fp, reval));
|
||||
go.putHiddenProperty("getUserBySession", new GlobalGetUserBySession ("getUserBySession", evaluator, fp, reval));
|
||||
go.putHiddenProperty("getAllUsers", new GlobalGetAllUsers ("getAllUsers", evaluator, fp, reval));
|
||||
go.putHiddenProperty("getActiveUsers", new GlobalGetActiveUsers ("getActiveUsers", evaluator, fp, reval));
|
||||
go.putHiddenProperty("isActive", new GlobalIsActive ("isActive", evaluator, fp));
|
||||
go.putHiddenProperty("getAge", new GlobalGetAge ("getAge", evaluator, fp));
|
||||
go.putHiddenProperty("getURL", new GlobalGetURL ("getURL", evaluator, fp));
|
||||
go.putHiddenProperty("encode", new GlobalEncode ("encode", evaluator, fp));
|
||||
go.putHiddenProperty("encodeXml", new GlobalEncodeXml ("encodeXml", evaluator, fp));
|
||||
go.putHiddenProperty("encodeForm", new GlobalEncodeForm ("encodeForm", evaluator, fp));
|
||||
go.putHiddenProperty("format", new GlobalFormat ("format", evaluator, fp));
|
||||
go.putHiddenProperty("stripTags", new GlobalStripTags ("stripTags", evaluator, fp));
|
||||
go.putHiddenProperty("getXmlDocument", new GlobalGetXmlDocument ("getXmlDocument", evaluator, fp));
|
||||
go.putHiddenProperty("getHtmlDocument", new GlobalGetHtmlDocument ("getHtmlDocument", evaluator, fp));
|
||||
go.putHiddenProperty("jdomize", new GlobalJDOM ("jdomize", evaluator, fp));
|
||||
go.putHiddenProperty("getSkin", new GlobalCreateSkin ("getSkin", evaluator, fp));
|
||||
go.putHiddenProperty("getSkin", new GlobalGetSkin ("getSkin", evaluator, fp));
|
||||
go.putHiddenProperty("createSkin", new GlobalCreateSkin ("createSkin", evaluator, fp));
|
||||
go.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, true, false));
|
||||
go.putHiddenProperty("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, true, true));
|
||||
go.putHiddenProperty("authenticate", new GlobalAuthenticate ("authenticate", evaluator, fp));
|
||||
go.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, reval, true, false));
|
||||
go.putHiddenProperty("renderSkin_as_string", new RenderSkin ("renderSkin_as_string", evaluator, fp, reval, true, true));
|
||||
go.deleteProperty("exit", "exit".hashCode());
|
||||
|
||||
// and some methods for session management from JS...
|
||||
esUserPrototype.putHiddenProperty("logon", new UserLogin ("logon", evaluator, fp));
|
||||
esUserPrototype.putHiddenProperty("login", new UserLogin ("login", evaluator, fp));
|
||||
esUserPrototype.putHiddenProperty("register", new UserRegister ("register", evaluator, fp));
|
||||
esUserPrototype.putHiddenProperty("logout", new UserLogout ("logout", evaluator, fp));
|
||||
esUserPrototype.putHiddenProperty("onSince", new UserOnSince ("onSince", evaluator, fp));
|
||||
esUserPrototype.putHiddenProperty("lastActive", new UserLastActive ("lastActive", evaluator, fp));
|
||||
esUserPrototype.putHiddenProperty("touch", new UserTouch ("touch", evaluator, fp));
|
||||
reval.esUserPrototype.putHiddenProperty("logon", new UserLogin ("logon", evaluator, fp));
|
||||
reval.esUserPrototype.putHiddenProperty("login", new UserLogin ("login", evaluator, fp));
|
||||
reval.esUserPrototype.putHiddenProperty("register", new UserRegister ("register", evaluator, fp, reval));
|
||||
reval.esUserPrototype.putHiddenProperty("logout", new UserLogout ("logout", evaluator, fp));
|
||||
reval.esUserPrototype.putHiddenProperty("onSince", new UserOnSince ("onSince", evaluator, fp));
|
||||
reval.esUserPrototype.putHiddenProperty("lastActive", new UserLastActive ("lastActive", evaluator, fp));
|
||||
reval.esUserPrototype.putHiddenProperty("touch", new UserTouch ("touch", evaluator, fp));
|
||||
|
||||
// register object prototypes with FesiEvaluator
|
||||
fesi.putPrototype ("global", go);
|
||||
fesi.putPrototype ("hopobject", esNodePrototype);
|
||||
fesi.putPrototype ("__javaobject__", esObjectPrototype);
|
||||
fesi.putPrototype ("user", esUserPrototype);
|
||||
}
|
||||
|
||||
|
||||
class NodeSetContent extends BuiltinFunctionObject {
|
||||
NodeSetContent (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
ESNode node = (ESNode) thisObject;
|
||||
return ESBoolean.makeBoolean (node.setContent (arguments));
|
||||
}
|
||||
}
|
||||
|
||||
class NodeGetContent extends BuiltinFunctionObject {
|
||||
NodeGetContent (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
ESNode node = (ESNode) thisObject;
|
||||
Object content = node.getContent ();
|
||||
if (content == null)
|
||||
return ESNull.theNull;
|
||||
else
|
||||
return ESLoader.normalizeValue (content, this.evaluator);
|
||||
}
|
||||
}
|
||||
|
||||
class NodeAdd extends BuiltinFunctionObject {
|
||||
|
@ -178,8 +183,10 @@ public class HopExtension {
|
|||
}
|
||||
|
||||
class NodeList extends BuiltinFunctionObject {
|
||||
NodeList (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
RequestEvaluator reval;
|
||||
NodeList (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
|
||||
super(fp, evaluator, name, 0);
|
||||
this.reval = reval;
|
||||
}
|
||||
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
ESNode node = (ESNode) thisObject;
|
||||
|
@ -198,10 +205,7 @@ public class HopExtension {
|
|||
esv = thisObject.getProperty (i);
|
||||
} else {
|
||||
String name = arguments[0].toString ();
|
||||
// call esNodeProperty() method special to ESNode because we want to avoid
|
||||
// retrieving prototype functions when calling hopobject.get().
|
||||
ESNode esn = (ESNode) thisObject;
|
||||
esv = esn.getNodeProperty (name);
|
||||
esv = thisObject.getProperty (name, name.hashCode ());
|
||||
}
|
||||
return (esv);
|
||||
}
|
||||
|
@ -253,7 +257,10 @@ public class HopExtension {
|
|||
INode node = esn.getNode ();
|
||||
if (node instanceof helma.objectmodel.db.Node) {
|
||||
((helma.objectmodel.db.Node) node).invalidate ();
|
||||
esn.checkNode ();
|
||||
try {
|
||||
node = app.nmgr.getNode (node.getID (), node.getDbMapping ());
|
||||
esn.setNode (node);
|
||||
} catch (Exception x) {}
|
||||
}
|
||||
return ESBoolean.makeBoolean (true);
|
||||
}
|
||||
|
@ -406,14 +413,44 @@ public class HopExtension {
|
|||
}
|
||||
}
|
||||
|
||||
class StringTrim extends BuiltinFunctionObject {
|
||||
StringTrim (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESString ( thisObject.toString().trim() );
|
||||
}
|
||||
}
|
||||
class NodeChooser extends BuiltinFunctionObject {
|
||||
NodeChooser (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
ESNode esn = (ESNode) thisObject;
|
||||
if (arguments.length < 1) {
|
||||
return ESBoolean.makeBoolean(false);
|
||||
}
|
||||
String nodename = arguments[0].toString ();
|
||||
INode target = esn.getNode ().getNode (nodename, false);
|
||||
ESNode collection = arguments.length > 1 ? (ESNode) arguments[1] : esn;
|
||||
if (arguments.length > 2)
|
||||
return new ESString (getNodeChooserDD (nodename, collection.getNode (), target, arguments[2].toString ()));
|
||||
else
|
||||
return new ESString (getNodeChooserRB (nodename, collection.getNode (), target));
|
||||
}
|
||||
}
|
||||
|
||||
class MultiNodeChooser extends BuiltinFunctionObject {
|
||||
MultiNodeChooser (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
ESNode esn = (ESNode) thisObject;
|
||||
if (arguments.length < 1) {
|
||||
return ESBoolean.makeBoolean(false);
|
||||
}
|
||||
String nodename = arguments[0].toString ();
|
||||
INode thisNode = esn.getNode ();
|
||||
INode target = thisNode.getNode (nodename, false);
|
||||
if (target == null) {
|
||||
target = thisNode.createNode (nodename);
|
||||
}
|
||||
ESNode collection = arguments.length > 1 ? (ESNode) arguments[1] : esn;
|
||||
return new ESString (getNodeChooserCB (nodename, collection.getNode (), target));
|
||||
}
|
||||
}
|
||||
|
||||
class UserLogin extends BuiltinFunctionObject {
|
||||
UserLogin (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
|
@ -434,8 +471,10 @@ public class HopExtension {
|
|||
}
|
||||
|
||||
class UserRegister extends BuiltinFunctionObject {
|
||||
UserRegister (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
RequestEvaluator reval;
|
||||
UserRegister (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
|
||||
super (fp, evaluator, name, 2);
|
||||
this.reval = reval;
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
if (arguments.length < 2)
|
||||
|
@ -444,7 +483,7 @@ public class HopExtension {
|
|||
if (unode == null)
|
||||
return ESNull.theNull;
|
||||
else
|
||||
return fesi.getNodeWrapper (unode);
|
||||
return reval.getNodeWrapper (unode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -471,7 +510,7 @@ public class HopExtension {
|
|||
ESUser u = (ESUser) thisObject;
|
||||
if (u.user == null)
|
||||
throw new EcmaScriptException ("onSince() can only be called for users that are online at the moment!");
|
||||
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.onSince ()));
|
||||
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.onSince));
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
@ -484,7 +523,7 @@ public class HopExtension {
|
|||
ESUser u = (ESUser) thisObject;
|
||||
if (u.user == null)
|
||||
throw new EcmaScriptException ("lastActive() can only be called for users that are online at the moment!");
|
||||
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.lastTouched ()));
|
||||
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.lastTouched));
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
@ -509,20 +548,28 @@ public class HopExtension {
|
|||
if (arguments.length == 0)
|
||||
return new ESString ("");
|
||||
String defval = (arguments.length > 1) ? arguments[1].toString () : "";
|
||||
return new ESString (app.getProperty (arguments[0].toString (), defval));
|
||||
return new ESString (app.props.getProperty (arguments[0].toString (), defval));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalAuthenticate extends BuiltinFunctionObject {
|
||||
GlobalAuthenticate (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
/**
|
||||
* Get a parsed Skin from the central skin cache if possible, otherwise create it
|
||||
*/
|
||||
class GlobalGetSkin extends BuiltinFunctionObject {
|
||||
GlobalGetSkin (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
if (arguments.length != 2)
|
||||
return ESBoolean.makeBoolean (false);
|
||||
return ESBoolean.makeBoolean (app.authenticate (arguments[0].toString (), arguments[1].toString ()));
|
||||
|
||||
if (arguments.length != 1 || ESNull.theNull.equals (arguments[0]))
|
||||
throw new EcmaScriptException ("getSkin must be called with one String argument!");
|
||||
String str = arguments[0].toString ();
|
||||
Skin skin = (Skin) app.skincache.get (str);
|
||||
if (skin == null) {
|
||||
skin = new Skin (str);
|
||||
app.skincache.put (str, skin);
|
||||
}
|
||||
return new ESWrapper (skin, evaluator);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -535,14 +582,8 @@ public class HopExtension {
|
|||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
if (arguments.length != 1 || ESNull.theNull.equals (arguments[0]))
|
||||
throw new EcmaScriptException ("createSkin must be called with one String argument");
|
||||
String str = arguments[0].toString ();
|
||||
Skin skin = (Skin) app.skincache.get (str);
|
||||
if (skin == null) {
|
||||
skin = new Skin (str, app);
|
||||
app.skincache.put (str, skin);
|
||||
}
|
||||
return new ESWrapper (skin, evaluator);
|
||||
throw new EcmaScriptException ("createSkin must be called with one String argument!");
|
||||
return new ESWrapper (new Skin (arguments[0].toString()), evaluator);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,29 +591,25 @@ public class HopExtension {
|
|||
* Render a skin
|
||||
*/
|
||||
class RenderSkin extends BuiltinFunctionObject {
|
||||
RequestEvaluator reval;
|
||||
boolean global;
|
||||
boolean asString;
|
||||
RenderSkin (String name, Evaluator evaluator, FunctionPrototype fp, boolean global, boolean asString) {
|
||||
RenderSkin (String name, Evaluator evaluator, FunctionPrototype fp,
|
||||
RequestEvaluator reval, boolean global, boolean asString) {
|
||||
super (fp, evaluator, name, 1);
|
||||
this.reval = reval;
|
||||
this.global = global;
|
||||
this.asString = asString;
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObj, ESValue[] arguments) throws EcmaScriptException {
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
if (arguments.length < 1 || arguments.length > 2 || arguments[0] ==null || arguments[0] == ESNull.theNull)
|
||||
throw new EcmaScriptException ("renderSkin requires one argument containing the skin name and an optional parameter object argument");
|
||||
throw new EcmaScriptException ("renderSkin must be called with one Skin argument and an optional parameter argument");
|
||||
try {
|
||||
Skin skin = null;
|
||||
ESObject thisObject = global ? null : thisObj;
|
||||
HashMap params = null;
|
||||
if (arguments.length > 1 && arguments[1] instanceof ESObject) {
|
||||
// create an parameter object to pass to the skin
|
||||
ESObject paramObject = (ESObject) arguments[1];
|
||||
params = new HashMap ();
|
||||
for (Enumeration en=paramObject.getProperties(); en.hasMoreElements(); ) {
|
||||
String propname = (String) en.nextElement();
|
||||
params.put (propname, paramObject.getProperty (propname, propname.hashCode()).toJavaObject());
|
||||
}
|
||||
}
|
||||
Skin skin = null;
|
||||
ESNode handlerNode = global ? null : (ESNode) thisObject;
|
||||
ESObject paramObject = null;
|
||||
if (arguments.length > 1 && arguments[1] instanceof ESObject)
|
||||
paramObject = (ESObject) arguments[1];
|
||||
|
||||
// first, see if the first argument already is a skin object. If not, it's the name of the skin to be called
|
||||
if (arguments[0] instanceof ESWrapper) {
|
||||
|
@ -581,41 +618,16 @@ public class HopExtension {
|
|||
skin = (Skin) obj;
|
||||
}
|
||||
|
||||
// if res.skinpath is set, transform it into an array of java objects
|
||||
// (strings for directory names and INodes for internal, db-stored skinsets)
|
||||
ResponseTrans res = fesi.getResponse();
|
||||
Object[] skinpath = res.getTranslatedSkinpath ();
|
||||
if (skinpath == null) {
|
||||
skinpath = new Object[0];
|
||||
Object rawSkinpath = res.getSkinpath ();
|
||||
if (rawSkinpath != null && rawSkinpath instanceof JSWrapper) {
|
||||
JSWrapper jsw = (JSWrapper) rawSkinpath;
|
||||
ESObject eso = jsw.getESObject ();
|
||||
if (eso instanceof ArrayPrototype) {
|
||||
ArrayPrototype array = (ArrayPrototype) eso;
|
||||
skinpath = new Object[array.size()];
|
||||
for (int i=0; i<skinpath.length; i++)
|
||||
skinpath[i] = array.getProperty(i).toJavaObject ();
|
||||
}
|
||||
}
|
||||
res.setTranslatedSkinpath (skinpath);
|
||||
}
|
||||
|
||||
// ready... retrieve the skin and render it.
|
||||
Object javaObject = thisObject == null ? null : thisObject.toJavaObject ();
|
||||
if (skin == null)
|
||||
skin = app.getSkin (javaObject, arguments[0].toString (), skinpath);
|
||||
skin = reval.getSkin (handlerNode, arguments[0].toString ());
|
||||
if (asString)
|
||||
res.pushStringBuffer ();
|
||||
reval.res.pushStringBuffer ();
|
||||
if (skin != null)
|
||||
skin.render (fesi.getRequestEvaluator(), javaObject, params);
|
||||
skin.render (reval, handlerNode, paramObject);
|
||||
else
|
||||
res.write ("[Skin not found: "+arguments[0]+"]");
|
||||
reval.res.write ("[Skin not found: "+arguments[0]+"]");
|
||||
if (asString)
|
||||
return new ESString (res.popStringBuffer ());
|
||||
} catch (RedirectException redir) {
|
||||
// let redirect pass through
|
||||
throw redir;
|
||||
return new ESString (reval.res.popStringBuffer ());
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace ();
|
||||
throw new EcmaScriptException ("renderSkin: "+x);
|
||||
|
@ -627,42 +639,48 @@ public class HopExtension {
|
|||
|
||||
|
||||
class GlobalGetUser extends BuiltinFunctionObject {
|
||||
GlobalGetUser (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
RequestEvaluator reval;
|
||||
GlobalGetUser (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
|
||||
super (fp, evaluator, name, 1);
|
||||
this.reval = reval;
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
INode 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);
|
||||
INode user = null;
|
||||
if (arguments.length > 0) {
|
||||
String uname = arguments[0].toString ().trim ();
|
||||
user = app.getUserNode (uname);
|
||||
}
|
||||
if (user == null)
|
||||
return ESNull.theNull;
|
||||
return reval.getNodeWrapper (user);
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalGetUserBySession extends BuiltinFunctionObject {
|
||||
GlobalGetUserBySession (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
RequestEvaluator reval;
|
||||
GlobalGetUserBySession (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
|
||||
super (fp, evaluator, name, 1);
|
||||
this.reval = reval;
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
User user = null;
|
||||
if (arguments.length > 0) {
|
||||
String sid = arguments[0].toString ().trim ();
|
||||
user = app.getUser (sid);
|
||||
}
|
||||
if (user == null || user.getUID() == null)
|
||||
return ESNull.theNull;
|
||||
user.touch ();
|
||||
return fesi.getNodeWrapper (user.getNode ());
|
||||
User user = null;
|
||||
if (arguments.length > 0) {
|
||||
String sid = arguments[0].toString ().trim ();
|
||||
user = app.getUser (sid);
|
||||
}
|
||||
if (user == null || user.uid == null)
|
||||
return ESNull.theNull;
|
||||
user.touch ();
|
||||
return reval.getNodeWrapper (user.getNode ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class GlobalGetAllUsers extends BuiltinFunctionObject {
|
||||
GlobalGetAllUsers (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
RequestEvaluator reval;
|
||||
GlobalGetAllUsers (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
|
||||
super (fp, evaluator, name, 1);
|
||||
this.reval = reval;
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
INode users = app.getUserRoot ();
|
||||
|
@ -678,37 +696,30 @@ public class HopExtension {
|
|||
}
|
||||
|
||||
class GlobalGetActiveUsers extends BuiltinFunctionObject {
|
||||
GlobalGetActiveUsers (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
RequestEvaluator reval;
|
||||
GlobalGetActiveUsers (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
|
||||
super (fp, evaluator, name, 1);
|
||||
this.reval = reval;
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
Hashtable sessions = (Hashtable) app.sessions.clone ();
|
||||
int l = sessions.size ();
|
||||
ESObject ap = this.evaluator.getArrayPrototype();
|
||||
ArrayPrototype theArray = new ArrayPrototype (ap, this.evaluator);
|
||||
theArray.setSize (sessions.size ());
|
||||
theArray.setSize(l);
|
||||
int i=0;
|
||||
// Hashtable visited = new Hashtable ();
|
||||
Hashtable visited = new Hashtable ();
|
||||
for (Enumeration e=sessions.elements(); e.hasMoreElements(); ) {
|
||||
User u = (User) e.nextElement ();
|
||||
// Note: we previously sorted out duplicate users - now we simply enumerate all active sessions.
|
||||
// if (u.uid == null || !visited.containsKey (u.uid)) {
|
||||
theArray.setElementAt (fesi.getNodeWrapper (u), i++);
|
||||
// if (u.uid != null) visited.put (u.uid, u);
|
||||
// }
|
||||
if (u.uid == null || !visited.containsKey (u.uid)) {
|
||||
theArray.setElementAt (reval.getNodeWrapper (u.getNode ()), i++);
|
||||
if (u.uid != null) visited.put (u.uid, u);
|
||||
}
|
||||
}
|
||||
return theArray;
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalCountActiveUsers extends BuiltinFunctionObject {
|
||||
GlobalCountActiveUsers (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
return new ESNumber (app.sessions.size ());
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalIsActive extends BuiltinFunctionObject {
|
||||
GlobalIsActive (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
|
@ -759,7 +770,7 @@ public class HopExtension {
|
|||
return new ESString (age.toString ());
|
||||
|
||||
} catch (Exception e) {
|
||||
app.logEvent ("Error formatting date: "+e);
|
||||
IServer.getLogger().log ("Error formatting date: "+e);
|
||||
e.printStackTrace ();
|
||||
return new ESString ("");
|
||||
}
|
||||
|
@ -810,17 +821,6 @@ public class HopExtension {
|
|||
}
|
||||
}
|
||||
|
||||
class GlobalEncodeForm extends BuiltinFunctionObject {
|
||||
GlobalEncodeForm (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
if (arguments.length < 1)
|
||||
return ESNull.theNull;
|
||||
return new ESString (HtmlEncoder.encodeFormValue (arguments[0].toString ()));
|
||||
}
|
||||
}
|
||||
|
||||
// strip tags from XML/HTML text
|
||||
class GlobalStripTags extends BuiltinFunctionObject {
|
||||
GlobalStripTags (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
|
@ -865,7 +865,7 @@ public class HopExtension {
|
|||
Object p = arguments[0].toJavaObject ();
|
||||
if (p instanceof String) try {
|
||||
// first try to interpret string as URL
|
||||
java.net.URL u = new java.net.URL (p.toString ());
|
||||
java.net.URL u = new java.net.URL (p.toString ());
|
||||
parser.parse (p.toString());
|
||||
} catch (java.net.MalformedURLException nourl) {
|
||||
// if not a URL, maybe it is the XML itself
|
||||
|
@ -877,7 +877,7 @@ public class HopExtension {
|
|||
parser.parse (new InputSource ((Reader) p));
|
||||
return ESLoader.normalizeObject (parser.getDocument(), evaluator);
|
||||
} catch (Exception noluck) {
|
||||
app.logEvent ("Error creating XML document: "+noluck);
|
||||
IServer.getLogger().log ("Error creating XML document: "+noluck);
|
||||
}
|
||||
return ESNull.theNull;
|
||||
}
|
||||
|
@ -894,7 +894,7 @@ public class HopExtension {
|
|||
Object p = arguments[0].toJavaObject ();
|
||||
if (p instanceof String) try {
|
||||
// first try to interpret string as URL
|
||||
java.net.URL u = new java.net.URL (p.toString ());
|
||||
java.net.URL u = new java.net.URL (p.toString ());
|
||||
parser.parse (p.toString());
|
||||
} catch (java.net.MalformedURLException nourl) {
|
||||
// if not a URL, maybe it is the HTML itself
|
||||
|
@ -906,7 +906,7 @@ public class HopExtension {
|
|||
parser.parse (new InputSource ((Reader) p));
|
||||
return ESLoader.normalizeObject (parser.getDocument(), evaluator);
|
||||
} catch (Exception noluck) {
|
||||
app.logEvent ("Error creating HTML document: "+noluck);
|
||||
IServer.getLogger().log ("Error creating HTML document: "+noluck);
|
||||
}
|
||||
return ESNull.theNull;
|
||||
}
|
||||
|
@ -924,12 +924,24 @@ public class HopExtension {
|
|||
org.jdom.input.DOMBuilder builder = new org.jdom.input.DOMBuilder ();
|
||||
return ESLoader.normalizeObject (builder.build (doc), evaluator);
|
||||
} catch (Exception noluck) {
|
||||
app.logEvent ("Error wrapping JDOM document: "+noluck);
|
||||
IServer.getLogger().log ("Error wrapping JDOM document: "+noluck);
|
||||
}
|
||||
return ESNull.theNull;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NodePath extends BuiltinFunctionObject {
|
||||
NodePath (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
INode n = ((ESNode) thisObject).getNode ();
|
||||
String tmpname = arguments[0].toString ();
|
||||
return new ESString (app.getNodePath (n, tmpname));
|
||||
}
|
||||
}
|
||||
|
||||
class NodeSetParent extends BuiltinFunctionObject {
|
||||
NodeSetParent (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 2);
|
||||
|
@ -940,52 +952,16 @@ public class HopExtension {
|
|||
}
|
||||
}
|
||||
|
||||
class NodeClearCache extends BuiltinFunctionObject {
|
||||
NodeClearCache (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 2);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
ESNode node = (ESNode) thisObject;
|
||||
return ESBoolean.makeBoolean (node.clearCache ());
|
||||
}
|
||||
}
|
||||
|
||||
class NodeHref extends BuiltinFunctionObject {
|
||||
NodeHref (String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super (fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
Object elem = thisObject.toJavaObject ();
|
||||
INode n = ((ESNode) thisObject).getNode ();
|
||||
String tmpname = arguments.length == 0 ? "" : arguments[0].toString ();
|
||||
String basicHref =app.getNodeHref (elem, tmpname);
|
||||
String hrefSkin = app.getProperty ("hrefSkin", null);
|
||||
// FIXME: we should actually walk down the path from the object we called href() on
|
||||
// instead we move down the URL path.
|
||||
if (hrefSkin != null) {
|
||||
// we need to post-process the href with a skin for this application
|
||||
// first, look in the object href was called on.
|
||||
Object skinElem = elem;
|
||||
Skin skin = null;
|
||||
while (skin == null && skinElem != null) {
|
||||
Prototype proto = app.getPrototype (skinElem);
|
||||
if (proto != null)
|
||||
skin = proto.getSkin (hrefSkin);
|
||||
if (skin == null)
|
||||
skinElem = app.getParentElement (skinElem);
|
||||
}
|
||||
return new ESString (app.getNodeHref (n, tmpname));
|
||||
|
||||
if (skin != null) {
|
||||
return renderSkin (skin, basicHref, skinElem);
|
||||
}
|
||||
}
|
||||
return new ESString (basicHref);
|
||||
}
|
||||
private ESString renderSkin (Skin skin, String path, Object skinElem) throws EcmaScriptException {
|
||||
fesi.getResponse().pushStringBuffer ();
|
||||
HashMap param = new HashMap ();
|
||||
param.put ("path", path);
|
||||
skin.render (fesi.getRequestEvaluator(), skinElem, param);
|
||||
return new ESString (fesi.getResponse().popStringBuffer ().trim ());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1002,7 +978,7 @@ public class HopExtension {
|
|||
double d = from <= to ? 1.0 : -1.0;
|
||||
for (double i=from; i*d<=to*d; i+=step) {
|
||||
if (Math.abs (i%1) < l) {
|
||||
int j = (int) i;
|
||||
int j = (int) i;
|
||||
b.append ("<option value=\""+j);
|
||||
if (i == value) b.append ("\" selected=\"true");
|
||||
b.append ("\">"+j);
|
||||
|
@ -1016,6 +992,164 @@ public class HopExtension {
|
|||
return b.toString ();
|
||||
}
|
||||
|
||||
private String getNodeChooserDD (String name, INode collection, INode target, String teaser) {
|
||||
StringBuffer buffer = new StringBuffer ("<select name=\"");
|
||||
buffer.append (name);
|
||||
buffer.append ("\">");
|
||||
if (collection.contains (target) == -1) {
|
||||
buffer.append ("<option value=>");
|
||||
buffer.append (HtmlEncoder.encodeAll (teaser));
|
||||
}
|
||||
if (collection != null) {
|
||||
int l = collection.numberOfNodes ();
|
||||
for (int i=0; i<l; i++) {
|
||||
INode next = collection.getSubnodeAt (i);
|
||||
buffer.append ("<option value=\"");
|
||||
buffer.append (next.getID ());
|
||||
if (target == next)
|
||||
buffer.append ("\" selected=\"true");
|
||||
buffer.append ("\">");
|
||||
String cname = next.getString ("name", false);
|
||||
if (cname == null) cname = next.getName ();
|
||||
buffer.append (HtmlEncoder.encodeAll (cname));
|
||||
}
|
||||
}
|
||||
buffer.append ("</select>");
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
private String getNodeChooserRB (String name, INode collection, INode target) {
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
if (collection != null) {
|
||||
int l = collection.numberOfNodes ();
|
||||
for (int i=0; i<l; i++) {
|
||||
INode next = collection.getSubnodeAt (i);
|
||||
buffer.append ("<input type=radio name=\"");
|
||||
buffer.append (name);
|
||||
buffer.append ("\" value=\"");
|
||||
buffer.append (next.getNameOrID ()+"\"");
|
||||
if (target == next)
|
||||
buffer.append (" checked");
|
||||
buffer.append (">");
|
||||
String cname = next.getString ("name", false);
|
||||
if (cname == null) cname = next.getName ();
|
||||
buffer.append (HtmlEncoder.encodeAll (cname));
|
||||
buffer.append ("<br>");
|
||||
}
|
||||
}
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
private String getNodeChooserCB (String name, INode collection, INode target) {
|
||||
StringBuffer buffer = new StringBuffer ();
|
||||
if (collection != null) {
|
||||
int l = collection.numberOfNodes ();
|
||||
for (int i=0; i<l; i++) {
|
||||
INode next = collection.getSubnodeAt (i);
|
||||
buffer.append ("<input type=checkbox name=\"");
|
||||
buffer.append (name);
|
||||
buffer.append ("\" value=");
|
||||
buffer.append (next.getNameOrID ());
|
||||
if (target.contains (next) > -1)
|
||||
buffer.append (" checked");
|
||||
buffer.append (">");
|
||||
buffer.append (HtmlEncoder.encodeAll (next.getName ()));
|
||||
buffer.append ("<br>");
|
||||
}
|
||||
}
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
// NodeConstructor.java
|
||||
// Copyright (c) Hannes Wallnöfer 2000
|
||||
|
||||
package helma.scripting.fesi;
|
||||
package helma.framework.core;
|
||||
|
||||
import helma.objectmodel.db.Node;
|
||||
import helma.framework.core.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Exceptions.*;
|
||||
import FESI.Interpreter.*;
|
||||
|
@ -16,13 +14,13 @@ import FESI.Interpreter.*;
|
|||
|
||||
public class NodeConstructor extends BuiltinFunctionObject {
|
||||
|
||||
FesiEvaluator fesi;
|
||||
RequestEvaluator reval;
|
||||
String typename;
|
||||
|
||||
public NodeConstructor (String name, FunctionPrototype fp, FesiEvaluator fesi) {
|
||||
super(fp, fesi.getEvaluator (), name, 1);
|
||||
public NodeConstructor (String name, FunctionPrototype fp, RequestEvaluator reval) {
|
||||
super(fp, reval.evaluator, name, 1);
|
||||
typename = name;
|
||||
this.fesi = fesi;
|
||||
this.reval = reval;
|
||||
}
|
||||
|
||||
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
|
@ -31,33 +29,32 @@ public class NodeConstructor extends BuiltinFunctionObject {
|
|||
|
||||
public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
ESNode node = null;
|
||||
Application app = fesi.getApplication ();
|
||||
if ("Node".equals (typename) || "hopobject".equalsIgnoreCase (typename)) {
|
||||
String nodeName = null;
|
||||
if (arguments.length > 0 && arguments[0] != null)
|
||||
nodeName = arguments[0].toString();
|
||||
Node n = new Node (nodeName, (String) null, app.getWrappedNodeManager ());
|
||||
node = new ESNode (fesi.getPrototype ("hopobject"), this.evaluator, n, fesi);
|
||||
fesi.putNodeWrapper (node.getNode (), node);
|
||||
if (arguments.length == 0) {
|
||||
node = new ESNode (reval.esNodePrototype, this.evaluator, null, reval);
|
||||
reval.objectcache.put (node.getNode (), node);
|
||||
} else {
|
||||
node = new ESNode (reval.esNodePrototype, this.evaluator, arguments[0], reval);
|
||||
reval.objectcache.put (node.getNode (), node);
|
||||
}
|
||||
} else {
|
||||
// Typed nodes are instantiated as helma.objectmodel.db.Node from the beginning
|
||||
// even if we don't know yet if they are going to be stored in a database. The reason
|
||||
// is that we want to be able to use the specail features like subnode relations even for
|
||||
// transient nodes.
|
||||
ObjectPrototype op = fesi.getPrototype (typename);
|
||||
Node n = new Node (typename, typename, app.getWrappedNodeManager ());
|
||||
node = new ESNode (op, fesi.getEvaluator (), n, fesi);
|
||||
ObjectPrototype op = reval.getPrototype (typename);
|
||||
node = new ESNode (op, reval.evaluator, typename, reval);
|
||||
node.setPrototype (typename);
|
||||
node.getNode ().setDbMapping (app.getDbMapping (typename));
|
||||
node.getNode ().setDbMapping (reval.app.getDbMapping (typename));
|
||||
try {
|
||||
// first try calling "constructor", if that doesn't work, try calling a function
|
||||
// with the name of the type.
|
||||
// HACK: There is an incompatibility problem here, because the property
|
||||
// constructor is defined as the constructor of the object by EcmaScript.
|
||||
if (op.getProperty ("constructor", "constructor".hashCode()) instanceof ConstructedFunctionObject)
|
||||
node.doIndirectCall (fesi.getEvaluator(), node, "constructor", arguments);
|
||||
if (op.getProperty("constructor", "constructor".hashCode()) instanceof ConstructedFunctionObject)
|
||||
node.doIndirectCall (reval.evaluator, node, "constructor", arguments);
|
||||
else
|
||||
node.doIndirectCall (fesi.getEvaluator(), node, typename, arguments);
|
||||
node.doIndirectCall (reval.evaluator, node, typename, arguments);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
return node;
|
||||
|
@ -68,9 +65,9 @@ public class NodeConstructor extends BuiltinFunctionObject {
|
|||
}
|
||||
|
||||
public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException {
|
||||
if ("prototype".equals (propertyName))
|
||||
return fesi.getPrototype (typename);
|
||||
return super.getProperty(propertyName, hash);
|
||||
if ("prototype".equals (propertyName))
|
||||
return reval.getPrototype (typename);
|
||||
return super.getProperty(propertyName, hash);
|
||||
}
|
||||
|
||||
public String[] getSpecialPropertyNames() {
|
|
@ -3,13 +3,12 @@
|
|||
|
||||
package helma.framework.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import helma.scripting.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.util.Updatable;
|
||||
import FESI.Data.*;
|
||||
import FESI.Exceptions.EcmaScriptException;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -25,65 +24,54 @@ public class Prototype {
|
|||
String id;
|
||||
String name;
|
||||
Application app;
|
||||
public HashMap templates, functions, actions, skins, updatables;
|
||||
Hashtable templates, functions, actions, skins;
|
||||
File codeDir;
|
||||
long lastUpdate;
|
||||
|
||||
Prototype parent;
|
||||
DbMapping dbmap;
|
||||
|
||||
// Tells us whether this prototype is used to script a generic Java object,
|
||||
// as opposed to a Helma objectmodel node object.
|
||||
boolean isJavaPrototype;
|
||||
Prototype prototype;
|
||||
|
||||
public Prototype (String name, Application app) {
|
||||
// app.logEvent ("Constructing Prototype "+app.getName()+"/"+name);
|
||||
|
||||
public Prototype (File codeDir, Application app) {
|
||||
|
||||
IServer.getLogger().log ("Constructing Prototype "+app.getName()+"/"+codeDir.getName ());
|
||||
|
||||
this.codeDir = codeDir;
|
||||
this.app = app;
|
||||
this.name = name;
|
||||
isJavaPrototype = app.isJavaPrototype (name);
|
||||
lastUpdate = 0; // System.currentTimeMillis ();
|
||||
}
|
||||
this.name = codeDir.getName ();
|
||||
|
||||
File propfile = new File (codeDir, "type.properties");
|
||||
SystemProperties props = new SystemProperties (propfile.getAbsolutePath ());
|
||||
dbmap = new DbMapping (app, name, props);
|
||||
|
||||
lastUpdate = System.currentTimeMillis ();
|
||||
|
||||
/**
|
||||
* Return the application this prototype is a part of
|
||||
*/
|
||||
public Application getApplication () {
|
||||
return app;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the parent prototype of this prototype, i.e. the prototype this one inherits from.
|
||||
*/
|
||||
public void setParentPrototype (Prototype parent) {
|
||||
// this is not allowed for the hopobject and global prototypes
|
||||
if ("hopobject".equalsIgnoreCase (name) || "global".equalsIgnoreCase (name))
|
||||
return;
|
||||
public Action getActionOrTemplate (String aname) {
|
||||
|
||||
Prototype old = this.parent;
|
||||
this.parent = parent;
|
||||
|
||||
// if parent has changed, update ES-prototypes in request evaluators
|
||||
if (parent != old) {
|
||||
/* Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
|
||||
while (evals.hasNext ()) {
|
||||
try {
|
||||
RequestEvaluator reval = (RequestEvaluator) evals.next ();
|
||||
ObjectPrototype op = reval.getPrototype (getName());
|
||||
// use hopobject (node) as prototype even if prototype is null -
|
||||
// this is the case if no hopobject directory exists
|
||||
ObjectPrototype opp = parent == null ?
|
||||
reval.esNodePrototype : reval.getPrototype (parent.getName ());
|
||||
// don't think this is possible, but check anyway
|
||||
if (opp == null)
|
||||
opp = reval.esNodePrototype;
|
||||
op.setPrototype (opp);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
} */
|
||||
}
|
||||
Action retval = null;
|
||||
if (aname == null || "".equals (aname))
|
||||
aname = "main";
|
||||
retval = (Action) actions.get (aname);
|
||||
// check if it's allowed to access templates via URL
|
||||
// this should be cached in the future
|
||||
if (retval == null && "true".equalsIgnoreCase (app.props.getProperty ("exposetemplates")))
|
||||
retval = (Action) templates.get (aname);
|
||||
// if still not found, check if the action is defined for the generic node prototype
|
||||
if (retval == null && this != app.typemgr.nodeProto && app.typemgr.nodeProto != null)
|
||||
retval = app.typemgr.nodeProto.getActionOrTemplate (aname);
|
||||
return retval;
|
||||
}
|
||||
|
||||
public Prototype getParentPrototype () {
|
||||
return parent;
|
||||
public void setPrototype (Prototype prototype) {
|
||||
this.prototype = prototype;
|
||||
}
|
||||
|
||||
public Prototype getPrototype () {
|
||||
return prototype;
|
||||
}
|
||||
|
||||
public Template getTemplate (String tmpname) {
|
||||
|
@ -94,8 +82,8 @@ public class Prototype {
|
|||
return (FunctionFile) functions.get (ffname);
|
||||
}
|
||||
|
||||
public ActionFile getActionFile (String afname) {
|
||||
return (ActionFile) actions.get (afname);
|
||||
public Action getAction (String afname) {
|
||||
return (Action) actions.get (afname);
|
||||
}
|
||||
|
||||
public SkinFile getSkinFile (String sfname) {
|
||||
|
@ -110,29 +98,131 @@ public class Prototype {
|
|||
return null;
|
||||
}
|
||||
|
||||
public File getCodeDir () {
|
||||
return codeDir;
|
||||
}
|
||||
|
||||
public synchronized boolean checkCodeDir () {
|
||||
|
||||
boolean retval = false;
|
||||
String[] list = codeDir.list ();
|
||||
|
||||
for (int i=0; i<list.length; i++) {
|
||||
if (list[i].endsWith (app.templateExtension) || list[i].endsWith (app.scriptExtension)) {
|
||||
File f = new File (codeDir, list[i]);
|
||||
|
||||
if (f.lastModified () > lastUpdate) {
|
||||
lastUpdate = System.currentTimeMillis ();
|
||||
try {
|
||||
app.typemgr.updatePrototype (this.name, codeDir, this);
|
||||
// TypeManager.broadcaster.broadcast ("Finished update for prototype "+name+" @ "+new Date ()+"<br><hr>");
|
||||
} catch (Exception x) {
|
||||
IServer.getLogger().log ("Error building function protos in prototype: "+x);
|
||||
// TypeManager.broadcaster.broadcast ("Error updating prototype "+name+" in application "+app.getName()+":<br>"+x.getMessage ()+"<br><hr>");
|
||||
}
|
||||
retval = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
public String getName () {
|
||||
return name;
|
||||
}
|
||||
|
||||
Updatable[] upd = null;
|
||||
public Updatable[] getUpdatables () {
|
||||
if (upd == null) {
|
||||
upd = new Updatable[updatables.size()];
|
||||
int i = 0;
|
||||
for (Iterator it = updatables.values().iterator(); it.hasNext(); ) {
|
||||
upd[i++] = (Updatable) it.next();
|
||||
}
|
||||
|
||||
public void initRequestEvaluator (RequestEvaluator reval) {
|
||||
ObjectPrototype op = null;
|
||||
if ("user".equalsIgnoreCase (name))
|
||||
op = reval.esUserPrototype;
|
||||
else if ("global".equalsIgnoreCase (name))
|
||||
op = reval.global;
|
||||
else if ("hopobject".equalsIgnoreCase (name))
|
||||
op = reval.esNodePrototype;
|
||||
else {
|
||||
op = new ObjectPrototype (reval.esNodePrototype, reval.evaluator);
|
||||
try {
|
||||
op.putProperty ("prototypename", new ESString (name), "prototypename".hashCode ());
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
reval.putPrototype (name, op);
|
||||
|
||||
// Register a constructor for all types except global.
|
||||
// This will first create a node and then call the actual (scripted) constructor on it.
|
||||
if (!"global".equalsIgnoreCase (name)) {
|
||||
try {
|
||||
FunctionPrototype fp = (FunctionPrototype) reval.evaluator.getFunctionPrototype();
|
||||
reval.global.putHiddenProperty (name, new NodeConstructor (name, fp, reval));
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
|
||||
for (Enumeration en = functions.elements(); en.hasMoreElements(); ) {
|
||||
FunctionFile ff = (FunctionFile) en.nextElement ();
|
||||
ff.updateRequestEvaluator (reval);
|
||||
}
|
||||
for (Enumeration en = templates.elements(); en.hasMoreElements(); ) {
|
||||
Template tmp = (Template) en.nextElement ();
|
||||
try {
|
||||
tmp.updateRequestEvaluator (reval);
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
for (Enumeration en = actions.elements(); en.hasMoreElements(); ) {
|
||||
Action act = (Action) en.nextElement ();
|
||||
try {
|
||||
act.updateRequestEvaluator (reval);
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
return upd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String toString () {
|
||||
return "[Prototype "+ app.getName()+"/"+name+"]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,134 +3,67 @@
|
|||
|
||||
package helma.framework.core;
|
||||
|
||||
import helma.framework.*;
|
||||
import helma.scripting.*;
|
||||
import helma.objectmodel.INode;
|
||||
import helma.objectmodel.ConcurrencyException;
|
||||
import helma.util.HtmlEncoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Exceptions.*;
|
||||
import helma.objectmodel.INode;
|
||||
import helma.objectmodel.IServer;
|
||||
|
||||
|
||||
/**
|
||||
* This represents a Helma skin, i.e. a template created from containing Macro tags
|
||||
* that will be dynamically evaluated.. It uses the request path array
|
||||
* from the RequestEvaluator object to resolve Macro handlers by type name.
|
||||
* This represents a HOP skin, i.e. a template created from JavaScript. It uses the request path array
|
||||
* from the RequestEvaluator object to resolve dynamic tokens.
|
||||
*/
|
||||
|
||||
public class Skin {
|
||||
|
||||
Macro[] parts;
|
||||
Application app;
|
||||
char[] source;
|
||||
int sourceLength;
|
||||
HashSet sandbox;
|
||||
Object[] parts;
|
||||
|
||||
/**
|
||||
* Create a skin without any restrictions on which macros are allowed to be called from it
|
||||
*/
|
||||
public Skin (String content, Application app) {
|
||||
this (content, app, null);
|
||||
public Skin (String content) {
|
||||
parse (content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a skin with a sandbox which contains the names of macros allowed to be called
|
||||
*/
|
||||
public Skin (String content, Application app, HashSet sandbox) {
|
||||
this.app = app;
|
||||
this.sandbox = sandbox;
|
||||
source = content.toCharArray ();
|
||||
sourceLength = source.length;
|
||||
parse ();
|
||||
}
|
||||
public void parse (String content) {
|
||||
|
||||
/**
|
||||
* Create a skin without any restrictions on the macros from a char array.
|
||||
*/
|
||||
public Skin (char[] content, int length, Application app) {
|
||||
this.app = app;
|
||||
this.sandbox = null;
|
||||
this.source = content;
|
||||
this.sourceLength = length;
|
||||
parse ();
|
||||
}
|
||||
Vector partBuffer = new Vector ();
|
||||
int l = content.length ();
|
||||
char cnt[] = new char[l];
|
||||
content.getChars (0, l, cnt, 0);
|
||||
|
||||
/**
|
||||
* Parse a skin object from source text
|
||||
*/
|
||||
private void parse () {
|
||||
|
||||
ArrayList partBuffer = new ArrayList ();
|
||||
|
||||
int start = 0;
|
||||
for (int i = 0; i < sourceLength-1; i++) {
|
||||
if (source[i] == '<' && source[i+1] == '%') {
|
||||
// found macro start tag
|
||||
int lastIdx = 0;
|
||||
for (int i = 0; i < l-1; i++) {
|
||||
if (cnt[i] == '<' && cnt[i+1] == '%') {
|
||||
int j = i+2;
|
||||
// search macr end tag
|
||||
while (j < sourceLength-1 && (source[j] != '%' || source[j+1] != '>')) {
|
||||
while (j < l-1 && (cnt[j] != '%' || cnt[j+1] != '>')) {
|
||||
j++;
|
||||
}
|
||||
if (j > i+2) {
|
||||
partBuffer.add (new Macro (i, j+2));
|
||||
start = j+2;
|
||||
if (i - lastIdx > 0)
|
||||
partBuffer.addElement (new String (cnt, lastIdx, i - lastIdx));
|
||||
String macrotext = new String (cnt, i+2, (j-i)-2);
|
||||
partBuffer.addElement (new Macro (macrotext));
|
||||
lastIdx = j+2;
|
||||
}
|
||||
i = j+1;
|
||||
}
|
||||
}
|
||||
if (lastIdx < l)
|
||||
partBuffer.addElement (new String (cnt, lastIdx, l - lastIdx));
|
||||
|
||||
parts = new Macro[partBuffer.size()];
|
||||
partBuffer.toArray (parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw source text this skin was parsed from
|
||||
*/
|
||||
public String getSource () {
|
||||
return new String (source, 0, sourceLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render this skin
|
||||
*/
|
||||
public void render (RequestEvaluator reval, Object thisObject, HashMap paramObject) throws RedirectException {
|
||||
parts = partBuffer.toArray ();
|
||||
}
|
||||
|
||||
public void render (RequestEvaluator reval, ESNode thisNode, ESObject paramObject) {
|
||||
if (parts == null)
|
||||
reval.res.writeCharArray (source, 0, sourceLength);
|
||||
|
||||
int written = 0;
|
||||
return;
|
||||
for (int i=0; i<parts.length; i++) {
|
||||
if (parts[i].start > written)
|
||||
reval.res.writeCharArray (source, written, parts[i].start-written);
|
||||
parts[i].render (reval, thisObject, paramObject);
|
||||
written = parts[i].end;
|
||||
if (parts[i] instanceof Macro)
|
||||
((Macro) parts[i]).render (reval, thisNode, paramObject);
|
||||
else
|
||||
reval.res.write (parts[i]);
|
||||
}
|
||||
if (written < sourceLength)
|
||||
reval.res.writeCharArray (source, written, sourceLength-written);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a certain macro is present in this skin. The macro name is in handler.name notation
|
||||
*/
|
||||
public boolean containsMacro (String macroname) {
|
||||
for (int i=0; i<parts.length; i++) {
|
||||
if (parts[i] instanceof Macro) {
|
||||
Macro m = (Macro) parts[i];
|
||||
if (macroname.equals (m.getFullName ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a macro to the list of allowed macros. The macro is in handler.name notation.
|
||||
*/
|
||||
public void allowMacro (String macroname) {
|
||||
if (sandbox == null) {
|
||||
sandbox = new HashSet ();
|
||||
}
|
||||
sandbox.add (macroname);
|
||||
}
|
||||
|
||||
static final int HANDLER = 0;
|
||||
|
@ -140,18 +73,17 @@ public class Skin {
|
|||
|
||||
class Macro {
|
||||
|
||||
int start, end;
|
||||
String handler;
|
||||
String name;
|
||||
String fullname;
|
||||
HashMap parameters;
|
||||
Hashtable parameters;
|
||||
|
||||
public Macro (int start, int end) {
|
||||
public Macro (String str) {
|
||||
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
parameters = new Hashtable ();
|
||||
|
||||
parameters = new HashMap ();
|
||||
int l = str.length ();
|
||||
char cnt[] = new char[l];
|
||||
str.getChars (0, l, cnt, 0);
|
||||
|
||||
int state = HANDLER;
|
||||
boolean escape = false;
|
||||
|
@ -159,37 +91,37 @@ public class Skin {
|
|||
String lastParamName = null;
|
||||
StringBuffer b = new StringBuffer();
|
||||
|
||||
for (int i=start+2; i<end-2; i++) {
|
||||
switch (source[i]) {
|
||||
for (int i=0; i<l; i++) {
|
||||
switch (cnt[i]) {
|
||||
case '.':
|
||||
if (state == HANDLER) {
|
||||
handler = b.toString ().trim();
|
||||
b.setLength (0);
|
||||
state = MACRO;
|
||||
} else
|
||||
b.append (source[i]);
|
||||
b.append (cnt[i]);
|
||||
break;
|
||||
case '\\':
|
||||
if (escape)
|
||||
b.append (source[i]);
|
||||
b.append (cnt[i]);
|
||||
escape = !escape;
|
||||
break;
|
||||
break;;
|
||||
case '"':
|
||||
case '\'':
|
||||
if (!escape && state == PARAMVALUE) {
|
||||
if (quotechar == source[i]) {
|
||||
if (quotechar == cnt[i]) {
|
||||
parameters.put (lastParamName, b.toString());
|
||||
lastParamName = null;
|
||||
b.setLength (0);
|
||||
state = PARAMNAME;
|
||||
quotechar = '\u0000';
|
||||
} else if (quotechar == '\u0000') {
|
||||
quotechar = source[i];
|
||||
quotechar = cnt[i];
|
||||
b.setLength (0);
|
||||
} else
|
||||
b.append (source[i]);
|
||||
b.append (cnt[i]);
|
||||
} else
|
||||
b.append (source[i]);
|
||||
b.append (cnt[i]);
|
||||
escape = false;
|
||||
break;
|
||||
case ' ':
|
||||
|
@ -207,7 +139,7 @@ public class Skin {
|
|||
b.setLength (0);
|
||||
state = PARAMNAME;
|
||||
} else if (state == PARAMVALUE)
|
||||
b.append (source[i]);
|
||||
b.append (cnt[i]);
|
||||
else
|
||||
b.setLength (0);
|
||||
break;
|
||||
|
@ -217,10 +149,10 @@ public class Skin {
|
|||
b.setLength (0);
|
||||
state = PARAMVALUE;
|
||||
} else
|
||||
b.append (source[i]);
|
||||
b.append (cnt[i]);
|
||||
break;
|
||||
default:
|
||||
b.append (source[i]);
|
||||
b.append (cnt[i]);
|
||||
escape = false;
|
||||
}
|
||||
}
|
||||
|
@ -233,16 +165,9 @@ public class Skin {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render the macro given a handler object
|
||||
*/
|
||||
public void render (RequestEvaluator reval, Object thisObject, HashMap paramObject) throws RedirectException {
|
||||
public void render (RequestEvaluator reval, ESNode thisNode, ESObject paramObject) {
|
||||
|
||||
if (sandbox != null && !sandbox.contains (getFullName ())) {
|
||||
String h = handler == null ? "global" : handler;
|
||||
reval.res.write ("[Macro "+getFullName()+" not allowed in sandbox]");
|
||||
return;
|
||||
} else if ("response".equalsIgnoreCase (handler)) {
|
||||
if ("response".equalsIgnoreCase (handler)) {
|
||||
renderFromResponse (reval);
|
||||
return;
|
||||
} else if ("request".equalsIgnoreCase (handler)) {
|
||||
|
@ -255,178 +180,129 @@ public class Skin {
|
|||
|
||||
try {
|
||||
|
||||
Object handlerObject = null;
|
||||
ESObject handlerObject = null;
|
||||
|
||||
Object[] arguments = new Object[1];
|
||||
arguments[0] = parameters;
|
||||
|
||||
// flag to tell whether we found our invocation target object
|
||||
boolean objectFound = true;
|
||||
ESValue[] arguments = new ESValue[1];
|
||||
ESRequestData par = new ESRequestData (reval);
|
||||
par.setData (parameters);
|
||||
arguments[0] = par;
|
||||
|
||||
if (handler != null) {
|
||||
if ("currentuser".equalsIgnoreCase (handler)) {
|
||||
// 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
|
||||
if (thisNode != null) {
|
||||
// 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 (thisNode.getPrototypeName ())) {
|
||||
// the handler object is not what we want
|
||||
Object n = thisObject;
|
||||
INode n = thisNode.getNode();
|
||||
// walk down parent chain to find handler object
|
||||
while (n != null) {
|
||||
if (handler.equalsIgnoreCase (app.getPrototypeName (n))) {
|
||||
handlerObject = n;
|
||||
if (handler.equalsIgnoreCase (n.getPrototype())) {
|
||||
handlerObject = reval.getNodeWrapper (n);
|
||||
break;
|
||||
}
|
||||
n = app.getParentElement (n);
|
||||
n = n.getParent ();
|
||||
}
|
||||
} else {
|
||||
// we already have the right handler object
|
||||
handlerObject = thisObject;
|
||||
handlerObject = thisNode;
|
||||
}
|
||||
}
|
||||
|
||||
if (handlerObject == null) {
|
||||
// eiter because thisObject == null or the right object wasn't found in the object's parent path
|
||||
// eiter because thisNode == null or the right object wasn't found in the targetNode path
|
||||
// go check request path for an object with matching prototype
|
||||
int l = reval.requestPath.size();
|
||||
int l = reval.reqPath.size();
|
||||
for (int i=l-1; i>=0; i--) {
|
||||
Object pathelem = reval.requestPath.get (i);
|
||||
if (handler.equalsIgnoreCase (app.getPrototypeName (pathelem))) {
|
||||
handlerObject = pathelem;
|
||||
if (handler.equalsIgnoreCase (((ESNode) reval.reqPath.getProperty(i)).getPrototypeName())) {
|
||||
handlerObject = (ESNode) reval.reqPath.getProperty(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the macro handler object couldn't be found
|
||||
if (handlerObject == null)
|
||||
objectFound = false;
|
||||
|
||||
} else {
|
||||
// this is a global macro with no handler specified
|
||||
handlerObject = null;
|
||||
handlerObject = reval.global;
|
||||
}
|
||||
|
||||
if (objectFound) {
|
||||
// check if a function called name_macro is defined.
|
||||
// if so, the macro evaluates to the function. Otherwise,
|
||||
// a property/field with the name is used, if defined.
|
||||
Object v = null;
|
||||
if (app.scriptingEngine.hasFunction (handlerObject, name+"_macro", reval)) {
|
||||
// System.err.println ("Getting macro from function");
|
||||
v = app.scriptingEngine.invoke (handlerObject, name+"_macro", arguments, null, reval);
|
||||
} else {
|
||||
// System.err.println ("Getting macro from property");
|
||||
v = app.scriptingEngine.get (handlerObject, name, reval);
|
||||
}
|
||||
if (v != null)
|
||||
writeToResponse (v.toString (), reval.res);
|
||||
if (handlerObject != null) {
|
||||
ESValue v = handlerObject.doIndirectCall (reval.evaluator, handlerObject, name+"_macro", arguments);
|
||||
if (v != ESUndefined.theUndefined && v != ESNull.theNull)
|
||||
reval.res.write (v);
|
||||
} else {
|
||||
String msg = "[HopMacro unhandled: "+getFullName()+"]";
|
||||
String msg = "[HopMacro unhandled: "+handler+"."+name+"]";
|
||||
reval.res.write (" "+msg+" ");
|
||||
app.logEvent (msg);
|
||||
IServer.getLogger().log (msg);
|
||||
}
|
||||
} catch (RedirectException redir) {
|
||||
throw redir;
|
||||
} catch (ConcurrencyException concur) {
|
||||
throw concur;
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace();
|
||||
String msg = "[HopMacro error: "+x+"]";
|
||||
reval.res.write (" "+msg+" ");
|
||||
app.logEvent (msg);
|
||||
IServer.getLogger().log (msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderFromResponse (RequestEvaluator reval) {
|
||||
Object value = null;
|
||||
// as a transitional solution, try to get the value from the
|
||||
// hardcoded fields in the response object. If not present, try
|
||||
// the response object's data object.
|
||||
if ("title".equals (name))
|
||||
value = reval.res.title;
|
||||
else if ("head".equals (name))
|
||||
value = reval.res.head;
|
||||
else if ("body".equals (name))
|
||||
value = reval.res.body;
|
||||
else if ("message".equals (name))
|
||||
value = reval.res.message;
|
||||
if (value == null)
|
||||
value = reval.res.get (name);
|
||||
if (value != null)
|
||||
writeToResponse (value.toString (), reval.res);
|
||||
if ("title".equals (name) && reval.res.title != null)
|
||||
reval.res.write (reval.res.title);
|
||||
else if ("head".equals (name) && reval.res.head != null)
|
||||
reval.res.write (reval.res.head);
|
||||
else if ("body".equals (name) && reval.res.body != null)
|
||||
reval.res.write (reval.res.body);
|
||||
else if ("message".equals (name) && reval.res.message != null)
|
||||
reval.res.write (reval.res.message);
|
||||
}
|
||||
|
||||
private void renderFromRequest (RequestEvaluator reval) {
|
||||
Object value = reval.req.get (name);
|
||||
if (value != null)
|
||||
writeToResponse (value.toString (), reval.res);
|
||||
reval.res.write (value);
|
||||
}
|
||||
|
||||
private void renderFromParam (RequestEvaluator reval, HashMap paramObject) {
|
||||
private void renderFromParam (RequestEvaluator reval, ESObject paramObject) {
|
||||
if (paramObject == null)
|
||||
reval.res.write ("[HopMacro error: Skin requires a parameter object]");
|
||||
else {
|
||||
Object value = paramObject.get (name);
|
||||
if (value != null)
|
||||
writeToResponse (value.toString (), reval.res);
|
||||
try {
|
||||
ESValue value = paramObject.getProperty (name, name.hashCode());
|
||||
if (value != null && value != ESUndefined.theUndefined)
|
||||
reval.res.write (value);
|
||||
} catch (EcmaScriptException ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for writing text out to the response object.
|
||||
*/
|
||||
void writeToResponse (String text, ResponseTrans res) {
|
||||
if (text == null || text.length() == 0)
|
||||
return;
|
||||
String encoding = (String) parameters.get ("encoding");
|
||||
String prefix = (String) parameters.get ("prefix");
|
||||
String suffix = (String) parameters.get ("suffix");
|
||||
res.write (prefix);
|
||||
res.write (encode (text, encoding));
|
||||
res.write (suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for performing different kind of character
|
||||
* encodings on the macro output.
|
||||
*/
|
||||
String encode (String text, String encoding) {
|
||||
if (encoding == null || text == null)
|
||||
return text;
|
||||
if ("html".equalsIgnoreCase (encoding))
|
||||
return HtmlEncoder.encode (text);
|
||||
if ("xml".equalsIgnoreCase (encoding))
|
||||
return HtmlEncoder.encodeXml (text);
|
||||
if ("form".equalsIgnoreCase (encoding))
|
||||
return HtmlEncoder.encodeFormValue (text);
|
||||
if ("url".equalsIgnoreCase (encoding))
|
||||
return URLEncoder.encode (text);
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
public String toString () {
|
||||
return "[HopMacro: "+getFullName()+"]";
|
||||
return "[HopMacro: "+handler+","+name+"]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full name of the macro in handler.name notation
|
||||
*/
|
||||
public String getFullName () {
|
||||
if (fullname == null) {
|
||||
if (handler == null)
|
||||
fullname = name;
|
||||
else
|
||||
fullname = handler+"."+name;
|
||||
}
|
||||
return fullname;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ package helma.framework.core;
|
|||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import helma.util.Updatable;
|
||||
import helma.objectmodel.IServer;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -13,7 +13,7 @@ import helma.util.Updatable;
|
|||
*/
|
||||
|
||||
|
||||
public class SkinFile implements Updatable {
|
||||
public class SkinFile {
|
||||
|
||||
String name;
|
||||
Prototype prototype;
|
||||
|
@ -30,65 +30,28 @@ public class SkinFile implements Updatable {
|
|||
this.skin = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a skinfile without a file, passing the skin body directly. This is used for
|
||||
* Skins contained in zipped applications. The whole update mechanism is bypassed
|
||||
* by immediately setting the skin member.
|
||||
*/
|
||||
public SkinFile (String body, String name, Prototype proto) {
|
||||
this.prototype = proto;
|
||||
this.app = proto.app;
|
||||
this.name = name;
|
||||
this.file = null;
|
||||
this.skin = new Skin (body, app);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a skinfile without that doesn't belong to a prototype, or at
|
||||
* least it doesn't know about its prototype and isn't managed by the prototype.
|
||||
*/
|
||||
public SkinFile (File file, String name, Application app) {
|
||||
this.prototype = null;
|
||||
this.app = app;
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
this.skin = null;
|
||||
}
|
||||
public void update (File f) {
|
||||
|
||||
this.file = f;
|
||||
|
||||
/**
|
||||
* Tell the type manager whether we need an update. this is the case when
|
||||
* the file has been modified or deleted.
|
||||
*/
|
||||
public boolean needsUpdate () {
|
||||
return (skin != null && lastmod != file.lastModified ()) || !file.exists ();
|
||||
}
|
||||
long fmod = file.lastModified ();
|
||||
// we only update this if we already have read the skin
|
||||
if (skin == null || lastmod == fmod)
|
||||
return;
|
||||
|
||||
|
||||
public void update () {
|
||||
|
||||
if (!file.exists ()) {
|
||||
// remove skin from prototype
|
||||
if (prototype != null) {
|
||||
prototype.skins.remove (name);
|
||||
prototype.updatables.remove (file.getName());
|
||||
}
|
||||
} else {
|
||||
// we only need to update if the skin has already been initialized
|
||||
if (skin != null)
|
||||
read ();
|
||||
}
|
||||
read ();
|
||||
}
|
||||
|
||||
private void read () {
|
||||
try {
|
||||
FileReader reader = new FileReader (file);
|
||||
char c[] = new char[(int) file.length()];
|
||||
int length = reader.read (c);
|
||||
reader.read (c);
|
||||
reader.close();
|
||||
skin = new Skin (c, length, app);
|
||||
skin = new Skin (new String (c));
|
||||
} catch (IOException x) {
|
||||
app.logEvent ("Error reading Skin "+file+": "+x);
|
||||
IServer.getLogger().log ("Error reading Skin "+file+": "+x);
|
||||
}
|
||||
|
||||
lastmod = file.lastModified ();
|
||||
|
@ -100,14 +63,44 @@ public class SkinFile implements Updatable {
|
|||
return skin;
|
||||
}
|
||||
|
||||
public String getName () {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return prototype.getName()+"/"+file.getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
// SkinManager.java
|
||||
// Copyright (c) Hannes Wallnöfer 2002
|
||||
|
||||
package helma.framework.core;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.Iterator;
|
||||
import helma.objectmodel.INode;
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* Manages skins for a Helma application
|
||||
*/
|
||||
|
||||
|
||||
public class SkinManager {
|
||||
|
||||
Application app;
|
||||
Map skincache;
|
||||
|
||||
public SkinManager (Application app) {
|
||||
this.app = app;
|
||||
skincache = new WeakHashMap ();
|
||||
}
|
||||
|
||||
public Skin getSkin (Object object, String skinname, Object[] skinpath) {
|
||||
Prototype proto = app.getPrototype (object);
|
||||
String key = new StringBuffer(proto.getName()).append ("/").append (skinname)
|
||||
.append ("#").append (skinpath.hashCode()).toString ();
|
||||
// System.err.print ("SKINKEY: "+key);
|
||||
Skin skin = (Skin) skincache.get (key);
|
||||
if (skin != null) {
|
||||
// System.err.println (" ... cached");
|
||||
return skin;
|
||||
}
|
||||
// System.err.println (" ... uncached");
|
||||
skin = getSkin (proto, skinname, "skin", skinpath);
|
||||
if (skin != null)
|
||||
skincache.put (key, skin);
|
||||
return skin;
|
||||
}
|
||||
|
||||
|
||||
protected Skin getSkin (Prototype proto, String skinname, String extension, Object[] skinpath) {
|
||||
if (proto == null)
|
||||
return null;
|
||||
Skin skin = null;
|
||||
// First check if the skin has been already used within the execution of this request
|
||||
// check for skinsets set via res.skinpath property
|
||||
do {
|
||||
if (skinpath != null) {
|
||||
for (int i=0; i<skinpath.length; i++) {
|
||||
skin = getSkinInternal (skinpath[i], proto.getName (), skinname, extension);
|
||||
if (skin != null) {
|
||||
return skin;
|
||||
}
|
||||
}
|
||||
}
|
||||
// skin for this prototype wasn't found in the skinsets.
|
||||
// the next step is to look if it is defined as skin file in the application directory
|
||||
skin = proto.getSkin (skinname);
|
||||
if (skin != null) {
|
||||
return skin;
|
||||
}
|
||||
// still not found. See if there is a parent prototype which might define the skin.
|
||||
proto = proto.getParentPrototype ();
|
||||
} while (proto != null);
|
||||
// looked every where, nothing to be found
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected Skin getSkinInternal (Object skinset, String prototype, String skinname, String extension) {
|
||||
if (prototype == null || skinset == null)
|
||||
return null;
|
||||
// check if the skinset object is a HopObject (db based skin)
|
||||
// or a String (file based skin)
|
||||
if (skinset instanceof INode) {
|
||||
INode n = ((INode) skinset).getNode (prototype, false);
|
||||
if (n != null) {
|
||||
n = n.getNode (skinname, false);
|
||||
if (n != null) {
|
||||
String skin = n.getString (extension, false);
|
||||
if (skin != null) {
|
||||
Skin s = (Skin) app.skincache.get (skin);
|
||||
if (s == null) {
|
||||
s = new Skin (skin, app);
|
||||
app.skincache.put (skin, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Skinset is interpreted as directory name from which to
|
||||
// retrieve the skin
|
||||
File f = new File (skinset.toString (), prototype);
|
||||
f = new File (f, skinname+"."+extension);
|
||||
if (f.exists() && f.canRead()) {
|
||||
SkinFile sf = new SkinFile (f, skinname, app);
|
||||
Skin s = sf.getSkin ();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
// Inheritance is taken care of in the above getSkin method.
|
||||
// the sequence is prototype.skin-from-db, prototype.skin-from-file, parent.from-db, parent.from-file etc.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility class to use for caching skins in a Hashtable.
|
||||
* The key consists out of two strings: prototype name and skin name.
|
||||
*/
|
||||
final class SkinKey {
|
||||
|
||||
final String first, second, third;
|
||||
|
||||
public SkinKey (String first, String second, String third) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.third = third;
|
||||
}
|
||||
|
||||
public boolean equals (Object other) {
|
||||
try {
|
||||
SkinKey key = (SkinKey) other;
|
||||
return first.equals (key.first) && second.equals (key.second) && third.equals (key.third);
|
||||
} catch (Exception x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode () {
|
||||
return first.hashCode () + second.hashCode () + third.hashCode ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,47 +1,37 @@
|
|||
// Template.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.scripting;
|
||||
package helma.framework.core;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
import java.util.StringTokenizer;
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
// import FESI.Data.*;
|
||||
// import FESI.Exceptions.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Exceptions.*;
|
||||
|
||||
|
||||
/**
|
||||
* This represents a Helma template, i.e. a file with the extension .hsp
|
||||
* (Helma server page) that contains both parts that are to be evaluated
|
||||
* This represents a HOP template, i.e. a file with the extension .hsp
|
||||
* (HOP server page) that contains both parts that are to be evaluated
|
||||
* as EcmaScript and parts that are to be delivered to the client as-is.
|
||||
* Internally, templates are regular functions.
|
||||
* Helma templates are callable via URL, but this is just a leftover from the
|
||||
* HOP templates are callable via URL, but this is just a leftover from the
|
||||
* days when there were no .hac (action) files. The recommended way
|
||||
* now is to have a .hac file with all the logic which in turn calls one or more
|
||||
* template files to do the formatting.
|
||||
*/
|
||||
|
||||
public class Template extends ActionFile {
|
||||
public class Template extends Action {
|
||||
|
||||
// this is the *_as_string function, which is in addition to the normal one
|
||||
// TypeUpdater psfunc;
|
||||
TypeUpdater psfunc;
|
||||
|
||||
|
||||
public Template (File file, String name, Prototype proto) {
|
||||
super (file, name, proto);
|
||||
functionName = name;
|
||||
}
|
||||
|
||||
public Template (String content, String name, Prototype proto) {
|
||||
super (content, name, proto);
|
||||
functionName = name;
|
||||
}
|
||||
|
||||
|
||||
public String getContent () {
|
||||
public void update (String content) throws Exception {
|
||||
// IServer.getLogger().log ("Reading text template " + name);
|
||||
|
||||
Vector partBuffer = new Vector ();
|
||||
|
@ -105,7 +95,7 @@ public class Template extends ActionFile {
|
|||
// append a CRLF
|
||||
newLineCount++;
|
||||
templateBody.append ("\\r\\n");
|
||||
} else if (!"\r".equals (nextLine)) try {
|
||||
} else if (!"\r".equals (nextLine)){
|
||||
StringReader lineReader = new StringReader (nextLine);
|
||||
int c = lineReader.read ();
|
||||
while (c > -1) {
|
||||
|
@ -115,7 +105,7 @@ public class Template extends ActionFile {
|
|||
templateBody.append ((char) c);
|
||||
c = lineReader.read ();
|
||||
}
|
||||
} catch (IOException srx) {}
|
||||
}
|
||||
|
||||
nextLine = st.hasMoreTokens () ? st.nextToken () : null;
|
||||
|
||||
|
@ -143,9 +133,7 @@ public class Template extends ActionFile {
|
|||
}
|
||||
// templateBody.append ("\r\nreturn null;\r\n");
|
||||
|
||||
return templateBody.toString ();
|
||||
|
||||
/*
|
||||
functionName = name;
|
||||
String fname = name+"_as_string";
|
||||
String body = templateBody.toString ();
|
||||
|
||||
|
@ -153,7 +141,7 @@ public class Template extends ActionFile {
|
|||
pfunc = parseFunction (name,
|
||||
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
||||
body+"\r\nreturn null;\r\n");
|
||||
} catch (Throwable x) {
|
||||
} catch (Exception x) {
|
||||
String message = x.getMessage ();
|
||||
pfunc = new ErrorFeedback (name, message);
|
||||
}
|
||||
|
@ -161,7 +149,7 @@ public class Template extends ActionFile {
|
|||
psfunc = parseFunction (fname,
|
||||
"arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10",
|
||||
"res.pushStringBuffer(); "+body+"\r\nreturn res.popStringBuffer();\r\n");
|
||||
} catch (Throwable x) {
|
||||
} catch (Exception x) {
|
||||
String message = x.getMessage ();
|
||||
psfunc = new ErrorFeedback (fname, message);
|
||||
}
|
||||
|
@ -172,40 +160,15 @@ public class Template extends ActionFile {
|
|||
RequestEvaluator reval = (RequestEvaluator) evals.next ();
|
||||
updateRequestEvaluator (reval);
|
||||
} catch (Exception ignore) {}
|
||||
} */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void remove () {
|
||||
prototype.templates.remove (name);
|
||||
if (file != null)
|
||||
prototype.updatables.remove (file.getName());
|
||||
|
||||
/* Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
|
||||
while (evals.hasNext ()) {
|
||||
try {
|
||||
RequestEvaluator reval = (RequestEvaluator) evals.next ();
|
||||
ObjectPrototype op = reval.getPrototype (prototype.getName());
|
||||
functionName = name;
|
||||
ESValue esv = (ESValue) op.getProperty (functionName, functionName.hashCode());
|
||||
if (esv instanceof ConstructedFunctionObject || esv instanceof ThrowException) {
|
||||
op.deleteProperty (functionName, functionName.hashCode());
|
||||
}
|
||||
String fname = name+"_as_string";
|
||||
esv = (ESValue) op.getProperty (fname, fname.hashCode());
|
||||
if (esv instanceof ConstructedFunctionObject || esv instanceof ThrowException) {
|
||||
op.deleteProperty (fname, fname.hashCode());
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
} */
|
||||
}
|
||||
|
||||
|
||||
/* public synchronized void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
|
||||
public synchronized void updateRequestEvaluator (RequestEvaluator reval) throws EcmaScriptException {
|
||||
if (pfunc != null)
|
||||
pfunc.updateRequestEvaluator (reval);
|
||||
if (psfunc != null)
|
||||
psfunc.updateRequestEvaluator (reval);
|
||||
} */
|
||||
}
|
||||
|
||||
class Part {
|
||||
|
||||
|
@ -233,9 +196,34 @@ public class Template extends ActionFile {
|
|||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -4,9 +4,9 @@
|
|||
package helma.framework.core;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
import helma.scripting.*;
|
||||
import helma.util.*;
|
||||
import FESI.Exceptions.*;
|
||||
import FESI.Data.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
|
@ -16,13 +16,12 @@ import java.io.*;
|
|||
* applications and updates the evaluators if anything has changed.
|
||||
*/
|
||||
|
||||
public class TypeManager {
|
||||
public class TypeManager implements Runnable {
|
||||
|
||||
Application app;
|
||||
File appDir;
|
||||
HashMap prototypes;
|
||||
HashMap zipfiles;
|
||||
long lastCheck = 0;
|
||||
Hashtable prototypes;
|
||||
Prototype nodeProto;
|
||||
long idleSeconds = 120; // if idle for longer than 5 minutes, slow down
|
||||
boolean rewire;
|
||||
|
||||
|
@ -30,366 +29,293 @@ public class TypeManager {
|
|||
// and thus need to get updates
|
||||
List registeredEvaluators;
|
||||
|
||||
Thread typechecker;
|
||||
|
||||
// The http broadcaster for pushing out parser output
|
||||
// static WebBroadcaster broadcaster;
|
||||
// static {
|
||||
// try {
|
||||
// broadcaster = new WebBroadcaster (9999);
|
||||
// } catch (IOException ignore) {}
|
||||
// }
|
||||
|
||||
static HashSet standardTypes;
|
||||
static {
|
||||
standardTypes = new HashSet ();
|
||||
standardTypes.add ("user");
|
||||
standardTypes.add ("global");
|
||||
standardTypes.add ("root");
|
||||
standardTypes.add ("hopobject");
|
||||
}
|
||||
|
||||
public TypeManager (Application app) {
|
||||
this.app = app;
|
||||
appDir = app.appDir;
|
||||
// make sure the directories for the standard prototypes exist, and lament otherwise
|
||||
if (appDir.list().length == 0) {
|
||||
for (Iterator it=standardTypes.iterator (); it.hasNext (); ) {
|
||||
File f = new File (appDir, (String) it.next ());
|
||||
if (!f.exists() && !f.mkdir ())
|
||||
app.logEvent ("Warning: directory "+f.getAbsolutePath ()+" could not be created.");
|
||||
else if (!f.isDirectory ())
|
||||
app.logEvent ("Warning: "+f.getAbsolutePath ()+" is not a directory.");
|
||||
}
|
||||
}
|
||||
prototypes = new HashMap ();
|
||||
zipfiles = new HashMap ();
|
||||
registeredEvaluators = Collections.synchronizedList (new ArrayList ());
|
||||
File f = new File (appDir, "user");
|
||||
if (!f.exists())
|
||||
f.mkdir ();
|
||||
f = new File (appDir, "root");
|
||||
if (!f.exists())
|
||||
f.mkdir ();
|
||||
f = new File (appDir, "global");
|
||||
if (!f.exists())
|
||||
f.mkdir ();
|
||||
prototypes = new Hashtable ();
|
||||
registeredEvaluators = Collections.synchronizedList (new ArrayList (30));
|
||||
nodeProto = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run through application's prototype directories and create prototypes, but don't
|
||||
* compile or evaluate any scripts.
|
||||
*/
|
||||
public void createPrototypes () {
|
||||
check (false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run through application's prototype directories and check if anything has been updated.
|
||||
* If so, update prototypes and scripts.
|
||||
*/
|
||||
public synchronized void checkPrototypes () {
|
||||
if (System.currentTimeMillis () - lastCheck < 500l)
|
||||
return;
|
||||
try {
|
||||
check (true);
|
||||
} catch (Exception ignore) {}
|
||||
lastCheck = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run through application's prototype directories and check if anything has been updated.
|
||||
*/
|
||||
public void check (boolean update) {
|
||||
public void check () {
|
||||
// long now = System.currentTimeMillis ();
|
||||
// System.out.print ("checking "+Thread.currentThread ());
|
||||
File[] list = appDir.listFiles ();
|
||||
if (list == null)
|
||||
throw new RuntimeException ("Can't read app directory "+appDir+" - check permissions");
|
||||
for (int i=0; i<list.length; i++) {
|
||||
String filename = list[i].getName ();
|
||||
Prototype proto = getPrototype (filename);
|
||||
if (proto != null) {
|
||||
// check if existing prototype needs update
|
||||
// app.logEvent (protoDir.lastModified ());
|
||||
updatePrototype (filename, list[i], proto);
|
||||
} else if (list[i].isDirectory () && isValidTypeName (filename)) {
|
||||
// leave out ".." and other directories that contain "."
|
||||
// create new prototype
|
||||
proto = new Prototype (filename, app);
|
||||
registerPrototype (filename, list[i], proto, update);
|
||||
prototypes.put (filename, proto);
|
||||
// give logger thread a chance to tell what's going on
|
||||
// Thread.yield();
|
||||
} else if (filename.toLowerCase().endsWith (".zip") && !list[i].isDirectory ()) {
|
||||
ZippedAppFile zipped = (ZippedAppFile) zipfiles.get (filename);
|
||||
if (zipped == null) {
|
||||
zipped = new ZippedAppFile (list[i], app);
|
||||
zipfiles.put (filename, zipped);
|
||||
try {
|
||||
String[] list = appDir.list ();
|
||||
for (int i=0; i<list.length; i++) {
|
||||
File protoDir = new File (appDir, list[i]);
|
||||
// cut out ".." and other directories that contain "."
|
||||
if (isValidTypeName (list[i]) && protoDir.isDirectory ()) {
|
||||
Prototype proto = getPrototype (list[i]);
|
||||
if (proto != null) {
|
||||
// check if existing prototype needs update
|
||||
// IServer.getLogger().log (protoDir.lastModified ());
|
||||
updatePrototype (list[i], protoDir, proto);
|
||||
} else {
|
||||
// create new prototype
|
||||
proto = new Prototype (protoDir, app);
|
||||
registerPrototype (list[i], protoDir, proto);
|
||||
prototypes.put (list[i], proto);
|
||||
if ("hopobject".equalsIgnoreCase (list[i]))
|
||||
nodeProto = proto;
|
||||
// give logger thread a chance to tell what's going on
|
||||
Thread.yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop through zip files to check for updates
|
||||
for (Iterator it=zipfiles.values ().iterator (); it.hasNext (); ) {
|
||||
ZippedAppFile zipped = (ZippedAppFile) it.next ();
|
||||
if (zipped.needsUpdate ()) {
|
||||
zipped.update ();
|
||||
}
|
||||
}
|
||||
|
||||
// check if standard prototypes have been created
|
||||
// as a performance hack, we only do this when update is false, i.e. the first time we're called.
|
||||
if (!update) {
|
||||
for (Iterator it=standardTypes.iterator (); it.hasNext (); ) {
|
||||
String pname = (String) it.next();
|
||||
if (prototypes.get (pname) == null) {
|
||||
Prototype proto = new Prototype (pname, app);
|
||||
registerPrototype (pname, new File (appDir, pname), proto, false);
|
||||
prototypes.put (pname, proto);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
IServer.getLogger().log (this+": "+ignore);
|
||||
}
|
||||
|
||||
if (rewire) {
|
||||
// there have been changes in the DbMappings
|
||||
// there have been changes @ DbMappings
|
||||
app.rewireDbMappings ();
|
||||
rewire = false;
|
||||
}
|
||||
// app.logEvent (" ...done @ "+ (System.currentTimeMillis () - now)+ "--- "+idleSeconds);
|
||||
// IServer.getLogger().log (" ...done @ "+ (System.currentTimeMillis () - now)+ "--- "+idleSeconds);
|
||||
}
|
||||
|
||||
|
||||
private boolean isValidTypeName (String str) {
|
||||
if (str == null)
|
||||
return false;
|
||||
char[] c = str.toCharArray ();
|
||||
for (int i=0; i<c.length; i++)
|
||||
if (!Character.isJavaIdentifierPart (c[i]))
|
||||
int l = str.length ();
|
||||
if (l == 0)
|
||||
return false;
|
||||
for (int i=0; i<l; i++)
|
||||
if (!Character.isJavaIdentifierPart (str.charAt (i)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a prototype defined for this application
|
||||
*/
|
||||
public void start () {
|
||||
stop ();
|
||||
typechecker = new Thread (this, "Typechecker-"+app.getName());
|
||||
typechecker.setPriority (Thread.MIN_PRIORITY);
|
||||
typechecker.start ();
|
||||
}
|
||||
|
||||
public void stop () {
|
||||
if (typechecker != null && typechecker.isAlive ())
|
||||
typechecker.interrupt ();
|
||||
typechecker = null;
|
||||
}
|
||||
|
||||
public Prototype getPrototype (String typename) {
|
||||
return (Prototype) prototypes.get (typename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a prototype, creating it if id doesn't already exist
|
||||
*/
|
||||
public Prototype createPrototype (String typename) {
|
||||
Prototype p = getPrototype (typename);
|
||||
if (p == null) {
|
||||
p = new Prototype (typename, app);
|
||||
p.templates = new HashMap ();
|
||||
p.functions = new HashMap ();
|
||||
p.actions = new HashMap ();
|
||||
p.skins = new HashMap ();
|
||||
p.updatables = new HashMap ();
|
||||
prototypes.put (typename, p);
|
||||
|
||||
public void run () {
|
||||
|
||||
while (Thread.currentThread () == typechecker) {
|
||||
idleSeconds++;
|
||||
try {
|
||||
// for each idle minute, add 300 ms to sleeptime until 5 secs are reached.
|
||||
// (10 secs are reached after 30 minutes of idle state)
|
||||
// the above is all false.
|
||||
long sleeptime = 1500 + Math.min (idleSeconds*30, 3500);
|
||||
typechecker.sleep (sleeptime);
|
||||
} catch (InterruptedException x) {
|
||||
// IServer.getLogger().log ("Typechecker interrupted");
|
||||
break;
|
||||
}
|
||||
check ();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a prototype from a directory containing scripts and other stuff
|
||||
*/
|
||||
public void registerPrototype (String name, File dir, Prototype proto, boolean update) {
|
||||
// app.logEvent ("registering prototype "+name);
|
||||
public void registerPrototype (String name, File dir, Prototype proto) {
|
||||
// IServer.getLogger().log ("registering prototype "+name);
|
||||
|
||||
// show the type checker thread that there has been type activity
|
||||
idleSeconds = 0;
|
||||
|
||||
HashMap ntemp = new HashMap ();
|
||||
HashMap nfunc = new HashMap ();
|
||||
HashMap nact = new HashMap ();
|
||||
HashMap nskins = new HashMap ();
|
||||
HashMap updatables = new HashMap ();
|
||||
String list[] = dir.list();
|
||||
Hashtable ntemp = new Hashtable ();
|
||||
Hashtable nfunc = new Hashtable ();
|
||||
Hashtable nact = new Hashtable ();
|
||||
Hashtable nskins = new Hashtable ();
|
||||
|
||||
if (update) {
|
||||
String list[] = dir.list();
|
||||
for (int i=0; i<list.length; i++) {
|
||||
File tmpfile = new File (dir, list[i]);
|
||||
int dot = list[i].indexOf (".");
|
||||
|
||||
if (dot < 0)
|
||||
continue;
|
||||
|
||||
String tmpname = list[i].substring(0, dot);
|
||||
|
||||
if (list[i].endsWith (app.templateExtension)) {
|
||||
try {
|
||||
Template t = new Template (tmpfile, tmpname, proto);
|
||||
updatables.put (list[i], t);
|
||||
ntemp.put (tmpname, t);
|
||||
} catch (Throwable x) {
|
||||
app.logEvent ("Error creating prototype: "+x);
|
||||
}
|
||||
|
||||
} else if (list[i].endsWith (app.scriptExtension) && tmpfile.length () > 0) {
|
||||
try {
|
||||
FunctionFile ff = new FunctionFile (tmpfile, tmpname, proto);
|
||||
updatables.put (list[i], ff);
|
||||
nfunc.put (tmpname, ff);
|
||||
} catch (Throwable x) {
|
||||
app.logEvent ("Error creating prototype: "+x);
|
||||
}
|
||||
|
||||
} else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) {
|
||||
try {
|
||||
ActionFile af = new ActionFile (tmpfile, tmpname, proto);
|
||||
updatables.put (list[i], af);
|
||||
nact.put (tmpname, af);
|
||||
} catch (Throwable x) {
|
||||
app.logEvent ("Error creating prototype: "+x);
|
||||
}
|
||||
} else if (list[i].endsWith (app.skinExtension)) {
|
||||
try {
|
||||
SkinFile sf = new SkinFile (tmpfile, tmpname, proto);
|
||||
updatables.put (list[i], sf);
|
||||
nskins.put (tmpname, sf);
|
||||
} catch (Throwable x) {
|
||||
app.logEvent ("Error creating prototype: "+x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create and register type properties file
|
||||
File propfile = new File (dir, "type.properties");
|
||||
SystemProperties props = new SystemProperties (propfile.getAbsolutePath ());
|
||||
DbMapping dbmap = new DbMapping (app, name, props);
|
||||
updatables.put ("type.properties", dbmap);
|
||||
|
||||
|
||||
proto.templates = ntemp;
|
||||
proto.functions = nfunc;
|
||||
proto.actions = nact;
|
||||
proto.skins = nskins;
|
||||
proto.updatables = updatables;
|
||||
|
||||
// init prototype on evaluators that are already initialized.
|
||||
/* Iterator evals = getRegisteredRequestEvaluators ();
|
||||
while (evals.hasNext ()) {
|
||||
RequestEvaluator reval = (RequestEvaluator) evals.next ();
|
||||
proto.initRequestEvaluator (reval);
|
||||
}*/
|
||||
app.scriptingEngine.updatePrototype (proto);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update a prototype based on the directory which defines it.
|
||||
*/
|
||||
public void updatePrototype (String name, File dir, Prototype proto) {
|
||||
|
||||
boolean needsUpdate = false;
|
||||
HashSet updatables = null;
|
||||
|
||||
// our plan is to do as little as possible, so first check if anything has changed at all...
|
||||
for (Iterator i = proto.updatables.values().iterator(); i.hasNext(); ) {
|
||||
Updatable upd = (Updatable) i.next();
|
||||
if (upd.needsUpdate ()) {
|
||||
if (updatables == null)
|
||||
updatables = new HashSet ();
|
||||
needsUpdate = true;
|
||||
updatables.add (upd);
|
||||
}
|
||||
}
|
||||
|
||||
// check if file have been created since last update
|
||||
if (proto.lastUpdate < dir.lastModified ()) {
|
||||
String[] list = dir.list();
|
||||
for (int i=0; i<list.length; i++) {
|
||||
String fn = list[i];
|
||||
if (!proto.updatables.containsKey (fn)) {
|
||||
if (fn.endsWith (app.templateExtension) || fn.endsWith (app.scriptExtension) ||
|
||||
fn.endsWith (app.actionExtension) || fn.endsWith (app.skinExtension) ||
|
||||
"type.properties".equalsIgnoreCase (fn)) {
|
||||
needsUpdate = true;
|
||||
// updatables.add ("[new:"+proto.getName()+"/"+fn+"]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!needsUpdate)
|
||||
return;
|
||||
|
||||
proto.lastUpdate = System.currentTimeMillis ();
|
||||
|
||||
// let the thread know we had to do something.
|
||||
idleSeconds = 0;
|
||||
// app.logEvent ("TypeManager: Updating prototypes for "+app.getName()+": "+updatables);
|
||||
|
||||
// first go through new files and create new items
|
||||
String[] list = dir.list ();
|
||||
for (int i=0; i<list.length; i++) {
|
||||
String fn = list[i];
|
||||
int dot = fn.indexOf (".");
|
||||
File tmpfile = new File (dir, list[i]);
|
||||
int dot = list[i].indexOf (".");
|
||||
|
||||
if (dot < 0)
|
||||
continue;
|
||||
|
||||
if (proto.updatables.containsKey (fn) || !(fn.endsWith (app.templateExtension) || fn.endsWith (app.scriptExtension) ||
|
||||
fn.endsWith (app.actionExtension) || fn.endsWith (app.skinExtension) || "type.properties".equalsIgnoreCase (fn))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String tmpname = list[i].substring(0, dot);
|
||||
File tmpfile = new File (dir, list[i]);
|
||||
|
||||
if (list[i].endsWith (app.templateExtension)) {
|
||||
try {
|
||||
Template t = new Template (tmpfile, tmpname, proto);
|
||||
proto.updatables.put (list[i], t);
|
||||
proto.templates.put (tmpname, t);
|
||||
ntemp.put (tmpname, t);
|
||||
} catch (Throwable x) {
|
||||
app.logEvent ("Error updating prototype: "+x);
|
||||
IServer.getLogger().log ("Error creating prototype: "+x);
|
||||
}
|
||||
|
||||
} else if (list[i].endsWith (app.scriptExtension)) {
|
||||
} else if (list[i].endsWith (app.scriptExtension) && tmpfile.length () > 0) {
|
||||
try {
|
||||
FunctionFile ff = new FunctionFile (tmpfile, tmpname, proto);
|
||||
proto.updatables.put (list[i], ff);
|
||||
proto.functions.put (tmpname, ff);
|
||||
nfunc.put (tmpname, ff);
|
||||
} catch (Throwable x) {
|
||||
app.logEvent ("Error updating prototype: "+x);
|
||||
IServer.getLogger().log ("Error creating prototype: "+x);
|
||||
}
|
||||
|
||||
} else if (list[i].endsWith (app.actionExtension)) {
|
||||
} else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) {
|
||||
try {
|
||||
ActionFile af = new ActionFile (tmpfile, tmpname, proto);
|
||||
proto.updatables.put (list[i], af);
|
||||
proto.actions.put (tmpname, af);
|
||||
Action af = new Action (tmpfile, tmpname, proto);
|
||||
nact.put (tmpname, af);
|
||||
} catch (Throwable x) {
|
||||
app.logEvent ("Error updating prototype: "+x);
|
||||
IServer.getLogger().log ("Error creating prototype: "+x);
|
||||
}
|
||||
} else if (list[i].endsWith (app.skinExtension)) {
|
||||
try {
|
||||
SkinFile sf = new SkinFile (tmpfile, tmpname, proto);
|
||||
nskins.put (tmpname, sf);
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error creating prototype: "+x);
|
||||
}
|
||||
}
|
||||
}
|
||||
proto.templates = ntemp;
|
||||
proto.functions = nfunc;
|
||||
proto.actions = nact;
|
||||
proto.skins = nskins;
|
||||
|
||||
} else if (list[i].endsWith (app.skinExtension)) {
|
||||
SkinFile sf = new SkinFile (tmpfile, tmpname, proto);
|
||||
proto.updatables.put (list[i], sf);
|
||||
proto.skins.put (tmpname, sf);
|
||||
}
|
||||
// init prototype on evaluators that are already initialized.
|
||||
Iterator evals = getRegisteredRequestEvaluators ();
|
||||
while (evals.hasNext ()) {
|
||||
RequestEvaluator reval = (RequestEvaluator) evals.next ();
|
||||
proto.initRequestEvaluator (reval);
|
||||
}
|
||||
|
||||
// next go through existing updatables
|
||||
if (updatables != null) {
|
||||
for (Iterator i = updatables.iterator(); i.hasNext(); ) {
|
||||
Updatable upd = (Updatable) i.next();
|
||||
|
||||
if (upd.needsUpdate ()) {
|
||||
if (upd instanceof DbMapping)
|
||||
rewire = true;
|
||||
try {
|
||||
upd.update ();
|
||||
} catch (Exception x) {
|
||||
if (upd instanceof DbMapping)
|
||||
app.logEvent ("Error updating db mapping for type "+name+": "+x);
|
||||
else
|
||||
app.logEvent ("Error updating "+upd+" of prototye type "+name+": "+x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
app.scriptingEngine.updatePrototype (proto);
|
||||
}
|
||||
|
||||
|
||||
/*public void initRequestEvaluator (RequestEvaluator reval) {
|
||||
public void updatePrototype (String name, File dir, Prototype proto) {
|
||||
// IServer.getLogger().log ("updating prototype "+name);
|
||||
|
||||
String list[] = dir.list();
|
||||
Hashtable ntemp = new Hashtable ();
|
||||
Hashtable nfunc = new Hashtable ();
|
||||
Hashtable nact = new Hashtable ();
|
||||
Hashtable nskins = new Hashtable ();
|
||||
|
||||
for (int i=0; i<list.length; i++) {
|
||||
File tmpfile = new File (dir, list[i]);
|
||||
int dot = list[i].indexOf (".");
|
||||
|
||||
if (dot < 0)
|
||||
continue;
|
||||
|
||||
String tmpname = list[i].substring(0, dot);
|
||||
if (list[i].endsWith (app.templateExtension)) {
|
||||
Template t = proto.getTemplate (tmpname);
|
||||
try {
|
||||
if (t == null) {
|
||||
t = new Template (tmpfile, tmpname, proto);
|
||||
idleSeconds = 0;
|
||||
} else if (t.lastmod != tmpfile.lastModified ()) {
|
||||
t.update (tmpfile);
|
||||
idleSeconds = 0;
|
||||
}
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error updating prototype: "+x);
|
||||
}
|
||||
ntemp.put (tmpname, t);
|
||||
|
||||
} else if (list[i].endsWith (app.scriptExtension) && tmpfile.length () > 0) {
|
||||
FunctionFile ff = proto.getFunctionFile (tmpname);
|
||||
try {
|
||||
if (ff == null) {
|
||||
ff = new FunctionFile (tmpfile, tmpname, proto);
|
||||
idleSeconds = 0;
|
||||
} else if (ff.lastmod != tmpfile.lastModified ()) {
|
||||
ff.update (tmpfile);
|
||||
idleSeconds = 0;
|
||||
}
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error updating prototype: "+x);
|
||||
}
|
||||
nfunc.put (tmpname, ff);
|
||||
|
||||
} else if (list[i].endsWith (app.actionExtension) && tmpfile.length () > 0) {
|
||||
Action af = proto.getAction (tmpname);
|
||||
try {
|
||||
if (af == null) {
|
||||
af = new Action (tmpfile, tmpname, proto);
|
||||
idleSeconds = 0;
|
||||
} else if (af.lastmod != tmpfile.lastModified ()) {
|
||||
af.update (tmpfile);
|
||||
idleSeconds = 0;
|
||||
}
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error updating prototype: "+x);
|
||||
}
|
||||
nact.put (tmpname, af);
|
||||
|
||||
} else if (list[i].endsWith (app.skinExtension)) {
|
||||
SkinFile sf = proto.getSkinFile (tmpname);
|
||||
try {
|
||||
if (sf == null) {
|
||||
sf = new SkinFile (tmpfile, tmpname, proto);
|
||||
idleSeconds = 0;
|
||||
} else if (sf.lastmod != tmpfile.lastModified ()) {
|
||||
sf.update (tmpfile);
|
||||
idleSeconds = 0;
|
||||
}
|
||||
} catch (Throwable x) {
|
||||
IServer.getLogger().log ("Error updating prototype: "+x);
|
||||
}
|
||||
nskins.put (tmpname, sf);
|
||||
|
||||
} else if ("type.properties".equalsIgnoreCase (list[i])) {
|
||||
try {
|
||||
if (proto.dbmap.read ()) {
|
||||
idleSeconds = 0;
|
||||
rewire = true;
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
IServer.getLogger().log ("Error updating db mapping for type "+name+": "+ignore);
|
||||
}
|
||||
}
|
||||
}
|
||||
proto.templates = ntemp;
|
||||
proto.functions = nfunc;
|
||||
proto.actions = nact;
|
||||
proto.skins = nskins;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void initRequestEvaluator (RequestEvaluator reval) {
|
||||
if (!registeredEvaluators.contains (reval))
|
||||
registeredEvaluators.add (reval);
|
||||
for (Iterator it = prototypes.values().iterator(); it.hasNext(); ) {
|
||||
Prototype p = (Prototype) it.next ();
|
||||
for (Enumeration en = prototypes.elements(); en.hasMoreElements(); ) {
|
||||
Prototype p = (Prototype) en.nextElement ();
|
||||
p.initRequestEvaluator (reval);
|
||||
}
|
||||
reval.initialized = true;
|
||||
|
@ -405,7 +331,103 @@ public class TypeManager {
|
|||
|
||||
public int countRegisteredRequestEvaluators () {
|
||||
return registeredEvaluators.size ();
|
||||
} */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -7,46 +7,29 @@ import java.io.*;
|
|||
import java.util.*;
|
||||
import java.net.URLEncoder;
|
||||
import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.*;
|
||||
|
||||
/**
|
||||
* This represents a user who is currently using the Hop application. This does
|
||||
* 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;
|
||||
String uid, nid;
|
||||
long onSince, lastTouched;
|
||||
|
||||
// used to remember messages to the user between requests -
|
||||
// used for redirects.
|
||||
Node cache;
|
||||
DbMapping umap;
|
||||
String message;
|
||||
|
||||
public User (String sid, Application app) {
|
||||
this.uid = null;
|
||||
this.nhandle = null;
|
||||
this.app = app;
|
||||
setNode (null);
|
||||
umap = app.getDbMapping ("user");
|
||||
cache = new TransientNode ("[session cache]");
|
||||
cache.setPrototype ("user");
|
||||
cache.setDbMapping (umap);
|
||||
this.nid = null;
|
||||
this.app = app;
|
||||
setNode (null);
|
||||
cache = new Node (sid);
|
||||
cache.setPrototype ("user");
|
||||
sessionID = sid;
|
||||
onSince = System.currentTimeMillis ();
|
||||
lastTouched = onSince;
|
||||
|
@ -54,38 +37,26 @@ public class User implements Serializable {
|
|||
|
||||
|
||||
/**
|
||||
* This is used to turn for login and logout.
|
||||
* Calling this weith a DB Node object will turn an anonymous user into a registered or known one.
|
||||
* The user object remains the same, but he or she gets some persistent storage.
|
||||
* On the other side, calling this method with a parameter value of null is means the user
|
||||
* is logged out and will be represented by its transient cache node.
|
||||
* This is used to turn an anonymous user into a registered or known one.
|
||||
* The user object remains the same, but she gets some persistent storage.
|
||||
*/
|
||||
public void setNode (INode n) {
|
||||
// IServer.getLogger().log ("esn = "+esn);
|
||||
if (n == null) {
|
||||
nhandle = null;
|
||||
nid = null;
|
||||
uid = null;
|
||||
} else {
|
||||
uid = n.getElementName ();
|
||||
nhandle = ((Node) n).getHandle ();
|
||||
uid = n.getNameOrID ();
|
||||
nid = n.getID ();
|
||||
umap = n.getDbMapping ();
|
||||
}
|
||||
// System.err.println ("User.setNode: "+nhandle);
|
||||
}
|
||||
|
||||
public INode getNode () {
|
||||
if (nhandle == null) {
|
||||
if (uid == null) {
|
||||
return cache;
|
||||
} else {
|
||||
// in some special cases, a user's node handle may go bad, for instance
|
||||
// if something bad happens during registration. For this reason, we check
|
||||
// if the handle actually works. If not, it is reset to the transient cache, which
|
||||
// means the user is logged out.
|
||||
Node n = nhandle.getNode (app.nmgr.safe);
|
||||
if (n == null) {
|
||||
setNode (null);
|
||||
return cache;
|
||||
}
|
||||
return n;
|
||||
return app.nmgr.safe.getNode (nid, umap);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,37 +69,39 @@ public class User implements Serializable {
|
|||
lastTouched = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
public long lastTouched () {
|
||||
public long touched () {
|
||||
return lastTouched;
|
||||
}
|
||||
|
||||
public long onSince () {
|
||||
return onSince;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the persistent user id of a registered user. This is usually the user name, or
|
||||
* null if the user is not logged in.
|
||||
*/
|
||||
public String getUID () {
|
||||
return uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transient cache node for this user.
|
||||
*/
|
||||
public INode getCache () {
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the session cache node, clearing all properties.
|
||||
* This is done by recreating the cache node object.
|
||||
*/
|
||||
public void clearCache () {
|
||||
cache = new TransientNode ("[session cache]");
|
||||
cache.setPrototype ("user");
|
||||
cache.setDbMapping (umap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,186 +0,0 @@
|
|||
// ZippedFile.java
|
||||
// Copyright (c) Hannes Wallnöfer 2001
|
||||
|
||||
package helma.framework.core;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.io.*;
|
||||
import helma.framework.*;
|
||||
import helma.scripting.*;
|
||||
import helma.util.Updatable;
|
||||
import helma.util.SystemProperties;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
|
||||
/**
|
||||
* This represents a Zip-File which may contain other Updatables for one or more prototypes.
|
||||
*/
|
||||
|
||||
|
||||
public class ZippedAppFile implements Updatable {
|
||||
|
||||
Application app;
|
||||
File file;
|
||||
long lastmod;
|
||||
|
||||
|
||||
public ZippedAppFile (File file, Application app) {
|
||||
this.app = app;
|
||||
this.file = file;
|
||||
// System.err.println ("CREATING ZIP FILE "+this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tell the type manager whether we need an update. this is the case when
|
||||
* the file has been modified or deleted.
|
||||
*/
|
||||
public boolean needsUpdate () {
|
||||
return lastmod != file.lastModified ();
|
||||
}
|
||||
|
||||
|
||||
public void update () {
|
||||
|
||||
if (!file.exists ()) {
|
||||
remove ();
|
||||
|
||||
} else {
|
||||
|
||||
ZipFile zip = null;
|
||||
// collect created protos - we need this to check DbMappings for each created
|
||||
// prototype afterwards
|
||||
HashSet newPrototypes = new HashSet ();
|
||||
try {
|
||||
lastmod = file.lastModified ();
|
||||
// System.err.println ("UPDATING ZIP FILE "+this);
|
||||
zip = new ZipFile (file);
|
||||
for (Enumeration en = zip.entries (); en.hasMoreElements (); ) {
|
||||
ZipEntry entry = (ZipEntry) en.nextElement ();
|
||||
String ename = entry.getName ();
|
||||
StringTokenizer st = new StringTokenizer (ename, "/");
|
||||
if (st.countTokens () == 2) {
|
||||
String dir = st.nextToken ();
|
||||
String fname = st.nextToken ();
|
||||
// System.err.println ("ZIPENTRY: "+ dir +" ~ "+fname);
|
||||
Prototype proto = app.typemgr.getPrototype (dir);
|
||||
if (proto == null) {
|
||||
proto = app.typemgr.createPrototype (dir);
|
||||
newPrototypes.add (proto);
|
||||
}
|
||||
if (fname.endsWith (".hac")) {
|
||||
String name = fname.substring (0, fname.lastIndexOf ("."));
|
||||
String content = getZipEntryContent (zip, entry);
|
||||
// System.err.println ("["+content+"]");
|
||||
ActionFile act = new ActionFile (content, name, proto);
|
||||
proto.actions.put (name, act);
|
||||
}
|
||||
else if (fname.endsWith (".hsp")) {
|
||||
String name = fname.substring (0, fname.lastIndexOf ("."));
|
||||
String content = getZipEntryContent (zip, entry);
|
||||
// System.err.println ("["+content+"]");
|
||||
Template tmp = new Template (content, name, proto);
|
||||
proto.templates.put (name, tmp);
|
||||
}
|
||||
else if (fname.endsWith (".skin")) {
|
||||
String name = fname.substring (0, fname.lastIndexOf ("."));
|
||||
String content = getZipEntryContent (zip, entry);
|
||||
// System.err.println ("["+content+"]");
|
||||
SkinFile skin = new SkinFile (content, name, proto);
|
||||
proto.skins.put (name, skin);
|
||||
}
|
||||
else if (fname.endsWith (".js")) {
|
||||
String name = fname.substring (0, fname.lastIndexOf ("."));
|
||||
String content = getZipEntryContent (zip, entry);
|
||||
// System.err.println ("["+content+"]");
|
||||
FunctionFile ff = new FunctionFile (content, name, proto);
|
||||
proto.functions.put (name, ff);
|
||||
}
|
||||
else if ("type.properties".equalsIgnoreCase (fname)) {
|
||||
String name = fname.substring (0, fname.lastIndexOf ("."));
|
||||
SystemProperties props = new SystemProperties (zip.getInputStream (entry));
|
||||
// DbMapping does its own registering, just construct it.
|
||||
new DbMapping (app, proto.getName (), props);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Iterator it = newPrototypes.iterator (); it.hasNext (); ) {
|
||||
Prototype proto = (Prototype) it.next ();
|
||||
if (app.getDbMapping (proto.getName ()) == null) {
|
||||
// DbMapping doesn't exist, we still need to create one
|
||||
SystemProperties props = new SystemProperties ();
|
||||
// DbMapping does its own registering, just construct it.
|
||||
new DbMapping (app, proto.getName (), props);
|
||||
}
|
||||
}
|
||||
} catch (Throwable x) {
|
||||
System.err.println ("Error updating ZipFile: "+x);
|
||||
} finally {
|
||||
try {
|
||||
zip.close ();
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void remove () {
|
||||
app.typemgr.zipfiles.remove (file.getName());
|
||||
// System.err.println ("REMOVING ZIP FILE "+this);
|
||||
}
|
||||
|
||||
|
||||
public String getZipEntryContent (ZipFile zip, ZipEntry entry) throws IOException {
|
||||
int size = (int) entry.getSize ();
|
||||
char[] c = new char[size];
|
||||
InputStreamReader reader = new InputStreamReader (zip.getInputStream (entry));
|
||||
reader.read (c);
|
||||
return new String (c);
|
||||
}
|
||||
|
||||
|
||||
public String toString () {
|
||||
return file.getName();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// SimplePathElement.java
|
||||
// Copyright Hannes Wallnöfer 2001
|
||||
|
||||
package helma.framework.demo;
|
||||
|
||||
import helma.framework.IPathElement;
|
||||
|
||||
/**
|
||||
* This is an example implementation for the helma.framework.IPathElement interface.
|
||||
* It creates any child element which is requested on the fly without ever asking.
|
||||
*/
|
||||
|
||||
public class SimplePathElement implements IPathElement {
|
||||
|
||||
String name;
|
||||
String prototype;
|
||||
IPathElement parent;
|
||||
|
||||
/**
|
||||
* Constructor for the root element.
|
||||
*/
|
||||
public SimplePathElement () {
|
||||
name = "root";
|
||||
prototype = "root";
|
||||
parent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for non-root elements.
|
||||
*/
|
||||
public SimplePathElement (String n, IPathElement p) {
|
||||
name = n;
|
||||
prototype = "hopobject";
|
||||
parent = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a child element for this object, creating it on the fly.
|
||||
*/
|
||||
public IPathElement getChildElement (String n) {
|
||||
return new SimplePathElement (n, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this object's parent element
|
||||
*/
|
||||
public IPathElement getParentElement () {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element name to be used for this object.
|
||||
*/
|
||||
public String getElementName () {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the scripting prototype to be used for this object.
|
||||
* This will be "root" for the root element and "hopobject for everything else.
|
||||
*/
|
||||
public String getPrototype () {
|
||||
return prototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this element.
|
||||
*/
|
||||
public String toString () {
|
||||
return "SimplePathElement "+name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,12 +16,11 @@
|
|||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
// Modified to use Helma database connections, Hannes Wallnöfer 2000
|
||||
// Modified to use HOP database connections, Hannes Wallnöfer 2000
|
||||
|
||||
package helma.scripting.fesi.extensions;
|
||||
package helma.framework.extensions;
|
||||
|
||||
import helma.framework.core.Application;
|
||||
import helma.objectmodel.db.DbSource;
|
||||
import helma.objectmodel.*;
|
||||
import FESI.Parser.*;
|
||||
import FESI.AST.*;
|
||||
import FESI.Interpreter.*;
|
||||
|
@ -60,12 +59,13 @@ class ESDatabase extends ESObject {
|
|||
ESDatabase(ESObject prototype,
|
||||
Evaluator evaluator,
|
||||
ESObject esRowSetPrototype,
|
||||
DbSource dbsource, int flag) {
|
||||
String dbsource, int flag) {
|
||||
super(prototype, evaluator);
|
||||
this.esRowSetPrototype = esRowSetPrototype; // specific to an evaluator
|
||||
try {
|
||||
connection = dbsource.getConnection ();
|
||||
driverName = dbsource.getDriverName ();
|
||||
DbSource src = (DbSource) IServer.dbSources.get (dbsource.toLowerCase ());
|
||||
connection = src.getConnection ();
|
||||
this.driverName = src.getDriverName ();
|
||||
} catch (Exception e) {
|
||||
// System.err.println("##Cannot find driver class: " + e);
|
||||
// e.printStackTrace();
|
||||
|
@ -717,17 +717,11 @@ public class Database extends Extension {
|
|||
private transient Evaluator evaluator = null;
|
||||
private ESObject esDatabasePrototype = null;
|
||||
private ESObject esRowSetPrototype = null;
|
||||
Application app;
|
||||
|
||||
public Database () {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
public void setApplication (Application app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
////////////////// Added by Hannes Wallnoefer
|
||||
class GlobalGetDBConnection extends BuiltinFunctionObject {
|
||||
GlobalGetDBConnection(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
|
@ -737,12 +731,8 @@ public class Database extends Extension {
|
|||
throws EcmaScriptException {
|
||||
if (arguments.length != 1)
|
||||
throw new EcmaScriptException ("Wrong number of arguments in getDBConnection(dbsource)");
|
||||
String srcname = arguments[0].toString ();
|
||||
DbSource dbsrc = app.getDbSource (srcname.toLowerCase ());
|
||||
if (dbsrc == null)
|
||||
throw new EcmaScriptException ("DbSource "+srcname+" does not exist");
|
||||
ESDatabase db = new ESDatabase (esDatabasePrototype, this.evaluator,
|
||||
esRowSetPrototype, dbsrc, 0);
|
||||
esRowSetPrototype, arguments[0].toString(), 0);
|
||||
return db;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
|
||||
package helma.scripting.fesi.extensions;
|
||||
package helma.framework.extensions;
|
||||
|
||||
import javax.mail.*;
|
||||
import javax.mail.internet.*;
|
||||
|
@ -10,18 +10,19 @@ import javax.activation.*;
|
|||
import java.io.*;
|
||||
import java.util.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.util.*;
|
||||
import helma.objectmodel.*;
|
||||
import FESI.Data.*;
|
||||
import FESI.Interpreter.*;
|
||||
import FESI.Exceptions.*;
|
||||
|
||||
/**
|
||||
* A JavaScript wrapper around a JavaMail message class to send
|
||||
* mail via SMTP from Helma
|
||||
* mail via SMTP from HOP
|
||||
*/
|
||||
|
||||
public class ESMail extends ESObject implements Serializable {
|
||||
|
||||
INode node;
|
||||
MailExtension mailx;
|
||||
Properties mprops;
|
||||
MimeMessage message;
|
||||
|
@ -56,7 +57,7 @@ public class ESMail extends ESObject implements Serializable {
|
|||
Session session = Session.getDefaultInstance(props, null);
|
||||
message = new MimeMessage (session);
|
||||
} catch (Throwable t) {
|
||||
this.evaluator.reval.app.logEvent ("Error in mail constructor: "+t);
|
||||
IServer.getLogger().log ("caught in mail constructor: "+t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,16 +94,20 @@ public class ESMail extends ESObject implements Serializable {
|
|||
multipart = new MimeMultipart ();
|
||||
}
|
||||
for (int i=0; i<val.length; i++) {
|
||||
// FIXME: addPart is broken.
|
||||
MimeBodyPart part = new MimeBodyPart ();
|
||||
Object obj = val[i].toJavaObject ();
|
||||
if (obj instanceof String) {
|
||||
part.setContent (obj.toString (), "text/plain");
|
||||
} else if (obj instanceof File) {
|
||||
FileDataSource source = new FileDataSource ((File) obj);
|
||||
part.setDataHandler (new DataHandler (source));
|
||||
INode node = getNode (val[i]);
|
||||
if (node != null) {
|
||||
BodyPart part = new MimeBodyPart ();
|
||||
IServer.getLogger().log ("Adding MimePart: "+node.getContentType ());
|
||||
NodeDataSource nds=new NodeDataSource (node);
|
||||
part.setDataHandler(new DataHandler(nds));
|
||||
// part.setFileName(filename);
|
||||
// part.setDataHandler (new javax.activation.DataHandler (node.getContent(), node.getContentType ()));
|
||||
multipart.addBodyPart (part);
|
||||
} else if (val[i] != null) {
|
||||
BodyPart part = new MimeBodyPart ();
|
||||
part.setContent (val[i].toString (), "text/plain");
|
||||
multipart.addBodyPart (part);
|
||||
}
|
||||
multipart.addBodyPart (part);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +185,20 @@ public class ESMail extends ESObject implements Serializable {
|
|||
}
|
||||
|
||||
|
||||
private final INode getNode (Object obj) {
|
||||
if (obj == null)
|
||||
return null;
|
||||
if (obj instanceof ESNode)
|
||||
return ((ESNode) obj).getNode ();
|
||||
if (obj instanceof ESWrapper) {
|
||||
Object n = ((ESWrapper) obj).getJavaObject();
|
||||
if (n instanceof INode)
|
||||
return (INode) n;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// FtpExtension.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.scripting.fesi.extensions;
|
||||
package helma.framework.extensions;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import FESI.Parser.*;
|
||||
|
@ -80,8 +80,8 @@ class ESFtpClient extends ESObject {
|
|||
try {
|
||||
ftpclient = new FTPClient ();
|
||||
ftpclient.connect (server);
|
||||
boolean b = ftpclient.login (arguments[0].toString(), arguments[1].toString());
|
||||
return ESBoolean.makeBoolean (b);
|
||||
ftpclient.login (arguments[0].toString(), arguments[1].toString());
|
||||
return ESBoolean.makeBoolean (true);
|
||||
} catch (Exception x) {
|
||||
return ESBoolean.makeBoolean (false);
|
||||
} catch (NoClassDefFoundError x) {
|
|
@ -1,7 +1,7 @@
|
|||
// ImageExtension.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.scripting.fesi.extensions;
|
||||
package helma.framework.extensions;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import helma.util.*;
|
||||
|
@ -13,7 +13,6 @@ import FESI.Extensions.*;
|
|||
import FESI.Data.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.awt.image.*;
|
||||
import java.util.*;
|
||||
import java.rmi.Naming;
|
||||
|
||||
|
@ -79,12 +78,7 @@ public class ImageExtension extends Extension {
|
|||
(Object) imggen.createPaintableImage (imgurl);
|
||||
}
|
||||
} else if (arguments.length == 2) {
|
||||
if (arguments[0] instanceof ESWrapper && arguments[1] instanceof ESWrapper) {
|
||||
// create a new image from an existing one and an image filter
|
||||
Object image = arguments[0].toJavaObject ();
|
||||
Object filter = arguments[1].toJavaObject ();
|
||||
img = imggen.createPaintableImage ((ImageWrapper) image, (ImageFilter) filter);
|
||||
} else if (arguments[0].isNumberValue () && arguments[1].isNumberValue ()) {
|
||||
if (arguments[0].isNumberValue () && arguments[1].isNumberValue ()) {
|
||||
img = remote ?
|
||||
(Object) rgen.createPaintableImage (arguments[0].toInt32(), arguments[1].toInt32()) :
|
||||
(Object) imggen.createPaintableImage (arguments[0].toInt32(), arguments[1].toInt32());
|
|
@ -1,8 +1,9 @@
|
|||
// MailExtension.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.scripting.fesi.extensions;
|
||||
package helma.framework.extensions;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import helma.util.*;
|
||||
|
||||
import FESI.Interpreter.*;
|
||||
|
@ -242,7 +243,7 @@ public class MailExtension extends Extension {
|
|||
try {
|
||||
mail.send ();
|
||||
} catch (Exception x) {
|
||||
this.evaluator.reval.app.logEvent ("Error sending mail: "+x);
|
||||
IServer.getLogger().log ("Error sending mail: "+x);
|
||||
mail.setStatus (ESMail.SEND);
|
||||
return ESBoolean.makeBoolean(false);
|
||||
}
|
47
src/helma/image/ActivatedImageWrapper.java
Normal file
47
src/helma/image/ActivatedImageWrapper.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
// ActivatedImageWrapper.java
|
||||
// Copyright (c) Hannes Wallnöfer 1999-2000
|
||||
|
||||
package helma.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import com.activated.jimi.*;
|
||||
import com.activated.jimi.util.*;
|
||||
|
||||
/**
|
||||
* A wrapper for an image that uses the Activated version of JIMI.
|
||||
*/
|
||||
|
||||
public class ActivatedImageWrapper extends ImageWrapper {
|
||||
|
||||
public ActivatedImageWrapper (Image img, Graphics g, int width, int height,
|
||||
ImageGenerator imggen) throws ClassNotFoundException {
|
||||
super (img, g, width, height, imggen);
|
||||
Class.forName ("com.activated.jimi.Jimi");
|
||||
}
|
||||
|
||||
|
||||
public void reduceColors (int colors) {
|
||||
try {
|
||||
ColorReducer redux = new ColorReducer (colors, true);
|
||||
img = redux.getColorReducedImage (img);
|
||||
} catch (Exception x) {
|
||||
throw new RuntimeException (x.getMessage ());
|
||||
}
|
||||
}
|
||||
|
||||
public void saveAs (String filename) {
|
||||
try {
|
||||
Jimi.putImage (img, filename);
|
||||
} catch (JimiException x) {
|
||||
throw new RuntimeException (x.getMessage ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -16,7 +16,6 @@ public interface IRemoteImage extends Remote {
|
|||
public void setFont (String name, int style, int size) throws RemoteException;
|
||||
public void setColor (int color) throws RemoteException;
|
||||
public void setColor (int r, int g, int b) throws RemoteException;
|
||||
|
||||
public void reduceColors (int colors) throws RemoteException;
|
||||
|
||||
public void drawString (String str, int x, int y) throws RemoteException;
|
||||
|
@ -30,5 +29,9 @@ public interface IRemoteImage extends Remote {
|
|||
public void resize (int w, int h) throws RemoteException;
|
||||
|
||||
public void saveAs (String filename) throws RemoteException;
|
||||
public void readFrom (String filename) throws RemoteException;
|
||||
|
||||
public byte[] getBytes (String type) throws RemoteException;
|
||||
public void setBytes (byte[] bytes, String type) throws RemoteException;
|
||||
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
package helma.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
|
@ -38,10 +37,14 @@ public class ImageGenerator extends Window {
|
|||
Graphics g = img.getGraphics ();
|
||||
ImageWrapper rimg = null;
|
||||
try {
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Can't create image: "+x);
|
||||
}
|
||||
try {
|
||||
rimg = new ActivatedImageWrapper (img, g, w, h, this);
|
||||
} catch (NoClassDefFoundError notfound) {
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
} catch (ClassNotFoundException notfound) {
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
}
|
||||
} catch (Exception x) {}
|
||||
return rimg;
|
||||
}
|
||||
|
||||
|
@ -57,10 +60,14 @@ public class ImageGenerator extends Window {
|
|||
Image img = createImage (w, h);
|
||||
Graphics g = img.getGraphics ();
|
||||
g.drawImage (img1, 0, 0, null);
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Can't create image: "+x);
|
||||
}
|
||||
try {
|
||||
rimg = new ActivatedImageWrapper (img, g, w, h, this);
|
||||
} catch (ClassNotFoundException notfound) {
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
} catch (NoClassDefFoundError notfound) {
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
}
|
||||
} catch (Exception x) {}
|
||||
return rimg;
|
||||
}
|
||||
|
||||
|
@ -73,10 +80,14 @@ public class ImageGenerator extends Window {
|
|||
tracker.waitForAll ();
|
||||
int w = img.getWidth (null);
|
||||
int h = img.getHeight (null);
|
||||
rimg = new SunImageWrapper (img, null, w, h, this);
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Can't create image: "+x);
|
||||
}
|
||||
try {
|
||||
rimg = new ActivatedImageWrapper (img, null, w, h, this);
|
||||
} catch (ClassNotFoundException notfound) {
|
||||
rimg = new SunImageWrapper (img, null, w, h, this);
|
||||
} catch (NoClassDefFoundError notfound) {
|
||||
rimg = new SunImageWrapper (img, null, w, h, this);
|
||||
}
|
||||
} catch (Exception x) {}
|
||||
return rimg;
|
||||
}
|
||||
|
||||
|
@ -86,7 +97,7 @@ public class ImageGenerator extends Window {
|
|||
MediaTracker tracker = new MediaTracker (this);
|
||||
try {
|
||||
URL url = new URL (urlstring);
|
||||
Image img1 = Toolkit.getDefaultToolkit ().createImage (url);
|
||||
Image img1 = Toolkit.getDefaultToolkit ().getImage (url);
|
||||
tracker.addImage (img1, 0);
|
||||
tracker.waitForAll ();
|
||||
int w = img1.getWidth (null);
|
||||
|
@ -94,44 +105,27 @@ public class ImageGenerator extends Window {
|
|||
Image img = createImage (w, h);
|
||||
Graphics g = img.getGraphics ();
|
||||
g.drawImage (img1, 0, 0, null);
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
try {
|
||||
rimg = new ActivatedImageWrapper (img, g, w, h, this);
|
||||
} catch (ClassNotFoundException notfound) {
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
} catch (NoClassDefFoundError notfound) {
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
}
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Can't create image: "+x);
|
||||
x.printStackTrace ();
|
||||
}
|
||||
return rimg;
|
||||
}
|
||||
|
||||
public ImageWrapper createPaintableImage (ImageWrapper iw, ImageFilter filter) {
|
||||
ImageWrapper rimg = null;
|
||||
MediaTracker tracker = new MediaTracker (this);
|
||||
try {
|
||||
FilteredImageSource fis = new FilteredImageSource (iw.getSource(), filter);
|
||||
Image img1 = createImage (fis);
|
||||
tracker.addImage (img1, 0);
|
||||
tracker.waitForAll ();
|
||||
int w = img1.getWidth (null);
|
||||
int h = img1.getHeight (null);
|
||||
Image img = createImage (w, h);
|
||||
Graphics g = img.getGraphics ();
|
||||
g.drawImage (img1, 0, 0, null);
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Can't create image: "+x);
|
||||
}
|
||||
return rimg;
|
||||
}
|
||||
|
||||
|
||||
public Image createImage (String filename) {
|
||||
Image img = null;
|
||||
MediaTracker tracker = new MediaTracker (this);
|
||||
try {
|
||||
img = Toolkit.getDefaultToolkit ().createImage (filename);
|
||||
img = Toolkit.getDefaultToolkit ().getImage (filename);
|
||||
tracker.addImage (img, 0);
|
||||
tracker.waitForAll ();
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Can't create image: "+x);
|
||||
x.printStackTrace ();
|
||||
}
|
||||
return img;
|
||||
|
|
|
@ -102,11 +102,16 @@ public abstract class ImageWrapper {
|
|||
|
||||
public abstract void saveAs (String filename);
|
||||
|
||||
/**
|
||||
* Get ImageProducer of the wrapped image
|
||||
*/
|
||||
public ImageProducer getSource () {
|
||||
return img.getSource ();
|
||||
public void readFrom (String filename) {
|
||||
throw new RuntimeException ("Image.readFrom() is currently not implemented.");
|
||||
}
|
||||
|
||||
public byte[] getBytes (String type) {
|
||||
throw new RuntimeException ("Image.getBytes() is currently not implemented.");
|
||||
}
|
||||
|
||||
public void setBytes (byte[] bytes, String type) {
|
||||
throw new RuntimeException ("Image.setBytes() is currently not implemented.");
|
||||
}
|
||||
|
||||
public void fillString (String str) {
|
||||
|
|
|
@ -77,6 +77,18 @@ public class RemoteImage extends UnicastRemoteObject implements IRemoteImage {
|
|||
wrapped.saveAs (filename);
|
||||
}
|
||||
|
||||
public void readFrom (String filename) {
|
||||
wrapped.readFrom (filename);
|
||||
}
|
||||
|
||||
public byte[] getBytes (String type) {
|
||||
return wrapped.getBytes (type);
|
||||
}
|
||||
|
||||
public void setBytes (byte[] bytes, String type) {
|
||||
wrapped.setBytes (bytes, type);
|
||||
}
|
||||
|
||||
public void fillString (String str) {
|
||||
wrapped.fillString (str);
|
||||
}
|
||||
|
|
|
@ -1,395 +0,0 @@
|
|||
// Server.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.main;
|
||||
|
||||
import java.io.*;
|
||||
import java.rmi.*;
|
||||
import java.rmi.server.*;
|
||||
import java.rmi.registry.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
// import helma.objectmodel.*;
|
||||
import helma.objectmodel.db.DbSource;
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.xmlrpc.*;
|
||||
import helma.util.*;
|
||||
import com.sleepycat.db.*;
|
||||
|
||||
|
||||
/**
|
||||
* Helma server main class.
|
||||
*/
|
||||
|
||||
public class Server implements IPathElement, Runnable {
|
||||
|
||||
public static final String version = "1.2pre3 2002/05/15";
|
||||
public static final long starttime = System.currentTimeMillis();
|
||||
|
||||
public static boolean useTransactions = true;
|
||||
public static boolean paranoid;
|
||||
public static String dbFilename = "hop.db";
|
||||
|
||||
private ApplicationManager appManager;
|
||||
|
||||
private Thread mainThread;
|
||||
|
||||
static String propfile;
|
||||
static String dbPropfile = "db.properties";
|
||||
static String appsPropfile;
|
||||
static SystemProperties appsProps;
|
||||
static SystemProperties dbProps;
|
||||
static SystemProperties sysProps;
|
||||
static int port = 5055;
|
||||
static int webport = 0;
|
||||
|
||||
Acme.Serve.Serve websrv;
|
||||
|
||||
static Hashtable dbSources;
|
||||
|
||||
private static Server server;
|
||||
|
||||
protected static File hopHome = null;
|
||||
|
||||
private static Logger logger;
|
||||
|
||||
protected static WebServer xmlrpc;
|
||||
|
||||
|
||||
public static void main (String args[]) throws IOException {
|
||||
|
||||
// check if we are running on a Java 2 VM - otherwise exit with an error message
|
||||
String jversion = System.getProperty ("java.version");
|
||||
if (jversion == null || jversion.startsWith ("1.1") || jversion.startsWith ("1.0")) {
|
||||
System.err.println ("This version of Helma requires Java 1.2 or greater.");
|
||||
if (jversion == null) // don't think this will ever happen, but you never know
|
||||
System.err.println ("Your Java Runtime did not provide a version number. Please update to a more recent version.");
|
||||
else
|
||||
System.err.println ("Your Java Runtime is version "+jversion+". Please update to a more recent version.");
|
||||
System.exit (1);
|
||||
}
|
||||
|
||||
String homeDir = null;
|
||||
|
||||
boolean usageError = false;
|
||||
|
||||
useTransactions = true;
|
||||
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (args[i].equals ("-h") && i+1<args.length)
|
||||
homeDir = args[++i];
|
||||
else if (args[i].equals ("-f") && i+1<args.length)
|
||||
propfile = args[++i];
|
||||
else if (args[i].equals ("-t"))
|
||||
useTransactions = false;
|
||||
else if (args[i].equals ("-p") && i+1<args.length) {
|
||||
try {
|
||||
port = Integer.parseInt (args[++i]);
|
||||
} catch (Exception portx) {
|
||||
usageError = true;
|
||||
}
|
||||
} else if (args[i].equals ("-w") && i+1<args.length) {
|
||||
try {
|
||||
webport = Integer.parseInt (args[++i]);
|
||||
} catch (Exception portx) {
|
||||
usageError = true;
|
||||
}
|
||||
} else
|
||||
usageError = true;
|
||||
}
|
||||
|
||||
if (usageError ) {
|
||||
System.out.println ("usage: java helma.objectmodel.db.Server [-h dir] [-f file] [-p port] [-w port] [-t]");
|
||||
System.out.println (" -h dir Specify hop home directory");
|
||||
System.out.println (" -f file Specify server.properties file");
|
||||
System.out.println (" -p port Specify TCP port number");
|
||||
System.out.println (" -w port Start embedded Web server on that port");
|
||||
System.out.println (" -t Disable Berkeley DB Transactions");
|
||||
getLogger().log ("Usage Error - exiting");
|
||||
System.exit (0);
|
||||
}
|
||||
|
||||
server = new Server (homeDir);
|
||||
}
|
||||
|
||||
public Server (String home) {
|
||||
|
||||
String homeDir = home;
|
||||
|
||||
// get main property file from home dir or vice versa, depending on what we have.
|
||||
// get property file from hopHome
|
||||
if (propfile == null) {
|
||||
if (homeDir != null)
|
||||
propfile = new File (homeDir, "server.properties").getAbsolutePath ();
|
||||
else
|
||||
propfile = new File ("server.properties").getAbsolutePath ();
|
||||
}
|
||||
|
||||
sysProps = new SystemProperties (propfile);
|
||||
// get hopHome from property file
|
||||
if (homeDir == null)
|
||||
homeDir = sysProps.getProperty ("hophome");
|
||||
if (homeDir == null)
|
||||
homeDir = new File (propfile).getParent ();
|
||||
|
||||
// create hopHome File object
|
||||
hopHome = new File (homeDir);
|
||||
|
||||
// from now on it's safe to call getLogger()
|
||||
|
||||
getLogger().log ("Starting Helma "+version);
|
||||
|
||||
getLogger().log ("propfile = "+propfile);
|
||||
getLogger().log ("hopHome = "+hopHome);
|
||||
|
||||
|
||||
File helper = new File (hopHome, "db.properties");
|
||||
dbPropfile = helper.getAbsolutePath ();
|
||||
dbProps = new SystemProperties (dbPropfile);
|
||||
DbSource.setDefaultProps (dbProps);
|
||||
getLogger().log ("dbPropfile = "+dbPropfile);
|
||||
|
||||
appsPropfile = sysProps.getProperty ("appsPropFile");
|
||||
if (appsPropfile != null && !"".equals (appsPropfile.trim()))
|
||||
helper = new File (appsPropfile);
|
||||
else
|
||||
helper = new File (hopHome, "apps.properties");
|
||||
appsPropfile = helper.getAbsolutePath ();
|
||||
getLogger().log ("appsPropfile = "+appsPropfile);
|
||||
|
||||
paranoid = "true".equalsIgnoreCase (sysProps.getProperty ("paranoid"));
|
||||
|
||||
String language = sysProps.getProperty ("language");
|
||||
String country = sysProps.getProperty ("country");
|
||||
String timezone = sysProps.getProperty ("timezone");
|
||||
|
||||
if (language != null && country != null)
|
||||
Locale.setDefault (new Locale (language, country));
|
||||
if (timezone != null)
|
||||
TimeZone.setDefault (TimeZone.getTimeZone (timezone));
|
||||
|
||||
getLogger().log ("Locale = "+Locale.getDefault());
|
||||
getLogger().log ("TimeZone = "+TimeZone.getDefault().getDisplayName (Locale.getDefault ()));
|
||||
|
||||
dbSources = new Hashtable ();
|
||||
|
||||
try {
|
||||
checkRunning (); // check if a server is already running with this db
|
||||
} catch (Exception running) {
|
||||
System.out.println (running.getMessage ());
|
||||
System.exit (1);
|
||||
}
|
||||
|
||||
// nmgr = new NodeManager (this, sysProps);
|
||||
|
||||
// Start running, finishing setup and then entering a loop to check changes
|
||||
// in the apps.properties file.
|
||||
mainThread = new Thread (this);
|
||||
mainThread.start ();
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method of the Server. Basically, we set up Applications and than
|
||||
* periodically check for changes in the apps.properties file, shutting down
|
||||
* apps or starting new ones.
|
||||
*/
|
||||
public void run () {
|
||||
|
||||
try {
|
||||
|
||||
// start embedded web server if port is specified
|
||||
if (webport > 0) {
|
||||
websrv = new Acme.Serve.Serve (webport, sysProps);
|
||||
}
|
||||
|
||||
String xmlparser = sysProps.getProperty ("xmlparser");
|
||||
if (xmlparser != null)
|
||||
XmlRpc.setDriver (xmlparser);
|
||||
// XmlRpc.setDebug (true);
|
||||
xmlrpc = new WebServer (port+1);
|
||||
if (paranoid) {
|
||||
xmlrpc.setParanoid (true);
|
||||
String xallow = sysProps.getProperty ("allowXmlRpc");
|
||||
if (xallow != null) {
|
||||
StringTokenizer st = new StringTokenizer (xallow, " ,;");
|
||||
while (st.hasMoreTokens ())
|
||||
xmlrpc.acceptClient (st.nextToken ());
|
||||
}
|
||||
}
|
||||
getLogger().log ("Starting XML-RPC server on port "+(port+1));
|
||||
|
||||
// the following seems not to be necessary after all ...
|
||||
// System.setSecurityManager(new RMISecurityManager());
|
||||
if (paranoid) {
|
||||
HopSocketFactory factory = new HopSocketFactory ();
|
||||
String rallow = sysProps.getProperty ("allowWeb");
|
||||
if (rallow != null) {
|
||||
StringTokenizer st = new StringTokenizer (rallow, " ,;");
|
||||
while (st.hasMoreTokens ())
|
||||
factory.addAddress (st.nextToken ());
|
||||
}
|
||||
RMISocketFactory.setSocketFactory (factory);
|
||||
}
|
||||
|
||||
if (websrv == null) {
|
||||
getLogger().log ("Starting server on port "+port);
|
||||
LocateRegistry.createRegistry (port);
|
||||
}
|
||||
|
||||
|
||||
// start application framework
|
||||
appsProps = new SystemProperties (appsPropfile);
|
||||
appManager = new ApplicationManager (port, hopHome, appsProps, this);
|
||||
|
||||
|
||||
} catch (Exception gx) {
|
||||
getLogger().log ("Error initializing embedded database: "+gx);
|
||||
gx.printStackTrace ();
|
||||
return;
|
||||
}
|
||||
|
||||
// start applications
|
||||
appManager.startAll ();
|
||||
|
||||
// start embedded web server
|
||||
if (websrv != null) {
|
||||
Thread webthread = new Thread (websrv, "WebServer");
|
||||
webthread.start ();
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
while (Thread.currentThread () == mainThread) {
|
||||
try {
|
||||
mainThread.sleep (3000l);
|
||||
} catch (InterruptedException ie) {}
|
||||
try {
|
||||
appManager.checkForChanges ();
|
||||
} catch (Exception x) {
|
||||
getLogger().log ("Caught in app manager loop: "+x);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Iterator over the applications currently running on this Server.
|
||||
*/
|
||||
public Object[] getApplications () {
|
||||
return appManager.getApplications ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Application by name
|
||||
*/
|
||||
public Application getApplication(String name) {
|
||||
return appManager.getApplication(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a logger to use for output in this server.
|
||||
*/
|
||||
protected static Logger getLogger () {
|
||||
if (logger == null) {
|
||||
String logDir = sysProps.getProperty ("logdir");
|
||||
if (logDir == null || "console".equalsIgnoreCase (logDir)) {
|
||||
logger = new Logger (System.out);
|
||||
} else {
|
||||
File helper = new File (logDir);
|
||||
if (hopHome != null && !helper.isAbsolute ())
|
||||
helper = new File (hopHome, logDir);
|
||||
logDir = helper.getAbsolutePath ();
|
||||
logger = Logger.getLogger (logDir, "hop");
|
||||
}
|
||||
}
|
||||
return logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Home directory of this server.
|
||||
*/
|
||||
public static File getHopHome () {
|
||||
return hopHome;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the main Server
|
||||
*/
|
||||
public static Server getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Server's XML-RPC web server.
|
||||
*/
|
||||
public static WebServer getXmlRpcServer() {
|
||||
return xmlrpc;
|
||||
}
|
||||
|
||||
/**
|
||||
* A primitive method to check whether a server is already running on our port.
|
||||
*/
|
||||
private void checkRunning () throws Exception {
|
||||
try {
|
||||
java.net.Socket socket = new java.net.Socket ("localhost", port);
|
||||
} catch (Exception x) {
|
||||
return;
|
||||
}
|
||||
// if we got so far, another server is already running on this port and db
|
||||
throw new Exception ("Error: Server already running on this port");
|
||||
}
|
||||
|
||||
public static String getProperty( String key ) {
|
||||
return (String)sysProps.get(key);
|
||||
}
|
||||
|
||||
public static SystemProperties getProperties() {
|
||||
return sysProps;
|
||||
}
|
||||
|
||||
public static File getAppsHome() {
|
||||
String appHome = sysProps.getProperty ("appHome");
|
||||
if (appHome != null && !"".equals (appHome.trim()))
|
||||
return new File (appHome);
|
||||
else
|
||||
return new File (hopHome, "apps");
|
||||
}
|
||||
|
||||
public void startApplication(String name) {
|
||||
appManager.start (name);
|
||||
appManager.register (name);
|
||||
}
|
||||
|
||||
public void stopApplication(String name) {
|
||||
appManager.stop (name);
|
||||
}
|
||||
|
||||
/**
|
||||
* method from helma.framework.IPathElement
|
||||
*/
|
||||
public String getElementName() {
|
||||
return "root";
|
||||
}
|
||||
|
||||
/**
|
||||
* method from helma.framework.IPathElement,
|
||||
* returning active applications
|
||||
*/
|
||||
public IPathElement getChildElement(String name) {
|
||||
return appManager.getApplication(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* method from helma.framework.IPathElement
|
||||
*/
|
||||
public IPathElement getParentElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* method from helma.framework.IPathElement
|
||||
*/
|
||||
public String getPrototype() {
|
||||
return "root";
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT, INRIA and Keio, 1999
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1996.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
import java.io.*;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1996.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1996.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
/**
|
||||
* A Mime header factory, that will build instances of the MimeHeaders class
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1996.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.* ;
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1996.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
public class MimeParserException extends Exception {
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1996.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
/**
|
||||
* This class is used by the MimeParser, to create new MIME message holders.
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1996.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1996.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
public class MimeTypeFormatException extends Exception {
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1996.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
import java.io.* ;
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
// (c) COPYRIGHT MIT and INRIA, 1998.
|
||||
// Please first read the full copyright statement in file COPYRIGHT.html
|
||||
|
||||
package helma.util.mime;
|
||||
package helma.mime;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
510
src/helma/objectmodel/DbMapping.java
Normal file
510
src/helma/objectmodel/DbMapping.java
Normal file
|
@ -0,0 +1,510 @@
|
|||
// DbMapping.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
import helma.framework.core.Application;
|
||||
import helma.objectmodel.db.WrappedNodeManager;
|
||||
import java.util.*;
|
||||
import java.sql.*;
|
||||
import com.workingdogs.village.*;
|
||||
|
||||
/**
|
||||
* A DbMapping describes how a certain type of Nodes is to mapped to a
|
||||
* relational database table. Basically it consists of a set of JavaScript property-to-
|
||||
* Database row bindings which are represented by instances of the Relation class.
|
||||
*/
|
||||
|
||||
public class DbMapping {
|
||||
|
||||
Application app;
|
||||
String typename;
|
||||
|
||||
SystemProperties props;
|
||||
|
||||
DbSource source;
|
||||
String table;
|
||||
|
||||
String[] parent; // list of properties to try for parent
|
||||
Boolean[] anonymous; // are parent relations anonymous or not?
|
||||
DbMapping subnodes;
|
||||
DbMapping properties;
|
||||
private Relation subnodesRel;
|
||||
private Relation propertiesRel;
|
||||
|
||||
// Map of property names to Relations objects
|
||||
public Hashtable prop2db;
|
||||
// Map of db columns to Relations objects
|
||||
public Hashtable db2prop;
|
||||
|
||||
String idField;
|
||||
String nameField;
|
||||
|
||||
// descriptor for key generation method
|
||||
private String idgen;
|
||||
// remember last key generated for this table
|
||||
public long lastID;
|
||||
|
||||
|
||||
Schema schema = null;
|
||||
KeyDef keydef = null;
|
||||
|
||||
private long lastTypeChange;
|
||||
public long lastDataChange;
|
||||
|
||||
public DbMapping () {
|
||||
|
||||
prop2db = new Hashtable ();
|
||||
db2prop = new Hashtable ();
|
||||
|
||||
parent = null;
|
||||
subnodes = null;
|
||||
properties = null;
|
||||
idField = "id";
|
||||
}
|
||||
|
||||
public DbMapping (Application app, String typename, SystemProperties props) {
|
||||
|
||||
this.app = app;
|
||||
this.typename = typename;
|
||||
|
||||
prop2db = new Hashtable ();
|
||||
db2prop = new Hashtable ();
|
||||
|
||||
parent = null;
|
||||
subnodes = null;
|
||||
properties = null;
|
||||
idField = "id";
|
||||
|
||||
this.props = props;
|
||||
read ();
|
||||
|
||||
app.putDbMapping (typename, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the mapping from the Properties. Return true if the properties were changed.
|
||||
* The read is split in two, this method and the rewire method. The reason is that in order
|
||||
* for rewire to work, all other db mappings must have been initialized and registered.
|
||||
*/
|
||||
public synchronized boolean read () {
|
||||
|
||||
long lastmod = props.lastModified ();
|
||||
if (lastmod == lastTypeChange)
|
||||
return false;
|
||||
|
||||
this.table = props.getProperty ("_tablename");
|
||||
this.idgen = props.getProperty ("_idgen");
|
||||
|
||||
String sourceName = props.getProperty ("_datasource");
|
||||
if (sourceName != null)
|
||||
source = (DbSource) IServer.dbSources.get (sourceName.toLowerCase ());
|
||||
|
||||
// id field must not be null, default is "id"
|
||||
idField = props.getProperty ("_id", "id");
|
||||
|
||||
nameField = props.getProperty ("_name");
|
||||
|
||||
lastTypeChange = lastmod;
|
||||
// set the cached schema & keydef to null so it's rebuilt the next time around
|
||||
schema = null;
|
||||
keydef = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the second part of the property reading process, called after the first part has been
|
||||
* completed on all other mappings in this application
|
||||
*/
|
||||
public synchronized void rewire () {
|
||||
|
||||
// if (table != null && source != null) {
|
||||
// IServer.getLogger().log ("set data source for "+typename+" to "+source);
|
||||
Hashtable p2d = new Hashtable ();
|
||||
Hashtable d2p = new Hashtable ();
|
||||
|
||||
for (Enumeration e=props.keys(); e.hasMoreElements(); ) {
|
||||
String propName = (String) e.nextElement ();
|
||||
|
||||
try {
|
||||
if (!propName.startsWith ("_") && propName.indexOf (".") < 0) {
|
||||
String dbField = props.getProperty (propName);
|
||||
Relation rel = new Relation (dbField, propName, this, props);
|
||||
p2d.put (propName, rel);
|
||||
if (rel.localField != null)
|
||||
d2p.put (rel.localField, rel);
|
||||
// IServer.getLogger().log ("Mapping "+propName+" -> "+dbField);
|
||||
}
|
||||
} catch (Exception x) {
|
||||
IServer.getLogger ().log ("Error in type.properties: "+x.getMessage ());
|
||||
}
|
||||
}
|
||||
|
||||
prop2db = p2d;
|
||||
db2prop = d2p;
|
||||
|
||||
String ano = props.getProperty ("_anonymous");
|
||||
if (ano != null) {
|
||||
// comma-separated list of true/false values
|
||||
StringTokenizer st = new StringTokenizer (ano, ",; ");
|
||||
anonymous = new Boolean[st.countTokens()];
|
||||
for (int i=0; i<anonymous.length; i++)
|
||||
anonymous[i] = "false".equalsIgnoreCase (st.nextToken().trim()) ? Boolean.FALSE : Boolean.TRUE;
|
||||
} else
|
||||
anonymous = null;
|
||||
|
||||
String parentMapping = props.getProperty ("_parent");
|
||||
if (parentMapping != null) {
|
||||
// comma-separated list of properties to be used as parent
|
||||
StringTokenizer st = new StringTokenizer (parentMapping, ",; ");
|
||||
parent = new String[st.countTokens()];
|
||||
for (int i=0; i<parent.length; i++)
|
||||
parent[i] = st.nextToken().trim();
|
||||
} else
|
||||
parent = null;
|
||||
|
||||
String subnodeMapping = props.getProperty ("_subnodes");
|
||||
if (subnodeMapping != null) {
|
||||
try {
|
||||
subnodesRel = new Relation (subnodeMapping, "_subnodes", this, props);
|
||||
if (subnodesRel.isReference ())
|
||||
subnodes = subnodesRel.other;
|
||||
else
|
||||
subnodes = (DbMapping) app.getDbMapping (subnodeMapping);
|
||||
} catch (Exception x) {
|
||||
IServer.getLogger ().log ("Error in type.properties: "+x.getMessage ());
|
||||
subnodesRel = null;
|
||||
}
|
||||
} else
|
||||
subnodesRel = null;
|
||||
|
||||
String propertiesMapping = props.getProperty ("_properties");
|
||||
if (propertiesMapping != null) {
|
||||
try {
|
||||
propertiesRel = new Relation (propertiesMapping, "_properties", this, props);
|
||||
if (propertiesRel.isReference ())
|
||||
properties = propertiesRel.other;
|
||||
else
|
||||
properties = (DbMapping) app.getDbMapping (propertiesMapping);
|
||||
// take over groupby flag from subnodes, if properties are subnodes
|
||||
if (propertiesRel.subnodesAreProperties && subnodesRel != null)
|
||||
propertiesRel.groupby = subnodesRel.groupby;
|
||||
} catch (Exception x) {
|
||||
IServer.getLogger ().log ("Error in type.properties: "+x.getMessage ());
|
||||
propertiesRel = null;
|
||||
}
|
||||
} else
|
||||
propertiesRel = null;
|
||||
|
||||
IServer.getLogger().log ("rewiring: "+this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Connection getConnection () throws ClassNotFoundException, SQLException {
|
||||
if (source == null)
|
||||
throw new SQLException ("Tried to get Connection from non-relational embedded data source.");
|
||||
return source.getConnection ();
|
||||
}
|
||||
|
||||
public DbSource getDbSource () {
|
||||
return source;
|
||||
}
|
||||
|
||||
public String getSourceID () {
|
||||
return source == null ? "" : source.url;
|
||||
}
|
||||
|
||||
public String getTableName () {
|
||||
return table;
|
||||
}
|
||||
|
||||
public Application getApplication () {
|
||||
return app;
|
||||
}
|
||||
|
||||
public String getAppName () {
|
||||
return app.getName();
|
||||
}
|
||||
|
||||
public String getTypeName () {
|
||||
return typename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the primary key column name for objects using this mapping.
|
||||
*/
|
||||
public String getIDField () {
|
||||
return idField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the column used for (internal) names of objects of this type.
|
||||
*/
|
||||
public String getNameField () {
|
||||
return nameField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a database column name to a JavaScript property name according to this mapping.
|
||||
*/
|
||||
public Relation columnNameToProperty (String columnName) {
|
||||
return (Relation) db2prop.get (columnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a JavaScript property name to a database column name according to this mapping.
|
||||
*/
|
||||
public Relation propertyToColumnName (String propName) {
|
||||
return (Relation) prop2db.get (propName);
|
||||
}
|
||||
|
||||
public synchronized String[] getParentPropNames () {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public synchronized Boolean[] getAnonymous () {
|
||||
return anonymous;
|
||||
}
|
||||
|
||||
public DbMapping getSubnodeMapping () {
|
||||
return subnodes;
|
||||
}
|
||||
|
||||
public void setSubnodeMapping (DbMapping sm) {
|
||||
subnodes = sm;
|
||||
}
|
||||
|
||||
public DbMapping getExactPropertyMapping (String propname) {
|
||||
if (propname == null)
|
||||
return null;
|
||||
Relation rel = (Relation) prop2db.get (propname.toLowerCase());
|
||||
return rel != null ? rel.other : null;
|
||||
}
|
||||
|
||||
public DbMapping getPropertyMapping (String propname) {
|
||||
if (propname == null)
|
||||
return properties;
|
||||
Relation rel = (Relation) prop2db.get (propname.toLowerCase());
|
||||
if (rel != null) {
|
||||
// if this is a virtual node, it doesn't have a dbmapping
|
||||
if (rel.virtual && rel.prototype == null)
|
||||
return null;
|
||||
else
|
||||
return rel.other;
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setPropertyMapping (DbMapping pm) {
|
||||
properties = pm;
|
||||
}
|
||||
|
||||
public void setSubnodeRelation (Relation rel) {
|
||||
subnodesRel = rel;
|
||||
}
|
||||
|
||||
public void setPropertyRelation (Relation rel) {
|
||||
propertiesRel = rel;
|
||||
}
|
||||
|
||||
public Relation getSubnodeRelation () {
|
||||
return subnodesRel;
|
||||
}
|
||||
|
||||
public Relation getPropertyRelation () {
|
||||
return propertiesRel;
|
||||
}
|
||||
|
||||
public Relation getPropertyRelation (String propname) {
|
||||
if (propname == null)
|
||||
return propertiesRel;
|
||||
Relation rel = (Relation) prop2db.get (propname.toLowerCase());
|
||||
return rel != null ? rel : propertiesRel;
|
||||
}
|
||||
|
||||
|
||||
public String getIDgen () {
|
||||
return idgen;
|
||||
}
|
||||
|
||||
|
||||
public WrappedNodeManager getWrappedNodeManager () {
|
||||
if (app == null)
|
||||
throw new RuntimeException ("Can't get node manager from internal db mapping");
|
||||
return app.getWrappedNodeManager ();
|
||||
}
|
||||
|
||||
public boolean isRelational () {
|
||||
return source != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Village Schema object for this DbMapping.
|
||||
*/
|
||||
public synchronized Schema getSchema () throws ClassNotFoundException, SQLException, DataSetException {
|
||||
if (!isRelational ())
|
||||
throw new SQLException ("Can't get Schema for non-relational data mapping");
|
||||
// Use local variable s to avoid synchronization (schema may be nulled elsewhere)
|
||||
Schema s = schema;
|
||||
if (s != null)
|
||||
return s;
|
||||
schema = new Schema ().schema (getConnection (), table, "*");
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Village Schema object for this DbMapping.
|
||||
*/
|
||||
public synchronized KeyDef getKeyDef () {
|
||||
if (!isRelational ())
|
||||
throw new RuntimeException ("Can't get KeyDef for non-relational data mapping");
|
||||
// Use local variable s to avoid synchronization (keydef may be nulled elsewhere)
|
||||
KeyDef k = keydef;
|
||||
if (k != null)
|
||||
return k;
|
||||
keydef = new KeyDef ().addAttrib (idField);
|
||||
return keydef;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
if (app == null)
|
||||
return "[unspecified internal DbMapping]";
|
||||
else
|
||||
return ("["+app.getName()+"."+typename+"]");
|
||||
}
|
||||
|
||||
public long getLastTypeChange () {
|
||||
return lastTypeChange;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
95
src/helma/objectmodel/DbSource.java
Normal file
95
src/helma/objectmodel/DbSource.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
// DbSource.java
|
||||
// Copyright (c) Hannes Wallnöfer 1999-2000
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.Hashtable;
|
||||
import helma.objectmodel.db.Transactor;
|
||||
|
||||
/**
|
||||
* This class describes a releational data source (URL, driver, user and password).
|
||||
*/
|
||||
|
||||
public class DbSource {
|
||||
|
||||
private String name;
|
||||
protected String url;
|
||||
private String driver;
|
||||
protected String user;
|
||||
private String password;
|
||||
|
||||
public DbSource (String name) throws ClassNotFoundException {
|
||||
this.name = name;
|
||||
IServer.dbSources.put (name.toLowerCase (), this);
|
||||
url = IServer.dbProps.getProperty (name+".url");
|
||||
driver = IServer.dbProps.getProperty (name+".driver");
|
||||
Class.forName (driver);
|
||||
user = IServer.dbProps.getProperty (name+".user");
|
||||
password = IServer.dbProps.getProperty (name+".password");
|
||||
IServer.getLogger().log ("created db source ["+name+", "+url+", "+driver+", "+user+"]");
|
||||
}
|
||||
|
||||
public Connection getConnection () throws ClassNotFoundException, SQLException {
|
||||
Transactor tx = (Transactor) Thread.currentThread ();
|
||||
Connection con = tx.getConnection (this);
|
||||
if (con == null || con.isClosed ()) {
|
||||
Class.forName (driver);
|
||||
con = DriverManager.getConnection (url, user, password);
|
||||
// If we wanted to use SQL transactions, we'd set autoCommit to
|
||||
// false here and make commit/rollback invocations in Transactor methods;
|
||||
IServer.getLogger().log ("Created new Connection to "+url);
|
||||
tx.registerConnection (this, con);
|
||||
}
|
||||
return con;
|
||||
}
|
||||
|
||||
public String getDriverName () {
|
||||
return driver;
|
||||
}
|
||||
|
||||
public String getName () {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -5,8 +5,6 @@ package helma.objectmodel;
|
|||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import helma.framework.IPathElement;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
|
||||
/**
|
||||
* Interface that all Nodes implement. Currently, there are two implementations:
|
||||
|
@ -14,7 +12,18 @@ import helma.objectmodel.db.DbMapping;
|
|||
* stored in a database (either the internal Object DB or an external relational DB).
|
||||
*/
|
||||
|
||||
public interface INode extends INodeState, IPathElement {
|
||||
public interface INode {
|
||||
|
||||
public final static String webTypes = "image/jpeg, image/gif, image/png";
|
||||
|
||||
public final static int TRANSIENT = -3;
|
||||
public final static int VIRTUAL = -2;
|
||||
public final static int INVALID = -1;
|
||||
public final static int CLEAN = 0;
|
||||
public final static int NEW = 1;
|
||||
public final static int MODIFIED = 2;
|
||||
public final static int DELETED = 3;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -23,10 +32,14 @@ public interface INode extends INodeState, IPathElement {
|
|||
|
||||
public String getID ();
|
||||
public String getName ();
|
||||
public String getNameOrID (); // get name or id depending if it's a named or an anonymous node.
|
||||
public void setDbMapping (DbMapping dbmap);
|
||||
public DbMapping getDbMapping ();
|
||||
public int getState ();
|
||||
public void setState (int s);
|
||||
public String getFullName ();
|
||||
public String getFullName (INode root);
|
||||
public INode[] getPath ();
|
||||
public void setName (String name);
|
||||
public long lastModified ();
|
||||
public long created ();
|
||||
|
@ -34,9 +47,6 @@ public interface INode extends INodeState, IPathElement {
|
|||
public String getPrototype ();
|
||||
public void setPrototype (String prototype);
|
||||
public INode getCacheNode ();
|
||||
public void clearCacheNode ();
|
||||
public String getFullName ();
|
||||
public String getFullName (INode root);
|
||||
|
||||
/**
|
||||
* node-related methods
|
||||
|
@ -64,7 +74,7 @@ public interface INode extends INodeState, IPathElement {
|
|||
public Enumeration properties ();
|
||||
public IProperty get (String name, boolean inherit);
|
||||
public String getString (String name, boolean inherit);
|
||||
// public String getString (String name, String defaultValue, boolean inherit);
|
||||
public String getString (String name, String defaultValue, boolean inherit);
|
||||
public boolean getBoolean (String name, boolean inherit);
|
||||
public Date getDate (String name, boolean inherit);
|
||||
public long getInteger (String name, boolean inherit);
|
||||
|
@ -82,6 +92,21 @@ public interface INode extends INodeState, IPathElement {
|
|||
|
||||
public void unset (String name);
|
||||
|
||||
/**
|
||||
* content-related methods
|
||||
*/
|
||||
|
||||
public String getContentType ();
|
||||
public void setContentType (String type);
|
||||
public int getContentLength ();
|
||||
public void setContent (byte content[], String type);
|
||||
public void setContent (String content);
|
||||
public byte[] getContent ();
|
||||
public String getText ();
|
||||
public String getUrl (INode root, INode userroot, String tmpname);
|
||||
public String getHref (INode root, INode userroot, String tmpname, String prefix);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
15
src/helma/objectmodel/INodeListener.java
Normal file
15
src/helma/objectmodel/INodeListener.java
Normal file
|
@ -0,0 +1,15 @@
|
|||
// INodeListener.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
/**
|
||||
* An interface for objects that wish to be notified when certain nodes are
|
||||
* modified. This is not used in the HOP as much as it used to be.
|
||||
*/
|
||||
|
||||
public interface INodeListener {
|
||||
|
||||
public void nodeChanged (NodeEvent event);
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
// INodeState.java
|
||||
// Copyright (c) Hannes Wallnöfer 2001
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Interface that defines states of nodes
|
||||
*/
|
||||
|
||||
public interface INodeState {
|
||||
|
||||
public final static int TRANSIENT = -3;
|
||||
public final static int VIRTUAL = -2;
|
||||
public final static int INVALID = -1;
|
||||
public final static int CLEAN = 0;
|
||||
public final static int NEW = 1;
|
||||
public final static int MODIFIED = 2;
|
||||
public final static int DELETED = 3;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
21
src/helma/objectmodel/IPathElement.java
Normal file
21
src/helma/objectmodel/IPathElement.java
Normal file
|
@ -0,0 +1,21 @@
|
|||
// INode.java
|
||||
// Copyright (c) Hannes Wallnöfer 2000
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
|
||||
/**
|
||||
* Minimal Interface for Nodes that build a hierarchic tree
|
||||
*/
|
||||
|
||||
public interface IPathElement {
|
||||
|
||||
public INode getSubnode (String name);
|
||||
public INode getNode (String name, boolean inherit);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
79
src/helma/objectmodel/IServer.java
Normal file
79
src/helma/objectmodel/IServer.java
Normal file
|
@ -0,0 +1,79 @@
|
|||
// IServer.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
import helma.util.*;
|
||||
import helma.xmlrpc.WebServer;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Abstract Server class. Defines the methods all servers have to implement.
|
||||
*/
|
||||
|
||||
public abstract class IServer {
|
||||
|
||||
// public static final Object sync = new Object ();
|
||||
public static SystemProperties sysProps, dbProps;
|
||||
public static Hashtable dbSources;
|
||||
|
||||
protected static String hopHome = null;
|
||||
|
||||
private static Logger logger;
|
||||
|
||||
protected static WebServer xmlrpc;
|
||||
|
||||
|
||||
/* public abstract INode getAppRoot (String appID);
|
||||
|
||||
public abstract INode getAppNode (String appID, Vector path, String name);
|
||||
|
||||
public abstract INode getSubnode (String path); */
|
||||
|
||||
public static void throwNodeEvent (NodeEvent evt) {
|
||||
// noop
|
||||
}
|
||||
|
||||
public static void addNodeListener (String id, INodeListener listener) {
|
||||
// noop
|
||||
}
|
||||
|
||||
public static void removeNodeListener (String node, INodeListener listener) {
|
||||
// noop
|
||||
}
|
||||
|
||||
public static Logger getLogger () {
|
||||
if (logger == null) {
|
||||
String logDir = sysProps.getProperty ("logdir");
|
||||
if (logDir == null) {
|
||||
logger = new Logger (System.out);
|
||||
} else {
|
||||
try {
|
||||
File helper = new File (logDir);
|
||||
if (hopHome != null && !helper.isAbsolute ())
|
||||
helper = new File (hopHome, logDir);
|
||||
logDir = helper.getAbsolutePath ();
|
||||
logger = new Logger (logDir, "hop");
|
||||
} catch (IOException iox) {
|
||||
System.err.println ("Could not create Logger for log/hop: "+iox);
|
||||
// fallback to System.out
|
||||
logger = new Logger (System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
return logger;
|
||||
}
|
||||
|
||||
public static String getHopHome () {
|
||||
return hopHome;
|
||||
}
|
||||
|
||||
public static WebServer getXmlRpcServer() {
|
||||
return xmlrpc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
136
src/helma/objectmodel/Key.java
Normal file
136
src/helma/objectmodel/Key.java
Normal file
|
@ -0,0 +1,136 @@
|
|||
// Key.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
|
||||
import helma.util.CacheMap;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* This is the internal representation of a database key. It is constructed
|
||||
* out of the database URL, the table name, the user name and the database
|
||||
* key of the node and unique within each HOP application. Currently only
|
||||
* single keys are supported.
|
||||
*/
|
||||
public class Key {
|
||||
|
||||
private String type;
|
||||
private String id;
|
||||
private int hash;
|
||||
|
||||
|
||||
public Key (DbMapping dbmap, String id) {
|
||||
this.type = dbmap == null ? null : dbmap.typename;
|
||||
this.id = id;
|
||||
hash = id.hashCode ();
|
||||
}
|
||||
|
||||
public Key (String type, String id) {
|
||||
this.type = type;
|
||||
this.id = id;
|
||||
hash = id.hashCode ();
|
||||
}
|
||||
|
||||
public boolean equals (Object what) {
|
||||
try {
|
||||
Key k = (Key) what;
|
||||
return ((type == k.type || type.equals (k.type)) && (id == k.id || id.equals (k.id)));
|
||||
} catch (Exception x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode () {
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Key for a virtual node contained by this node, that is, a node that does
|
||||
* not represent a record in the database. The main objective here is to generate
|
||||
* a key that can't be mistaken for a relational db key.
|
||||
*/
|
||||
public Key getVirtualKey (String sid) {
|
||||
return new Key ((String) null, makeVirtualID (type, id, sid));
|
||||
}
|
||||
|
||||
public String getVirtualID (String sid) {
|
||||
return makeVirtualID (type, id, sid);
|
||||
}
|
||||
|
||||
public static String makeVirtualID (DbMapping pmap, String pid, String sid) {
|
||||
return makeVirtualID (pmap == null ? (String) null : pmap.typename, pid, sid);
|
||||
}
|
||||
|
||||
public static String makeVirtualID (String ptype, String pid, String sid) {
|
||||
return ptype+"/"+pid + "~" + sid;
|
||||
}
|
||||
|
||||
public String getType () {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getID () {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return type+"["+id+"]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,32 +1,25 @@
|
|||
// TransientNode.java
|
||||
// Node.java
|
||||
// Copyright (c) Hannes Wallnöfer 1997-2000
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Date;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import helma.util.*;
|
||||
import helma.framework.IPathElement;
|
||||
import helma.objectmodel.db.DbMapping;
|
||||
import helma.objectmodel.db.Relation;
|
||||
|
||||
/**
|
||||
* A transient implementation of INode. An instance of this class can't be
|
||||
* made persistent by reachability from a persistent node. To make a persistent-capable
|
||||
* object, class helma.objectmodel.db.Node has to be used.
|
||||
* A transient implementation of INode. If a transient node is stored in a
|
||||
* database, it is automatically (along with all reachable subnodes) rebuilt
|
||||
* as a persistent node.
|
||||
*/
|
||||
|
||||
public class TransientNode implements INode, Serializable {
|
||||
public class Node implements INode, Serializable {
|
||||
|
||||
|
||||
protected Hashtable propMap, nodeMap;
|
||||
protected Vector nodes;
|
||||
protected TransientNode parent;
|
||||
protected Node parent;
|
||||
protected Vector links; // links to this node
|
||||
protected Vector proplinks; // nodes using this node as property
|
||||
|
||||
|
@ -48,27 +41,69 @@ public class TransientNode implements INode, Serializable {
|
|||
|
||||
private static long idgen = 0;
|
||||
|
||||
public static String generateID () {
|
||||
// make transient ids differ from persistent ones
|
||||
// and are unique within on runtime session
|
||||
return "t"+idgen++;
|
||||
public String generateID () {
|
||||
return "t"+idgen++; // make transient ids differ from persistent ones
|
||||
}
|
||||
|
||||
public TransientNode () {
|
||||
public Node () {
|
||||
id = generateID ();
|
||||
name = id;
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new TransientNode object with a given name
|
||||
* Make a new Node object with a given name
|
||||
*/
|
||||
public TransientNode (String n) {
|
||||
public Node (String n) {
|
||||
id = generateID ();
|
||||
name = n == null || "".equals (n) ? id : n;
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of a given node that implements this class
|
||||
*/
|
||||
public Node (INode node, Hashtable ntable, boolean conversionRoot) {
|
||||
this.id = generateID ();
|
||||
this.name = node.getName ();
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
setContent (node.getContent (), node.getContentType ());
|
||||
created = lastmodified = System.currentTimeMillis ();
|
||||
ntable.put (node, this);
|
||||
adoptName = !conversionRoot; // only take over name from property if this is not the transient root
|
||||
for (Enumeration e = node.getSubnodes (); e.hasMoreElements (); ) {
|
||||
INode next = (INode) e.nextElement ();
|
||||
Node nextc = (Node) ntable.get (next);
|
||||
if (nextc == null)
|
||||
nextc = new Node (next, ntable, true);
|
||||
addNode (nextc);
|
||||
}
|
||||
for (Enumeration e = node.properties (); e.hasMoreElements (); ) {
|
||||
IProperty next = node.get ((String) e.nextElement (), false);
|
||||
if (next == null)
|
||||
continue;
|
||||
int t = next.getType ();
|
||||
if (t == IProperty.NODE) {
|
||||
INode n = next.getNodeValue ();
|
||||
Node nextc = (Node) ntable.get (n);
|
||||
if (nextc == null)
|
||||
nextc = new Node (n, ntable, true);
|
||||
setNode (next.getName (), nextc);
|
||||
} else if (t == IProperty.STRING) {
|
||||
setString (next.getName (), next.getStringValue ());
|
||||
} else if (t == IProperty.INTEGER) {
|
||||
setInteger (next.getName (), next.getIntegerValue ());
|
||||
} else if (t == IProperty.FLOAT) {
|
||||
setFloat (next.getName (), next.getFloatValue ());
|
||||
} else if (t == IProperty.BOOLEAN) {
|
||||
setBoolean (next.getName (), next.getBooleanValue ());
|
||||
} else if (t == IProperty.DATE) {
|
||||
setDate (next.getName (), next.getDateValue ());
|
||||
}
|
||||
}
|
||||
adoptName = true; // switch back to normal name adoption behaviour
|
||||
}
|
||||
|
||||
|
||||
public void setDbMapping (DbMapping dbmap) {
|
||||
this.dbmap = dbmap;
|
||||
|
@ -96,7 +131,7 @@ public class TransientNode implements INode, Serializable {
|
|||
return name;
|
||||
}
|
||||
|
||||
public String getElementName () {
|
||||
public String getNameOrID () {
|
||||
return anonymous ? id : name;
|
||||
}
|
||||
|
||||
|
@ -116,22 +151,37 @@ public class TransientNode implements INode, Serializable {
|
|||
String fullname = "";
|
||||
String divider = null;
|
||||
StringBuffer b = new StringBuffer ();
|
||||
TransientNode p = this;
|
||||
Node p = this;
|
||||
while (p != null && p.parent != null && p != root) {
|
||||
if (divider != null)
|
||||
b.insert (0, divider);
|
||||
else
|
||||
divider = "/";
|
||||
b.insert (0, p.getElementName ());
|
||||
b.insert (0, p.getNameOrID ());
|
||||
p = p.parent;
|
||||
}
|
||||
return b.toString ();
|
||||
}
|
||||
|
||||
public INode[] getPath () {
|
||||
int pathSize = 1;
|
||||
INode p = getParent ();
|
||||
while (p != null) {
|
||||
pathSize +=1;
|
||||
p = p.getParent ();
|
||||
}
|
||||
INode path[] = new INode[pathSize];
|
||||
p = this;
|
||||
for (int i = pathSize-1; i>=0; i--) {
|
||||
path[i] = p;
|
||||
p = p.getParent ();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setName (String name) {
|
||||
// if (name.indexOf('/') > -1)
|
||||
// throw new RuntimeException ("The name of the node must not contain \"/\".");
|
||||
if (name.indexOf('/') > -1)
|
||||
throw new RuntimeException ("The name of the node must not contain \"/\".");
|
||||
if (name == null || name.trim().length() == 0)
|
||||
this.name = id;
|
||||
else
|
||||
|
@ -195,12 +245,15 @@ public class TransientNode implements INode, Serializable {
|
|||
nodeMap.put (elem.getID (), elem);
|
||||
nodes.insertElementAt (elem, where);
|
||||
|
||||
if (elem instanceof TransientNode) {
|
||||
TransientNode node = (TransientNode) elem;
|
||||
if (elem instanceof Node) {
|
||||
Node node = (Node) elem;
|
||||
if (node.parent == null) {
|
||||
node.parent = this;
|
||||
node.anonymous = true;
|
||||
}
|
||||
if (node.parent != null && (node.parent != this || !node.anonymous)) {
|
||||
node.registerLink (this);
|
||||
}
|
||||
}
|
||||
|
||||
lastmodified = System.currentTimeMillis ();
|
||||
|
@ -224,7 +277,7 @@ public class TransientNode implements INode, Serializable {
|
|||
boolean anon = false;
|
||||
if (nm == null || "".equals (nm.trim ()))
|
||||
anon = true;
|
||||
INode n = new TransientNode (nm);
|
||||
INode n = new Node (nm);
|
||||
if (anon)
|
||||
addNode (n, where);
|
||||
else
|
||||
|
@ -236,19 +289,11 @@ public class TransientNode implements INode, Serializable {
|
|||
/**
|
||||
* register a node that links to this node.
|
||||
*/
|
||||
/* protected void registerLink (TransientNode from) {
|
||||
protected void registerLink (Node from) {
|
||||
if (links == null)
|
||||
links = new Vector ();
|
||||
if (!links.contains (from))
|
||||
links.addElement (from);
|
||||
} */
|
||||
|
||||
public IPathElement getParentElement () {
|
||||
return getParent ();
|
||||
}
|
||||
|
||||
public IPathElement getChildElement (String name) {
|
||||
return getNode (name, false);
|
||||
}
|
||||
|
||||
public INode getSubnode (String name) {
|
||||
|
@ -257,18 +302,18 @@ public class TransientNode implements INode, Serializable {
|
|||
|
||||
public INode getSubnode (String name, boolean inherit) {
|
||||
StringTokenizer st = new StringTokenizer (name, "/");
|
||||
TransientNode retval = this, runner;
|
||||
Node retval = this, runner;
|
||||
while (st.hasMoreTokens () && retval != null) {
|
||||
runner = retval;
|
||||
String next = st.nextToken().trim().toLowerCase ();
|
||||
if ("".equals (next))
|
||||
retval = this;
|
||||
else
|
||||
retval = runner.nodeMap == null ? null : (TransientNode) runner.nodeMap.get (next);
|
||||
retval = runner.nodeMap == null ? null : (Node) runner.nodeMap.get (next);
|
||||
if (retval == null)
|
||||
retval = (TransientNode) runner.getNode (next, inherit);
|
||||
retval = (Node) runner.getNode (next, inherit);
|
||||
if (retval == null && inherit && runner == this && parent != null)
|
||||
retval = (TransientNode) parent.getSubnode (next, inherit);
|
||||
retval = (Node) parent.getSubnode (next, inherit);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
@ -296,11 +341,11 @@ public class TransientNode implements INode, Serializable {
|
|||
public void removeNode (INode node) {
|
||||
// IServer.getLogger().log ("removing: "+ node);
|
||||
releaseNode (node);
|
||||
TransientNode n = (TransientNode) node;
|
||||
Node n = (Node) node;
|
||||
if (n.getParent () == this && n.anonymous) {
|
||||
int l = n.links == null ? 0 : n.links.size (); // notify nodes that link to n that n is going down.
|
||||
for (int i = 0; i < l; i++) {
|
||||
TransientNode link = (TransientNode) n.links.elementAt (i);
|
||||
Node link = (Node) n.links.elementAt (i);
|
||||
link.releaseNode (n);
|
||||
}
|
||||
if (n.proplinks != null) {
|
||||
|
@ -310,12 +355,12 @@ public class TransientNode implements INode, Serializable {
|
|||
p.node.propMap.remove (p.propname.toLowerCase ());
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
/* for (Enumeration e2 = n.properties (); e2.hasMoreElements (); ) {
|
||||
for (Enumeration e2 = n.properties (); e2.hasMoreElements (); ) {
|
||||
// tell all nodes that are properties of n that they are no longer used as such
|
||||
Property p = (Property) n.get ((String) e2.nextElement (), false);
|
||||
if (p != null && p.type == Property.NODE)
|
||||
p.unregisterNode ();
|
||||
} */
|
||||
}
|
||||
// remove all subnodes, giving them a chance to destroy themselves.
|
||||
Vector v = new Vector (); // removeElement modifies the Vector we are enumerating, so we are extra careful.
|
||||
for (Enumeration e3 = n.getSubnodes (); e3.hasMoreElements (); ) {
|
||||
|
@ -323,7 +368,7 @@ public class TransientNode implements INode, Serializable {
|
|||
}
|
||||
int m = v.size ();
|
||||
for (int i=0; i<m; i++) {
|
||||
n.removeNode ((TransientNode) v.elementAt (i));
|
||||
n.removeNode ((Node) v.elementAt (i));
|
||||
}
|
||||
if (n.content != null) {
|
||||
// IServer.getLogger().log ("destroying content of node "+n.getName ());
|
||||
|
@ -379,7 +424,7 @@ public class TransientNode implements INode, Serializable {
|
|||
// check if we have to create a virtual node
|
||||
if (prop == null && dbmap != null) {
|
||||
Relation rel = dbmap.getPropertyRelation (propname);
|
||||
if (rel != null && rel.isVirtual ()) {
|
||||
if (rel != null && rel.virtual) {
|
||||
prop = makeVirtualNode (propname, rel);
|
||||
}
|
||||
}
|
||||
|
@ -387,13 +432,15 @@ public class TransientNode implements INode, Serializable {
|
|||
}
|
||||
|
||||
private Property makeVirtualNode (String propname, Relation rel) {
|
||||
INode node = new helma.objectmodel.db.Node (rel.getPropName (), rel.getPrototype (), dbmap.getWrappedNodeManager());
|
||||
INode node = new helma.objectmodel.db.Node (rel.propname, dbmap.getWrappedNodeManager());
|
||||
// node.setState (TRANSIENT);
|
||||
// make a db mapping good enough that the virtual node finds its subnodes
|
||||
// DbMapping dbm = new DbMapping ();
|
||||
// dbm.setSubnodeRelation (rel);
|
||||
// dbm.setPropertyRelation (rel);
|
||||
node.setDbMapping (rel.getVirtualMapping ());
|
||||
DbMapping dbm = new DbMapping ();
|
||||
dbm.setSubnodeMapping (rel.other);
|
||||
dbm.setSubnodeRelation (rel);
|
||||
dbm.setPropertyMapping (rel.other);
|
||||
dbm.setPropertyRelation (rel);
|
||||
node.setDbMapping (dbm);
|
||||
setNode (propname, node);
|
||||
return (Property) propMap.get (propname);
|
||||
}
|
||||
|
@ -547,8 +594,8 @@ public class TransientNode implements INode, Serializable {
|
|||
|
||||
// check if the main identity of this node is as a named property
|
||||
// or as an anonymous node in a collection
|
||||
if (value instanceof TransientNode) {
|
||||
TransientNode n = (TransientNode) value;
|
||||
if (value instanceof Node) {
|
||||
Node n = (Node) value;
|
||||
if (n.parent == null && n.adoptName) {
|
||||
n.name = propname;
|
||||
n.parent = this;
|
||||
|
@ -556,6 +603,8 @@ public class TransientNode implements INode, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.SUBNODE_ADDED, n));
|
||||
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||
lastmodified = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
|
@ -564,14 +613,132 @@ public class TransientNode implements INode, Serializable {
|
|||
return;
|
||||
try {
|
||||
Property p = (Property) propMap.remove (propname.toLowerCase ());
|
||||
if (p != null && p.type == Property.NODE)
|
||||
p.unregisterNode ();
|
||||
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||
lastmodified = System.currentTimeMillis ();
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
protected void registerPropLink (Property p) {
|
||||
if (proplinks == null)
|
||||
proplinks = new Vector ();
|
||||
proplinks.addElement (p);
|
||||
// IServer.getLogger().log ("registered proplink from "+p.node.getFullName ());
|
||||
// the NodeEvent is thrown later, since the node is not yet in the prop table
|
||||
}
|
||||
|
||||
/* public String getUrl (INode root, INode users, String tmpname, String rootproto) {
|
||||
protected void unregisterPropLink (Property p) {
|
||||
if (proplinks != null)
|
||||
proplinks.removeElement (p);
|
||||
// IServer.getLogger().log ("unregistered proplink from "+p.node.getFullName ());
|
||||
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.NODE_REMOVED));
|
||||
// Server.throwNodeEvent (new NodeEvent (p.node, NodeEvent.SUBNODE_REMOVED, this));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* content-related
|
||||
*/
|
||||
|
||||
public boolean isText () throws IOException {
|
||||
return getContentType().indexOf ("text/") == 0;
|
||||
}
|
||||
|
||||
public boolean isBinary () throws IOException {
|
||||
return getContentType().indexOf ("text/") != 0;
|
||||
}
|
||||
|
||||
public String getContentType () {
|
||||
if (contentType == null)
|
||||
return "text/plain";
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setContentType (String type) {
|
||||
contentType = type;
|
||||
lastmodified = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
public int getContentLength () {
|
||||
if (content == null)
|
||||
return 0;
|
||||
return content.length;
|
||||
}
|
||||
|
||||
public void setContent (byte cnt[], String type) {
|
||||
if (type != null)
|
||||
contentType = type;
|
||||
content = cnt;
|
||||
lastmodified = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
public void setContent (String cstr) {
|
||||
content = cstr == null ? null : cstr.getBytes ();
|
||||
lastmodified = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
public byte[] getContent () {
|
||||
if (content == null || content.length == 0)
|
||||
return "".getBytes ();
|
||||
byte retval[] = new byte[content.length];
|
||||
System.arraycopy (content, 0, retval, 0, content.length);
|
||||
return retval;
|
||||
}
|
||||
|
||||
public String writeToFile (String dir) {
|
||||
return writeToFile (dir, null);
|
||||
}
|
||||
|
||||
public String writeToFile (String dir, String fname) {
|
||||
try {
|
||||
File base = new File (dir);
|
||||
// make directories if they don't exist
|
||||
if (!base.exists ())
|
||||
base.mkdirs ();
|
||||
|
||||
String filename = name;
|
||||
if (fname != null) {
|
||||
if (fname.indexOf (".") < 0) {
|
||||
// check if we can use extension from name
|
||||
int ndot = name == null ? -1 : name.lastIndexOf (".");
|
||||
if (ndot > -1)
|
||||
filename = fname + name.substring (ndot);
|
||||
else
|
||||
filename = fname;
|
||||
} else {
|
||||
filename = fname;
|
||||
}
|
||||
}
|
||||
File file = new File (base, filename);
|
||||
FileOutputStream fout = new FileOutputStream (file);
|
||||
fout.write (getContent ());
|
||||
fout.close ();
|
||||
return filename;
|
||||
} catch (Exception x) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getText () {
|
||||
if (content != null) {
|
||||
if (getContentType ().indexOf ("text/") == 0) {
|
||||
return new String (content);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public String getHref (INode root, INode userroot, String tmpname, String prefix) {
|
||||
return prefix + getUrl (root, userroot, tmpname);
|
||||
}
|
||||
|
||||
public String getUrl (INode root, INode userroot, String tmpname) {
|
||||
throw new RuntimeException ("HREFs on transient (non-db based) Nodes not supported");
|
||||
} */
|
||||
}
|
||||
|
||||
|
||||
public long lastModified () {
|
||||
|
@ -583,29 +750,26 @@ public class TransientNode implements INode, Serializable {
|
|||
}
|
||||
|
||||
public String toString () {
|
||||
return "TransientNode " + name;
|
||||
return "Node " + name;
|
||||
}
|
||||
|
||||
|
||||
protected Node convert (INode n) {
|
||||
Hashtable ntable = new Hashtable ();
|
||||
Node converted = new Node (n, ntable, false);
|
||||
return converted;
|
||||
}
|
||||
|
||||
INode cacheNode;
|
||||
/**
|
||||
* Get the cache node for this node. This can
|
||||
* be used to store transient cache data per node
|
||||
* from Javascript.
|
||||
* Get the cache node for this node. This can be used to store transient cache data per node from Javascript.
|
||||
*/
|
||||
public synchronized INode getCacheNode () {
|
||||
if (cacheNode == null)
|
||||
cacheNode = new TransientNode();
|
||||
cacheNode = new Node();
|
||||
return cacheNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the cache node for this node.
|
||||
*/
|
||||
public synchronized void clearCacheNode () {
|
||||
cacheNode = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
46
src/helma/objectmodel/NodeDataSource.java
Normal file
46
src/helma/objectmodel/NodeDataSource.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
// NodeDataSource.java
|
||||
// Copyright (c) Hannes Wallnöfer 1999-2000
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
import javax.activation.*;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Makes Nodes usable as Datasources in the Java Activation Framework (JAF)
|
||||
*/
|
||||
|
||||
public class NodeDataSource implements DataSource {
|
||||
|
||||
private INode node;
|
||||
private String name;
|
||||
|
||||
public NodeDataSource (INode node) {
|
||||
this.node = node;
|
||||
this.name = node.getName ();
|
||||
}
|
||||
|
||||
public NodeDataSource (INode node, String name) {
|
||||
this.node = node;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(node.getContent ());
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream () throws IOException {
|
||||
throw new IOException ("Can't write to Node object.");
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return node.getContentType ();
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,10 +4,7 @@
|
|||
package helma.objectmodel;
|
||||
|
||||
import helma.util.*;
|
||||
import java.util.Vector;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.text.*;
|
||||
|
||||
|
@ -15,11 +12,11 @@ import java.text.*;
|
|||
* A property implementation for Nodes stored inside a database.
|
||||
*/
|
||||
|
||||
public final class Property implements IProperty, Serializable {
|
||||
public final class Property implements IProperty, Serializable, Cloneable {
|
||||
|
||||
|
||||
protected String propname;
|
||||
protected TransientNode node;
|
||||
protected Node node;
|
||||
|
||||
public String svalue;
|
||||
public boolean bvalue;
|
||||
|
@ -31,11 +28,11 @@ public final class Property implements IProperty, Serializable {
|
|||
public int type;
|
||||
|
||||
|
||||
public Property (TransientNode node) {
|
||||
public Property (Node node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public Property (String propname, TransientNode node) {
|
||||
public Property (String propname, Node node) {
|
||||
this.propname = propname;
|
||||
this.node = node;
|
||||
}
|
||||
|
@ -66,16 +63,39 @@ public final class Property implements IProperty, Serializable {
|
|||
|
||||
public void setStringValue (String value) throws ParseException {
|
||||
if (type == NODE)
|
||||
this.nvalue = null;
|
||||
unregisterNode ();
|
||||
// IServer.getLogger().log ("setting string value of property "+propname + " to "+value);
|
||||
if (type == DATE) {
|
||||
SimpleDateFormat dateformat = new SimpleDateFormat ();
|
||||
dateformat.setLenient (true);
|
||||
Date date = dateformat.parse (value);
|
||||
this.lvalue = date.getTime ();
|
||||
return;
|
||||
}
|
||||
if (type == BOOLEAN) {
|
||||
if ("true".equalsIgnoreCase (value))
|
||||
this.bvalue = true;
|
||||
else if ("false".equalsIgnoreCase (value))
|
||||
this.bvalue = false;
|
||||
return;
|
||||
}
|
||||
if (type == INTEGER) {
|
||||
this.lvalue = Long.parseLong (value);
|
||||
return;
|
||||
}
|
||||
if (type == FLOAT) {
|
||||
this.dvalue = new Double (value).doubleValue ();
|
||||
return;
|
||||
}
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = STRING;
|
||||
this.svalue = value;
|
||||
type = STRING;
|
||||
}
|
||||
|
||||
public void setIntegerValue (long value) {
|
||||
if (type == NODE)
|
||||
this.nvalue = null;
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = INTEGER;
|
||||
|
@ -84,7 +104,7 @@ public final class Property implements IProperty, Serializable {
|
|||
|
||||
public void setFloatValue (double value) {
|
||||
if (type == NODE)
|
||||
this.nvalue = null;
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = FLOAT;
|
||||
|
@ -93,7 +113,7 @@ public final class Property implements IProperty, Serializable {
|
|||
|
||||
public void setDateValue (Date value) {
|
||||
if (type == NODE)
|
||||
this.nvalue = null;
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = DATE;
|
||||
|
@ -102,7 +122,7 @@ public final class Property implements IProperty, Serializable {
|
|||
|
||||
public void setBooleanValue (boolean value) {
|
||||
if (type == NODE)
|
||||
this.nvalue = null;
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = BOOLEAN;
|
||||
|
@ -112,18 +132,58 @@ public final class Property implements IProperty, Serializable {
|
|||
public void setNodeValue (INode value) {
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
if (type == NODE && nvalue != value) {
|
||||
unregisterNode ();
|
||||
registerNode (value);
|
||||
} else if (type != NODE)
|
||||
registerNode (value);
|
||||
type = NODE;
|
||||
this.nvalue = value;
|
||||
}
|
||||
|
||||
public void setJavaObjectValue (Object value) {
|
||||
if (type == NODE)
|
||||
this.nvalue = null;
|
||||
unregisterNode ();
|
||||
type = JAVAOBJECT;
|
||||
this.jvalue = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tell a the value node that it is no longer used as a property.
|
||||
*/
|
||||
protected void unregisterNode () {
|
||||
if (nvalue != null && nvalue instanceof Node) {
|
||||
Node n = (Node) nvalue;
|
||||
if (!n.anonymous && propname.equals (n.getName()) && this.node == n.getParent()) {
|
||||
// this is the "main" property of a named node, so handle this as a total delete.
|
||||
IServer.getLogger().log ("deleting named property");
|
||||
if (n.proplinks != null) {
|
||||
for (Enumeration e = n.proplinks.elements (); e.hasMoreElements (); ) {
|
||||
Property p = (Property) e.nextElement ();
|
||||
p.node.propMap.remove (p.propname.toLowerCase ());
|
||||
}
|
||||
}
|
||||
if (n.links != null) {
|
||||
for (Enumeration e = n.links.elements (); e.hasMoreElements (); ) {
|
||||
Node n2 = (Node) e.nextElement ();
|
||||
n2.releaseNode (n);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
n.unregisterPropLink (this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tell the value node that it is being used as a property value.
|
||||
*/
|
||||
protected void registerNode (INode n) {
|
||||
if (n != null && n instanceof Node)
|
||||
((Node) n).registerPropLink (this);
|
||||
}
|
||||
|
||||
public String getStringValue () {
|
||||
switch (type) {
|
||||
|
@ -141,7 +201,7 @@ public final class Property implements IProperty, Serializable {
|
|||
case NODE:
|
||||
return nvalue.getName ();
|
||||
case JAVAOBJECT:
|
||||
return jvalue == null ? null : jvalue.toString ();
|
||||
return jvalue.toString ();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -187,9 +247,86 @@ public final class Property implements IProperty, Serializable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public String getEditor () {
|
||||
switch (type) {
|
||||
case STRING:
|
||||
return "password".equalsIgnoreCase (propname) ?
|
||||
"<input type=password name=\""+propname+"\" value='"+ svalue.replace ('\'', '"') +"'>" :
|
||||
"<input type=text name=\""+propname+"\" value='"+ svalue.replace ('\'', '"') +"'>" ;
|
||||
case BOOLEAN:
|
||||
return "<select name=\""+propname+"\"><option selected value="+bvalue+">"+bvalue+"</option><option value="+!bvalue+">"+!bvalue+"</option></select>";
|
||||
case INTEGER:
|
||||
return "<input type=text name=\""+propname+"\" value=\""+lvalue+"\">" ;
|
||||
case FLOAT:
|
||||
return "<input type=text name=\""+propname+"\" value=\""+dvalue+"\">" ;
|
||||
case DATE:
|
||||
SimpleDateFormat format = new SimpleDateFormat ("dd.MM.yy hh:mm");
|
||||
String date = format.format (new Date (lvalue));
|
||||
return "<input type=text name=\""+propname+"\" value=\""+date+"\">";
|
||||
case NODE:
|
||||
return "<input type=text size=25 name="+propname+" value='"+ nvalue.getFullName () +"'>";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String escape (String s) {
|
||||
char c[] = new char[s.length()];
|
||||
s.getChars (0, c.length, c, 0);
|
||||
StringBuffer b = new StringBuffer ();
|
||||
int copyfrom = 0;
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
switch (c[i]) {
|
||||
case '\\':
|
||||
case '"':
|
||||
if (i-copyfrom > 0)
|
||||
b.append (c, copyfrom, i-copyfrom);
|
||||
b.append ('\\');
|
||||
b.append (c[i]);
|
||||
copyfrom = i+1;
|
||||
}
|
||||
}
|
||||
if (c.length-copyfrom > 0)
|
||||
b.append (c, copyfrom, c.length-copyfrom);
|
||||
return b.toString ();
|
||||
}
|
||||
|
||||
public int getType () {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getTypeString () {
|
||||
switch (type) {
|
||||
case STRING:
|
||||
return "string";
|
||||
case BOOLEAN:
|
||||
return "boolean";
|
||||
case DATE:
|
||||
return "date";
|
||||
case INTEGER:
|
||||
return "integer";
|
||||
case FLOAT:
|
||||
return "float";
|
||||
case NODE:
|
||||
return "node";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
public Object clone () {
|
||||
try {
|
||||
Property c = (Property) super.clone();
|
||||
c.propname = this.propname;
|
||||
c.svalue = this.svalue;
|
||||
c.bvalue = this.bvalue;
|
||||
c.lvalue = this.lvalue;
|
||||
c.dvalue = this.dvalue;
|
||||
c.type = this.type;
|
||||
return c;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// this shouldn't happen, since we are Cloneable
|
||||
throw new InternalError ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
341
src/helma/objectmodel/Relation.java
Normal file
341
src/helma/objectmodel/Relation.java
Normal file
|
@ -0,0 +1,341 @@
|
|||
// Relation.java
|
||||
// Copyright (c) Hannes Wallnöfer 1997-2000
|
||||
|
||||
package helma.objectmodel;
|
||||
|
||||
import helma.framework.core.Application;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* This describes how a property of a persistent Object is stored in a
|
||||
* relational database table. This can be either a scalar property (string, date, number etc.)
|
||||
* or a reference to one or more other objects.
|
||||
*/
|
||||
public class Relation {
|
||||
|
||||
// TODO: explain hop mapping types
|
||||
public final static int INVALID = -1;
|
||||
public final static int PRIMITIVE = 0;
|
||||
public final static int FORWARD = 1;
|
||||
public final static int BACKWARD = 2;
|
||||
public final static int DIRECT = 3;
|
||||
|
||||
public DbMapping home;
|
||||
public DbMapping other;
|
||||
public String propname;
|
||||
protected String localField, remoteField;
|
||||
public int direction;
|
||||
|
||||
public boolean virtual;
|
||||
public boolean readonly;
|
||||
public boolean aggressiveLoading;
|
||||
public boolean aggressiveCaching;
|
||||
public boolean subnodesAreProperties;
|
||||
public String order;
|
||||
public String groupbyorder;
|
||||
public String groupby;
|
||||
public String prototype;
|
||||
|
||||
Relation filter = null; // additional relation used to filter subnodes
|
||||
|
||||
/**
|
||||
* This constructor is used to directly construct a Relation, as opposed to reading it from a proerty file
|
||||
*/
|
||||
public Relation (DbMapping other, String localField, String remoteField, int direction, boolean subnodesAreProperties) {
|
||||
this.other = other;
|
||||
this.localField = localField;
|
||||
this.remoteField = remoteField;
|
||||
this.direction = direction;
|
||||
this.subnodesAreProperties = subnodesAreProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a relation entry from a line in a properties file.
|
||||
*/
|
||||
public Relation (String desc, String propname, DbMapping home, Properties props) {
|
||||
|
||||
this.home = home;
|
||||
this.propname = propname;
|
||||
other = null;
|
||||
Application app = home.getApplication ();
|
||||
boolean mountpoint = false;
|
||||
|
||||
if (desc == null || "".equals (desc.trim ())) {
|
||||
if (propname != null) {
|
||||
direction = PRIMITIVE;
|
||||
localField = propname;
|
||||
} else {
|
||||
direction = INVALID;
|
||||
localField = propname;
|
||||
}
|
||||
} else {
|
||||
desc = desc.trim ();
|
||||
String descLower = desc.toLowerCase ();
|
||||
if (descLower.startsWith ("[virtual]")) {
|
||||
desc = desc.substring (9).trim ();
|
||||
virtual = true;
|
||||
} else if (descLower.startsWith ("[collection]")) {
|
||||
desc = desc.substring (12).trim ();
|
||||
virtual = true;
|
||||
} else if (descLower.startsWith ("[mountpoint]")) {
|
||||
desc = desc.substring (12).trim ();
|
||||
virtual = true;
|
||||
mountpoint = true;
|
||||
} else {
|
||||
virtual = false;
|
||||
}
|
||||
if (descLower.startsWith ("[readonly]")) {
|
||||
desc = desc.substring (10).trim ();
|
||||
readonly = true;
|
||||
} else {
|
||||
readonly = false;
|
||||
}
|
||||
if (desc.indexOf ("<") > -1) {
|
||||
direction = BACKWARD;
|
||||
int lt = desc.indexOf ("<");
|
||||
int dot = desc.indexOf (".");
|
||||
String otherType = dot < 0 ? desc.substring (1).trim () : desc.substring (1, dot).trim ();
|
||||
other = app.getDbMapping (otherType);
|
||||
if (other == null)
|
||||
throw new RuntimeException ("DbMapping for "+otherType+" not found from "+home.typename);
|
||||
remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
|
||||
localField = lt < 0 ? null : desc.substring (0, lt).trim ();
|
||||
if (mountpoint) prototype = otherType;
|
||||
} else if (desc.indexOf (">") > -1) {
|
||||
direction = FORWARD;
|
||||
int bt = desc.indexOf (">");
|
||||
int dot = desc.indexOf (".");
|
||||
String otherType = dot > -1 ? desc.substring (bt+1, dot).trim () : desc.substring (bt+1).trim ();
|
||||
other = app.getDbMapping (otherType);
|
||||
if (other == null)
|
||||
throw new RuntimeException ("DbMapping for "+otherType+" not found from "+home.typename);
|
||||
localField = desc.substring (0, bt).trim ();
|
||||
remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
|
||||
if (mountpoint) prototype = otherType;
|
||||
} else if (desc.indexOf (".") > -1) {
|
||||
direction = DIRECT;
|
||||
int dot = desc.indexOf (".");
|
||||
String otherType = desc.substring (0, dot).trim ();
|
||||
other = app.getDbMapping (otherType);
|
||||
if (other == null)
|
||||
throw new RuntimeException ("DbMapping for "+otherType+" not found from "+home.typename);
|
||||
remoteField = desc.substring (dot+1).trim ();
|
||||
localField = null;
|
||||
if (mountpoint) prototype = otherType;
|
||||
} else {
|
||||
if (virtual) {
|
||||
direction = DIRECT;
|
||||
other = app.getDbMapping (desc);
|
||||
if (other == null)
|
||||
throw new RuntimeException ("DbMapping for "+desc+" not found from "+home.typename);
|
||||
remoteField = localField = null;
|
||||
if (mountpoint) prototype = desc;
|
||||
} else {
|
||||
direction = PRIMITIVE;
|
||||
localField = desc.trim ();
|
||||
}
|
||||
}
|
||||
}
|
||||
String loading = props.getProperty (propname+".loadmode");
|
||||
aggressiveLoading = loading != null && "aggressive".equalsIgnoreCase (loading.trim());
|
||||
String caching = props.getProperty (propname+".cachemode");
|
||||
aggressiveCaching = caching != null && "aggressive".equalsIgnoreCase (caching.trim());
|
||||
// get order property
|
||||
order = props.getProperty (propname+".order");
|
||||
if (order != null && order.trim().length() == 0) order = null;
|
||||
// get group by property
|
||||
groupby = props.getProperty (propname+".groupby");
|
||||
if (groupby != null && groupby.trim().length() == 0)
|
||||
groupby = null;
|
||||
if (groupby != null) {
|
||||
groupbyorder = props.getProperty (propname+".groupby.order");
|
||||
if (groupbyorder != null && groupbyorder.trim().length() == 0)
|
||||
groupbyorder = null;
|
||||
}
|
||||
// check if subnode condition should be applied for property relations
|
||||
if ("_properties".equalsIgnoreCase (propname) || virtual) {
|
||||
String subnodes2props = props.getProperty (propname+".aresubnodes");
|
||||
subnodesAreProperties = "true".equalsIgnoreCase (subnodes2props);
|
||||
if (virtual) {
|
||||
String subnodefilter = props.getProperty (propname+".subnoderelation");
|
||||
if (subnodefilter != null) {
|
||||
filter = new Relation (subnodefilter, propname+".subnoderelation", home, props);
|
||||
filter.groupby = groupby;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isReference () {
|
||||
return direction > PRIMITIVE;
|
||||
}
|
||||
|
||||
public boolean usesPrimaryKey () {
|
||||
if (other == null)
|
||||
return false;
|
||||
if (remoteField == null)
|
||||
// if remote field is null, it is assumed that it points to the primary key
|
||||
return true;
|
||||
return remoteField.equalsIgnoreCase (other.getIDField());
|
||||
}
|
||||
|
||||
public Relation getFilter () {
|
||||
return filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a key string to cache a node with a specific value for this relation. If the
|
||||
* Relation uses the primary key return just the key value, otherwise include info on the
|
||||
* used column or even the base node to avoid collisions.
|
||||
*/
|
||||
public String getKeyID (INode home, String kval) {
|
||||
// if the column is not the primary key, we add the column name to the key
|
||||
if ((direction == DIRECT || direction == FORWARD) && !usesPrimaryKey ()) {
|
||||
// check if the subnode relation also has to be considered
|
||||
if (subnodesAreProperties)
|
||||
return "["+home.getID()+"]"+remoteField+"="+kval; // HACK
|
||||
else
|
||||
return remoteField+"="+kval;
|
||||
} else {
|
||||
return kval;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the local column name for this relation to use in where clauses of select statements.
|
||||
* This uses the home node's id as fallback if local field is not specified.
|
||||
*/
|
||||
public String getLocalField () {
|
||||
// only assume local field is primary key if other objects "point" to this object
|
||||
if (localField == null && direction == BACKWARD)
|
||||
return home.getIDField ();
|
||||
return localField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the local field name for updates. This is the same as getLocalField, but does not return the
|
||||
* primary key name as a fallback.
|
||||
*/
|
||||
public String getDbField () {
|
||||
return localField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "remote" column name for this relation. Uses the remote node's id as fallback if the remote field is not specified.
|
||||
*/
|
||||
public String getRemoteField () {
|
||||
// only assume remote field is primary key if this relation "points" to an object
|
||||
if (remoteField == null && direction == FORWARD)
|
||||
return other.getIDField ();
|
||||
return remoteField;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a Relation that defines the subnodes of a virtual node.
|
||||
*/
|
||||
public Relation getVirtualSubnodeRelation () {
|
||||
if (!virtual)
|
||||
throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation");
|
||||
if (filter != null)
|
||||
return filter;
|
||||
Relation vr = new Relation (other, localField, remoteField, direction, subnodesAreProperties);
|
||||
vr.groupby = groupby;
|
||||
vr.groupbyorder = groupbyorder;
|
||||
vr.order = order;
|
||||
vr.filter = filter;
|
||||
return vr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Relation that defines the properties of a virtual node.
|
||||
*/
|
||||
public Relation getVirtualPropertyRelation () {
|
||||
if (!virtual)
|
||||
throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation");
|
||||
Relation vr = new Relation (other, localField, remoteField, direction, subnodesAreProperties);
|
||||
vr.groupby = groupby;
|
||||
vr.groupbyorder = groupbyorder;
|
||||
vr.order = order;
|
||||
vr.filter = filter;
|
||||
return vr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Relation that defines the subnodes of a group-by node.
|
||||
*/
|
||||
public Relation getGroupbySubnodeRelation () {
|
||||
if (groupby == null)
|
||||
throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
|
||||
if (filter != null)
|
||||
return filter;
|
||||
Relation vr = new Relation (other, localField, remoteField, direction, true);
|
||||
vr.order = order;
|
||||
return vr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Relation that defines the properties of a group-by node.
|
||||
*/
|
||||
public Relation getGroupbyPropertyRelation () {
|
||||
if (groupby == null)
|
||||
throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
|
||||
Relation vr = new Relation (other, localField, remoteField, direction, true);
|
||||
vr.order = order;
|
||||
return vr;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
// Property.java
|
||||
// Copyright (c) Hannes Wallnöfer 1997-2000
|
||||
|
||||
package helma.util;
|
||||
package helma.objectmodel;
|
||||
|
||||
import helma.util.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
|
@ -19,27 +20,11 @@ public final class SystemProperties extends Properties {
|
|||
private File file;
|
||||
private long lastread, lastcheck;
|
||||
|
||||
final static long cacheTime = 1500l;
|
||||
|
||||
|
||||
public SystemProperties () {
|
||||
this (null, null);
|
||||
}
|
||||
|
||||
public SystemProperties (InputStream in) {
|
||||
this (null, null);
|
||||
try {
|
||||
load (in);
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Error reading properties from file "+file+": "+x);
|
||||
} finally {
|
||||
try {
|
||||
in.close ();
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
lastread = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
public SystemProperties (String filename) {
|
||||
this (filename, null);
|
||||
}
|
||||
|
@ -49,7 +34,7 @@ public final class SystemProperties extends Properties {
|
|||
}
|
||||
|
||||
public SystemProperties (String filename, Properties defaultProps) {
|
||||
// System.err.println ("building sysprops with file "+filename+" and node "+node);
|
||||
// IServer.getLogger().log ("building sysprops with file "+filename+" and node "+node);
|
||||
this.defaultProps = defaultProps;
|
||||
props = defaultProps == null ?
|
||||
new Properties () : new Properties (defaultProps);
|
||||
|
@ -79,7 +64,7 @@ public final class SystemProperties extends Properties {
|
|||
load (bpin);
|
||||
bpin.close ();
|
||||
} catch (Exception x) {
|
||||
System.err.println ("Error reading properties from file "+file+": "+x);
|
||||
IServer.getLogger().log ("Error reading properties from file "+file+": "+x);
|
||||
}
|
||||
lastread = System.currentTimeMillis ();
|
||||
props = newProps;
|
||||
|
@ -124,42 +109,30 @@ public final class SystemProperties extends Properties {
|
|||
}
|
||||
|
||||
public String getProperty (String name) {
|
||||
if (System.currentTimeMillis () - lastcheck > cacheTime)
|
||||
if (System.currentTimeMillis () - lastcheck > 1500l)
|
||||
checkFile ();
|
||||
return props.getProperty (name.toLowerCase());
|
||||
}
|
||||
|
||||
public String getProperty (String name, String defaultValue) {
|
||||
if (System.currentTimeMillis () - lastcheck > cacheTime)
|
||||
if (System.currentTimeMillis () - lastcheck > 1500l)
|
||||
checkFile ();
|
||||
return props.getProperty (name.toLowerCase(), defaultValue);
|
||||
}
|
||||
|
||||
public Enumeration keys () {
|
||||
if (System.currentTimeMillis () - lastcheck > cacheTime)
|
||||
if (System.currentTimeMillis () - lastcheck > 1500l)
|
||||
checkFile ();
|
||||
return props.keys();
|
||||
}
|
||||
|
||||
public Enumeration elements () {
|
||||
if (System.currentTimeMillis () - lastcheck > cacheTime)
|
||||
if (System.currentTimeMillis () - lastcheck > 1500l)
|
||||
checkFile ();
|
||||
return props.elements();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
if (System.currentTimeMillis () - lastcheck > cacheTime)
|
||||
checkFile ();
|
||||
return props.size();
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return props.toString ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
// ApplicationManager.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.main;
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.rmi.*;
|
||||
|
@ -13,27 +12,27 @@ import helma.framework.*;
|
|||
import helma.framework.core.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.servlet.*;
|
||||
import helma.util.SystemProperties;
|
||||
import Acme.Serve.*;
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
|
||||
/**
|
||||
* This class is responsible for starting and stopping Helma applications.
|
||||
* This class is responsible for starting and stopping HOP applications.
|
||||
*/
|
||||
|
||||
public class ApplicationManager {
|
||||
|
||||
private Hashtable applications;
|
||||
private int port;
|
||||
private File hopHome;
|
||||
private File appHome, dbHome;
|
||||
private SystemProperties props;
|
||||
private Server server;
|
||||
private long lastModified;
|
||||
|
||||
public ApplicationManager (int port, File hopHome, SystemProperties props, Server server) {
|
||||
public ApplicationManager (int port, File appHome, File dbHome, SystemProperties props, Server server) {
|
||||
this.port = port;
|
||||
this.hopHome = hopHome;
|
||||
this.appHome = appHome;
|
||||
this.dbHome = dbHome;
|
||||
this.props = props;
|
||||
this.server = server;
|
||||
applications = new Hashtable ();
|
||||
|
@ -60,65 +59,60 @@ public class ApplicationManager {
|
|||
}
|
||||
}
|
||||
} catch (Exception mx) {
|
||||
Server.getLogger().log ("Error starting applications: "+mx);
|
||||
IServer.getLogger().log ("Error starting applications: "+mx);
|
||||
}
|
||||
|
||||
lastModified = System.currentTimeMillis ();
|
||||
}
|
||||
}
|
||||
|
||||
void start (String appName) {
|
||||
Server.getLogger().log ("Building application "+appName);
|
||||
|
||||
private void start (String appName) {
|
||||
IServer.getLogger().log ("Building application "+appName);
|
||||
try {
|
||||
Application app = new Application (appName, hopHome, Server.sysProps, Server.dbProps);
|
||||
Application app = new Application (appName, dbHome, appHome);
|
||||
applications.put (appName, app);
|
||||
// if we're running with the embedded web server, set app base uri to /appname
|
||||
if (server.websrv != null && !"base".equalsIgnoreCase (appName))
|
||||
if (server.websrv != null)
|
||||
app.setBaseURI ("/"+java.net.URLEncoder.encode (appName));
|
||||
// the application is started later in the register method, when it's bound
|
||||
app.init ();
|
||||
app.start ();
|
||||
} catch (Exception x) {
|
||||
Server.getLogger().log ("Error creating application "+appName+": "+x);
|
||||
IServer.getLogger().log ("Error creating application "+appName+": "+x);
|
||||
x.printStackTrace ();
|
||||
}
|
||||
}
|
||||
|
||||
void stop (String appName) {
|
||||
Server.getLogger().log ("Stopping application "+appName);
|
||||
private void stop (String appName) {
|
||||
IServer.getLogger().log ("Stopping application "+appName);
|
||||
try {
|
||||
Application app = (Application) applications.get (appName);
|
||||
if (server.websrv == null) {
|
||||
Naming.unbind ("//:"+port+"/"+appName);
|
||||
} else {
|
||||
// server.websrv.removeServlet ("/"+appName+"/");
|
||||
server.websrv.removeServlet ("/"+appName+"/");
|
||||
server.websrv.removeServlet ("/"+appName+"/*");
|
||||
}
|
||||
app.stop ();
|
||||
Server.getLogger().log ("Unregistered application "+appName);
|
||||
IServer.getLogger().log ("Unregistered application "+appName);
|
||||
} catch (Exception x) {
|
||||
Server.getLogger().log ("Couldn't unregister app: "+x);
|
||||
IServer.getLogger().log ("Couldn't unregister app: "+x);
|
||||
}
|
||||
applications.remove (appName);
|
||||
}
|
||||
|
||||
void register (String appName) {
|
||||
private void register (String appName) {
|
||||
try {
|
||||
Server.getLogger().log ("Binding application "+appName);
|
||||
IServer.getLogger().log ("Binding application "+appName);
|
||||
Application app = (Application) applications.get (appName);
|
||||
if (server.websrv == null) {
|
||||
Naming.rebind ("//:"+port+"/"+appName, app);
|
||||
} else {
|
||||
AcmeServletClient servlet = new AcmeServletClient (app);
|
||||
if ("base".equalsIgnoreCase (appName))
|
||||
server.websrv.setDefaultServlet (servlet);
|
||||
else {
|
||||
// server.websrv.addServlet ("/"+appName+"/", servlet);
|
||||
server.websrv.addServlet ("/"+appName+"/*", servlet);
|
||||
}
|
||||
server.websrv.addServlet ("/"+appName+"/", servlet);
|
||||
server.websrv.addServlet ("/"+appName+"/*", servlet);
|
||||
}
|
||||
app.start ();
|
||||
} catch (Exception x) {
|
||||
Server.getLogger().log ("Couldn't register and start app: "+x);
|
||||
IServer.getLogger().log ("Couldn't register app: "+x);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,27 +128,16 @@ public class ApplicationManager {
|
|||
}
|
||||
if (server.websrv != null) {
|
||||
File staticContent = new File (server.getHopHome(), "static");
|
||||
Server.getLogger().log("Serving static content from "+staticContent.getAbsolutePath());
|
||||
IServer.getLogger().log("Serving static content from "+staticContent.getAbsolutePath());
|
||||
AcmeFileServlet fsrv = new AcmeFileServlet (staticContent);
|
||||
server.websrv.addServlet ("/static/", fsrv);
|
||||
server.websrv.addServlet ("/static/*", fsrv);
|
||||
}
|
||||
lastModified = System.currentTimeMillis ();
|
||||
} catch (Exception mx) {
|
||||
Server.getLogger().log ("Error starting applications: "+mx);
|
||||
IServer.getLogger().log ("Error starting applications: "+mx);
|
||||
mx.printStackTrace ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an enumeration of all currently running applications.
|
||||
*/
|
||||
public Object[] getApplications () {
|
||||
return applications.values ().toArray ();
|
||||
}
|
||||
|
||||
public Application getApplication(String name) {
|
||||
return (Application)applications.get(name);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
// DbKey.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* This is the internal representation of a database key. It is constructed
|
||||
* out of the database URL, the table name, the user name and the database
|
||||
* key of the node and unique within each Helma application. Currently only
|
||||
* single keys are supported.
|
||||
*/
|
||||
public final class DbKey implements Key, Serializable {
|
||||
|
||||
// the name of the prototype which defines the storage of this object.
|
||||
// this is the name of the object's prototype, or one of its ancestors.
|
||||
// If null, the object is stored in the embedded db.
|
||||
private final String storageName;
|
||||
// the id that defines this key's object within the above storage space
|
||||
private final String id;
|
||||
|
||||
// lazily initialized hashcode
|
||||
private transient int hashcode = 0;
|
||||
|
||||
/**
|
||||
* make a key for a persistent Object, describing its datasource and id.
|
||||
*/
|
||||
public DbKey (DbMapping dbmap, String id) {
|
||||
this.id = id;
|
||||
this.storageName = dbmap == null ? null : dbmap.getStorageTypeName ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean equals (Object what) {
|
||||
if (what == this)
|
||||
return true;
|
||||
try {
|
||||
DbKey k = (DbKey) what;
|
||||
return (storageName == k.storageName || storageName.equals (k.storageName)) &&
|
||||
(id == k.id || id.equals (k.id));
|
||||
} catch (Exception x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode () {
|
||||
if (hashcode == 0) {
|
||||
hashcode = storageName == null ?
|
||||
17 + 37*id.hashCode () :
|
||||
17 + 37*storageName.hashCode() + +37*id.hashCode ();
|
||||
}
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
public Key getParentKey () {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getStorageName () {
|
||||
return storageName;
|
||||
}
|
||||
|
||||
public String getID () {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return storageName == null ? "["+id+"]" : storageName+"["+id+"]";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,725 +0,0 @@
|
|||
// DbMapping.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import helma.framework.core.Application;
|
||||
import helma.util.Updatable;
|
||||
import helma.util.SystemProperties;
|
||||
import java.util.HashMap;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.StringTokenizer;
|
||||
import java.sql.*;
|
||||
import com.workingdogs.village.*;
|
||||
|
||||
/**
|
||||
* A DbMapping describes how a certain type of Nodes is to mapped to a
|
||||
* relational database table. Basically it consists of a set of JavaScript property-to-
|
||||
* Database row bindings which are represented by instances of the Relation class.
|
||||
*/
|
||||
|
||||
public class DbMapping implements Updatable {
|
||||
|
||||
// DbMappings belong to an application
|
||||
Application app;
|
||||
// prototype name of this mapping
|
||||
String typename;
|
||||
|
||||
int version;
|
||||
|
||||
// properties from where the mapping is read
|
||||
SystemProperties props;
|
||||
|
||||
// name of data source to which this mapping writes
|
||||
DbSource source;
|
||||
// name of datasource
|
||||
String sourceName;
|
||||
// name of db table
|
||||
String table;
|
||||
|
||||
// list of properties to try for parent
|
||||
ParentInfo[] parent;
|
||||
|
||||
// Relations describing subnodes and properties.
|
||||
Relation subnodesRel;
|
||||
Relation propertiesRel;
|
||||
|
||||
// if this defines a subnode mapping with groupby layer, we need a DbMapping for those groupby nodes
|
||||
DbMapping groupbyMapping;
|
||||
|
||||
// Map of property names to Relations objects
|
||||
HashMap prop2db;
|
||||
// Map of db columns to Relations objects
|
||||
HashMap db2prop;
|
||||
|
||||
// db field used as primary key
|
||||
private String idField;
|
||||
// db field used as object name
|
||||
String nameField;
|
||||
// db field used to identify name of prototype to use for object instantiation
|
||||
String protoField;
|
||||
|
||||
// name of parent prototype, if any
|
||||
String extendsProto;
|
||||
// dbmapping of parent prototype, if any
|
||||
DbMapping parentMapping;
|
||||
|
||||
// db field that specifies the prototype of an object
|
||||
String prototypeField;
|
||||
|
||||
// descriptor for key generation method
|
||||
private String idgen;
|
||||
// remember last key generated for this table
|
||||
long lastID;
|
||||
|
||||
// the (village) schema of the database table
|
||||
Schema schema = null;
|
||||
// the (village) keydef of the db table
|
||||
KeyDef keydef = null;
|
||||
|
||||
// timestamp of last modification of the mapping (type.properties)
|
||||
long lastTypeChange;
|
||||
// timestamp of last modification of an object of this type
|
||||
long lastDataChange;
|
||||
|
||||
/**
|
||||
* Create an empty DbMapping
|
||||
*/
|
||||
public DbMapping (Application app) {
|
||||
|
||||
this.app = app;
|
||||
|
||||
prop2db = new HashMap ();
|
||||
db2prop = new HashMap ();
|
||||
|
||||
parent = null;
|
||||
|
||||
idField = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a DbMapping from a type.properties property file
|
||||
*/
|
||||
public DbMapping (Application app, String typename, SystemProperties props) {
|
||||
|
||||
this.app = app;
|
||||
this.typename = typename;
|
||||
|
||||
prop2db = new HashMap ();
|
||||
db2prop = new HashMap ();
|
||||
|
||||
parent = null;
|
||||
|
||||
idField = null;
|
||||
|
||||
this.props = props;
|
||||
update ();
|
||||
|
||||
app.putDbMapping (typename, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the type manager whether we need update() to be called
|
||||
*/
|
||||
public boolean needsUpdate () {
|
||||
return props.lastModified () != lastTypeChange;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the mapping from the Properties. Return true if the properties were changed.
|
||||
* The read is split in two, this method and the rewire method. The reason is that in order
|
||||
* for rewire to work, all other db mappings must have been initialized and registered.
|
||||
*/
|
||||
public synchronized void update () {
|
||||
|
||||
// determin file format version of type.properties file
|
||||
String versionInfo = props.getProperty ("_version");
|
||||
if ("1.2".equals (versionInfo))
|
||||
version = 1;
|
||||
else
|
||||
version = 0;
|
||||
|
||||
table = props.getProperty (version == 0 ? "_tablename" : "_table");
|
||||
idgen = props.getProperty ("_idgen");
|
||||
// see if there is a field which specifies the prototype of objects, if different prototypes
|
||||
// can be stored in this table
|
||||
prototypeField = props.getProperty ("_prototypefield");
|
||||
// see if this prototype extends (inherits from) any other prototype
|
||||
extendsProto = props.getProperty ("_extends");
|
||||
|
||||
sourceName = props.getProperty (version == 0 ? "_datasource" : "_db");
|
||||
if (sourceName != null) {
|
||||
source = app.getDbSource (sourceName);
|
||||
if (source == null) {
|
||||
app.logEvent ("*** Data Source for prototype "+typename+" does not exist: "+sourceName);
|
||||
app.logEvent ("*** accessing or storing a "+typename+" object will cause an error.");
|
||||
}
|
||||
}
|
||||
|
||||
// if id field is null, we assume "ID" as default. We don't set it
|
||||
// however, so that if null we check the parent prototype first.
|
||||
idField = props.getProperty ("_id");
|
||||
|
||||
nameField = props.getProperty ("_name");
|
||||
|
||||
protoField = props.getProperty ("_prototype");
|
||||
|
||||
String parentMapping = props.getProperty ("_parent");
|
||||
if (parentMapping != null) {
|
||||
// comma-separated list of properties to be used as parent
|
||||
StringTokenizer st = new StringTokenizer (parentMapping, ",;");
|
||||
parent = new ParentInfo[st.countTokens()];
|
||||
for (int i=0; i<parent.length; i++)
|
||||
parent[i] = new ParentInfo (st.nextToken().trim());
|
||||
} else
|
||||
parent = null;
|
||||
|
||||
lastTypeChange = props.lastModified ();
|
||||
// set the cached schema & keydef to null so it's rebuilt the next time around
|
||||
schema = null;
|
||||
keydef = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the second part of the property reading process, called after the first part has been
|
||||
* completed on all other mappings in this application
|
||||
*/
|
||||
public synchronized void rewire () {
|
||||
if (extendsProto != null) {
|
||||
parentMapping = app.getDbMapping (extendsProto);
|
||||
}
|
||||
|
||||
// if (table != null && source != null) {
|
||||
// app.logEvent ("set data source for "+typename+" to "+source);
|
||||
HashMap p2d = new HashMap ();
|
||||
HashMap d2p = new HashMap ();
|
||||
|
||||
for (Enumeration e=props.keys(); e.hasMoreElements(); ) {
|
||||
String propName = (String) e.nextElement ();
|
||||
|
||||
try {
|
||||
// ignore internal properties (starting with "_") and sub-options (containing a ".")
|
||||
if (!propName.startsWith ("_") && propName.indexOf (".") < 0) {
|
||||
String dbField = props.getProperty (propName);
|
||||
// check if a relation for this propery already exists. If so, reuse it
|
||||
Relation rel = propertyToRelation (propName);
|
||||
if (rel == null)
|
||||
rel = new Relation (dbField, propName, this, props);
|
||||
rel.update (dbField, props, version);
|
||||
p2d.put (propName, rel);
|
||||
if (rel.columnName != null &&
|
||||
(rel.reftype == Relation.PRIMITIVE ||
|
||||
rel.reftype == Relation.REFERENCE))
|
||||
d2p.put (rel.columnName.toUpperCase (), rel);
|
||||
// app.logEvent ("Mapping "+propName+" -> "+dbField);
|
||||
}
|
||||
} catch (Exception x) {
|
||||
app.logEvent ("Error in type.properties: "+x.getMessage ());
|
||||
}
|
||||
}
|
||||
|
||||
prop2db = p2d;
|
||||
db2prop = d2p;
|
||||
|
||||
if (version == 1) {
|
||||
String subnodeMapping = props.getProperty ("_children");
|
||||
if (subnodeMapping != null) {
|
||||
try {
|
||||
// check if subnode relation already exists. If so, reuse it
|
||||
if (subnodesRel == null)
|
||||
subnodesRel = new Relation (subnodeMapping, "_children", this, props);
|
||||
subnodesRel.update (subnodeMapping, props, version);
|
||||
if (subnodesRel.accessor != null)
|
||||
propertiesRel = subnodesRel;
|
||||
|
||||
} catch (Exception x) {
|
||||
app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
|
||||
// subnodesRel = null;
|
||||
}
|
||||
} else
|
||||
subnodesRel = null;
|
||||
} else {
|
||||
String subnodeMapping = props.getProperty ("_subnodes");
|
||||
if (subnodeMapping != null) {
|
||||
try {
|
||||
// check if subnode relation already exists. If so, reuse it
|
||||
if (subnodesRel == null)
|
||||
subnodesRel = new Relation (subnodeMapping, "_subnodes", this, props);
|
||||
subnodesRel.update (subnodeMapping, props, version);
|
||||
|
||||
} catch (Exception x) {
|
||||
app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
|
||||
// subnodesRel = null;
|
||||
}
|
||||
} else
|
||||
subnodesRel = null;
|
||||
|
||||
String propertiesMapping = props.getProperty ("_properties");
|
||||
if (propertiesMapping != null) {
|
||||
try {
|
||||
// check if property relation already exists. If so, reuse it
|
||||
if (propertiesRel == null)
|
||||
propertiesRel = new Relation (propertiesMapping, "_properties", this, props);
|
||||
propertiesRel.update (propertiesMapping, props, version);
|
||||
|
||||
// take over groupby flag from subnodes, if properties are subnodes
|
||||
if (propertiesRel.subnodesAreProperties && subnodesRel != null) {
|
||||
propertiesRel.groupby = subnodesRel.groupby;
|
||||
propertiesRel.constraints = subnodesRel.constraints;
|
||||
propertiesRel.filter = subnodesRel.filter;
|
||||
}
|
||||
|
||||
} catch (Exception x) {
|
||||
app.logEvent ("Error reading _properties relation for "+typename+": "+x.getMessage ());
|
||||
// propertiesRel = null;
|
||||
}
|
||||
} else
|
||||
propertiesRel = null;
|
||||
}
|
||||
|
||||
if (groupbyMapping != null) {
|
||||
initGroupbyMapping ();
|
||||
groupbyMapping.lastTypeChange = this.lastTypeChange;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a JDBC connection for this DbMapping.
|
||||
*/
|
||||
public Connection getConnection () throws ClassNotFoundException, SQLException {
|
||||
// if source was previously not available, check again
|
||||
if (source == null && sourceName != null)
|
||||
source = app.getDbSource (sourceName);
|
||||
if (sourceName == null && parentMapping != null)
|
||||
return parentMapping.getConnection ();
|
||||
if (source == null) {
|
||||
if (sourceName == null)
|
||||
throw new SQLException ("Tried to get Connection from non-relational embedded data source.");
|
||||
else
|
||||
throw new SQLException ("Datasource is not defined: "+sourceName+".");
|
||||
}
|
||||
return source.getConnection ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DbSource object for this DbMapping. The DbSource describes a JDBC
|
||||
* data source including URL, JDBC driver, username and password.
|
||||
*/
|
||||
public DbSource getDbSource () {
|
||||
if (source == null && parentMapping != null)
|
||||
return parentMapping.getDbSource ();
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL of the data source used for this mapping.
|
||||
*/
|
||||
public String getSourceID () {
|
||||
if (source == null && parentMapping != null)
|
||||
return parentMapping.getSourceID ();
|
||||
return source == null ? "" : source.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table name used for this type mapping.
|
||||
*/
|
||||
public String getTableName () {
|
||||
if (source == null && parentMapping != null)
|
||||
return parentMapping.getTableName ();
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the application this DbMapping belongs to.
|
||||
*/
|
||||
public Application getApplication () {
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this mapping's application
|
||||
*/
|
||||
public String getAppName () {
|
||||
return app.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the object type this DbMapping belongs to.
|
||||
*/
|
||||
public String getTypeName () {
|
||||
return typename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this type's parent type, if any.
|
||||
*/
|
||||
public String getExtends () {
|
||||
return extendsProto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the primary key column name for objects using this mapping.
|
||||
*/
|
||||
public String getIDField () {
|
||||
if (idField == null && parentMapping != null)
|
||||
return parentMapping.getIDField ();
|
||||
return idField == null ? "ID" : idField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the column used for (internal) names of objects of this type.
|
||||
*/
|
||||
public String getNameField () {
|
||||
if (nameField == null && parentMapping != null)
|
||||
return parentMapping.getNameField ();
|
||||
return nameField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the column used for names of prototype.
|
||||
*/
|
||||
public String getPrototypeField () {
|
||||
if (protoField == null && parentMapping != null)
|
||||
return parentMapping.getPrototypeField ();
|
||||
return protoField;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translate a database column name to an object property name according to this mapping.
|
||||
*/
|
||||
public String columnNameToProperty (String columnName) {
|
||||
if (columnName == null)
|
||||
return null;
|
||||
if (table == null && parentMapping != null)
|
||||
return parentMapping.columnNameToProperty (columnName);
|
||||
Relation rel = (Relation) db2prop.get (columnName.toUpperCase ());
|
||||
if (rel != null && (rel.reftype == Relation.PRIMITIVE || rel.reftype == Relation.REFERENCE))
|
||||
return rel.propName;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an object property name to a database column name according to this mapping.
|
||||
*/
|
||||
public String propertyToColumnName (String propName) {
|
||||
if (propName == null)
|
||||
return null;
|
||||
if (table == null && parentMapping != null)
|
||||
return parentMapping.propertyToColumnName (propName);
|
||||
Relation rel = (Relation) prop2db.get (propName);
|
||||
if (rel != null && (rel.reftype == Relation.PRIMITIVE || rel.reftype == Relation.REFERENCE))
|
||||
return rel.columnName;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a database column name to an object property name according to this mapping.
|
||||
*/
|
||||
public Relation columnNameToRelation (String columnName) {
|
||||
if (columnName == null)
|
||||
return null;
|
||||
if (table == null && parentMapping != null)
|
||||
return parentMapping.columnNameToRelation (columnName);
|
||||
return (Relation) db2prop.get (columnName.toUpperCase ());
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an object property name to a database column name according to this mapping.
|
||||
*/
|
||||
public Relation propertyToRelation (String propName) {
|
||||
if (propName == null)
|
||||
return null;
|
||||
if (table == null && parentMapping != null)
|
||||
return parentMapping.propertyToRelation (propName);
|
||||
return (Relation) prop2db.get (propName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This returns the parent info array, which tells an object of this type how to
|
||||
* determine its parent object.
|
||||
*/
|
||||
public synchronized ParentInfo[] getParentInfo () {
|
||||
if (parent == null && parentMapping != null)
|
||||
return parentMapping.getParentInfo ();
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
public DbMapping getSubnodeMapping () {
|
||||
if (subnodesRel != null)
|
||||
return subnodesRel.otherType;
|
||||
if (parentMapping != null)
|
||||
return parentMapping.getSubnodeMapping ();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public DbMapping getExactPropertyMapping (String propname) {
|
||||
Relation rel = getExactPropertyRelation (propname);
|
||||
return rel != null ? rel.otherType : null;
|
||||
}
|
||||
|
||||
public DbMapping getPropertyMapping (String propname) {
|
||||
Relation rel = getPropertyRelation (propname);
|
||||
if (rel != null) {
|
||||
// if this is a virtual node, it doesn't have a dbmapping
|
||||
if (rel.virtual && rel.prototype == null)
|
||||
return null;
|
||||
else
|
||||
return rel.otherType;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If subnodes are grouped by one of their properties, return the
|
||||
* db-mapping with the right relations to create the group-by nodes
|
||||
*/
|
||||
public synchronized DbMapping getGroupbyMapping () {
|
||||
if (subnodesRel == null || subnodesRel.groupby == null)
|
||||
return null;
|
||||
if (groupbyMapping == null) {
|
||||
initGroupbyMapping ();
|
||||
}
|
||||
return groupbyMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the dbmapping used for group-by nodes.
|
||||
*/
|
||||
private void initGroupbyMapping () {
|
||||
// if a prototype is defined for groupby nodes, use that
|
||||
// if mapping doesn' exist or isn't defined, create a new (anonymous internal) one
|
||||
groupbyMapping = new DbMapping (app);
|
||||
// If a mapping is defined, make the internal mapping inherit from
|
||||
// the defined named prototype.
|
||||
if (subnodesRel.groupbyprototype != null)
|
||||
groupbyMapping.parentMapping = app.getDbMapping (subnodesRel.groupbyprototype);
|
||||
groupbyMapping.subnodesRel = subnodesRel.getGroupbySubnodeRelation ();
|
||||
if (propertiesRel != null)
|
||||
groupbyMapping.propertiesRel = propertiesRel.getGroupbyPropertyRelation ();
|
||||
else
|
||||
groupbyMapping.propertiesRel = subnodesRel.getGroupbyPropertyRelation ();
|
||||
groupbyMapping.typename = subnodesRel.groupbyprototype;
|
||||
}
|
||||
|
||||
/* public void setPropertyMapping (DbMapping pm) {
|
||||
properties = pm;
|
||||
} */
|
||||
|
||||
/* public void setSubnodeRelation (Relation rel) {
|
||||
subnodesRel = rel;
|
||||
} */
|
||||
|
||||
public void setPropertyRelation (Relation rel) {
|
||||
propertiesRel = rel;
|
||||
}
|
||||
|
||||
public Relation getSubnodeRelation () {
|
||||
if (subnodesRel == null && parentMapping != null)
|
||||
return parentMapping.getSubnodeRelation ();
|
||||
return subnodesRel;
|
||||
}
|
||||
|
||||
public Relation getPropertyRelation () {
|
||||
if (propertiesRel == null && parentMapping != null)
|
||||
return parentMapping.getPropertyRelation ();
|
||||
return propertiesRel;
|
||||
}
|
||||
|
||||
public Relation getPropertyRelation (String propname) {
|
||||
if (propname == null)
|
||||
return getPropertyRelation ();
|
||||
// first try finding an exact match for the property name
|
||||
Relation rel = getExactPropertyRelation (propname);
|
||||
// if not defined, return the generic property mapping
|
||||
if (rel == null)
|
||||
rel = getPropertyRelation ();
|
||||
return rel;
|
||||
}
|
||||
|
||||
public Relation getExactPropertyRelation (String propname) {
|
||||
if (propname == null)
|
||||
return null;
|
||||
Relation rel = (Relation) prop2db.get (propname.toLowerCase());
|
||||
if (rel == null && parentMapping != null)
|
||||
rel = parentMapping.getExactPropertyRelation (propname);
|
||||
return rel;
|
||||
}
|
||||
|
||||
public String getSubnodeGroupby () {
|
||||
if (subnodesRel == null && parentMapping != null)
|
||||
return parentMapping.getSubnodeGroupby ();
|
||||
return subnodesRel == null ? null : subnodesRel.groupby;
|
||||
}
|
||||
|
||||
public String getIDgen () {
|
||||
if (idgen == null && parentMapping != null)
|
||||
return parentMapping.getIDgen ();
|
||||
return idgen;
|
||||
}
|
||||
|
||||
|
||||
public WrappedNodeManager getWrappedNodeManager () {
|
||||
if (app == null)
|
||||
throw new RuntimeException ("Can't get node manager from internal db mapping");
|
||||
return app.getWrappedNodeManager ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell whether this data mapping maps to a relational database table. This returns true
|
||||
* if a datasource is specified, even if it is not a valid one. Otherwise, objects with invalid
|
||||
* mappings would be stored in the embedded db instead of an error being thrown, which is
|
||||
* not what we want.
|
||||
*/
|
||||
public boolean isRelational () {
|
||||
if (sourceName != null)
|
||||
return true;
|
||||
if (parentMapping != null)
|
||||
return parentMapping.isRelational ();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Village Schema object for this DbMapping.
|
||||
*/
|
||||
public synchronized Schema getSchema () throws ClassNotFoundException, SQLException, DataSetException {
|
||||
if (!isRelational ())
|
||||
throw new SQLException ("Can't get Schema for non-relational data mapping");
|
||||
if (source == null && parentMapping != null)
|
||||
return parentMapping.getSchema ();
|
||||
// Use local variable s to avoid synchronization (schema may be nulled elsewhere)
|
||||
Schema s = schema;
|
||||
if (s != null)
|
||||
return s;
|
||||
schema = new Schema ().schema (getConnection (), table, "*");
|
||||
return schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the column identified by the parameter is a string type. This is
|
||||
* used in query building to determine if a value needs to be quoted.
|
||||
*/
|
||||
public boolean isStringColumn (String columnName) throws SQLException {
|
||||
try {
|
||||
Schema s = getSchema ();
|
||||
if (s == null)
|
||||
throw new SQLException ("Error retrieving relational schema for "+this);
|
||||
Column c = s.getColumn (columnName);
|
||||
if (c == null)
|
||||
throw new SQLException ("Column "+columnName+" not found in "+this);
|
||||
return c.isString () || c.isVarBinary () || c.isLongVarBinary ();
|
||||
} catch (Exception x) {
|
||||
throw new SQLException (x.getMessage ());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Village Schema object for this DbMapping.
|
||||
*/
|
||||
public synchronized KeyDef getKeyDef () {
|
||||
if (!isRelational ())
|
||||
throw new RuntimeException ("Can't get KeyDef for non-relational data mapping");
|
||||
if (source == null && parentMapping != null)
|
||||
return parentMapping.getKeyDef ();
|
||||
// Use local variable s to avoid synchronization (keydef may be nulled elsewhere)
|
||||
KeyDef k = keydef;
|
||||
if (k != null)
|
||||
return k;
|
||||
keydef = new KeyDef ().addAttrib (getIDField ());
|
||||
return keydef;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
if (typename == null)
|
||||
return "[unspecified internal DbMapping]";
|
||||
else
|
||||
return ("["+app.getName()+"."+typename+"]");
|
||||
}
|
||||
|
||||
public long getLastTypeChange () {
|
||||
return lastTypeChange;
|
||||
}
|
||||
|
||||
|
||||
public long getLastDataChange () {
|
||||
return lastDataChange;
|
||||
}
|
||||
|
||||
public void notifyDataChange () {
|
||||
lastDataChange = System.currentTimeMillis ();
|
||||
if (parentMapping != null && source == null)
|
||||
parentMapping.notifyDataChange ();
|
||||
}
|
||||
|
||||
public synchronized long getNewID (long dbmax) {
|
||||
if (parentMapping != null && source == null)
|
||||
return parentMapping.getNewID (dbmax);
|
||||
lastID = Math.max (dbmax+1, lastID+1);
|
||||
return lastID;
|
||||
}
|
||||
|
||||
public HashMap getProp2DB () {
|
||||
if (table == null && parentMapping != null)
|
||||
return parentMapping.getProp2DB ();
|
||||
return prop2db;
|
||||
}
|
||||
|
||||
public Iterator getDBPropertyIterator () {
|
||||
if (table == null && parentMapping != null)
|
||||
return parentMapping.getDBPropertyIterator ();
|
||||
return db2prop.values ().iterator ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the prototype which specifies the storage location
|
||||
* (dbsource + tablename) for this type, or null if it is stored in the embedded
|
||||
* db.
|
||||
*/
|
||||
public String getStorageTypeName () {
|
||||
if (table == null && parentMapping != null)
|
||||
return parentMapping.getStorageTypeName ();
|
||||
return sourceName == null ? null : typename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if another DbMapping is storage-compatible to this one, i.e. it is stored in the same table or
|
||||
* embedded database.
|
||||
*/
|
||||
public boolean isStorageCompatible (DbMapping other) {
|
||||
if (other == null)
|
||||
return !isRelational ();
|
||||
if (isRelational ())
|
||||
return getTableName().equals (other.getTableName ()) &&
|
||||
getDbSource().equals (other.getDbSource ());
|
||||
return !other.isRelational ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this db mapping represents the prototype indicated
|
||||
* by the string argument, either itself or via one of its parent prototypes.
|
||||
*/
|
||||
public boolean isInstanceOf (String other) {
|
||||
if (typename != null && typename.equals (other))
|
||||
return true;
|
||||
DbMapping p = parentMapping;
|
||||
while (p != null) {
|
||||
if (p.typename != null && p.typename.equals (other))
|
||||
return true;
|
||||
p = p.parentMapping;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public DbMapping getParentMapping () {
|
||||
return parentMapping;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
// DbSource.java
|
||||
// Copyright (c) Hannes Wallnöfer 1999-2000
|
||||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.Hashtable;
|
||||
import helma.util.SystemProperties;
|
||||
|
||||
/**
|
||||
* This class describes a releational data source (URL, driver, user and password).
|
||||
*/
|
||||
|
||||
public class DbSource {
|
||||
|
||||
private String name;
|
||||
private SystemProperties props;
|
||||
private static SystemProperties defaultProps = null;
|
||||
protected String url;
|
||||
private String driver;
|
||||
protected String user;
|
||||
private String password;
|
||||
|
||||
private long lastRead = 0l;
|
||||
|
||||
public DbSource (String name, SystemProperties props) throws ClassNotFoundException {
|
||||
this.name = name;
|
||||
this.props = props;
|
||||
init ();
|
||||
}
|
||||
|
||||
public Connection getConnection () throws ClassNotFoundException, SQLException {
|
||||
Transactor tx = (Transactor) Thread.currentThread ();
|
||||
Connection con = tx.getConnection (this);
|
||||
boolean fileUpdated = props.lastModified () > lastRead;
|
||||
if (!fileUpdated && defaultProps != null)
|
||||
fileUpdated = defaultProps.lastModified () > lastRead;
|
||||
if (con == null || con.isClosed () || fileUpdated) {
|
||||
init ();
|
||||
Class.forName (driver);
|
||||
con = DriverManager.getConnection (url, user, password);
|
||||
// If we wanted to use SQL transactions, we'd set autoCommit to
|
||||
// false here and make commit/rollback invocations in Transactor methods;
|
||||
// System.err.println ("Created new Connection to "+url);
|
||||
tx.registerConnection (this, con);
|
||||
//////////////////////////////////////////////
|
||||
/* DatabaseMetaData meta = con.getMetaData ();
|
||||
ResultSet tables = meta.getCatalogs ();
|
||||
while (tables.next())
|
||||
System.err.println ("********* TABLE: "+ tables.getObject (1));
|
||||
ResultSet types = meta.getTypeInfo ();
|
||||
while (types.next())
|
||||
System.err.println ("******* TYPE: "+types.getObject(1) +" - "+types.getObject(2)+" - "+types.getObject(6));
|
||||
*/
|
||||
}
|
||||
return con;
|
||||
}
|
||||
|
||||
private void init () throws ClassNotFoundException {
|
||||
lastRead = defaultProps == null ? props.lastModified () : Math.max (props.lastModified (), defaultProps.lastModified ());
|
||||
url = props.getProperty (name+".url");
|
||||
driver = props.getProperty (name+".driver");
|
||||
Class.forName (driver);
|
||||
user = props.getProperty (name+".user");
|
||||
password = props.getProperty (name+".password");
|
||||
}
|
||||
|
||||
public String getDriverName () {
|
||||
return driver;
|
||||
}
|
||||
|
||||
public String getName () {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static void setDefaultProps (SystemProperties props) {
|
||||
defaultProps = props;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -24,15 +24,13 @@ public class DbWrapper {
|
|||
volatile long txncount=0;
|
||||
|
||||
private File dbBaseDir;
|
||||
private NodeManager nmgr;
|
||||
private String dbHome;
|
||||
|
||||
public DbWrapper (String dbHome, String dbFilename, NodeManager nmgr, boolean useTx) throws DbException {
|
||||
|
||||
this.dbHome = dbHome;
|
||||
this.nmgr = nmgr;
|
||||
public DbWrapper (String dbHome, String dbFilename, boolean useTx) throws DbException {
|
||||
|
||||
try {
|
||||
|
||||
this.dbHome = dbHome;
|
||||
dbBaseDir = new File (dbHome);
|
||||
if (!dbBaseDir.exists())
|
||||
dbBaseDir.mkdirs();
|
||||
|
@ -73,12 +71,12 @@ public class DbWrapper {
|
|||
loaded = true;
|
||||
|
||||
} catch (NoClassDefFoundError noclass) {
|
||||
nmgr.app.logEvent ("Warning: Using internal file based db as fallback.");
|
||||
nmgr.app.logEvent ("Reason: "+noclass);
|
||||
Server.getLogger().log ("Warning: Using internal file based db as fallback.");
|
||||
Server.getLogger().log ("Reason: "+noclass);
|
||||
loaded = false;
|
||||
} catch (UnsatisfiedLinkError nolib) {
|
||||
nmgr.app.logEvent ("Warning: Using internal file based db as fallback.");
|
||||
nmgr.app.logEvent ("Reason: "+nolib);
|
||||
Server.getLogger().log ("Warning: Using internal file based db as fallback.");
|
||||
Server.getLogger().log ("Reason: "+nolib);
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
|
@ -91,7 +89,7 @@ public class DbWrapper {
|
|||
// closing the dbenv leads to segfault when app is restarted
|
||||
// dbenv.close (0);
|
||||
// dbenv.remove (dbHome, Db.DB_FORCE);
|
||||
nmgr.app.logEvent ("Closed Berkeley DB");
|
||||
Server.getLogger ().log ("Closed Berkeley DB");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +126,7 @@ public class DbWrapper {
|
|||
dbenv.txn_checkpoint (0, 0, 0); // for berkeley 3.0, remove third 0 parameter
|
||||
txncount = 0;
|
||||
lastCheckpoint = now;
|
||||
nmgr.app.logEvent ("Spent "+(System.currentTimeMillis()-now)+" in checkpoint");
|
||||
Server.getLogger().log ("Spent "+(System.currentTimeMillis()-now)+" in checkpoint");
|
||||
}
|
||||
|
||||
public IDGenerator getIDGenerator (DbTxn txn, String kstr) throws Exception {
|
||||
|
@ -222,7 +220,7 @@ public class DbWrapper {
|
|||
value.set_size (vbuf.length);
|
||||
|
||||
db.put (txn, key, value, 0);
|
||||
// nmgr.app.logEvent ("saved "+obj+", size = "+vbuf.length);
|
||||
// IServer.getLogger().log ("saved "+obj+", size = "+vbuf.length);
|
||||
}
|
||||
|
||||
private void deleteFromDB (DbTxn txn, String kstr) throws Exception {
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
package helma.objectmodel.db;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A subclass of Vector that implements the Externalizable interface in order
|
||||
* to be able to control how it is serialized and deserialized.
|
||||
*/
|
||||
|
||||
public class ExternalizableVector extends ArrayList implements Externalizable {
|
||||
public class ExternalizableVector extends Vector implements Externalizable {
|
||||
|
||||
static final long serialVersionUID = 2316243615310540423L;
|
||||
|
||||
|
@ -19,7 +19,7 @@ public class ExternalizableVector extends ArrayList implements Externalizable {
|
|||
try {
|
||||
int size = in.readInt ();
|
||||
for (int i=0; i<size; i++)
|
||||
add (in.readObject ());
|
||||
addElement (in.readObject ());
|
||||
} catch (ClassNotFoundException x) {
|
||||
throw new IOException (x.toString ());
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class ExternalizableVector extends ArrayList implements Externalizable {
|
|||
int size = size ();
|
||||
out.writeInt (size);
|
||||
for (int i=0; i<size; i++)
|
||||
out.writeObject (get (i));
|
||||
out.writeObject (elementAt (i));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
// Copyright (c) Hannes Wallnöfer 1999-2000
|
||||
|
||||
|
||||
package helma.main;
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import helma.objectmodel.IServer;
|
||||
import helma.util.*;
|
||||
import java.net.*;
|
||||
import java.rmi.server.*;
|
||||
|
@ -27,7 +28,7 @@ public class HopSocketFactory extends RMISocketFactory {
|
|||
try {
|
||||
filter.addAddress (address);
|
||||
} catch (IOException x) {
|
||||
Server.getLogger().log ("Could not add "+address+" to Socket Filter: invalid address.");
|
||||
IServer.getLogger().log ("Could not add "+address+" to Socket Filter: invalid address.");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// Key.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
|
||||
/**
|
||||
* This is the interface for the internal representation of an object key.
|
||||
*
|
||||
*/
|
||||
public interface Key {
|
||||
|
||||
|
||||
public Key getParentKey ();
|
||||
|
||||
public String getID ();
|
||||
|
||||
public String getStorageName ();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,119 +0,0 @@
|
|||
// NodeHandle.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* This class is a handle or reference to a Node. This is to abstract from different
|
||||
* methods of reference: Transient Nodes are referred to directly, while persistent
|
||||
* nodes are referred to via key/node manager.
|
||||
*
|
||||
* A handle is used to refer to a node in a safe way over a longer period.
|
||||
* While a direct reference may point to a node that has been evicted from the cache
|
||||
* and reinstanciated since being set, NodeHandle will always return an up-to-date
|
||||
* instance of its node.
|
||||
*/
|
||||
|
||||
public final class NodeHandle implements INodeState, Serializable {
|
||||
|
||||
// direct reference to the node
|
||||
private Node node;
|
||||
|
||||
// the node's key
|
||||
private Key key;
|
||||
|
||||
// cached DbMapping
|
||||
private transient DbMapping dbmap;
|
||||
|
||||
static final long serialVersionUID = 3067763116576910931L;
|
||||
|
||||
/**
|
||||
* Builds a handle for a node
|
||||
*/
|
||||
public NodeHandle (Node node) {
|
||||
int state = node.getState ();
|
||||
if (state == TRANSIENT) {
|
||||
this.node = node;
|
||||
key = null;
|
||||
} else {
|
||||
this.node = null;
|
||||
key = node.getKey ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a handle given a node's retrieval information. At the time this is called,
|
||||
* the node is ususally not yet created. It will be fetched on demand when accessed by
|
||||
* application code.
|
||||
*/
|
||||
public NodeHandle (Key key) {
|
||||
this.node = null;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the node described by this node handle
|
||||
*/
|
||||
public Node getNode (WrappedNodeManager nodemgr) {
|
||||
if (node != null)
|
||||
return node;
|
||||
return nodemgr.getNode (key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the key for the node described by this handle. This may only be called on persistent Nodes.
|
||||
*/
|
||||
public Key getKey () {
|
||||
if (key == null)
|
||||
throw new RuntimeException ("getKey called on transient Node");
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID for the node described by this handle. This may only be called on persistent Nodes.
|
||||
*/
|
||||
public String getID () {
|
||||
if (key == null)
|
||||
return node.getID ();
|
||||
return key.getID ();
|
||||
}
|
||||
|
||||
private Object getObject () {
|
||||
if (node != null)
|
||||
return node;
|
||||
else
|
||||
return key;
|
||||
}
|
||||
|
||||
public boolean equals (Object other) {
|
||||
try {
|
||||
return getObject ().equals (((NodeHandle) other).getObject ());
|
||||
} catch (Exception x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is to notify the handle that the underlying node is becoming
|
||||
* persistent and we have to refer to it via the key from now on.
|
||||
*/
|
||||
protected void becomePersistent () {
|
||||
if (node != null) {
|
||||
key = node.getKey ();
|
||||
node = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString () {
|
||||
if (node != null)
|
||||
return "NodeHandle[transient:"+node+"]";
|
||||
else
|
||||
return "NodeHandle["+key+"]";
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,41 +0,0 @@
|
|||
// ParentInfo.java
|
||||
// Copyright (c) Hannes Wallnöfer 1999-2000
|
||||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
|
||||
/**
|
||||
* This class describes a parent relation between releational nodes.
|
||||
*/
|
||||
|
||||
public class ParentInfo {
|
||||
|
||||
public final String propname;
|
||||
public final String virtualname;
|
||||
public final boolean named;
|
||||
public final boolean isroot;
|
||||
|
||||
|
||||
public ParentInfo (String desc) {
|
||||
int n = desc.indexOf ("[named]");
|
||||
named = n > -1;
|
||||
String d = named ? desc.substring (0, n) : desc;
|
||||
|
||||
int dot = d.indexOf (".");
|
||||
if (dot > -1) {
|
||||
propname = d.substring (0, dot).trim();
|
||||
virtualname = d.substring (dot+1).trim();
|
||||
} else {
|
||||
propname = d.trim();
|
||||
virtualname = null;
|
||||
}
|
||||
|
||||
isroot = "root".equals (propname);
|
||||
// System.err.println ("created "+this);
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return "ParentInfo["+propname+","+virtualname+","+named+"]";
|
||||
}
|
||||
|
||||
}
|
|
@ -23,8 +23,8 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
protected boolean bvalue;
|
||||
protected long lvalue;
|
||||
protected double dvalue;
|
||||
// protected String nvalueID;
|
||||
protected NodeHandle nhandle;
|
||||
protected String nvalueID;
|
||||
private transient DbMapping dbm;
|
||||
protected Object jvalue;
|
||||
|
||||
protected int type;
|
||||
|
@ -40,11 +40,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
type = in.readInt ();
|
||||
switch (type) {
|
||||
case STRING:
|
||||
// try to convert from old format
|
||||
if (node.version < 7)
|
||||
svalue = in.readUTF ();
|
||||
else
|
||||
svalue = (String) in.readObject ();
|
||||
svalue = in.readUTF ();
|
||||
break;
|
||||
case BOOLEAN:
|
||||
bvalue = in.readBoolean ();
|
||||
|
@ -57,11 +53,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
dvalue = in.readDouble ();
|
||||
break;
|
||||
case NODE:
|
||||
// try to convert from old format
|
||||
if (node.version > 4)
|
||||
nhandle = (NodeHandle) in.readObject ();
|
||||
else
|
||||
nhandle = new NodeHandle (new DbKey (null, in.readUTF ()));
|
||||
nvalueID = in.readUTF ();
|
||||
break;
|
||||
case JAVAOBJECT:
|
||||
jvalue = in.readObject ();
|
||||
|
@ -73,12 +65,15 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
}
|
||||
|
||||
private void writeObject (ObjectOutputStream out) throws IOException {
|
||||
// don't even start if this is a non-serializable Java object
|
||||
if (type == JAVAOBJECT && jvalue != null && !(jvalue instanceof Serializable))
|
||||
return;
|
||||
out.writeUTF (propname);
|
||||
out.writeObject (node);
|
||||
out.writeInt (type);
|
||||
switch (type) {
|
||||
case STRING:
|
||||
out.writeObject (svalue);
|
||||
out.writeUTF (svalue);
|
||||
break;
|
||||
case BOOLEAN:
|
||||
out.writeBoolean (bvalue);
|
||||
|
@ -91,13 +86,10 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
out.writeDouble (dvalue);
|
||||
break;
|
||||
case NODE:
|
||||
out.writeObject (nhandle);
|
||||
out.writeUTF (nvalueID);
|
||||
break;
|
||||
case JAVAOBJECT:
|
||||
if (jvalue != null && !(jvalue instanceof Serializable))
|
||||
out.writeObject (null);
|
||||
else
|
||||
out.writeObject (jvalue);
|
||||
out.writeObject (jvalue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +109,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
public Property (String propname, Node node, Node value) {
|
||||
this (propname, node);
|
||||
type = NODE;
|
||||
nhandle = value == null ? null : value.getHandle ();
|
||||
nvalueID = value == null ? null : value.getID ();
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
|
@ -148,11 +140,41 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
public void setStringValue (String value) {
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
// IServer.getLogger().log ("setting string value of property "+propname + " to "+value);
|
||||
// mark property as dirty
|
||||
dirty = true;
|
||||
// if this is not a string property, try to parse a value out of it
|
||||
if (type == DATE) {
|
||||
SimpleDateFormat dateformat = new SimpleDateFormat ();
|
||||
try {
|
||||
dateformat.setLenient (true);
|
||||
Date date = dateformat.parse (value);
|
||||
this.lvalue = date.getTime ();
|
||||
return;
|
||||
} catch (ParseException nodate) {
|
||||
IServer.getLogger().log ("Couldn't parse date: was expecting something like "+dateformat.format (new Date()));
|
||||
// store as plain string
|
||||
}
|
||||
}
|
||||
if (type == BOOLEAN) {
|
||||
if ("true".equalsIgnoreCase (value))
|
||||
this.bvalue = true;
|
||||
else if ("false".equalsIgnoreCase (value))
|
||||
this.bvalue = false;
|
||||
return;
|
||||
}
|
||||
if (type == INTEGER) {
|
||||
this.lvalue = Long.parseLong (value);
|
||||
return;
|
||||
}
|
||||
if (type == FLOAT) {
|
||||
this.dvalue = new Double (value).doubleValue ();
|
||||
return;
|
||||
}
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = STRING;
|
||||
this.svalue = value;
|
||||
dirty = true;
|
||||
type = STRING;
|
||||
}
|
||||
|
||||
|
||||
|
@ -197,16 +219,39 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
}
|
||||
|
||||
public void setNodeValue (Node value) {
|
||||
// value.checkWriteLock ();
|
||||
value.checkWriteLock ();
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
|
||||
// registerNode (value);
|
||||
registerNode (value);
|
||||
type = NODE;
|
||||
|
||||
nhandle = value.getHandle ();
|
||||
if (node.dbmap != null) {
|
||||
Relation rel = node.dbmap.getPropertyRelation (propname);
|
||||
if (rel != null && rel.other != null) {
|
||||
DbMapping vmap = value.getDbMapping ();
|
||||
// check if actual type matches expected type
|
||||
if (rel.other != vmap && (!rel.virtual || rel.prototype != null)) {
|
||||
throw new RuntimeException ("Can't assign property: expected prototype "+rel.other+", got "+vmap);
|
||||
}
|
||||
// check if this is a forward relation, i.e. if we point to a field in the value object
|
||||
// if so, we may use something else than the object's id to refer to it.
|
||||
if (!rel.virtual && rel.direction == Relation.FORWARD) {
|
||||
if (rel.usesPrimaryKey ()) {
|
||||
this.nvalueID = value.getID ();
|
||||
} else try {
|
||||
this.nvalueID = value.getString (vmap.columnNameToProperty (rel.getRemoteField()).propname, false);
|
||||
} catch (Exception x) {
|
||||
throw new RuntimeException ("Can't set "+propname+" to "+value+": error retrieving target property");
|
||||
}
|
||||
this.dbm = null;
|
||||
dirty = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.nvalueID = value == null ? null : value.getID ();
|
||||
this.dbm = value == null ? null : value.getDbMapping ();
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
|
@ -223,39 +268,48 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
* If this was the "main" property for the node, also remove all other references.
|
||||
*/
|
||||
protected void unregisterNode () {
|
||||
Node nvalue = null;
|
||||
if (nhandle != null)
|
||||
nvalue = nhandle.getNode (node.nmgr);
|
||||
|
||||
DbMapping nvmap = null;
|
||||
Relation nvrel = null;
|
||||
if (node.dbmap != null) {
|
||||
nvmap = node.dbmap.getPropertyMapping (propname);
|
||||
nvrel = node.dbmap.getPropertyRelation (propname);
|
||||
}
|
||||
|
||||
if (nvalue == null)
|
||||
return;
|
||||
|
||||
nvalue.checkWriteLock ();
|
||||
// check if the property node is also a subnode
|
||||
// BUG: this doesn't work because properties for subnode/properties are never stored and therefore
|
||||
// never reused.
|
||||
if (nvrel != null && nvrel.subnodesAreProperties) {
|
||||
node.removeNode (nvalue);
|
||||
}
|
||||
// only need to call unregisterPropLink if the value node is not stored in a relational db
|
||||
// also, getParent is heuristical/implicit for relational nodes, so we don't do deepRemoveNode
|
||||
// based on that for relational nodes.
|
||||
if (nvmap == null || !nvmap.isRelational()) {
|
||||
if (!nvalue.isAnonymous() && propname.equals (nvalue.getName()) && this.node == nvalue.getParent()) {
|
||||
// this is the "main" property of a named node, so handle this as a cascading delete.
|
||||
nvalue.deepRemoveNode ();
|
||||
if (nvalueID != null) {
|
||||
DbMapping nvmap = null;
|
||||
Relation nvrel = null;
|
||||
if (node.dbmap != null) {
|
||||
nvmap = node.dbmap.getPropertyMapping (propname);
|
||||
nvrel = node.dbmap.getPropertyRelation (propname);
|
||||
}
|
||||
Node nvalue = node.nmgr.getNode (nvalueID, nvmap);
|
||||
if (nvalue == null)
|
||||
return;
|
||||
nvalue.checkWriteLock ();
|
||||
// check if the property node is also a subnode
|
||||
// BUG: this doesn't work because properties for subnode/properties are never stored and therefore
|
||||
// never reused.
|
||||
if (nvrel != null && nvrel.subnodesAreProperties) {
|
||||
node.removeNode (nvalue);
|
||||
}
|
||||
// only need to call unregisterPropLink if the value node is not stored in a relational db
|
||||
// also, getParent is heuristical/implicit for relational nodes, so we don't do deepRemoveNode
|
||||
// based on that for relational nodes.
|
||||
if (nvmap == null || !nvmap.isRelational()) {
|
||||
if (!nvalue.isAnonymous() && propname.equals (nvalue.getName()) && this.node == nvalue.getParent()) {
|
||||
// this is the "main" property of a named node, so handle this as a cascading delete.
|
||||
nvalue.deepRemoveNode ();
|
||||
} else {
|
||||
nvalue.unregisterPropLink (this.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tell the value node that it is being used as a property value.
|
||||
*/
|
||||
protected void registerNode (Node n) {
|
||||
// only need to call registerPropLink if the value node is not stored in a relational db
|
||||
if (n != null && (n.dbmap == null || !n.dbmap.isRelational())) {
|
||||
n.registerPropLink (this.node);
|
||||
}
|
||||
}
|
||||
|
||||
public String getStringValue () {
|
||||
switch (type) {
|
||||
case STRING:
|
||||
|
@ -270,9 +324,9 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
case FLOAT:
|
||||
return Double.toString (dvalue);
|
||||
case NODE:
|
||||
return nhandle.getID ();
|
||||
return nvalueID;
|
||||
case JAVAOBJECT:
|
||||
return jvalue == null ? null : jvalue.toString ();
|
||||
return jvalue.toString ();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -308,9 +362,45 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
|
||||
public INode getNodeValue () {
|
||||
|
||||
if (nhandle != null) {
|
||||
Node n = nhandle.getNode (node.nmgr);
|
||||
if (n != null) return n;
|
||||
if (type == NODE && nvalueID != null) {
|
||||
Relation rel = null;
|
||||
if (dbm == null && node.dbmap != null) {
|
||||
// try to get DbMap for property, if it isn't known yet
|
||||
rel = node.dbmap.getPropertyRelation (propname);
|
||||
// figure out db mapping from relation
|
||||
if (rel != null) {
|
||||
// is the property a virtual node containing objects from relational db?
|
||||
if (rel.virtual && rel.other.isRelational ())
|
||||
return node.nmgr.getNode (node, propname, rel);
|
||||
else if (!rel.virtual && rel.direction == Relation.FORWARD)
|
||||
return node.nmgr.getNode (node, nvalueID, rel);
|
||||
// avoid setting dbm for virtual and groupby relations, except for
|
||||
// [mountpoint] kind of prototyped virtual nodes
|
||||
else if ((!rel.virtual || rel.prototype != null) && rel.groupby == null)
|
||||
dbm = rel.other;
|
||||
}
|
||||
}
|
||||
|
||||
// we have what we need, now get the node from the node manager
|
||||
Node retval = node.nmgr.getNode (nvalueID, dbm);
|
||||
if (retval != null && retval.parentID == null && !"root".equalsIgnoreCase (retval.getPrototype ())) {
|
||||
retval.setParent (node);
|
||||
retval.setName (propname);
|
||||
retval.anonymous = false;
|
||||
}
|
||||
|
||||
if (retval != null && retval.getDbMapping () == null && rel != null && rel.virtual && rel.prototype == null) {
|
||||
// a virtual node whose child nodes are not relational -
|
||||
// set up dbmapping that describes subnodes and properties
|
||||
DbMapping _dbm = new DbMapping ();
|
||||
_dbm.setSubnodeMapping (rel.other);
|
||||
_dbm.setPropertyMapping (rel.other);
|
||||
_dbm.setSubnodeRelation (rel.getVirtualSubnodeRelation());
|
||||
_dbm.setPropertyRelation (rel.getVirtualPropertyRelation());
|
||||
retval.setDbMapping (_dbm);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -321,9 +411,91 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public String getEditor () {
|
||||
switch (type) {
|
||||
case STRING:
|
||||
return "password".equalsIgnoreCase (propname) ?
|
||||
"<input type=password name=\""+propname+"\" value='"+ svalue.replace ('\'', '"') +"'>" :
|
||||
"<input type=text name=\""+propname+"\" value='"+ svalue.replace ('\'', '"') +"'>" ;
|
||||
case BOOLEAN:
|
||||
return "<select name=\""+propname+"\"><option selected value="+bvalue+">"+bvalue+"</option><option value="+!bvalue+">"+!bvalue+"</option></select>";
|
||||
case INTEGER:
|
||||
return "<input type=text name=\""+propname+"\" value=\""+lvalue+"\">" ;
|
||||
case FLOAT:
|
||||
return "<input type=text name=\""+propname+"\" value=\""+dvalue+"\">" ;
|
||||
case DATE:
|
||||
SimpleDateFormat format = new SimpleDateFormat ("dd.MM.yy hh:mm");
|
||||
String date = format.format (new Date (lvalue));
|
||||
return "<input type=text name=\""+propname+"\" value=\""+date+"\">";
|
||||
case NODE:
|
||||
DbMapping nvmap = null;
|
||||
if (node.dbmap != null)
|
||||
nvmap = node.dbmap.getPropertyMapping (propname);
|
||||
return "<input type=text size=25 name="+propname+" value='"+ node.nmgr.getNode (nvalueID, nvmap).getName () +"'>";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String escape (String s) {
|
||||
char c[] = new char[s.length()];
|
||||
s.getChars (0, c.length, c, 0);
|
||||
StringBuffer b = new StringBuffer ();
|
||||
int copyfrom = 0;
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
switch (c[i]) {
|
||||
case '\\':
|
||||
case '"':
|
||||
if (i-copyfrom > 0)
|
||||
b.append (c, copyfrom, i-copyfrom);
|
||||
b.append ('\\');
|
||||
b.append (c[i]);
|
||||
copyfrom = i+1;
|
||||
}
|
||||
}
|
||||
if (c.length-copyfrom > 0)
|
||||
b.append (c, copyfrom, c.length-copyfrom);
|
||||
return b.toString ();
|
||||
}
|
||||
|
||||
public int getType () {
|
||||
return type;
|
||||
|
||||
}
|
||||
|
||||
public String getTypeString () {
|
||||
switch (type) {
|
||||
case STRING:
|
||||
return "string";
|
||||
case BOOLEAN:
|
||||
return "boolean";
|
||||
case DATE:
|
||||
return "date";
|
||||
case INTEGER:
|
||||
return "integer";
|
||||
case FLOAT:
|
||||
return "float";
|
||||
case NODE:
|
||||
return "node";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
public Object clone () {
|
||||
try {
|
||||
Property c = (Property) super.clone();
|
||||
c.propname = this.propname;
|
||||
c.svalue = this.svalue;
|
||||
c.bvalue = this.bvalue;
|
||||
c.lvalue = this.lvalue;
|
||||
c.dvalue = this.dvalue;
|
||||
c.nvalueID = this.nvalueID;
|
||||
c.type = this.type;
|
||||
return c;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// this shouldn't happen, since we are Cloneable
|
||||
throw new InternalError ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,773 +0,0 @@
|
|||
// Relation.java
|
||||
// Copyright (c) Hannes Wallnöfer 1997-2000
|
||||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import helma.framework.core.Application;
|
||||
import java.util.Properties;
|
||||
import java.util.Vector;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* This describes how a property of a persistent Object is stored in a
|
||||
* relational database table. This can be either a scalar property (string, date, number etc.)
|
||||
* or a reference to one or more other objects.
|
||||
*/
|
||||
public class Relation {
|
||||
|
||||
// these constants define different type of property-to-db-mappings
|
||||
|
||||
// there is an error in the description of this relation
|
||||
public final static int INVALID = -1;
|
||||
// a mapping of a non-object, scalar type
|
||||
public final static int PRIMITIVE = 0;
|
||||
// a 1-to-1 relation, i.e. a field in the table is a foreign key to another object
|
||||
public final static int REFERENCE = 1;
|
||||
// a 1-to-many relation, a field in another table points to objects of this type
|
||||
public final static int COLLECTION = 2;
|
||||
// direct mapping is a very powerful feature: objects of some types can be directly accessed
|
||||
// by one of their properties/db fields.
|
||||
// public final static int DIRECT = 3;
|
||||
|
||||
// the DbMapping of the type we come from
|
||||
DbMapping ownType;
|
||||
// the DbMapping of the prototype we link to, unless this is a "primitive" (non-object) relation
|
||||
DbMapping otherType;
|
||||
|
||||
// if this relation defines a virtual node, we need to provide a DbMapping for these virtual nodes
|
||||
DbMapping virtualMapping;
|
||||
|
||||
Relation virtualRelation;
|
||||
Relation groupRelation;
|
||||
|
||||
String propName;
|
||||
String columnName;
|
||||
|
||||
int reftype;
|
||||
|
||||
Constraint[] constraints;
|
||||
|
||||
boolean virtual;
|
||||
boolean readonly;
|
||||
boolean aggressiveLoading;
|
||||
boolean aggressiveCaching;
|
||||
boolean subnodesAreProperties;
|
||||
String accessor; // db column used to access objects through this relation
|
||||
String order;
|
||||
String groupbyorder;
|
||||
String groupby;
|
||||
String prototype;
|
||||
String groupbyprototype;
|
||||
String filter;
|
||||
int maxSize = 0;
|
||||
|
||||
// Relation subnoderelation = null; // additional relation used to filter subnodes for virtual nodes
|
||||
|
||||
/**
|
||||
* This constructor makes a copy of an existing relation. Not all fields are copied, just those
|
||||
* which are needed in groupby- and virtual nodes defined by this relation.
|
||||
*/
|
||||
public Relation (Relation rel) {
|
||||
this.ownType = rel.ownType;
|
||||
this.otherType = rel.otherType;
|
||||
this.propName = rel.propName;
|
||||
this.columnName = rel.columnName;
|
||||
this.reftype = rel.reftype;
|
||||
this.constraints = rel.constraints;
|
||||
this.accessor = rel.accessor;
|
||||
this.maxSize = rel.maxSize;
|
||||
this.subnodesAreProperties = rel.subnodesAreProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a relation entry from a line in a properties file.
|
||||
*/
|
||||
public Relation (String desc, String propName, DbMapping ownType, Properties props) {
|
||||
this.ownType = ownType;
|
||||
this.propName = propName;
|
||||
otherType = null;
|
||||
}
|
||||
|
||||
public void update (String desc, Properties props, int version) {
|
||||
if (version == 0)
|
||||
update_v0 (desc, props);
|
||||
else if (version == 1)
|
||||
update_v1 (desc, props);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parse methods for file format v0
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void update_v0 (String desc, Properties props) {
|
||||
boolean mountpoint = false;
|
||||
Vector cnst = null;
|
||||
|
||||
if (desc == null || "".equals (desc.trim ())) {
|
||||
if (propName != null) {
|
||||
reftype = PRIMITIVE;
|
||||
columnName = propName;
|
||||
} else {
|
||||
reftype = INVALID;
|
||||
columnName = propName;
|
||||
}
|
||||
} else {
|
||||
desc = desc.trim ();
|
||||
String descLower = desc.toLowerCase ();
|
||||
if (descLower.startsWith ("[virtual]")) {
|
||||
desc = desc.substring (9).trim ();
|
||||
virtual = true;
|
||||
} else if (descLower.startsWith ("[collection]")) {
|
||||
desc = desc.substring (12).trim ();
|
||||
virtual = true;
|
||||
} else if (descLower.startsWith ("[mountpoint]")) {
|
||||
desc = desc.substring (12).trim ();
|
||||
virtual = true;
|
||||
mountpoint = true;
|
||||
} else {
|
||||
virtual = false;
|
||||
}
|
||||
if (descLower.startsWith ("[readonly]")) {
|
||||
desc = desc.substring (10).trim ();
|
||||
readonly = true;
|
||||
} else {
|
||||
readonly = false;
|
||||
}
|
||||
}
|
||||
|
||||
// parse the basic properties of this mapping
|
||||
parseMapping_v0 (desc, mountpoint);
|
||||
|
||||
// the following options only apply to object relations
|
||||
if (reftype != PRIMITIVE && reftype != INVALID) {
|
||||
|
||||
cnst = new Vector ();
|
||||
|
||||
Constraint c = parseConstraint_v0 (desc);
|
||||
|
||||
if (c != null)
|
||||
cnst.add (c);
|
||||
|
||||
parseOptions_v0 (cnst, props);
|
||||
|
||||
constraints = new Constraint[cnst.size()];
|
||||
cnst.copyInto (constraints);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a line describing a mapping of a property field. If the mapping is a
|
||||
* object reference of a collection of objects, put any constraints in the Vector.
|
||||
*/
|
||||
protected void parseMapping_v0 (String desc, boolean mountpoint) {
|
||||
|
||||
Application app = ownType.getApplication ();
|
||||
|
||||
if (desc.indexOf ("<") > -1) {
|
||||
reftype = COLLECTION;
|
||||
int lt = desc.indexOf ("<");
|
||||
int dot = desc.indexOf (".");
|
||||
String other = dot < 0 ? desc.substring (lt+1).trim () : desc.substring (lt+1, dot).trim ();
|
||||
otherType = app.getDbMapping (other);
|
||||
if (otherType == null)
|
||||
throw new RuntimeException ("DbMapping for "+other+" not found from "+ownType.typename);
|
||||
columnName = null;
|
||||
if (mountpoint)
|
||||
prototype = other;
|
||||
} else if (desc.indexOf (">") > -1) {
|
||||
reftype = REFERENCE;
|
||||
int bt = desc.indexOf (">");
|
||||
int dot = desc.indexOf (".");
|
||||
String other = dot > -1 ? desc.substring (bt+1, dot).trim () : desc.substring (bt+1).trim ();
|
||||
otherType = app.getDbMapping (other);
|
||||
if (otherType == null)
|
||||
throw new RuntimeException ("DbMapping for "+other+" not found from "+ownType.typename);
|
||||
columnName = desc.substring (0, bt).trim ();
|
||||
if (mountpoint)
|
||||
prototype = other;
|
||||
} else if (desc.indexOf (".") > -1) {
|
||||
reftype = COLLECTION;
|
||||
int dot = desc.indexOf (".");
|
||||
String other = desc.substring (0, dot).trim ();
|
||||
otherType = app.getDbMapping (other);
|
||||
if (otherType == null)
|
||||
throw new RuntimeException ("DbMapping for "+other+" not found from "+ownType.typename);
|
||||
columnName = null;
|
||||
// set accessor
|
||||
accessor = desc.substring (dot+1).trim ();
|
||||
if (mountpoint)
|
||||
prototype = other;
|
||||
} else {
|
||||
if (virtual) {
|
||||
reftype = COLLECTION;
|
||||
otherType = app.getDbMapping (desc);
|
||||
if (otherType == null)
|
||||
throw new RuntimeException ("DbMapping for "+desc+" not found from "+ownType.typename);
|
||||
if (mountpoint)
|
||||
prototype = desc;
|
||||
} else {
|
||||
reftype = PRIMITIVE;
|
||||
columnName = desc.trim ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a line describing a mapping of a property field. If the mapping is a
|
||||
* object reference of a collection of objects, put any constraints in the Vector.
|
||||
*/
|
||||
protected Constraint parseConstraint_v0 (String desc) {
|
||||
if (desc.indexOf ("<") > -1) {
|
||||
int lt = desc.indexOf ("<");
|
||||
int dot = desc.indexOf (".");
|
||||
String remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
|
||||
String localField = lt <= 0 ? null : desc.substring (0, lt).trim ();
|
||||
return new Constraint (localField, otherType.getTableName (), remoteField, false);
|
||||
} else if (desc.indexOf (">") > -1) {
|
||||
int bt = desc.indexOf (">");
|
||||
int dot = desc.indexOf (".");
|
||||
String localField = desc.substring (0, bt).trim ();
|
||||
String remoteField = dot < 0 ? null : desc.substring (dot+1).trim ();
|
||||
return new Constraint (localField, otherType.getTableName (), remoteField, false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void parseOptions_v0 (Vector cnst, Properties props) {
|
||||
String loading = props.getProperty (propName+".loadmode");
|
||||
aggressiveLoading = loading != null && "aggressive".equalsIgnoreCase (loading.trim());
|
||||
String caching = props.getProperty (propName+".cachemode");
|
||||
aggressiveCaching = caching != null && "aggressive".equalsIgnoreCase (caching.trim());
|
||||
// get order property
|
||||
order = props.getProperty (propName+".order");
|
||||
if (order != null && order.trim().length() == 0)
|
||||
order = null;
|
||||
// get additional filter property
|
||||
filter = props.getProperty (propName+".filter");
|
||||
if (filter != null && filter.trim().length() == 0)
|
||||
filter = null;
|
||||
// get max size of collection
|
||||
String max = props.getProperty (propName+".maxSize");
|
||||
if (max != null) try {
|
||||
maxSize = Integer.parseInt (max);
|
||||
} catch (NumberFormatException nfe) {
|
||||
maxSize = 0;
|
||||
}
|
||||
// get group by property
|
||||
groupby = props.getProperty (propName+".groupby");
|
||||
if (groupby != null && groupby.trim().length() == 0)
|
||||
groupby = null;
|
||||
if (groupby != null) {
|
||||
groupbyorder = props.getProperty (propName+".groupby.order");
|
||||
if (groupbyorder != null && groupbyorder.trim().length() == 0)
|
||||
groupbyorder = null;
|
||||
groupbyprototype = props.getProperty (propName+".groupby.prototype");
|
||||
if (groupbyprototype != null && groupbyprototype.trim().length() == 0)
|
||||
groupbyprototype = null;
|
||||
// aggressive loading and caching is not supported for groupby-nodes
|
||||
aggressiveLoading = aggressiveCaching = false;
|
||||
}
|
||||
// check if subnode condition should be applied for property relations
|
||||
if ("_properties".equalsIgnoreCase (propName) || virtual) {
|
||||
String subnodes2props = props.getProperty (propName+".aresubnodes");
|
||||
subnodesAreProperties = "true".equalsIgnoreCase (subnodes2props);
|
||||
if (virtual) {
|
||||
String subnodefilter = props.getProperty (propName+".subnoderelation");
|
||||
if (subnodefilter != null) {
|
||||
Constraint c = parseConstraint_v0 (subnodefilter);
|
||||
if (c != null) {
|
||||
cnst.add (c);
|
||||
}
|
||||
}
|
||||
}
|
||||
// update virtual mapping, if it already exists
|
||||
if (virtualMapping != null) {
|
||||
virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
|
||||
virtualMapping.propertiesRel = getVirtualPropertyRelation ();
|
||||
virtualMapping.lastTypeChange = ownType.lastTypeChange;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parse methods for file format v1
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void update_v1 (String desc, Properties props) {
|
||||
Application app = ownType.getApplication ();
|
||||
if (desc == null || "".equals (desc.trim ())) {
|
||||
if (propName != null) {
|
||||
reftype = PRIMITIVE;
|
||||
columnName = propName;
|
||||
} else {
|
||||
reftype = INVALID;
|
||||
columnName = propName;
|
||||
}
|
||||
} else {
|
||||
desc = desc.trim ();
|
||||
int open = desc.indexOf ("(");
|
||||
int close = desc.indexOf (")");
|
||||
if (open > -1 && close > open) {
|
||||
String ref = desc.substring (0, open).trim ();
|
||||
String proto = desc.substring (open+1, close).trim ();
|
||||
if ("collection".equalsIgnoreCase (ref)) {
|
||||
virtual = !"_children".equalsIgnoreCase (propName);
|
||||
reftype = COLLECTION;
|
||||
} else if ("mountpoint".equalsIgnoreCase (ref)) {
|
||||
virtual = true;
|
||||
reftype = COLLECTION;
|
||||
prototype = proto;
|
||||
} else if ("object".equalsIgnoreCase (ref)) {
|
||||
virtual = false;
|
||||
reftype = REFERENCE;
|
||||
} else {
|
||||
throw new RuntimeException ("Invalid property Mapping: "+desc);
|
||||
}
|
||||
otherType = app.getDbMapping (proto);
|
||||
if (otherType == null)
|
||||
throw new RuntimeException ("DbMapping for "+proto+" not found from "+ownType.typename);
|
||||
} else {
|
||||
virtual = false;
|
||||
columnName = desc;
|
||||
reftype = PRIMITIVE;
|
||||
}
|
||||
String rdonly = props.getProperty (desc+".readonly");
|
||||
if (rdonly != null && "true".equalsIgnoreCase (rdonly)) {
|
||||
readonly = true;
|
||||
} else {
|
||||
readonly = false;
|
||||
}
|
||||
}
|
||||
// the following options only apply to object and collection relations
|
||||
if (reftype != PRIMITIVE && reftype != INVALID) {
|
||||
|
||||
Vector newConstraints = new Vector ();
|
||||
parseOptions_v1 (newConstraints, props);
|
||||
|
||||
constraints = new Constraint[newConstraints.size()];
|
||||
newConstraints.copyInto (constraints);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void parseOptions_v1 (Vector cnst, Properties props) {
|
||||
String loading = props.getProperty (propName+".loadmode");
|
||||
aggressiveLoading = loading != null && "aggressive".equalsIgnoreCase (loading.trim());
|
||||
String caching = props.getProperty (propName+".cachemode");
|
||||
aggressiveCaching = caching != null && "aggressive".equalsIgnoreCase (caching.trim());
|
||||
// get order property
|
||||
order = props.getProperty (propName+".order");
|
||||
if (order != null && order.trim().length() == 0)
|
||||
order = null;
|
||||
// get additional filter property
|
||||
filter = props.getProperty (propName+".filter");
|
||||
if (filter != null && filter.trim().length() == 0)
|
||||
filter = null;
|
||||
// get max size of collection
|
||||
String max = props.getProperty (propName+".maxSize");
|
||||
if (max != null) try {
|
||||
maxSize = Integer.parseInt (max);
|
||||
} catch (NumberFormatException nfe) {
|
||||
maxSize = 0;
|
||||
}
|
||||
// get group by property
|
||||
groupby = props.getProperty (propName+".group");
|
||||
if (groupby != null && groupby.trim().length() == 0)
|
||||
groupby = null;
|
||||
if (groupby != null) {
|
||||
groupbyorder = props.getProperty (propName+".group.order");
|
||||
if (groupbyorder != null && groupbyorder.trim().length() == 0)
|
||||
groupbyorder = null;
|
||||
groupbyprototype = props.getProperty (propName+".group.prototype");
|
||||
if (groupbyprototype != null && groupbyprototype.trim().length() == 0)
|
||||
groupbyprototype = null;
|
||||
// aggressive loading and caching is not supported for groupby-nodes
|
||||
aggressiveLoading = aggressiveCaching = false;
|
||||
}
|
||||
// check if subnode condition should be applied for property relations
|
||||
accessor = props.getProperty (propName+".accessname");
|
||||
if (accessor != null)
|
||||
subnodesAreProperties = true;
|
||||
// parse contstraints
|
||||
String local = props.getProperty (propName+".local");
|
||||
String foreign = props.getProperty (propName+".foreign");
|
||||
if (local != null && foreign != null) {
|
||||
cnst.addElement (new Constraint (local, otherType.getTableName (), foreign, false));
|
||||
columnName = local;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Does this relation describe a virtual (collection) node?
|
||||
*/
|
||||
public boolean isVirtual () {
|
||||
return virtual;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if this relation represents a primitive (scalar) value mapping.
|
||||
*/
|
||||
public boolean isPrimitive () {
|
||||
return reftype == PRIMITIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prototype to be used for object reached by this relation
|
||||
*/
|
||||
public String getPrototype () {
|
||||
return prototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the local property this relation is defined for
|
||||
*/
|
||||
public String getPropName () {
|
||||
return propName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a constraint to the current list of constraints
|
||||
*/
|
||||
protected void addConstraint (Constraint c) {
|
||||
if (constraints == null) {
|
||||
constraints = new Constraint[1];
|
||||
constraints[0] = c;
|
||||
} else {
|
||||
Constraint[] nc = new Constraint[constraints.length+1];
|
||||
System.arraycopy (constraints, 0, nc, 0, constraints.length);
|
||||
nc[nc.length-1] = c;
|
||||
constraints = nc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean usesPrimaryKey () {
|
||||
if (otherType != null) {
|
||||
if (reftype == REFERENCE)
|
||||
return constraints.length == 1 && constraints[0].foreignKeyIsPrimary ();
|
||||
if (reftype == COLLECTION)
|
||||
return accessor == null || accessor.equalsIgnoreCase (otherType.getIDField ());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getAccessor () {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
public Relation getSubnodeRelation () {
|
||||
// return subnoderelation;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the local field name for updates.
|
||||
*/
|
||||
public String getDbField () {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
|
||||
public DbMapping getVirtualMapping () {
|
||||
if (!virtual)
|
||||
return null;
|
||||
if (virtualMapping == null) {
|
||||
virtualMapping = new DbMapping (ownType.app);
|
||||
virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
|
||||
virtualMapping.propertiesRel = getVirtualPropertyRelation ();
|
||||
}
|
||||
return virtualMapping;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a Relation that defines the subnodes of a virtual node.
|
||||
*/
|
||||
Relation getVirtualSubnodeRelation () {
|
||||
if (!virtual)
|
||||
throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation");
|
||||
Relation vr = new Relation (this);
|
||||
vr.groupby = groupby;
|
||||
vr.groupbyorder = groupbyorder;
|
||||
vr.groupbyprototype = groupbyprototype;
|
||||
vr.order = order;
|
||||
vr.filter = filter;
|
||||
vr.constraints = constraints;
|
||||
vr.aggressiveLoading = aggressiveLoading;
|
||||
vr.aggressiveCaching = aggressiveCaching;
|
||||
return vr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Relation that defines the properties of a virtual node.
|
||||
*/
|
||||
Relation getVirtualPropertyRelation () {
|
||||
if (!virtual)
|
||||
throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation");
|
||||
Relation vr = new Relation (this);
|
||||
vr.groupby = groupby;
|
||||
vr.groupbyorder = groupbyorder;
|
||||
vr.groupbyprototype = groupbyprototype;
|
||||
vr.order = order;
|
||||
vr.filter = filter;
|
||||
vr.constraints = constraints;
|
||||
return vr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Relation that defines the subnodes of a group-by node.
|
||||
*/
|
||||
Relation getGroupbySubnodeRelation () {
|
||||
if (groupby == null)
|
||||
throw new RuntimeException ("getGroupbySubnodeRelation called on non-group-by relation");
|
||||
Relation vr = new Relation (this);
|
||||
vr.order = order;
|
||||
vr.prototype = groupbyprototype;
|
||||
vr.filter = filter;
|
||||
vr.constraints = constraints;
|
||||
vr.addConstraint (new Constraint (null, null, groupby, true));
|
||||
return vr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Relation that defines the properties of a group-by node.
|
||||
*/
|
||||
Relation getGroupbyPropertyRelation () {
|
||||
if (groupby == null)
|
||||
throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
|
||||
Relation vr = new Relation (this);
|
||||
vr.order = order;
|
||||
vr.prototype = groupbyprototype;
|
||||
vr.filter = filter;
|
||||
vr.constraints = constraints;
|
||||
vr.addConstraint (new Constraint (null, null, groupby, true));
|
||||
return vr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build the second half of an SQL select statement according to this relation
|
||||
* and a local object.
|
||||
*/
|
||||
public String buildQuery (INode home, INode nonvirtual, String kstr, String pre, boolean useOrder) throws SQLException {
|
||||
StringBuffer q = new StringBuffer ();
|
||||
String prefix = pre;
|
||||
if (kstr != null) {
|
||||
q.append (prefix);
|
||||
String accessColumn = accessor == null ? otherType.getIDField () : accessor;
|
||||
q.append (accessColumn);
|
||||
q.append (" = ");
|
||||
// check if column is string type and value needs to be quoted
|
||||
if (otherType.isStringColumn (accessColumn)) {
|
||||
q.append ("'");
|
||||
q.append (escape (kstr));
|
||||
q.append ("'");
|
||||
} else
|
||||
q.append (escape (kstr));
|
||||
prefix = " AND ";
|
||||
}
|
||||
for (int i=0; i<constraints.length; i++) {
|
||||
q.append (prefix);
|
||||
constraints[i].addToQuery (q, home, nonvirtual);
|
||||
prefix = " AND ";
|
||||
}
|
||||
|
||||
if (filter != null) {
|
||||
q.append (prefix);
|
||||
q.append (filter);
|
||||
}
|
||||
if (groupby != null) {
|
||||
q.append (" GROUP BY "+groupby);
|
||||
if (useOrder && groupbyorder != null)
|
||||
q.append (" ORDER BY "+groupbyorder);
|
||||
} else if (useOrder && order != null)
|
||||
q.append (" ORDER BY "+order);
|
||||
return q.toString ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order section to use for this relation
|
||||
*/
|
||||
public String getOrder () {
|
||||
if (groupby != null)
|
||||
return groupbyorder;
|
||||
else
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell wether the property described by this relation is to be handled as readonly/write protected.
|
||||
*/
|
||||
public boolean isReadonly () {
|
||||
return readonly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the child node fullfills the constraints defined by this relation.
|
||||
*/
|
||||
public boolean checkConstraints (Node parent, Node child) {
|
||||
// problem: if a filter property is defined for this relation,
|
||||
// i.e. a piece of static SQL-where clause, we'd have to evaluate it
|
||||
// in order to check the constraints. Because of this, if a filter
|
||||
// is defined, we return false as soon as the modified-time is greater
|
||||
// than the create-time of the child, i.e. if the child node has been
|
||||
// modified since it was first fetched from the db.
|
||||
if (filter != null && child.lastModified() > child.created())
|
||||
return false;
|
||||
for (int i=0; i<constraints.length; i++) {
|
||||
String propname = constraints[i].foreignProperty ();
|
||||
if (propname != null) {
|
||||
INode home = constraints[i].isGroupby ? parent : parent.getNonVirtualParent ();
|
||||
String localName = constraints[i].localName;
|
||||
String value = null;
|
||||
if (localName == null || localName.equalsIgnoreCase (ownType.getIDField ()))
|
||||
value = home.getID ();
|
||||
else if (ownType.isRelational ())
|
||||
value = home.getString (ownType.columnNameToProperty (localName), false);
|
||||
else
|
||||
value = home.getString (localName, false);
|
||||
if (value != null && !value.equals (child.getString (propname, false))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make sure that the child node fullfills the constraints defined by this relation by setting the
|
||||
* appropriate properties
|
||||
*/
|
||||
public void setConstraints (Node parent, Node child) {
|
||||
INode home = parent.getNonVirtualParent ();
|
||||
for (int i=0; i<constraints.length; i++) {
|
||||
// don't set groupby constraints since we don't know if the
|
||||
// parent node is the base node or a group node
|
||||
if (constraints[i].isGroupby)
|
||||
continue;
|
||||
Relation crel = otherType.columnNameToRelation (constraints[i].foreignName);
|
||||
if (crel != null) {
|
||||
// INode home = constraints[i].isGroupby ? parent : nonVirtual;
|
||||
String localName = constraints[i].localName;
|
||||
if (localName == null || localName.equalsIgnoreCase (ownType.getIDField ())) {
|
||||
// only set node if property in child object is defined as reference.
|
||||
if (crel.reftype == REFERENCE) {
|
||||
INode currentValue = child.getNode (crel.propName, false);
|
||||
// we set the backwards reference iff the reference is currently unset, if
|
||||
// is set to a transient object, or if the new target is not transient. This
|
||||
// prevents us from overwriting a persistent refererence with a transient one,
|
||||
// which would most probably not be what we want.
|
||||
if (currentValue == null ||
|
||||
(currentValue != home &&
|
||||
(currentValue.getState() == Node.TRANSIENT ||
|
||||
home.getState() != Node.TRANSIENT)))
|
||||
child.setNode (crel.propName, home);
|
||||
} else if (crel.reftype == PRIMITIVE) {
|
||||
child.setString (crel.propName, home.getID ());
|
||||
}
|
||||
} else if (crel.reftype == PRIMITIVE) {
|
||||
String value = null;
|
||||
if (ownType.isRelational ())
|
||||
value = home.getString (ownType.columnNameToProperty (localName), false);
|
||||
else
|
||||
value = home.getString (localName, false);
|
||||
if (value != null) {
|
||||
child.setString (crel.propName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// a utility method to escape single quotes
|
||||
String escape (String str) {
|
||||
if (str == null)
|
||||
return null;
|
||||
if (str.indexOf ("'") < 0)
|
||||
return str;
|
||||
int l = str.length();
|
||||
StringBuffer sbuf = new StringBuffer (l + 10);
|
||||
for (int i=0; i<l; i++) {
|
||||
char c = str.charAt (i);
|
||||
if (c == '\'')
|
||||
sbuf.append ("\\");
|
||||
sbuf.append (c);
|
||||
}
|
||||
return sbuf.toString ();
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
String c = "";
|
||||
if (constraints != null) {
|
||||
for (int i=0; i<constraints.length; i++)
|
||||
c += constraints[i].toString ();
|
||||
}
|
||||
return "Relation["+ownType+"."+propName+">"+otherType+"]" + c;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Constraint class represents a part of the where clause in the query used to
|
||||
* establish a relation between database mapped objects.
|
||||
*/
|
||||
class Constraint {
|
||||
|
||||
String localName;
|
||||
String tableName;
|
||||
String foreignName;
|
||||
boolean isGroupby;
|
||||
|
||||
Constraint (String local, String table, String foreign, boolean groupby) {
|
||||
localName = local;
|
||||
tableName = table;
|
||||
foreignName = foreign;
|
||||
isGroupby = groupby;
|
||||
}
|
||||
|
||||
public void addToQuery (StringBuffer q, INode home, INode nonvirtual) throws SQLException {
|
||||
String local = null;
|
||||
INode ref = isGroupby ? home : nonvirtual;
|
||||
if (localName == null || localName.equalsIgnoreCase (ref.getDbMapping ().getIDField ()))
|
||||
local = ref.getID ();
|
||||
else {
|
||||
String homeprop = ownType.columnNameToProperty (localName);
|
||||
local = ref.getString (homeprop, false);
|
||||
}
|
||||
q.append (foreignName);
|
||||
q.append (" = ");
|
||||
if (otherType.isStringColumn (foreignName)) {
|
||||
q.append ("'");
|
||||
q.append (escape (local));
|
||||
q.append ("'");
|
||||
} else
|
||||
q.append (escape (local));
|
||||
}
|
||||
|
||||
public boolean foreignKeyIsPrimary () {
|
||||
return foreignName == null || foreignName.equalsIgnoreCase (otherType.getIDField ());
|
||||
}
|
||||
|
||||
public String foreignProperty () {
|
||||
return otherType.columnNameToProperty (foreignName);
|
||||
}
|
||||
|
||||
public String localProperty () {
|
||||
return ownType.columnNameToProperty (localName);
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return ownType+"."+localName+"="+tableName+"."+foreignName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
// Replicator.java
|
||||
// Copyright (c) Hannes Wallnöfer 2001
|
||||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import helma.framework.IReplicatedApp;
|
||||
import java.rmi.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class replicates the updates of transactions to other applications via RMI
|
||||
*/
|
||||
|
||||
public class Replicator implements Runnable {
|
||||
|
||||
Vector urls;
|
||||
Vector apps;
|
||||
Vector add, delete, currentAdd, currentDelete;
|
||||
Thread runner;
|
||||
|
||||
public Replicator () {
|
||||
urls = new Vector ();
|
||||
apps = new Vector ();
|
||||
add = new Vector ();
|
||||
delete = new Vector ();
|
||||
runner = new Thread (this);
|
||||
runner.start ();
|
||||
}
|
||||
|
||||
public void addUrl (String url) {
|
||||
urls.addElement (url);
|
||||
}
|
||||
|
||||
public void addApp (IReplicatedApp app) {
|
||||
apps.addElement (app);
|
||||
}
|
||||
|
||||
public void run () {
|
||||
while (Thread.currentThread () == runner) {
|
||||
if (prepareReplication ()) {
|
||||
for (int i=0; i<urls.size(); i++) {
|
||||
try {
|
||||
IReplicatedApp app = (IReplicatedApp) Naming.lookup ((String) urls.elementAt (i));
|
||||
app.replicateCache (currentAdd, currentDelete);
|
||||
} catch (Exception x) {
|
||||
System.err.println ("ERROR REPLICATING CACHE: "+x);
|
||||
}
|
||||
}
|
||||
for (int i=0; i<apps.size(); i++) {
|
||||
try {
|
||||
IReplicatedApp app = (IReplicatedApp) apps.elementAt (i);
|
||||
app.replicateCache (currentAdd, currentDelete);
|
||||
} catch (Exception x) {
|
||||
System.err.println ("ERROR REPLICATING CACHE: "+x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (runner != null)
|
||||
runner.sleep (1000l);
|
||||
} catch (InterruptedException ir) {
|
||||
runner = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void addNewNode (Node n) {
|
||||
add.addElement (n);
|
||||
}
|
||||
|
||||
public synchronized void addModifiedNode (Node n) {
|
||||
add.addElement (n);
|
||||
}
|
||||
|
||||
public synchronized void addDeletedNode (Node n) {
|
||||
delete.addElement (n);
|
||||
}
|
||||
|
||||
private synchronized boolean prepareReplication () {
|
||||
if (add.size() == 0 && delete.size() == 0)
|
||||
return false;
|
||||
currentAdd = add;
|
||||
currentDelete = delete;
|
||||
add = new Vector ();
|
||||
delete = new Vector ();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -3,22 +3,346 @@
|
|||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.rmi.*;
|
||||
import java.rmi.server.*;
|
||||
import java.rmi.registry.*;
|
||||
import java.net.*;
|
||||
import helma.objectmodel.*;
|
||||
import helma.framework.*;
|
||||
import helma.framework.core.*;
|
||||
import helma.xmlrpc.*;
|
||||
import helma.util.*;
|
||||
import com.sleepycat.db.*;
|
||||
|
||||
|
||||
/**
|
||||
* Helma server main class. This moved to the helma.main package but a
|
||||
* simple redirector is kept here for backwards compatibility.
|
||||
* HOP main class.
|
||||
*/
|
||||
|
||||
public class Server {
|
||||
public class Server extends IServer implements Runnable {
|
||||
|
||||
|
||||
static boolean useTransactions, paranoid;
|
||||
|
||||
private ApplicationManager appManager;
|
||||
|
||||
private Thread mainThread;
|
||||
|
||||
static String dbFilename = "hop.db";
|
||||
static String propfile;
|
||||
static String dbPropfile = "db.properties";
|
||||
static String appsPropfile = "apps.properties";
|
||||
static SystemProperties appsProps;
|
||||
static String dbDir = null;
|
||||
static int port = 5055;
|
||||
static int webport = 0;
|
||||
|
||||
Acme.Serve.Serve websrv;
|
||||
|
||||
/**
|
||||
* Just invoke the main method in the new Server class.
|
||||
*/
|
||||
public static void main (String args[]) throws IOException {
|
||||
System.err.println ("The Helma main class is now in helma.main.Server. Please update your start script accordingly.");
|
||||
helma.main.Server.main (args);
|
||||
|
||||
boolean usageError = false;
|
||||
|
||||
useTransactions = true;
|
||||
|
||||
for (int i=0; i<args.length; i++) {
|
||||
if (args[i].equals ("-h") && i+1<args.length)
|
||||
hopHome = args[++i];
|
||||
else if (args[i].equals ("-f") && i+1<args.length)
|
||||
propfile = args[++i];
|
||||
else if (args[i].equals ("-t"))
|
||||
useTransactions = false;
|
||||
else if (args[i].equals ("-p") && i+1<args.length) {
|
||||
try {
|
||||
port = Integer.parseInt (args[++i]);
|
||||
} catch (Exception portx) {
|
||||
usageError = true;
|
||||
}
|
||||
} else if (args[i].equals ("-w") && i+1<args.length) {
|
||||
try {
|
||||
webport = Integer.parseInt (args[++i]);
|
||||
} catch (Exception portx) {
|
||||
usageError = true;
|
||||
}
|
||||
} else
|
||||
usageError = true;
|
||||
}
|
||||
|
||||
// get main property file from home dir or vice versa, depending on what we have.
|
||||
// get property file from hopHome
|
||||
if (propfile == null) {
|
||||
if (hopHome != null)
|
||||
propfile = new File (hopHome, "server.properties").getAbsolutePath ();
|
||||
else
|
||||
propfile = new File ("server.properties").getAbsolutePath ();
|
||||
}
|
||||
sysProps = new SystemProperties (propfile);
|
||||
// get hopHome from property file
|
||||
if (hopHome == null)
|
||||
hopHome = sysProps.getProperty ("hophome");
|
||||
if (hopHome == null)
|
||||
hopHome = new File (propfile).getParent ();
|
||||
|
||||
getLogger().log ("propfile = "+propfile);
|
||||
getLogger().log ("hopHome = "+hopHome);
|
||||
|
||||
if (usageError ) {
|
||||
System.out.println ("usage: java helma.objectmodel.db.Server [-h dir] [-f file] [-p port] [-w port] [-t]");
|
||||
System.out.println (" -h dir Specify hop home directory");
|
||||
System.out.println (" -f file Specify server.properties file");
|
||||
System.out.println (" -p port Specify TCP port number");
|
||||
System.out.println (" -w port Start embedded Web server on that port");
|
||||
System.out.println (" -t Disable Berkeley DB Transactions");
|
||||
getLogger().log ("Usage Error - exiting");
|
||||
System.exit (0);
|
||||
}
|
||||
|
||||
dbDir = sysProps.getProperty ("dbhome", "db");
|
||||
File helper = new File (dbDir);
|
||||
if (hopHome != null && !helper.isAbsolute ())
|
||||
helper = new File (hopHome, dbDir);
|
||||
dbDir = helper.getAbsolutePath ();
|
||||
getLogger().log ("dbHome = "+dbDir);
|
||||
|
||||
dbPropfile = sysProps.getProperty ("dbpropfile", "db.properties");
|
||||
helper = new File (dbPropfile);
|
||||
if (hopHome != null && !helper.isAbsolute ())
|
||||
helper = new File (hopHome, dbPropfile);
|
||||
dbPropfile = helper.getAbsolutePath ();
|
||||
getLogger().log ("dbPropfile = "+dbPropfile);
|
||||
|
||||
appsPropfile = sysProps.getProperty ("appspropfile", "apps.properties");
|
||||
helper = new File (appsPropfile);
|
||||
if (hopHome != null && !helper.isAbsolute ())
|
||||
helper = new File (hopHome, appsPropfile);
|
||||
appsPropfile = helper.getAbsolutePath ();
|
||||
getLogger().log ("appsPropfile = "+appsPropfile);
|
||||
|
||||
File libdir = new File (hopHome, "lib");
|
||||
Properties p = System.getProperties ();
|
||||
String libpath = p.getProperty ("java.library.path");
|
||||
if (libpath != null && libpath.length () > 0)
|
||||
p.put ("java.library.path", libpath+System.getProperty("path.separator")+libdir.getCanonicalPath());
|
||||
else
|
||||
p.put ("java.library.path", libdir.getCanonicalPath());
|
||||
|
||||
paranoid = "true".equalsIgnoreCase (sysProps.getProperty ("paranoid"));
|
||||
|
||||
String language = sysProps.getProperty ("language");
|
||||
String country = sysProps.getProperty ("country");
|
||||
String timezone = sysProps.getProperty ("timezone");
|
||||
|
||||
if (language != null && country != null)
|
||||
Locale.setDefault (new Locale (language, country));
|
||||
if (timezone != null)
|
||||
TimeZone.setDefault (TimeZone.getTimeZone (timezone));
|
||||
|
||||
getLogger().log ("Locale = "+Locale.getDefault());
|
||||
getLogger().log ("TimeZone = "+TimeZone.getDefault());
|
||||
|
||||
dbSources = new Hashtable ();
|
||||
|
||||
new Server ();
|
||||
|
||||
}
|
||||
|
||||
public Server () {
|
||||
|
||||
try {
|
||||
checkRunning (); // check if a server is already running with this db
|
||||
} catch (Exception running) {
|
||||
System.out.println (running.getMessage ());
|
||||
System.exit (1);
|
||||
}
|
||||
|
||||
// nmgr = new NodeManager (this, sysProps);
|
||||
|
||||
mainThread = new Thread (this);
|
||||
mainThread.start ();
|
||||
}
|
||||
|
||||
public void run () {
|
||||
|
||||
try {
|
||||
|
||||
// set up dbSources
|
||||
try {
|
||||
dbProps = new SystemProperties (dbPropfile);
|
||||
String sources = dbProps.getProperty ("sources", "");
|
||||
StringTokenizer st = new StringTokenizer (sources, ",; ");
|
||||
String next = null;
|
||||
while (st.hasMoreTokens ()) try {
|
||||
next = st.nextToken ();
|
||||
new DbSource (next);
|
||||
} catch (Exception wrong) {
|
||||
getLogger().log ("Error creating DbSource "+next);
|
||||
getLogger().log ("Reason: "+wrong);
|
||||
}
|
||||
} catch (Exception x) {
|
||||
getLogger().log ("Error loading data source properties: "+x);
|
||||
}
|
||||
|
||||
// start embedded web server if port is specified
|
||||
if (webport > 0) {
|
||||
websrv = new Acme.Serve.Serve (webport, sysProps);
|
||||
}
|
||||
|
||||
String xmlparser = sysProps.getProperty ("xmlparser");
|
||||
if (xmlparser != null)
|
||||
XmlRpc.setDriver (xmlparser);
|
||||
// XmlRpc.setDebug (true);
|
||||
xmlrpc = new WebServer (port+1);
|
||||
if (paranoid) {
|
||||
xmlrpc.setParanoid (true);
|
||||
String xallow = sysProps.getProperty ("allowXmlRpc");
|
||||
if (xallow != null) {
|
||||
StringTokenizer st = new StringTokenizer (xallow, " ,;");
|
||||
while (st.hasMoreTokens ())
|
||||
xmlrpc.acceptClient (st.nextToken ());
|
||||
}
|
||||
}
|
||||
getLogger().log ("Starting XML-RPC server on port "+(port+1));
|
||||
|
||||
// the following seems not to be necessary after all ...
|
||||
// System.setSecurityManager(new RMISecurityManager());
|
||||
if (paranoid) {
|
||||
HopSocketFactory factory = new HopSocketFactory ();
|
||||
String rallow = sysProps.getProperty ("allowWeb");
|
||||
if (rallow != null) {
|
||||
StringTokenizer st = new StringTokenizer (rallow, " ,;");
|
||||
while (st.hasMoreTokens ())
|
||||
factory.addAddress (st.nextToken ());
|
||||
}
|
||||
RMISocketFactory.setSocketFactory (factory);
|
||||
}
|
||||
|
||||
if (websrv == null) {
|
||||
getLogger().log ("Starting server on port "+port);
|
||||
LocateRegistry.createRegistry (port);
|
||||
}
|
||||
|
||||
|
||||
// start application framework
|
||||
String appDir = sysProps.getProperty ("apphome", "apps");
|
||||
File appHome = new File (appDir);
|
||||
if (hopHome != null && !appHome.isAbsolute())
|
||||
appHome = new File (hopHome, appDir);
|
||||
appsProps = new SystemProperties (appsPropfile);
|
||||
File dbHome = new File (dbDir);
|
||||
appManager = new ApplicationManager (port, appHome, dbHome, appsProps, this);
|
||||
|
||||
|
||||
} catch (Exception gx) {
|
||||
getLogger().log ("Error initializing embedded database: "+gx);
|
||||
gx.printStackTrace ();
|
||||
/* try {
|
||||
transactor.abort ();
|
||||
} catch (Exception ignore) {} */
|
||||
return;
|
||||
}
|
||||
|
||||
// start applications
|
||||
appManager.startAll ();
|
||||
|
||||
// start embedded web server
|
||||
if (websrv != null) {
|
||||
Thread webthread = new Thread (websrv, "WebServer");
|
||||
webthread.start ();
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
while (Thread.currentThread () == mainThread) {
|
||||
try {
|
||||
mainThread.sleep (3000l);
|
||||
} catch (InterruptedException ie) {}
|
||||
try {
|
||||
appManager.checkForChanges ();
|
||||
} catch (Exception x) {
|
||||
getLogger().log ("Caught in app manager loop: "+x);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void checkRunning () throws Exception {
|
||||
try {
|
||||
java.net.Socket socket = new java.net.Socket ("localhost", port);
|
||||
} catch (Exception x) {
|
||||
return;
|
||||
}
|
||||
// if we got so far, another server is already running on this port and db
|
||||
throw new Exception ("Error: Server already running on this port");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
// SyntheticKey.java
|
||||
// Copyright (c) Hannes Wallnöfer 1998-2000
|
||||
|
||||
package helma.objectmodel.db;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* This is the internal key for an object that is not - or not directly - fetched from a db,
|
||||
* but derived from another object. This is useful for all kinds of object accessed via a
|
||||
* symbolic name from another object, like objects mounted via a property name column,
|
||||
* virtual nodes and groupby nodes.
|
||||
*/
|
||||
public final class SyntheticKey implements Key, Serializable {
|
||||
|
||||
private final Key parentKey;
|
||||
private final String name;
|
||||
|
||||
// lazily initialized hashcode
|
||||
private transient int hashcode = 0;
|
||||
|
||||
|
||||
/**
|
||||
* make a key for a persistent Object, describing its datasource and id.
|
||||
*/
|
||||
public SyntheticKey (Key key, String name) {
|
||||
this.parentKey = key;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public boolean equals (Object what) {
|
||||
if (what == this)
|
||||
return true;
|
||||
try {
|
||||
SyntheticKey k = (SyntheticKey) what;
|
||||
return parentKey.equals (k.parentKey) &&
|
||||
(name == k.name || name.equals (k.name));
|
||||
} catch (Exception x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode () {
|
||||
if (hashcode == 0)
|
||||
hashcode = 17 + 37*name.hashCode () + 37*parentKey.hashCode ();
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
|
||||
public Key getParentKey () {
|
||||
return parentKey;
|
||||
}
|
||||
|
||||
public String getID () {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getStorageName () {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return parentKey+"/"+name;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -22,7 +22,6 @@ public class Transactor extends Thread {
|
|||
|
||||
// List of nodes to be updated
|
||||
private HashMap nodes;
|
||||
private ArrayList nodesArray;
|
||||
// List of visited clean nodes
|
||||
private HashMap cleannodes;
|
||||
// Is a transaction in progress?
|
||||
|
@ -45,7 +44,6 @@ public class Transactor extends Thread {
|
|||
super (group, runnable, group.getName ());
|
||||
this.nmgr = nmgr;
|
||||
nodes = new HashMap ();
|
||||
nodesArray = new ArrayList ();
|
||||
cleannodes = new HashMap ();
|
||||
sqlCon = new HashMap ();
|
||||
active = false;
|
||||
|
@ -58,7 +56,6 @@ public class Transactor extends Thread {
|
|||
Key key = node.getKey ();
|
||||
if (!nodes.containsKey (key)) {
|
||||
nodes.put (key, node);
|
||||
nodesArray.add (node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +64,6 @@ public class Transactor extends Thread {
|
|||
if (node != null) {
|
||||
Key key = node.getKey ();
|
||||
nodes.remove (key);
|
||||
nodesArray.remove (node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +110,6 @@ public class Transactor extends Thread {
|
|||
abort ();
|
||||
|
||||
nodes.clear ();
|
||||
nodesArray.clear ();
|
||||
cleannodes.clear ();
|
||||
txn = nmgr.db.beginTransaction ();
|
||||
active = true;
|
||||
|
@ -130,44 +125,36 @@ public class Transactor extends Thread {
|
|||
}
|
||||
|
||||
int ins = 0, upd = 0, dlt = 0;
|
||||
int l = nodesArray.size ();
|
||||
int l = nodes.size ();
|
||||
|
||||
Replicator replicator = nmgr.getReplicator ();
|
||||
for (Iterator i=nodes.values().iterator(); i.hasNext (); ) {
|
||||
Node node = (Node) i.next ();
|
||||
|
||||
for (int i=0; i<l; i++) {
|
||||
Node node = (Node) nodesArray.get (i);
|
||||
// update nodes in db
|
||||
int nstate = node.getState ();
|
||||
if (nstate == Node.NEW) {
|
||||
nmgr.registerNode (node); // register node with nodemanager cache
|
||||
nmgr.insertNode (nmgr.db, txn, node);
|
||||
node.setState (Node.CLEAN);
|
||||
if (replicator != null)
|
||||
replicator.addNewNode (node);
|
||||
ins++;
|
||||
nmgr.app.logEvent ("inserted: Node "+node.getPrototype ()+"/"+node.getID ());
|
||||
IServer.getLogger().log ("inserted: Node "+node.getName ()+"/"+node.getID ());
|
||||
} else if (nstate == Node.MODIFIED) {
|
||||
nmgr.updateNode (nmgr.db, txn, node);
|
||||
node.setState (Node.CLEAN);
|
||||
if (replicator != null)
|
||||
replicator.addModifiedNode (node);
|
||||
upd++;
|
||||
nmgr.app.logEvent ("updated: Node "+node.getPrototype ()+"/"+node.getID ());
|
||||
IServer.getLogger().log ("updated: Node "+node.getName ()+"/"+node.getID ());
|
||||
} else if (nstate == Node.DELETED) {
|
||||
// nmgr.app.logEvent ("deleted: "+node.getFullName ()+" ("+node.getName ()+")");
|
||||
// IServer.getLogger().log ("deleted: "+node.getFullName ()+" ("+node.getName ()+")");
|
||||
nmgr.deleteNode (nmgr.db, txn, node);
|
||||
nmgr.evictNode (node);
|
||||
if (replicator != null)
|
||||
replicator.addDeletedNode (node);
|
||||
dlt++;
|
||||
} else {
|
||||
// nmgr.app.logEvent ("noop: "+node.getFullName ());
|
||||
// IServer.getLogger().log ("noop: "+node.getFullName ());
|
||||
}
|
||||
node.clearWriteLock ();
|
||||
}
|
||||
|
||||
nodes.clear ();
|
||||
nodesArray.clear ();
|
||||
cleannodes.clear ();
|
||||
|
||||
if (nmgr.idgen.dirty) {
|
||||
|
@ -181,21 +168,19 @@ public class Transactor extends Thread {
|
|||
txn = null;
|
||||
}
|
||||
|
||||
nmgr.app.logAccess (tname+" "+l+" marked, "+ins+" inserted, "+upd+" updated, "+dlt+" deleted in "+(System.currentTimeMillis()-tstart)+" millis");
|
||||
IServer.getLogger().log (tname+" "+l+" marked, "+ins+" inserted, "+upd+" updated, "+dlt+" deleted in "+(System.currentTimeMillis()-tstart)+" millis");
|
||||
}
|
||||
|
||||
public synchronized void abort () throws Exception {
|
||||
|
||||
int l = nodesArray.size ();
|
||||
for (int i=0; i<l; i++ ) {
|
||||
Node node = (Node) nodesArray.get (i);
|
||||
for (Iterator i=nodes.values().iterator(); i.hasNext(); ) {
|
||||
Node node = (Node) i.next ();
|
||||
// Declare node as invalid, so it won't be used by other threads that want to
|
||||
// write on it and remove it from cache
|
||||
nmgr.evictNode (node);
|
||||
node.clearWriteLock ();
|
||||
}
|
||||
nodes.clear ();
|
||||
nodesArray.clear ();
|
||||
cleannodes.clear ();
|
||||
// close any JDBC connections associated with this transactor thread
|
||||
closeConnections ();
|
||||
|
@ -206,7 +191,7 @@ public class Transactor extends Thread {
|
|||
nmgr.db.abortTransaction (txn);
|
||||
txn = null;
|
||||
}
|
||||
nmgr.app.logEvent (tname+" aborted after "+(System.currentTimeMillis()-tstart)+" millis");
|
||||
IServer.getLogger().log (tname+" aborted after "+(System.currentTimeMillis()-tstart)+" millis");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,13 +214,13 @@ public class Transactor extends Thread {
|
|||
}
|
||||
|
||||
public void closeConnections () {
|
||||
// nmgr.app.logEvent("Cleaning up Transactor thread");
|
||||
// IServer.getLogger().log("Cleaning up Transactor thread");
|
||||
if (sqlCon != null) {
|
||||
for (Iterator i=sqlCon.values().iterator(); i.hasNext(); ) {
|
||||
try {
|
||||
Connection con = (Connection) i.next();
|
||||
con.close ();
|
||||
nmgr.app.logEvent ("Closing DB connection: "+con);
|
||||
IServer.getLogger ().log ("Closing DB connection: "+con);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
sqlCon.clear ();
|
||||
|
@ -250,3 +235,101 @@ public class Transactor extends Thread {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
package helma.objectmodel.db;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
|
@ -23,17 +22,13 @@ import java.util.Vector;
|
|||
}
|
||||
|
||||
public Node getNode (String id, DbMapping dbmap) {
|
||||
return getNode (new DbKey (dbmap, id));
|
||||
}
|
||||
|
||||
public Node getNode (Key key) {
|
||||
try {
|
||||
return nmgr.getNode (key);
|
||||
return nmgr.getNode (id, dbmap);
|
||||
} catch (ObjectNotFoundException x) {
|
||||
return null;
|
||||
} catch (Exception x) {
|
||||
nmgr.app.logEvent ("Error retrieving Node via DbMapping: "+x.getMessage ());
|
||||
if (nmgr.app.debug ())
|
||||
Server.getLogger().log ("Error retrieving Node via DbMapping: "+x.getMessage ());
|
||||
if ("true".equalsIgnoreCase (Server.sysProps.getProperty("debug")))
|
||||
x.printStackTrace();
|
||||
throw new RuntimeException ("Error retrieving Node: "+x.getMessage ());
|
||||
}
|
||||
|
@ -45,28 +40,28 @@ import java.util.Vector;
|
|||
} catch (ObjectNotFoundException x) {
|
||||
return null;
|
||||
} catch (Exception x) {
|
||||
nmgr.app.logEvent ("Error retrieving Node \""+id+"\" from "+home+": "+x.getMessage ());
|
||||
if (nmgr.app.debug ())
|
||||
Server.getLogger().log ("Error retrieving Node \""+id+"\" from "+home+": "+x.getMessage ());
|
||||
if ("true".equalsIgnoreCase (Server.sysProps.getProperty("debug")))
|
||||
x.printStackTrace();
|
||||
throw new RuntimeException ("Error retrieving Node: "+x.getMessage ());
|
||||
}
|
||||
}
|
||||
|
||||
public List getNodes (Node home, Relation rel) {
|
||||
public Vector getNodes (Node home, Relation rel) {
|
||||
try {
|
||||
return nmgr.getNodes (home, rel);
|
||||
} catch (Exception x) {
|
||||
if (nmgr.app.debug ())
|
||||
if ("true".equalsIgnoreCase (Server.sysProps.getProperty("debug")))
|
||||
x.printStackTrace();
|
||||
throw new RuntimeException ("Error retrieving Nodes: "+x.getMessage ());
|
||||
}
|
||||
}
|
||||
|
||||
public List getNodeIDs (Node home, Relation rel) {
|
||||
public Vector getNodeIDs (Node home, Relation rel) {
|
||||
try {
|
||||
return nmgr.getNodeIDs (home, rel);
|
||||
} catch (Exception x) {
|
||||
if (nmgr.app.debug ())
|
||||
if ("true".equalsIgnoreCase (Server.sysProps.getProperty("debug")))
|
||||
x.printStackTrace();
|
||||
throw new RuntimeException ("Error retrieving NodeIDs: "+x.getMessage ());
|
||||
}
|
||||
|
@ -76,7 +71,7 @@ import java.util.Vector;
|
|||
try {
|
||||
return nmgr.countNodes (home, rel);
|
||||
} catch (Exception x) {
|
||||
if (nmgr.app.debug ())
|
||||
if ("true".equalsIgnoreCase (Server.sysProps.getProperty("debug")))
|
||||
x.printStackTrace();
|
||||
throw new RuntimeException ("Error counting Node: "+x.getMessage ());
|
||||
}
|
||||
|
@ -86,7 +81,7 @@ import java.util.Vector;
|
|||
try {
|
||||
nmgr.deleteNode (node);
|
||||
} catch (Exception x) {
|
||||
if (nmgr.app.debug ())
|
||||
if ("true".equalsIgnoreCase (Server.sysProps.getProperty("debug")))
|
||||
x.printStackTrace();
|
||||
throw new RuntimeException ("Error deleting Node: "+x.getMessage ());
|
||||
}
|
||||
|
@ -96,7 +91,7 @@ import java.util.Vector;
|
|||
try {
|
||||
return nmgr.getPropertyNames (home, rel);
|
||||
} catch (Exception x) {
|
||||
if (nmgr.app.debug ())
|
||||
if ("true".equalsIgnoreCase (Server.sysProps.getProperty("debug")))
|
||||
x.printStackTrace();
|
||||
throw new RuntimeException ("Error retrieving property names: "+x.getMessage ());
|
||||
}
|
||||
|
@ -139,14 +134,6 @@ import java.util.Vector;
|
|||
return nmgr.getCacheEntries ();
|
||||
}
|
||||
|
||||
public void logEvent (String msg) {
|
||||
nmgr.app.logEvent (msg);
|
||||
}
|
||||
|
||||
public DbMapping getDbMapping (String name) {
|
||||
return nmgr.app.getDbMapping (name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
package helma.objectmodel.dom;
|
||||
|
||||
public interface XmlConstants {
|
||||
|
||||
public final String NAMESPACE = "http://www.helma.org/";
|
||||
public final String DATEFORMAT = "dd.MM.yyyy HH:mm:ss z";
|
||||
|
||||
}
|
|
@ -1,239 +0,0 @@
|
|||
package helma.objectmodel.dom;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
import javax.xml.parsers.*;
|
||||
import org.w3c.dom.*;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import helma.util.SystemProperties;
|
||||
|
||||
public class XmlConverter implements XmlConstants {
|
||||
|
||||
private boolean DEBUG=false;
|
||||
|
||||
private Properties props;
|
||||
|
||||
private char defaultSeparator = '_';
|
||||
|
||||
private int offset = 0;
|
||||
|
||||
public XmlConverter() {
|
||||
props = new SystemProperties();
|
||||
}
|
||||
|
||||
public XmlConverter(String propFile) {
|
||||
props = new SystemProperties(propFile);
|
||||
extractProperties(props);
|
||||
}
|
||||
|
||||
public XmlConverter(File propFile) {
|
||||
this ( propFile.getAbsolutePath() );
|
||||
}
|
||||
|
||||
public XmlConverter(Properties props) {
|
||||
this.props = props;
|
||||
extractProperties(props);
|
||||
}
|
||||
|
||||
public INode convert( String desc ) {
|
||||
return convert(desc, new TransientNode() );
|
||||
}
|
||||
|
||||
public INode convert( String desc, INode helmaNode ) throws RuntimeException {
|
||||
try {
|
||||
return convert( new URL(desc), helmaNode );
|
||||
} catch ( MalformedURLException notanurl ) {
|
||||
try {
|
||||
return convert( new File(desc), helmaNode );
|
||||
} catch ( FileNotFoundException notfound ) {
|
||||
throw new RuntimeException( "couldn't read xml: " + desc );
|
||||
}
|
||||
} catch ( IOException ioerror ) {
|
||||
throw new RuntimeException( "couldn't read xml: " + desc );
|
||||
}
|
||||
}
|
||||
|
||||
public INode convert( File file, INode helmaNode ) throws RuntimeException, FileNotFoundException {
|
||||
return convert( new FileInputStream(file), helmaNode );
|
||||
}
|
||||
|
||||
public INode convert( URL url, INode helmaNode ) throws RuntimeException, IOException, MalformedURLException {
|
||||
return convert( url.openConnection().getInputStream(), helmaNode );
|
||||
}
|
||||
|
||||
public INode convert( InputStream in, INode helmaNode ) throws RuntimeException {
|
||||
Document document = XmlUtil.parse (in);
|
||||
if ( document!=null && document.getDocumentElement()!=null ) {
|
||||
return convert( document.getDocumentElement(), helmaNode );
|
||||
} else {
|
||||
return helmaNode;
|
||||
}
|
||||
}
|
||||
|
||||
public INode convert( Element element, INode helmaNode ) {
|
||||
offset++;
|
||||
if (DEBUG) debug("reading " + element.getNodeName() );
|
||||
helmaNode.setName( element.getNodeName() );
|
||||
String prototype = (String)props.get(element.getNodeName().toLowerCase()+"._prototype");
|
||||
if ( prototype == null )
|
||||
prototype = "HopObject";
|
||||
helmaNode.setPrototype( prototype );
|
||||
attributes(element, helmaNode);
|
||||
if ( element.hasChildNodes() ) {
|
||||
children(element, helmaNode);
|
||||
}
|
||||
offset--;
|
||||
return helmaNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse xml children and create hopobject-children
|
||||
*/
|
||||
private INode children( Element element, helma.objectmodel.INode helmaNode ) {
|
||||
NodeList list = element.getChildNodes();
|
||||
int len = list.getLength();
|
||||
StringBuffer textcontent = new StringBuffer();
|
||||
String domKey, helmaKey;
|
||||
for ( int i=0; i<len; i++ ) {
|
||||
|
||||
// loop through the list of children
|
||||
org.w3c.dom.Node childNode = list.item(i);
|
||||
|
||||
// if it's text content of this element -> append to StringBuffer
|
||||
if ( childNode.getNodeType()==org.w3c.dom.Node.TEXT_NODE ) {
|
||||
textcontent.append( childNode.getNodeValue().trim() );
|
||||
continue;
|
||||
}
|
||||
|
||||
// it's some kind of element (property or child)
|
||||
if ( childNode.getNodeType()==org.w3c.dom.Node.ELEMENT_NODE ) {
|
||||
|
||||
Element childElement = (Element)childNode;
|
||||
|
||||
// get the basic key we have to look for in the properties-table
|
||||
domKey = (element.getNodeName()+"."+childElement.getNodeName()).toLowerCase();
|
||||
|
||||
// is there a childtext-2-property mapping?
|
||||
if ( props!=null && props.containsKey(domKey+"._text") ) {
|
||||
helmaKey = (String)props.get(domKey+"._text");
|
||||
if( helmaKey.equals("") )
|
||||
// if property is set but without value, read elementname for this mapping
|
||||
helmaKey = childElement.getNodeName().replace(':',defaultSeparator);
|
||||
if (DEBUG) debug("childtext-2-property mapping, helmaKey " + helmaKey + " for domKey " + domKey );
|
||||
if ( helmaNode.getString(helmaKey,false)==null ) {
|
||||
helmaNode.setString( helmaKey, XmlUtil.getTextContent(childNode) );
|
||||
if (DEBUG) debug("childtext-2-property mapping, setting " + helmaKey + " as string" );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// is there a simple child-2-property mapping?
|
||||
// (lets the user define to use only one element and make this a property
|
||||
// and simply ignore other elements of the same name)
|
||||
if ( props!=null && props.containsKey(domKey+"._property") ) {
|
||||
helmaKey = (String)props.get(domKey+"._property");
|
||||
// if property is set but without value, read elementname for this mapping:
|
||||
if ( helmaKey.equals("") )
|
||||
helmaKey = childElement.getNodeName().replace(':',defaultSeparator);
|
||||
if (DEBUG) debug("child-2-property mapping, helmaKey " + helmaKey + " for domKey " + domKey);
|
||||
if ( helmaNode.getNode(helmaKey,false)==null ) {
|
||||
convert( childElement, helmaNode.createNode(helmaKey) );
|
||||
if (DEBUG) debug( "read " + childElement.toString() + helmaNode.getNode(helmaKey,false).toString() );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// map it to one of the children-lists
|
||||
helma.objectmodel.INode newHelmaNode = null;
|
||||
String childrenMapping = (String)props.get(element.getNodeName().toLowerCase()+"._children");
|
||||
// do we need a mapping directly among _children of helmaNode?
|
||||
// can either be through property elname._children=_all or elname._children=childname
|
||||
if( childrenMapping!=null && ( childrenMapping.equals("_all") || childrenMapping.equals(childElement.getNodeName()) ) ) {
|
||||
newHelmaNode = convert(childElement, helmaNode.createNode(null) );
|
||||
}
|
||||
// which name to choose for a virtual subnode:
|
||||
helmaKey = (String)props.get(domKey);
|
||||
if ( helmaKey==null ) {
|
||||
helmaKey = childElement.getNodeName().replace(':',defaultSeparator);
|
||||
}
|
||||
// try to get the virtual node
|
||||
helma.objectmodel.INode worknode = helmaNode.getNode( helmaKey, false );
|
||||
if ( worknode==null ) {
|
||||
// if virtual node doesn't exist, create it
|
||||
worknode = helmaNode.createNode( helmaKey );
|
||||
}
|
||||
if (DEBUG) debug( "mounting child "+ childElement.getNodeName() + " at worknode " + worknode.toString() );
|
||||
// now mount it, possibly re-using the helmaNode that's been created before
|
||||
if ( newHelmaNode!=null ) {
|
||||
worknode.addNode(newHelmaNode);
|
||||
} else {
|
||||
convert( childElement, worknode.createNode( null ) );
|
||||
}
|
||||
}
|
||||
// forget about other types (comments etc)
|
||||
continue;
|
||||
}
|
||||
|
||||
// if there's some text content for this element, map it:
|
||||
if ( textcontent.length()>0 ) {
|
||||
helmaKey = (String)props.get(element.getNodeName().toLowerCase()+"._text");
|
||||
if ( helmaKey==null )
|
||||
helmaKey = "text";
|
||||
helmaNode.setString(helmaKey, textcontent.toString().trim() );
|
||||
}
|
||||
|
||||
return helmaNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* set element's attributes as properties of helmaNode
|
||||
*/
|
||||
private INode attributes( Element element, INode helmaNode ) {
|
||||
NamedNodeMap nnm = element.getAttributes();
|
||||
int len = nnm.getLength();
|
||||
for ( int i=0; i<len; i++ ) {
|
||||
org.w3c.dom.Node attr = nnm.item(i);
|
||||
if ( attr.getNodeName().equals("_prototype") ) {
|
||||
helmaNode.setPrototype( attr.getNodeValue() );
|
||||
} else if ( attr.getNodeName().equals("_name") ) {
|
||||
helmaNode.setName( attr.getNodeValue() );
|
||||
} else {
|
||||
String helmaKey = (String)props.get(element.getNodeName().toLowerCase()+"._attribute."+attr.getNodeName().toLowerCase());
|
||||
if ( helmaKey==null )
|
||||
helmaKey = attr.getNodeName().replace(':',defaultSeparator);
|
||||
helmaNode.setString( helmaKey, attr.getNodeValue() );
|
||||
}
|
||||
}
|
||||
return helmaNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* utility function
|
||||
*/
|
||||
private void extractProperties( Properties props ) {
|
||||
if ( props.containsKey("separator") ) {
|
||||
defaultSeparator = ((String)props.get("separator")).charAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
/** for testing */
|
||||
void debug(Object msg) {
|
||||
for ( int i=0; i<offset; i++ ) {
|
||||
System.out.print(" ");
|
||||
}
|
||||
System.out.println(msg.toString());
|
||||
}
|
||||
|
||||
|
||||
public static void main ( String args[] ) {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue