This commit was manufactured by cvs2svn to create tag

'Pre1_2001_02_27_stable'.
This commit is contained in:
hns 2002-05-16 15:37:39 +00:00
parent 84f281fb77
commit 8bf0f8dee6
140 changed files with 7090 additions and 13818 deletions

View file

@ -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 );

View file

@ -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
{

View file

@ -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
}
}

View file

@ -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)";

View file

@ -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)

View file

@ -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");
}

View file

@ -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.

View file

@ -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
}
}

View file

@ -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");

View file

@ -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";
}
}

View file

@ -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;
}
}
}

View file

@ -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 ("");
}
}
}

View file

@ -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;
}
}

View file

@ -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";
}
}

View file

@ -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>&nbsp;</TD>");
else
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1><A HREF=\"" + urlPrefix + "app.html\"><FONT ID=NavBarFont1><B>Application</B></FONT></A>&nbsp;</TD>");
if ( page==PROTOTYPE )
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1Rev>&nbsp;<FONT ID=NavBarFont1Rev><B>Prototype</B></FONT>&nbsp;</TD>");
else if ( page==METHOD )
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1>&nbsp;<a href=\"" + urlPrefix + "prototype_" + pt.getName() + ".html\"><FONT ID=NavBarFont1><B>Prototype</B></A></FONT>&nbsp;</TD>");
else
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1>&nbsp;<FONT ID=NavBarFont1><B>Prototype</B></FONT>&nbsp;</TD>");
if ( page==INDEX )
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1Rev><FONT ID=NavBarFont1><B>Index</B></FONT>&nbsp;</TD>");
else
print("<TD BGCOLOR=#EEEEFF ID=NavBarCell1><A HREF=\"" + urlPrefix + "index-1.html\"><FONT ID=NavBarFont1><B>Index</B></FONT></A>&nbsp;</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>&nbsp;|&nbsp;");
print("<a href=\"#Templates\">TEMPLATES</a>&nbsp;|&nbsp;");
print("<a href=\"#Functions\">FUNCTIONS</a>&nbsp;|&nbsp;");
print("<a href=\"#Macros\">MACROS</a>&nbsp;|&nbsp;");
print("<a href=\"#Skins\">SKINS</a>&nbsp;");
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>&nbsp;" + dl[i].getTypeName() + "</CODE></FONT></TD>");
print("<TD><CODE><B><A HREF=\"" + dl[i].getDocFileName() + "\">" + dl[i].getName() + "</A></B></CODE>");
print("<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + 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>&nbsp;" + 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 "";
}
}
}

View file

@ -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";
}
}

View file

@ -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);
}
}

View file

@ -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 + "]";
}
}

View file

@ -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() ); }
}
}
}

View file

@ -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 ();
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -3,13 +3,14 @@
package helma.framework;
import FESI.Exceptions.EcmaScriptException;
/**
/**
* RedirectException is thrown internally when a response is redirected to a
* new URL.
*/
public class RedirectException extends RuntimeException {
public class RedirectException extends EcmaScriptException {
String url;
@ -17,17 +18,17 @@ public class RedirectException extends RuntimeException {
super ("Redirection Request to "+url);
this.url = url;
}
public String getMessage () {
return url;
return url;
}
public void printStackTrace(java.io.PrintStream s) {
public void printStackTrace(java.io.PrintStream s) {
// do nothing
}
public void printStackTrace(java.io.PrintWriter w) {
// do nothing
}
}

View file

@ -6,83 +6,52 @@ package helma.framework;
import java.io.*;
import java.util.*;
import helma.objectmodel.*;
import helma.xmlrpc.Base64;
/**
* A Transmitter for a request from the servlet client. Objects of this
* class are directly exposed to JavaScript as global property req.
*/
public class RequestTrans implements Externalizable {
public class RequestTrans implements Serializable {
// the uri path of the request
public String path;
// the request's session id
public String session;
// the map of form and cookie data
private Map values;
// the request method - 0 for GET, 1 for POST
private byte httpMethod = 0;
private Hashtable values;
// this is used to hold the EcmaScript form data object
public transient Object data;
// when was execution started on this request?
public transient long startTime;
// the name of the action being invoked
public transient String action;
private transient String httpUsername;
private transient String httpPassword;
static final long serialVersionUID = 5398880083482000580L;
/**
* Create a new Request transmitter with an empty data map.
*/
public RequestTrans () {
httpMethod = 0;
values = new HashMap ();
super ();
values = new Hashtable ();
}
/**
* Create a new request transmitter with the given data map.
*/
public RequestTrans (byte method) {
httpMethod = method;
values = new HashMap ();
public RequestTrans (Hashtable values) {
this.values = values;
}
/**
* Set a parameter value in this request transmitter.
*/
public void set (String name, Object value) {
values.put (name, value);
}
public Enumeration keys () {
return values.keys ();
}
/**
* Get a value from the requests map by key.
*/
public Object get (String name) {
try {
return values.get (name);
} catch (Exception x) {
return null;
return null;
}
}
/**
* Get the data map for this request transmitter.
*/
public Map getRequestData () {
public Hashtable getReqData () {
return values;
}
/**
* The hash code is computed from the session id if available. This is used to
* detect multiple identic requests.
*/
public int hashCode () {
return session == null ? super.hashCode () : session.hashCode ();
}
@ -97,80 +66,10 @@ public class RequestTrans implements Externalizable {
RequestTrans other = (RequestTrans) what;
return (session.equals (other.session) &&
path.equalsIgnoreCase (other.path) &&
values.equals (other.getRequestData ()));
values.equals (other.getReqData ()));
} catch (Exception x) {
return false;
}
}
/**
* Return true if this object represents a HTTP GET Request.
*/
public boolean isGet () {
return httpMethod == 0;
}
/**
* Return true if this object represents a HTTP GET Request.
*/
public boolean isPost () {
return httpMethod == 1;
}
/**
* Custom externalization code for quicker serialization.
*/
public void readExternal (ObjectInput s) throws ClassNotFoundException, IOException {
path = s.readUTF ();
session = s.readUTF ();
values = (Map) s.readObject ();
httpMethod = s.readByte ();
}
/**
* Custom externalization code for quicker serialization.
*/
public void writeExternal (ObjectOutput s) throws IOException {
s.writeUTF (path);
s.writeUTF (session);
s.writeObject (values);
s.writeByte (httpMethod);
}
public String getUsername() {
if ( httpUsername!=null )
return httpUsername;
String auth = (String)get("authorization");
if ( auth==null || "".equals(auth) ) {
return null;
}
decodeHttpAuth(auth);
return httpUsername;
}
public String getPassword() {
if ( httpPassword!=null )
return httpPassword;
String auth = (String)get("authorization");
if ( auth==null || "".equals(auth) ) {
return null;
}
decodeHttpAuth(auth);
return httpPassword;
}
private void decodeHttpAuth(String auth) {
if ( auth==null )
return;
StringTokenizer tok;
if( auth.startsWith("Basic ") )
tok = new StringTokenizer ( new String( Base64.decode((auth.substring(6)).toCharArray()) ), ":" );
else
tok = new StringTokenizer ( new String( Base64.decode(auth.toCharArray()) ), ":" );
try { httpUsername = tok.nextToken(); }
catch ( NoSuchElementException e ) { httpUsername = null; }
try { httpPassword = tok.nextToken(); }
catch ( NoSuchElementException e ) { httpPassword = null; }
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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 ());
}
}

View file

@ -2,11 +2,9 @@
// Copyright (c) Hannes Wallnöfer 1998-2000
package helma.scripting.fesi;
package helma.framework.core;
import helma.objectmodel.*;
import helma.objectmodel.db.*;
import helma.framework.core.*;
import helma.util.*;
import FESI.Interpreter.*;
import FESI.Exceptions.*;
@ -24,106 +22,158 @@ import java.util.*;
public class ESNode extends ObjectPrototype {
INode node;
// the cache node - persistent nodes have a transient property as a commodity to
// store temporary stuff.
INode cache;
// the ecmascript wrapper for the cache.
ESNode cacheWrapper;
// The handle of the wrapped Node. Makes ESNodes comparable without accessing the wrapped node.
NodeHandle handle;
// The ID of the wrapped Node. Makes ESNodes comparable without accessing the wrapped node.
String nodeID;
DbMapping dbmap;
ESObject cacheWrapper;
Throwable lastError = null;
FesiEvaluator eval;
RequestEvaluator eval;
/**
* Constructor used to create transient cache nodes
*/
public ESNode (INode node, FesiEvaluator eval) {
super (eval.getPrototype("hopobject"), eval.getEvaluator());
this.eval = eval;
this.node = node;
cache = null;
cacheWrapper = null;
// used to create cache nodes
protected ESNode (INode node, RequestEvaluator eval) {
super (eval.esNodePrototype, eval.evaluator);
this.eval = eval;
this.node = node;
cache = null;
// this is a transient node, set node handle to null
handle = null;
cacheWrapper = null;
nodeID = node.getID ();
dbmap = node.getDbMapping ();
}
public ESNode (ESObject prototype, Evaluator evaluator, Object obj, RequestEvaluator eval) {
super (prototype, evaluator);
// IServer.getLogger().log ("in ESNode constructor: "+o.getClass ());
this.eval = eval;
if (obj == null)
node = new Node ();
else if (obj instanceof ESWrapper)
node = (INode) ((ESWrapper) obj).getJavaObject ();
else if (obj instanceof INode)
node = (INode) obj;
else
node = new Node (obj.toString ());
// set nodeID to id of wrapped node
nodeID = node.getID ();
dbmap = node.getDbMapping ();
public ESNode (ESObject prototype, Evaluator evaluator, Object obj, FesiEvaluator eval) {
super (prototype, evaluator);
// eval.app.logEvent ("in ESNode constructor: "+o.getClass ());
this.eval = eval;
if (obj == null)
node = new TransientNode (null);
else if (obj instanceof ESWrapper)
node = (INode) ((ESWrapper) obj).getJavaObject ();
else if (obj instanceof INode)
node = (INode) obj;
else
node = new TransientNode (obj.toString ());
// set node handle to wrapped node
if (node instanceof Node)
handle = ((Node) node).getHandle ();
else
handle = null;
// cache Node is initialized on demend when it is needed
cache = null;
cacheWrapper = null;
// get transient cache Node
cache = node.getCacheNode ();
cacheWrapper = new ESNode (cache, eval);
}
/**
* Check if the node has been invalidated. If so, it has to be re-fetched
* from the db via the app's node manager.
*/
protected void checkNode () {
private void checkNode () {
if (node.getState () == INode.INVALID) try {
node = handle.getNode (eval.app.getWrappedNodeManager ());
setNode (eval.app.nmgr.getNode (node.getID (), node.getDbMapping ()));
} catch (Exception nx) {}
}
public INode getNode () {
checkNode ();
return node;
public INode getNode () {
checkNode ();
return node;
}
public void setNode (INode node) {
if (node != null) {
this.node = node;
nodeID = node.getID ();
dbmap = node.getDbMapping ();
eval.objectcache.put (node, this);
// get transient cache Node
cache = node.getCacheNode ();
cacheWrapper = new ESNode (cache, eval);
}
}
public void setPrototype (String protoName) {
checkNode ();
node.setPrototype (protoName);
checkNode ();
node.setPrototype (protoName);
}
public String getPrototypeName () {
return node.getPrototype ();
return node.getPrototype ();
}
public String getESClassName () {
return "HopObject";
return "HopObject";
}
public String toString () {
if (node == null)
return "<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);
@ -363,7 +423,7 @@ public class ESNode extends ObjectPrototype {
}
if (p.getType () == IProperty.BOOLEAN)
return ESBoolean.makeBoolean (p.getBooleanValue ());
if (p.getType () == IProperty.DATE)
if (p.getType () == IProperty.DATE)
return new DatePrototype (evaluator, p.getDateValue ());
if (p.getType () == IProperty.INTEGER)
return new ESNumber ((double) p.getIntegerValue ());
@ -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 ();
}
@ -457,13 +501,9 @@ public class ESNode extends ObjectPrototype {
public void clearError() {
lastError = null;
}
public Object toJavaObject () {
return getNode ();
}
/**
* An ESNode equals another object if it is an ESNode that wraps the same INode
/**
* An ESNode equals another object if it is an ESNode that wraps the same INode
* or the wrapped INode itself. FIXME: doesen't check dbmapping/type!
*/
public boolean equals (Object what) {
@ -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

View 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();
}
}

View 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 ());
}
}

View 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) {}
}
}
}
}

View file

@ -1,13 +1,10 @@
// HopExtension.java
// Copyright (c) Hannes Wallnöfer 1998-2000
package helma.scripting.fesi;
package helma.framework.core;
import helma.framework.*;
import helma.framework.core.*;
import helma.objectmodel.*;
import helma.util.*;
import helma.framework.IPathElement;
import FESI.Interpreter.*;
import FESI.Exceptions.*;
import FESI.Extensions.*;
@ -17,34 +14,33 @@ import java.util.*;
import java.text.*;
import org.xml.sax.InputSource;
/**
* This is the basic Extension for FESI interpreters used in Helma. It sets up
* varios constructors, global functions and properties on the HopObject prototype
* (Node objects), the user prototype, the global prototype etc.
/**
* This is the basic Extension for FESI interpreters used in HOP. It sets up
* varios constructors, global functions and properties etc.
*/
public class HopExtension {
protected Application app;
protected FesiEvaluator fesi;
public HopExtension (Application app) {
this.app = app;
public HopExtension () {
super();
}
/**
* Called by the evaluator after the extension is loaded.
*/
public void initializeExtension (FesiEvaluator fesi) throws EcmaScriptException {
this.fesi = fesi;
Evaluator evaluator = fesi.getEvaluator ();
public void initializeExtension (RequestEvaluator reval) throws EcmaScriptException {
this.app = reval.app;
Evaluator evaluator = reval.evaluator;
GlobalObject go = evaluator.getGlobalObject();
FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
ESObject op = evaluator.getObjectPrototype();
// The editor functions for String, Boolean and Number are deprecated!
////////// The editor functions for String, Boolean and Number are deprecated!
ESObject sp = evaluator.getStringPrototype ();
sp.putHiddenProperty ("editor", new StringEditor ("editor", evaluator, fp));
ESObject np = evaluator.getNumberPrototype ();
@ -55,87 +51,96 @@ public class HopExtension {
ESObject dp = evaluator.getDatePrototype ();
dp.putHiddenProperty ("format", new DatePrototypeFormat ("format", evaluator, fp));
sp.putHiddenProperty ("trim", new StringTrim ("trim", evaluator, fp));
reval.esNodePrototype = new ObjectPrototype(op, evaluator); // the Node prototype
// generic (Java wrapper) object prototype
ObjectPrototype esObjectPrototype = new ObjectPrototype (op, evaluator);
// the Node prototype
ObjectPrototype esNodePrototype = new ObjectPrototype(op, evaluator);
// the User prototype
ObjectPrototype esUserPrototype = new ObjectPrototype (esNodePrototype, evaluator);
// the Node constructor
ESObject node = new NodeConstructor ("Node", fp, fesi);
reval.esUserPrototype = new ObjectPrototype (reval.esNodePrototype, evaluator); // the User prototype
ESObject node = new NodeConstructor ("Node", fp, reval); // the Node constructor
// register the default methods of Node objects in the Node prototype
esNodePrototype.putHiddenProperty ("add", new NodeAdd ("add", evaluator, fp));
esNodePrototype.putHiddenProperty ("addAt", new NodeAddAt ("addAt", evaluator, fp));
esNodePrototype.putHiddenProperty ("remove", new NodeRemove ("remove", evaluator, fp));
esNodePrototype.putHiddenProperty ("link", new NodeLink ("link", evaluator, fp));
esNodePrototype.putHiddenProperty ("list", new NodeList ("list", evaluator, fp));
esNodePrototype.putHiddenProperty ("set", new NodeSet ("set", evaluator, fp));
esNodePrototype.putHiddenProperty ("get", new NodeGet ("get", evaluator, fp));
esNodePrototype.putHiddenProperty ("count", new NodeCount ("count", evaluator, fp));
esNodePrototype.putHiddenProperty ("contains", new NodeContains ("contains", evaluator, fp));
esNodePrototype.putHiddenProperty ("size", new NodeCount ("size", evaluator, fp));
esNodePrototype.putHiddenProperty ("editor", new NodeEditor ("editor", evaluator, fp));
esNodePrototype.putHiddenProperty ("path", new NodeHref ("path", evaluator, fp));
esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp));
esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp));
esNodePrototype.putHiddenProperty ("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false));
esNodePrototype.putHiddenProperty ("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true));
esNodePrototype.putHiddenProperty ("clearCache", new NodeClearCache ("clearCache", evaluator, fp));
// default methods for generic Java wrapper object prototype.
// This is a small subset of the methods in esNodePrototype.
esObjectPrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
esObjectPrototype.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, false, false));
esObjectPrototype.putHiddenProperty("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, false, true));
reval.esNodePrototype.putHiddenProperty ("add", new NodeAdd ("add", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("addAt", new NodeAddAt ("addAt", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("remove", new NodeRemove ("remove", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("link", new NodeLink ("link", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("list", new NodeList ("list", evaluator, fp, reval));
reval.esNodePrototype.putHiddenProperty ("set", new NodeSet ("set", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("get", new NodeGet ("get", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("count", new NodeCount ("count", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("contains", new NodeContains ("contains", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("size", new NodeCount ("size", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("editor", new NodeEditor ("editor", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("chooser", new NodeChooser ("chooser", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("multiChooser", new MultiNodeChooser ("multiChooser", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("getContent", new NodeGetContent ("getContent", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("setContent", new NodeSetContent ("setContent", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("path", new NodePath ("path", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp));
reval.esNodePrototype.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, reval, false, false));
reval.esNodePrototype.putHiddenProperty("renderSkin_as_string", new RenderSkin ("renderSkin_as_string", evaluator, fp, reval, false, true));
// methods that give access to properties and global user lists
go.putHiddenProperty("Node", node); // register the constructor for a plain Node object.
go.putHiddenProperty("HopObject", node); // HopObject is the new name for node.
go.putHiddenProperty("getProperty", new GlobalGetProperty ("getProperty", evaluator, fp));
go.putHiddenProperty("token", new GlobalGetProperty ("token", evaluator, fp));
go.putHiddenProperty("getUser", new GlobalGetUser ("getUser", evaluator, fp));
go.putHiddenProperty("getUserBySession", new GlobalGetUserBySession ("getUserBySession", evaluator, fp));
go.putHiddenProperty("getAllUsers", new GlobalGetAllUsers ("getAllUsers", evaluator, fp));
go.putHiddenProperty("getActiveUsers", new GlobalGetActiveUsers ("getActiveUsers", evaluator, fp));
go.putHiddenProperty("countActiveUsers", new GlobalCountActiveUsers ("countActiveUsers", evaluator, fp));
go.putHiddenProperty("getUser", new GlobalGetUser ("getUser", evaluator, fp, reval));
go.putHiddenProperty("getUserBySession", new GlobalGetUserBySession ("getUserBySession", evaluator, fp, reval));
go.putHiddenProperty("getAllUsers", new GlobalGetAllUsers ("getAllUsers", evaluator, fp, reval));
go.putHiddenProperty("getActiveUsers", new GlobalGetActiveUsers ("getActiveUsers", evaluator, fp, reval));
go.putHiddenProperty("isActive", new GlobalIsActive ("isActive", evaluator, fp));
go.putHiddenProperty("getAge", new GlobalGetAge ("getAge", evaluator, fp));
go.putHiddenProperty("getURL", new GlobalGetURL ("getURL", evaluator, fp));
go.putHiddenProperty("encode", new GlobalEncode ("encode", evaluator, fp));
go.putHiddenProperty("encodeXml", new GlobalEncodeXml ("encodeXml", evaluator, fp));
go.putHiddenProperty("encodeForm", new GlobalEncodeForm ("encodeForm", evaluator, fp));
go.putHiddenProperty("format", new GlobalFormat ("format", evaluator, fp));
go.putHiddenProperty("stripTags", new GlobalStripTags ("stripTags", evaluator, fp));
go.putHiddenProperty("getXmlDocument", new GlobalGetXmlDocument ("getXmlDocument", evaluator, fp));
go.putHiddenProperty("getHtmlDocument", new GlobalGetHtmlDocument ("getHtmlDocument", evaluator, fp));
go.putHiddenProperty("jdomize", new GlobalJDOM ("jdomize", evaluator, fp));
go.putHiddenProperty("getSkin", new GlobalCreateSkin ("getSkin", evaluator, fp));
go.putHiddenProperty("getSkin", new GlobalGetSkin ("getSkin", evaluator, fp));
go.putHiddenProperty("createSkin", new GlobalCreateSkin ("createSkin", evaluator, fp));
go.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, true, false));
go.putHiddenProperty("renderSkinAsString", new RenderSkin ("renderSkinAsString", evaluator, fp, true, true));
go.putHiddenProperty("authenticate", new GlobalAuthenticate ("authenticate", evaluator, fp));
go.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, reval, true, false));
go.putHiddenProperty("renderSkin_as_string", new RenderSkin ("renderSkin_as_string", evaluator, fp, reval, true, true));
go.deleteProperty("exit", "exit".hashCode());
// and some methods for session management from JS...
esUserPrototype.putHiddenProperty("logon", new UserLogin ("logon", evaluator, fp));
esUserPrototype.putHiddenProperty("login", new UserLogin ("login", evaluator, fp));
esUserPrototype.putHiddenProperty("register", new UserRegister ("register", evaluator, fp));
esUserPrototype.putHiddenProperty("logout", new UserLogout ("logout", evaluator, fp));
esUserPrototype.putHiddenProperty("onSince", new UserOnSince ("onSince", evaluator, fp));
esUserPrototype.putHiddenProperty("lastActive", new UserLastActive ("lastActive", evaluator, fp));
esUserPrototype.putHiddenProperty("touch", new UserTouch ("touch", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("logon", new UserLogin ("logon", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("login", new UserLogin ("login", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("register", new UserRegister ("register", evaluator, fp, reval));
reval.esUserPrototype.putHiddenProperty("logout", new UserLogout ("logout", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("onSince", new UserOnSince ("onSince", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("lastActive", new UserLastActive ("lastActive", evaluator, fp));
reval.esUserPrototype.putHiddenProperty("touch", new UserTouch ("touch", evaluator, fp));
// register object prototypes with FesiEvaluator
fesi.putPrototype ("global", go);
fesi.putPrototype ("hopobject", esNodePrototype);
fesi.putPrototype ("__javaobject__", esObjectPrototype);
fesi.putPrototype ("user", esUserPrototype);
}
class NodeSetContent extends BuiltinFunctionObject {
NodeSetContent (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
ESNode node = (ESNode) thisObject;
return ESBoolean.makeBoolean (node.setContent (arguments));
}
}
class NodeGetContent extends BuiltinFunctionObject {
NodeGetContent (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
ESNode node = (ESNode) thisObject;
Object content = node.getContent ();
if (content == null)
return ESNull.theNull;
else
return ESLoader.normalizeValue (content, this.evaluator);
}
}
class NodeAdd extends BuiltinFunctionObject {
NodeAdd (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
@ -178,8 +183,10 @@ public class HopExtension {
}
class NodeList extends BuiltinFunctionObject {
NodeList (String name, Evaluator evaluator, FunctionPrototype fp) {
RequestEvaluator reval;
NodeList (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
super(fp, evaluator, name, 0);
this.reval = reval;
}
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
ESNode node = (ESNode) thisObject;
@ -198,10 +205,7 @@ public class HopExtension {
esv = thisObject.getProperty (i);
} else {
String name = arguments[0].toString ();
// call esNodeProperty() method special to ESNode because we want to avoid
// retrieving prototype functions when calling hopobject.get().
ESNode esn = (ESNode) thisObject;
esv = esn.getNodeProperty (name);
esv = thisObject.getProperty (name, name.hashCode ());
}
return (esv);
}
@ -253,7 +257,10 @@ public class HopExtension {
INode node = esn.getNode ();
if (node instanceof helma.objectmodel.db.Node) {
((helma.objectmodel.db.Node) node).invalidate ();
esn.checkNode ();
try {
node = app.nmgr.getNode (node.getID (), node.getDbMapping ());
esn.setNode (node);
} catch (Exception x) {}
}
return ESBoolean.makeBoolean (true);
}
@ -406,21 +413,51 @@ public class HopExtension {
}
}
class StringTrim extends BuiltinFunctionObject {
StringTrim (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
return new ESString ( thisObject.toString().trim() );
}
}
class NodeChooser extends BuiltinFunctionObject {
NodeChooser (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
ESNode esn = (ESNode) thisObject;
if (arguments.length < 1) {
return ESBoolean.makeBoolean(false);
}
String nodename = arguments[0].toString ();
INode target = esn.getNode ().getNode (nodename, false);
ESNode collection = arguments.length > 1 ? (ESNode) arguments[1] : esn;
if (arguments.length > 2)
return new ESString (getNodeChooserDD (nodename, collection.getNode (), target, arguments[2].toString ()));
else
return new ESString (getNodeChooserRB (nodename, collection.getNode (), target));
}
}
class MultiNodeChooser extends BuiltinFunctionObject {
MultiNodeChooser (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
ESNode esn = (ESNode) thisObject;
if (arguments.length < 1) {
return ESBoolean.makeBoolean(false);
}
String nodename = arguments[0].toString ();
INode thisNode = esn.getNode ();
INode target = thisNode.getNode (nodename, false);
if (target == null) {
target = thisNode.createNode (nodename);
}
ESNode collection = arguments.length > 1 ? (ESNode) arguments[1] : esn;
return new ESString (getNodeChooserCB (nodename, collection.getNode (), target));
}
}
class UserLogin extends BuiltinFunctionObject {
UserLogin (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length < 2)
if (arguments.length < 2)
return ESBoolean.makeBoolean(false);
ESUser u = (ESUser) thisObject;
if (u.user == null)
@ -434,8 +471,10 @@ public class HopExtension {
}
class UserRegister extends BuiltinFunctionObject {
UserRegister (String name, Evaluator evaluator, FunctionPrototype fp) {
RequestEvaluator reval;
UserRegister (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {
super (fp, evaluator, name, 2);
this.reval = reval;
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length < 2)
@ -444,7 +483,7 @@ public class HopExtension {
if (unode == null)
return ESNull.theNull;
else
return fesi.getNodeWrapper (unode);
return reval.getNodeWrapper (unode);
}
}
@ -471,7 +510,7 @@ public class HopExtension {
ESUser u = (ESUser) thisObject;
if (u.user == null)
throw new EcmaScriptException ("onSince() can only be called for users that are online at the moment!");
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.onSince ()));
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.onSince));
return date;
}
}
@ -484,7 +523,7 @@ public class HopExtension {
ESUser u = (ESUser) thisObject;
if (u.user == null)
throw new EcmaScriptException ("lastActive() can only be called for users that are online at the moment!");
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.lastTouched ()));
DatePrototype date = new DatePrototype(this.evaluator, new Date (u.user.lastTouched));
return date;
}
}
@ -509,20 +548,28 @@ public class HopExtension {
if (arguments.length == 0)
return new ESString ("");
String defval = (arguments.length > 1) ? arguments[1].toString () : "";
return new ESString (app.getProperty (arguments[0].toString (), defval));
return new ESString (app.props.getProperty (arguments[0].toString (), defval));
}
}
class GlobalAuthenticate extends BuiltinFunctionObject {
GlobalAuthenticate (String name, Evaluator evaluator, FunctionPrototype fp) {
/**
* Get a parsed Skin from the central skin cache if possible, otherwise create it
*/
class GlobalGetSkin extends BuiltinFunctionObject {
GlobalGetSkin (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length != 2)
return ESBoolean.makeBoolean (false);
return ESBoolean.makeBoolean (app.authenticate (arguments[0].toString (), arguments[1].toString ()));
if (arguments.length != 1 || ESNull.theNull.equals (arguments[0]))
throw new EcmaScriptException ("getSkin must be called with one String argument!");
String str = arguments[0].toString ();
Skin skin = (Skin) app.skincache.get (str);
if (skin == null) {
skin = new Skin (str);
app.skincache.put (str, skin);
}
return new ESWrapper (skin, evaluator);
}
}
@ -535,14 +582,8 @@ public class HopExtension {
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length != 1 || ESNull.theNull.equals (arguments[0]))
throw new EcmaScriptException ("createSkin must be called with one String argument");
String str = arguments[0].toString ();
Skin skin = (Skin) app.skincache.get (str);
if (skin == null) {
skin = new Skin (str, app);
app.skincache.put (str, skin);
}
return new ESWrapper (skin, evaluator);
throw new EcmaScriptException ("createSkin must be called with one String argument!");
return new ESWrapper (new Skin (arguments[0].toString()), evaluator);
}
}
@ -550,29 +591,25 @@ public class HopExtension {
* Render a skin
*/
class RenderSkin extends BuiltinFunctionObject {
RequestEvaluator reval;
boolean global;
boolean asString;
RenderSkin (String name, Evaluator evaluator, FunctionPrototype fp, boolean global, boolean asString) {
RenderSkin (String name, Evaluator evaluator, FunctionPrototype fp,
RequestEvaluator reval, boolean global, boolean asString) {
super (fp, evaluator, name, 1);
this.reval = reval;
this.global = global;
this.asString = asString;
}
public ESValue callFunction (ESObject thisObj, ESValue[] arguments) throws EcmaScriptException {
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length < 1 || arguments.length > 2 || arguments[0] ==null || arguments[0] == ESNull.theNull)
throw new EcmaScriptException ("renderSkin requires one argument containing the skin name and an optional parameter object argument");
throw new EcmaScriptException ("renderSkin must be called with one Skin argument and an optional parameter argument");
try {
Skin skin = null;
ESObject thisObject = global ? null : thisObj;
HashMap params = null;
if (arguments.length > 1 && arguments[1] instanceof ESObject) {
// create an parameter object to pass to the skin
ESObject paramObject = (ESObject) arguments[1];
params = new HashMap ();
for (Enumeration en=paramObject.getProperties(); en.hasMoreElements(); ) {
String propname = (String) en.nextElement();
params.put (propname, paramObject.getProperty (propname, propname.hashCode()).toJavaObject());
}
}
Skin skin = null;
ESNode handlerNode = global ? null : (ESNode) thisObject;
ESObject paramObject = null;
if (arguments.length > 1 && arguments[1] instanceof ESObject)
paramObject = (ESObject) arguments[1];
// first, see if the first argument already is a skin object. If not, it's the name of the skin to be called
if (arguments[0] instanceof ESWrapper) {
@ -581,41 +618,16 @@ public class HopExtension {
skin = (Skin) obj;
}
// if res.skinpath is set, transform it into an array of java objects
// (strings for directory names and INodes for internal, db-stored skinsets)
ResponseTrans res = fesi.getResponse();
Object[] skinpath = res.getTranslatedSkinpath ();
if (skinpath == null) {
skinpath = new Object[0];
Object rawSkinpath = res.getSkinpath ();
if (rawSkinpath != null && rawSkinpath instanceof JSWrapper) {
JSWrapper jsw = (JSWrapper) rawSkinpath;
ESObject eso = jsw.getESObject ();
if (eso instanceof ArrayPrototype) {
ArrayPrototype array = (ArrayPrototype) eso;
skinpath = new Object[array.size()];
for (int i=0; i<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);
}
if (skin != null) {
return renderSkin (skin, basicHref, skinElem);
}
}
return new ESString (basicHref);
}
private ESString renderSkin (Skin skin, String path, Object skinElem) throws EcmaScriptException {
fesi.getResponse().pushStringBuffer ();
HashMap param = new HashMap ();
param.put ("path", path);
skin.render (fesi.getRequestEvaluator(), skinElem, param);
return new ESString (fesi.getResponse().popStringBuffer ().trim ());
return new ESString (app.getNodeHref (n, tmpname));
}
}
@ -1002,7 +978,7 @@ public class HopExtension {
double d = from <= to ? 1.0 : -1.0;
for (double i=from; i*d<=to*d; i+=step) {
if (Math.abs (i%1) < l) {
int j = (int) i;
int j = (int) i;
b.append ("<option value=\""+j);
if (i == value) b.append ("\" selected=\"true");
b.append ("\">"+j);
@ -1015,7 +991,165 @@ public class HopExtension {
b.append ("</select>");
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 ();
}
}

View file

@ -1,10 +1,8 @@
// NodeConstructor.java
// Copyright (c) Hannes Wallnöfer 2000
package helma.scripting.fesi;
package helma.framework.core;
import helma.objectmodel.db.Node;
import helma.framework.core.*;
import FESI.Data.*;
import FESI.Exceptions.*;
import FESI.Interpreter.*;
@ -15,14 +13,14 @@ import FESI.Interpreter.*;
*/
public class NodeConstructor extends BuiltinFunctionObject {
FesiEvaluator fesi;
RequestEvaluator reval;
String typename;
public NodeConstructor (String name, FunctionPrototype fp, FesiEvaluator fesi) {
super(fp, fesi.getEvaluator (), name, 1);
public NodeConstructor (String name, FunctionPrototype fp, RequestEvaluator reval) {
super(fp, reval.evaluator, name, 1);
typename = name;
this.fesi = fesi;
this.reval = reval;
}
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
@ -31,33 +29,32 @@ public class NodeConstructor extends BuiltinFunctionObject {
public ESObject doConstruct(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
ESNode node = null;
Application app = fesi.getApplication ();
if ("Node".equals (typename) || "hopobject".equalsIgnoreCase (typename)) {
String nodeName = null;
if (arguments.length > 0 && arguments[0] != null)
nodeName = arguments[0].toString();
Node n = new Node (nodeName, (String) null, app.getWrappedNodeManager ());
node = new ESNode (fesi.getPrototype ("hopobject"), this.evaluator, n, fesi);
fesi.putNodeWrapper (node.getNode (), node);
if (arguments.length == 0) {
node = new ESNode (reval.esNodePrototype, this.evaluator, null, reval);
reval.objectcache.put (node.getNode (), node);
} else {
node = new ESNode (reval.esNodePrototype, this.evaluator, arguments[0], reval);
reval.objectcache.put (node.getNode (), node);
}
} else {
// Typed nodes are instantiated as helma.objectmodel.db.Node from the beginning
// even if we don't know yet if they are going to be stored in a database. The reason
// is that we want to be able to use the specail features like subnode relations even for
// transient nodes.
ObjectPrototype op = fesi.getPrototype (typename);
Node n = new Node (typename, typename, app.getWrappedNodeManager ());
node = new ESNode (op, fesi.getEvaluator (), n, fesi);
ObjectPrototype op = reval.getPrototype (typename);
node = new ESNode (op, reval.evaluator, typename, reval);
node.setPrototype (typename);
node.getNode ().setDbMapping (app.getDbMapping (typename));
node.getNode ().setDbMapping (reval.app.getDbMapping (typename));
try {
// first try calling "constructor", if that doesn't work, try calling a function
// with the name of the type.
// HACK: There is an incompatibility problem here, because the property
// constructor is defined as the constructor of the object by EcmaScript.
if (op.getProperty ("constructor", "constructor".hashCode()) instanceof ConstructedFunctionObject)
node.doIndirectCall (fesi.getEvaluator(), node, "constructor", arguments);
if (op.getProperty("constructor", "constructor".hashCode()) instanceof ConstructedFunctionObject)
node.doIndirectCall (reval.evaluator, node, "constructor", arguments);
else
node.doIndirectCall (fesi.getEvaluator(), node, typename, arguments);
node.doIndirectCall (reval.evaluator, node, typename, arguments);
} catch (Exception ignore) {}
}
return node;
@ -68,9 +65,9 @@ public class NodeConstructor extends BuiltinFunctionObject {
}
public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException {
if ("prototype".equals (propertyName))
return fesi.getPrototype (typename);
return super.getProperty(propertyName, hash);
if ("prototype".equals (propertyName))
return reval.getPrototype (typename);
return super.getProperty(propertyName, hash);
}
public String[] getSpecialPropertyNames() {

View file

@ -3,13 +3,12 @@
package helma.framework.core;
import java.util.HashMap;
import java.util.Iterator;
import java.util.*;
import java.io.*;
import helma.framework.*;
import helma.scripting.*;
import helma.objectmodel.*;
import helma.util.Updatable;
import FESI.Data.*;
import FESI.Exceptions.EcmaScriptException;
/**
@ -25,65 +24,54 @@ public class Prototype {
String id;
String name;
Application app;
public HashMap templates, functions, actions, skins, updatables;
Hashtable templates, functions, actions, skins;
File codeDir;
long lastUpdate;
Prototype parent;
DbMapping dbmap;
// Tells us whether this prototype is used to script a generic Java object,
// as opposed to a Helma objectmodel node object.
boolean isJavaPrototype;
Prototype prototype;
public Prototype (String name, Application app) {
// app.logEvent ("Constructing Prototype "+app.getName()+"/"+name);
public Prototype (File codeDir, Application app) {
IServer.getLogger().log ("Constructing Prototype "+app.getName()+"/"+codeDir.getName ());
this.codeDir = codeDir;
this.app = app;
this.name = name;
isJavaPrototype = app.isJavaPrototype (name);
lastUpdate = 0; // System.currentTimeMillis ();
}
this.name = codeDir.getName ();
File propfile = new File (codeDir, "type.properties");
SystemProperties props = new SystemProperties (propfile.getAbsolutePath ());
dbmap = new DbMapping (app, name, props);
lastUpdate = System.currentTimeMillis ();
/**
* Return the application this prototype is a part of
*/
public Application getApplication () {
return app;
}
/**
* Set the parent prototype of this prototype, i.e. the prototype this one inherits from.
*/
public void setParentPrototype (Prototype parent) {
// this is not allowed for the hopobject and global prototypes
if ("hopobject".equalsIgnoreCase (name) || "global".equalsIgnoreCase (name))
return;
Prototype old = this.parent;
this.parent = parent;
public Action getActionOrTemplate (String aname) {
// if parent has changed, update ES-prototypes in request evaluators
if (parent != old) {
/* Iterator evals = app.typemgr.getRegisteredRequestEvaluators ();
while (evals.hasNext ()) {
try {
RequestEvaluator reval = (RequestEvaluator) evals.next ();
ObjectPrototype op = reval.getPrototype (getName());
// use hopobject (node) as prototype even if prototype is null -
// this is the case if no hopobject directory exists
ObjectPrototype opp = parent == null ?
reval.esNodePrototype : reval.getPrototype (parent.getName ());
// don't think this is possible, but check anyway
if (opp == null)
opp = reval.esNodePrototype;
op.setPrototype (opp);
} catch (Exception ignore) {
}
} */
}
Action retval = null;
if (aname == null || "".equals (aname))
aname = "main";
retval = (Action) actions.get (aname);
// check if it's allowed to access templates via URL
// this should be cached in the future
if (retval == null && "true".equalsIgnoreCase (app.props.getProperty ("exposetemplates")))
retval = (Action) templates.get (aname);
// if still not found, check if the action is defined for the generic node prototype
if (retval == null && this != app.typemgr.nodeProto && app.typemgr.nodeProto != null)
retval = app.typemgr.nodeProto.getActionOrTemplate (aname);
return retval;
}
public Prototype getParentPrototype () {
return parent;
public void setPrototype (Prototype prototype) {
this.prototype = prototype;
}
public Prototype getPrototype () {
return prototype;
}
public Template getTemplate (String tmpname) {
@ -94,8 +82,8 @@ public class Prototype {
return (FunctionFile) functions.get (ffname);
}
public ActionFile getActionFile (String afname) {
return (ActionFile) actions.get (afname);
public Action getAction (String afname) {
return (Action) actions.get (afname);
}
public SkinFile getSkinFile (String sfname) {
@ -110,29 +98,131 @@ public class Prototype {
return null;
}
public File getCodeDir () {
return codeDir;
}
public synchronized boolean checkCodeDir () {
boolean retval = false;
String[] list = codeDir.list ();
for (int i=0; i<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

View file

@ -1,136 +1,69 @@
// Skin.java
// Copyright (c) Hannes Wallnöfer 2001
package helma.framework.core;
import helma.framework.*;
import helma.scripting.*;
import helma.objectmodel.INode;
import helma.objectmodel.ConcurrencyException;
import helma.util.HtmlEncoder;
import java.net.URLEncoder;
import java.io.*;
import java.util.*;
import java.io.*;
import helma.framework.*;
import FESI.Data.*;
import FESI.Exceptions.*;
import helma.objectmodel.INode;
import helma.objectmodel.IServer;
/**
* This represents a Helma skin, i.e. a template created from containing Macro tags
* that will be dynamically evaluated.. It uses the request path array
* from the RequestEvaluator object to resolve Macro handlers by type name.
* This represents a HOP skin, i.e. a template created from JavaScript. It uses the request path array
* from the RequestEvaluator object to resolve dynamic tokens.
*/
public class Skin {
Macro[] parts;
Application app;
char[] source;
int sourceLength;
HashSet sandbox;
Object[] parts;
/**
* Create a skin without any restrictions on which macros are allowed to be called from it
*/
public Skin (String content, Application app) {
this (content, app, null);
public Skin (String content) {
parse (content);
}
/**
* Create a skin with a sandbox which contains the names of macros allowed to be called
*/
public Skin (String content, Application app, HashSet sandbox) {
this.app = app;
this.sandbox = sandbox;
source = content.toCharArray ();
sourceLength = source.length;
parse ();
}
public void parse (String content) {
/**
* Create a skin without any restrictions on the macros from a char array.
*/
public Skin (char[] content, int length, Application app) {
this.app = app;
this.sandbox = null;
this.source = content;
this.sourceLength = length;
parse ();
}
Vector partBuffer = new Vector ();
int l = content.length ();
char cnt[] = new char[l];
content.getChars (0, l, cnt, 0);
/**
* Parse a skin object from source text
*/
private void parse () {
ArrayList partBuffer = new ArrayList ();
int start = 0;
for (int i = 0; i < sourceLength-1; i++) {
if (source[i] == '<' && source[i+1] == '%') {
// found macro start tag
int lastIdx = 0;
for (int i = 0; i < l-1; i++) {
if (cnt[i] == '<' && cnt[i+1] == '%') {
int j = i+2;
// search macr end tag
while (j < sourceLength-1 && (source[j] != '%' || source[j+1] != '>')) {
while (j < l-1 && (cnt[j] != '%' || cnt[j+1] != '>')) {
j++;
}
if (j > i+2) {
partBuffer.add (new Macro (i, j+2));
start = j+2;
if (i - lastIdx > 0)
partBuffer.addElement (new String (cnt, lastIdx, i - lastIdx));
String macrotext = new String (cnt, i+2, (j-i)-2);
partBuffer.addElement (new Macro (macrotext));
lastIdx = j+2;
}
i = j+1;
}
}
if (lastIdx < l)
partBuffer.addElement (new String (cnt, lastIdx, l - lastIdx));
parts = new Macro[partBuffer.size()];
partBuffer.toArray (parts);
}
/**
* Get the raw source text this skin was parsed from
*/
public String getSource () {
return new String (source, 0, sourceLength);
}
/**
* Render this skin
*/
public void render (RequestEvaluator reval, Object thisObject, HashMap paramObject) throws RedirectException {
parts = partBuffer.toArray ();
}
public void render (RequestEvaluator reval, ESNode thisNode, ESObject paramObject) {
if (parts == null)
reval.res.writeCharArray (source, 0, sourceLength);
int written = 0;
return;
for (int i=0; i<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;
}
}
}

View file

@ -5,7 +5,7 @@ package helma.framework.core;
import java.util.*;
import java.io.*;
import helma.util.Updatable;
import helma.objectmodel.IServer;
/**
@ -13,7 +13,7 @@ import helma.util.Updatable;
*/
public class SkinFile implements Updatable {
public class SkinFile {
String name;
Prototype prototype;
@ -30,65 +30,28 @@ public class SkinFile implements Updatable {
this.skin = null;
}
/**
* Create a skinfile without a file, passing the skin body directly. This is used for
* Skins contained in zipped applications. The whole update mechanism is bypassed
* by immediately setting the skin member.
*/
public SkinFile (String body, String name, Prototype proto) {
this.prototype = proto;
this.app = proto.app;
this.name = name;
this.file = null;
this.skin = new Skin (body, app);
}
/**
* Create a skinfile without that doesn't belong to a prototype, or at
* least it doesn't know about its prototype and isn't managed by the prototype.
*/
public SkinFile (File file, String name, Application app) {
this.prototype = null;
this.app = app;
this.name = name;
this.file = file;
this.skin = null;
}
public void update (File f) {
this.file = f;
/**
* Tell the type manager whether we need an update. this is the case when
* the file has been modified or deleted.
*/
public boolean needsUpdate () {
return (skin != null && lastmod != file.lastModified ()) || !file.exists ();
}
long fmod = file.lastModified ();
// we only update this if we already have read the skin
if (skin == null || lastmod == fmod)
return;
public void update () {
if (!file.exists ()) {
// remove skin from prototype
if (prototype != null) {
prototype.skins.remove (name);
prototype.updatables.remove (file.getName());
}
} else {
// we only need to update if the skin has already been initialized
if (skin != null)
read ();
}
read ();
}
private void read () {
try {
FileReader reader = new FileReader (file);
char c[] = new char[(int) file.length()];
int length = reader.read (c);
reader.read (c);
reader.close();
skin = new Skin (c, length, app);
skin = new Skin (new String (c));
} catch (IOException x) {
app.logEvent ("Error reading Skin "+file+": "+x);
IServer.getLogger().log ("Error reading Skin "+file+": "+x);
}
lastmod = file.lastModified ();
@ -99,15 +62,45 @@ public class SkinFile implements Updatable {
read ();
return skin;
}
public String getName () {
return name;
}
public String toString () {
return prototype.getName()+"/"+file.getName();
}
}

View file

@ -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 ();
}
}
}

View file

@ -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
* as EcmaScript and parts that are to be delivered to the client as-is.
* 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;
@ -130,7 +120,7 @@ public class Template extends ActionFile {
// append the number of lines we have "swallowed" into
// one write statement, so error messages will *approximately*
// give correct line numbers.
for (int i=0; i<newLineCount; i++) {
for (int i=0; i<newLineCount; i++) {
templateBody.append ("\r\n");
}
@ -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 {
}
}

View file

@ -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();
}
}
}
} catch (Exception ignore) {
IServer.getLogger().log (this+": "+ignore);
}
// 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);
}
}
}
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 ();
} */
}
}

View file

@ -7,46 +7,29 @@ import java.io.*;
import java.util.*;
import java.net.URLEncoder;
import helma.objectmodel.*;
import helma.objectmodel.db.*;
/**
* This represents a user who is currently using the Hop application. This does
* not just comprend registered users, but anybody who happens to surf the site.
* Depending on whether the user is logged in or not, the user object holds a
* persistent user node or just a transient cache node
* This represents a user who is currently using the HOP application. This does
* not just comprend registered users, but anybody who happens to surf the site.
*/
public class User implements Serializable {
Application app;
String sessionID;
// the unique id (login name) for the user, if logged in
String uid;
// the handle to this user's persistent db node, if logged in
NodeHandle nhandle;
// the transient cache node. This stays the same across logins and logouts.
// If logged out, this also represents the user's main node.
TransientNode cache;
DbMapping umap;
String uid, nid;
long onSince, lastTouched;
// used to remember messages to the user between requests -
// used for redirects.
Node cache;
DbMapping umap;
String message;
public User (String sid, Application app) {
this.uid = null;
this.nhandle = null;
this.app = app;
setNode (null);
umap = app.getDbMapping ("user");
cache = new TransientNode ("[session cache]");
cache.setPrototype ("user");
cache.setDbMapping (umap);
this.nid = null;
this.app = app;
setNode (null);
cache = new Node (sid);
cache.setPrototype ("user");
sessionID = sid;
onSince = System.currentTimeMillis ();
lastTouched = onSince;
@ -54,38 +37,26 @@ public class User implements Serializable {
/**
* This is used to turn for login and logout.
* Calling this weith a DB Node object will turn an anonymous user into a registered or known one.
* The user object remains the same, but he or she gets some persistent storage.
* On the other side, calling this method with a parameter value of null is means the user
* is logged out and will be represented by its transient cache node.
* This is used to turn an anonymous user into a registered or known one.
* The user object remains the same, but she gets some persistent storage.
*/
public void setNode (INode n) {
// IServer.getLogger().log ("esn = "+esn);
if (n == null) {
nhandle = null;
nid = null;
uid = null;
} else {
uid = n.getElementName ();
nhandle = ((Node) n).getHandle ();
uid = n.getNameOrID ();
nid = n.getID ();
umap = n.getDbMapping ();
}
// System.err.println ("User.setNode: "+nhandle);
}
public INode getNode () {
if (nhandle == null) {
if (uid == null) {
return cache;
} else {
// in some special cases, a user's node handle may go bad, for instance
// if something bad happens during registration. For this reason, we check
// if the handle actually works. If not, it is reset to the transient cache, which
// means the user is logged out.
Node n = nhandle.getNode (app.nmgr.safe);
if (n == null) {
setNode (null);
return cache;
}
return n;
return app.nmgr.safe.getNode (nid, umap);
}
}
@ -98,37 +69,39 @@ public class User implements Serializable {
lastTouched = System.currentTimeMillis ();
}
public long lastTouched () {
public long touched () {
return lastTouched;
}
public long onSince () {
return onSince;
}
/**
* Get the persistent user id of a registered user. This is usually the user name, or
* null if the user is not logged in.
*/
public String getUID () {
return uid;
}
/**
* Return the transient cache node for this user.
*/
public INode getCache () {
return cache;
}
/**
* Reset the session cache node, clearing all properties.
* This is done by recreating the cache node object.
*/
public void clearCache () {
cache = new TransientNode ("[session cache]");
cache.setPrototype ("user");
cache.setDbMapping (umap);
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -16,12 +16,11 @@
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Modified to use Helma database connections, Hannes Wallnöfer 2000
// Modified to use HOP database connections, Hannes Wallnöfer 2000
package helma.scripting.fesi.extensions;
package helma.framework.extensions;
import helma.framework.core.Application;
import helma.objectmodel.db.DbSource;
import helma.objectmodel.*;
import FESI.Parser.*;
import FESI.AST.*;
import FESI.Interpreter.*;
@ -60,12 +59,13 @@ class ESDatabase extends ESObject {
ESDatabase(ESObject prototype,
Evaluator evaluator,
ESObject esRowSetPrototype,
DbSource dbsource, int flag) {
String dbsource, int flag) {
super(prototype, evaluator);
this.esRowSetPrototype = esRowSetPrototype; // specific to an evaluator
try {
connection = dbsource.getConnection ();
driverName = dbsource.getDriverName ();
DbSource src = (DbSource) IServer.dbSources.get (dbsource.toLowerCase ());
connection = src.getConnection ();
this.driverName = src.getDriverName ();
} catch (Exception e) {
// System.err.println("##Cannot find driver class: " + e);
// e.printStackTrace();
@ -717,17 +717,11 @@ public class Database extends Extension {
private transient Evaluator evaluator = null;
private ESObject esDatabasePrototype = null;
private ESObject esRowSetPrototype = null;
Application app;
public Database () {
super();
}
public void setApplication (Application app) {
this.app = app;
}
////////////////// Added by Hannes Wallnoefer
class GlobalGetDBConnection extends BuiltinFunctionObject {
GlobalGetDBConnection(String name, Evaluator evaluator, FunctionPrototype fp) {
@ -737,17 +731,13 @@ public class Database extends Extension {
throws EcmaScriptException {
if (arguments.length != 1)
throw new EcmaScriptException ("Wrong number of arguments in getDBConnection(dbsource)");
String srcname = arguments[0].toString ();
DbSource dbsrc = app.getDbSource (srcname.toLowerCase ());
if (dbsrc == null)
throw new EcmaScriptException ("DbSource "+srcname+" does not exist");
ESDatabase db = new ESDatabase (esDatabasePrototype, this.evaluator,
esRowSetPrototype, dbsrc, 0);
esRowSetPrototype, arguments[0].toString(), 0);
return db;
}
}
class GlobalObjectDatabase extends BuiltinFunctionObject {
GlobalObjectDatabase(String name, Evaluator evaluator, FunctionPrototype fp) {
super(fp, evaluator, name, 1);

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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());

View file

@ -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);
}

View 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 ());
}
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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) {

View file

@ -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);
}

View file

@ -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";
}
}

View file

@ -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.*;

View file

@ -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.*;

View file

@ -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.*;

View file

@ -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

View file

@ -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.* ;

View file

@ -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 {

View file

@ -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.

View file

@ -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.*;

View file

@ -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 {

View file

@ -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.* ;

View file

@ -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;

View 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;
}
}

View 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;
}
}

View file

@ -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);
}

View 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);
}

View file

@ -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;
}

View 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);
}

View 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;
}
}

View 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+"]";
}
}

View file

@ -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;
}
}

View 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;
}
}

View file

@ -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 ();
}
}
}

View 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;
}
}

View file

@ -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 ();
}
}

View file

@ -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);
}
}

View file

@ -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+"]";
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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));
}
}

View file

@ -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.");
}
}
@ -39,4 +40,4 @@ public class HopSocketFactory extends RMISocketFactory {
return new ParanoidServerSocket (port, filter);
}
}
}

View file

@ -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

View file

@ -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

View file

@ -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+"]";
}
}

View file

@ -23,8 +23,8 @@ public final class Property implements IProperty, Serializable, Cloneable {
protected boolean bvalue;
protected long lvalue;
protected double dvalue;
// protected String nvalueID;
protected NodeHandle nhandle;
protected String nvalueID;
private transient DbMapping dbm;
protected Object jvalue;
protected int type;
@ -40,11 +40,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
type = in.readInt ();
switch (type) {
case STRING:
// try to convert from old format
if (node.version < 7)
svalue = in.readUTF ();
else
svalue = (String) in.readObject ();
svalue = in.readUTF ();
break;
case BOOLEAN:
bvalue = in.readBoolean ();
@ -57,11 +53,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
dvalue = in.readDouble ();
break;
case NODE:
// try to convert from old format
if (node.version > 4)
nhandle = (NodeHandle) in.readObject ();
else
nhandle = new NodeHandle (new DbKey (null, in.readUTF ()));
nvalueID = in.readUTF ();
break;
case JAVAOBJECT:
jvalue = in.readObject ();
@ -73,12 +65,15 @@ public final class Property implements IProperty, Serializable, Cloneable {
}
private void writeObject (ObjectOutputStream out) throws IOException {
// don't even start if this is a non-serializable Java object
if (type == JAVAOBJECT && jvalue != null && !(jvalue instanceof Serializable))
return;
out.writeUTF (propname);
out.writeObject (node);
out.writeInt (type);
switch (type) {
case STRING:
out.writeObject (svalue);
out.writeUTF (svalue);
break;
case BOOLEAN:
out.writeBoolean (bvalue);
@ -91,13 +86,10 @@ public final class Property implements IProperty, Serializable, Cloneable {
out.writeDouble (dvalue);
break;
case NODE:
out.writeObject (nhandle);
out.writeUTF (nvalueID);
break;
case JAVAOBJECT:
if (jvalue != null && !(jvalue instanceof Serializable))
out.writeObject (null);
else
out.writeObject (jvalue);
out.writeObject (jvalue);
break;
}
}
@ -117,7 +109,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
public Property (String propname, Node node, Node value) {
this (propname, node);
type = NODE;
nhandle = value == null ? null : value.getHandle ();
nvalueID = value == null ? null : value.getID ();
dirty = true;
}
@ -148,11 +140,41 @@ public final class Property implements IProperty, Serializable, Cloneable {
public void setStringValue (String value) {
if (type == NODE)
unregisterNode ();
// IServer.getLogger().log ("setting string value of property "+propname + " to "+value);
// mark property as dirty
dirty = true;
// if this is not a string property, try to parse a value out of it
if (type == DATE) {
SimpleDateFormat dateformat = new SimpleDateFormat ();
try {
dateformat.setLenient (true);
Date date = dateformat.parse (value);
this.lvalue = date.getTime ();
return;
} catch (ParseException nodate) {
IServer.getLogger().log ("Couldn't parse date: was expecting something like "+dateformat.format (new Date()));
// store as plain string
}
}
if (type == BOOLEAN) {
if ("true".equalsIgnoreCase (value))
this.bvalue = true;
else if ("false".equalsIgnoreCase (value))
this.bvalue = false;
return;
}
if (type == INTEGER) {
this.lvalue = Long.parseLong (value);
return;
}
if (type == FLOAT) {
this.dvalue = new Double (value).doubleValue ();
return;
}
if (type == JAVAOBJECT)
this.jvalue = null;
type = STRING;
this.svalue = value;
dirty = true;
type = STRING;
}
@ -197,16 +219,39 @@ public final class Property implements IProperty, Serializable, Cloneable {
}
public void setNodeValue (Node value) {
// value.checkWriteLock ();
value.checkWriteLock ();
if (type == NODE)
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
// registerNode (value);
registerNode (value);
type = NODE;
nhandle = value.getHandle ();
if (node.dbmap != null) {
Relation rel = node.dbmap.getPropertyRelation (propname);
if (rel != null && rel.other != null) {
DbMapping vmap = value.getDbMapping ();
// check if actual type matches expected type
if (rel.other != vmap && (!rel.virtual || rel.prototype != null)) {
throw new RuntimeException ("Can't assign property: expected prototype "+rel.other+", got "+vmap);
}
// check if this is a forward relation, i.e. if we point to a field in the value object
// if so, we may use something else than the object's id to refer to it.
if (!rel.virtual && rel.direction == Relation.FORWARD) {
if (rel.usesPrimaryKey ()) {
this.nvalueID = value.getID ();
} else try {
this.nvalueID = value.getString (vmap.columnNameToProperty (rel.getRemoteField()).propname, false);
} catch (Exception x) {
throw new RuntimeException ("Can't set "+propname+" to "+value+": error retrieving target property");
}
this.dbm = null;
dirty = true;
return;
}
}
}
this.nvalueID = value == null ? null : value.getID ();
this.dbm = value == null ? null : value.getDbMapping ();
dirty = true;
}
@ -223,39 +268,48 @@ public final class Property implements IProperty, Serializable, Cloneable {
* If this was the "main" property for the node, also remove all other references.
*/
protected void unregisterNode () {
Node nvalue = null;
if (nhandle != null)
nvalue = nhandle.getNode (node.nmgr);
DbMapping nvmap = null;
Relation nvrel = null;
if (node.dbmap != null) {
nvmap = node.dbmap.getPropertyMapping (propname);
nvrel = node.dbmap.getPropertyRelation (propname);
}
if (nvalue == null)
return;
nvalue.checkWriteLock ();
// check if the property node is also a subnode
// BUG: this doesn't work because properties for subnode/properties are never stored and therefore
// never reused.
if (nvrel != null && nvrel.subnodesAreProperties) {
node.removeNode (nvalue);
}
// only need to call unregisterPropLink if the value node is not stored in a relational db
// also, getParent is heuristical/implicit for relational nodes, so we don't do deepRemoveNode
// based on that for relational nodes.
if (nvmap == null || !nvmap.isRelational()) {
if (!nvalue.isAnonymous() && propname.equals (nvalue.getName()) && this.node == nvalue.getParent()) {
// this is the "main" property of a named node, so handle this as a cascading delete.
nvalue.deepRemoveNode ();
if (nvalueID != null) {
DbMapping nvmap = null;
Relation nvrel = null;
if (node.dbmap != null) {
nvmap = node.dbmap.getPropertyMapping (propname);
nvrel = node.dbmap.getPropertyRelation (propname);
}
Node nvalue = node.nmgr.getNode (nvalueID, nvmap);
if (nvalue == null)
return;
nvalue.checkWriteLock ();
// check if the property node is also a subnode
// BUG: this doesn't work because properties for subnode/properties are never stored and therefore
// never reused.
if (nvrel != null && nvrel.subnodesAreProperties) {
node.removeNode (nvalue);
}
// only need to call unregisterPropLink if the value node is not stored in a relational db
// also, getParent is heuristical/implicit for relational nodes, so we don't do deepRemoveNode
// based on that for relational nodes.
if (nvmap == null || !nvmap.isRelational()) {
if (!nvalue.isAnonymous() && propname.equals (nvalue.getName()) && this.node == nvalue.getParent()) {
// this is the "main" property of a named node, so handle this as a cascading delete.
nvalue.deepRemoveNode ();
} else {
nvalue.unregisterPropLink (this.node);
}
}
}
}
/**
* Tell the value node that it is being used as a property value.
*/
protected void registerNode (Node n) {
// only need to call registerPropLink if the value node is not stored in a relational db
if (n != null && (n.dbmap == null || !n.dbmap.isRelational())) {
n.registerPropLink (this.node);
}
}
public String getStringValue () {
switch (type) {
case STRING:
@ -270,9 +324,9 @@ public final class Property implements IProperty, Serializable, Cloneable {
case FLOAT:
return Double.toString (dvalue);
case NODE:
return nhandle.getID ();
return nvalueID;
case JAVAOBJECT:
return jvalue == null ? null : jvalue.toString ();
return jvalue.toString ();
}
return "";
}
@ -307,10 +361,46 @@ public final class Property implements IProperty, Serializable, Cloneable {
}
public INode getNodeValue () {
if (nhandle != null) {
Node n = nhandle.getNode (node.nmgr);
if (n != null) return n;
if (type == NODE && nvalueID != null) {
Relation rel = null;
if (dbm == null && node.dbmap != null) {
// try to get DbMap for property, if it isn't known yet
rel = node.dbmap.getPropertyRelation (propname);
// figure out db mapping from relation
if (rel != null) {
// is the property a virtual node containing objects from relational db?
if (rel.virtual && rel.other.isRelational ())
return node.nmgr.getNode (node, propname, rel);
else if (!rel.virtual && rel.direction == Relation.FORWARD)
return node.nmgr.getNode (node, nvalueID, rel);
// avoid setting dbm for virtual and groupby relations, except for
// [mountpoint] kind of prototyped virtual nodes
else if ((!rel.virtual || rel.prototype != null) && rel.groupby == null)
dbm = rel.other;
}
}
// we have what we need, now get the node from the node manager
Node retval = node.nmgr.getNode (nvalueID, dbm);
if (retval != null && retval.parentID == null && !"root".equalsIgnoreCase (retval.getPrototype ())) {
retval.setParent (node);
retval.setName (propname);
retval.anonymous = false;
}
if (retval != null && retval.getDbMapping () == null && rel != null && rel.virtual && rel.prototype == null) {
// a virtual node whose child nodes are not relational -
// set up dbmapping that describes subnodes and properties
DbMapping _dbm = new DbMapping ();
_dbm.setSubnodeMapping (rel.other);
_dbm.setPropertyMapping (rel.other);
_dbm.setSubnodeRelation (rel.getVirtualSubnodeRelation());
_dbm.setPropertyRelation (rel.getVirtualPropertyRelation());
retval.setDbMapping (_dbm);
}
return retval;
}
return null;
}
@ -321,9 +411,91 @@ public final class Property implements IProperty, Serializable, Cloneable {
return null;
}
public String getEditor () {
switch (type) {
case STRING:
return "password".equalsIgnoreCase (propname) ?
"<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 ();
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}

View file

@ -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");
}
}

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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);
}
}

View file

@ -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";
}

View file

@ -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