Merged in changes from helma_1_2 branch

This commit is contained in:
hns 2003-02-26 12:41:54 +00:00
parent 9d73c836ed
commit ed15173b8c
32 changed files with 1056 additions and 632 deletions

View file

@ -8,7 +8,7 @@
<target name="init">
<property name="Name" value="helma"/>
<property name="year" value="1998-${year}"/>
<property name="version" value="1.2-rc2"/>
<property name="version" value="1.2.2"/>
<property name="project" value="helma"/>
<property name="build.compiler" value="classic"/>

Binary file not shown.

View file

@ -432,11 +432,7 @@ public abstract class ESLoader extends ESObject {
debugInfo = " rejected (not widening numbers)";
}
// Handle String of length 1 as a Char, which can be converted to a number
} else if ((targetClass == Character.class ||
targetClass == Integer.class ||
targetClass == Long.class ||
targetClass == Float.class ||
targetClass == Double.class)
} else if (targetClass == Character.class
&& params[i] instanceof String) {
if (((String) params[i]).length()==1) {
accepted = true; // will require conversion of parameter

View file

@ -74,11 +74,11 @@ public class ClassInfo {
* @return the ClassInfo of cls, added to the cache if needed
*/
private static ClassInfo ensureClassInfo(Class cls) {
boolean debug = ESLoader.isDebugJavaAccess();
// boolean debug = ESLoader.isDebugJavaAccess();
ClassInfo classInfo = (ClassInfo) allClassInfo.get(cls);
if (classInfo == null) {
if (debug) System.out.println("** Class info for class '" +
cls + "' not found in cache, created");
// if (debug) System.out.println("** Class info for class '" +
// cls + "' not found in cache, created");
classInfo = new ClassInfo();
allClassInfo.put(cls, classInfo);
}
@ -94,7 +94,7 @@ public class ClassInfo {
* @param cls The class for which we look for the property.
* @return The PropertyDescriptor or null if not found or in case of error
*/
synchronized public static PropertyDescriptor lookupBeanField(String fieldName, Class cls) {
public static PropertyDescriptor lookupBeanField(String fieldName, Class cls) {
ClassInfo classInfo = ClassInfo.ensureClassInfo(cls);
return classInfo.cachedBeanFieldLookup(fieldName, cls);
}
@ -110,29 +110,29 @@ public class ClassInfo {
* @return The PropertyDescriptor or null if not found or in case of error
*/
private PropertyDescriptor cachedBeanFieldLookup(String propertyName, Class cls) {
boolean debug = ESLoader.isDebugJavaAccess();
// boolean debug = ESLoader.isDebugJavaAccess();
// Check that there is a bean properties cache, chech if the property was cached
if (beanProperties != null) {
if (debug) System.out.println("** Bean properties for class '" +
cls + "' found in cache");
// if (debug) System.out.println("** Bean properties for class '" +
// cls + "' found in cache");
PropertyDescriptor descriptor =
(PropertyDescriptor) beanProperties.get(propertyName);
if (descriptor!= null) {
if (debug) System.out.println("** property descriptor '" + propertyName + "' found in cache");
// if (debug) System.out.println("** property descriptor '" + propertyName + "' found in cache");
return descriptor;
}
}
// Not in cache
if (debug) System.out.println("** No property named '" +
propertyName + "' found in cache, lookup started");
// if (debug) System.out.println("** No property named '" +
// propertyName + "' found in cache, lookup started");
// Do we have a cached BeanInfo ? create it if no
if (beanInfo == null) {
try {
beanInfo = Introspector.getBeanInfo(cls);
} catch (IntrospectionException e) {
if (debug) System.out.println(" ** Error getting beaninfo: " + e);
// if (debug) System.out.println(" ** Error getting beaninfo: " + e);
return null;
}
}
@ -142,7 +142,7 @@ public class ClassInfo {
PropertyDescriptor descriptor = null; // none found
for (int i=0; i<allProperties.length; i++) {
PropertyDescriptor property = allProperties[i];
if (debug) System.out.println("** Property examined: " + property.getName());
// if (debug) System.out.println("** Property examined: " + property.getName());
if (!property.getName().equals(propertyName)) continue;
descriptor = property;
break;
@ -238,13 +238,13 @@ public class ClassInfo {
}
// Add to cache
if (debug) System.out.println("** property '" + propertyName + "' + found, add to cache");
// if (debug) System.out.println("** property '" + propertyName + "' + found, add to cache");
if (beanProperties==null) {
beanProperties = new Hashtable();
}
beanProperties.put(propertyName, descriptor);
} else {
if (debug) System.out.println("** No method named '" + propertyName + "' found");
// if (debug) System.out.println("** No method named '" + propertyName + "' found");
}
return descriptor;
}
@ -258,7 +258,7 @@ public class ClassInfo {
* @param cls The class of the method being looked up
* @return The method array or null if none found or in case of error
*/
synchronized public static Method[] lookupPublicMethod(String functionName, Class cls) throws EcmaScriptException {
public static Method[] lookupPublicMethod(String functionName, Class cls) throws EcmaScriptException {
ClassInfo classInfo = ClassInfo.ensureClassInfo(cls);
return classInfo.cachedPublicMethodLookup(functionName, cls);
}
@ -274,52 +274,52 @@ public class ClassInfo {
* @return The method if found, null otherwise
*/
private Method getInInterfaces(String functionName, Class [] interfaces, Class[] paramTypes) {
boolean debug = ESLoader.isDebugJavaAccess();
// boolean debug = ESLoader.isDebugJavaAccess();
if (debug && interfaces.length>0) {
System.out.println("** Looking in " + interfaces.length + " interfaces");
}
// if (debug && interfaces.length>0) {
// System.out.println("** Looking in " + interfaces.length + " interfaces");
// }
SEARCHININTERFACE:
for (int ix=0; ix<interfaces.length; ix++) {
Class theInterface=interfaces[ix];
if (Modifier.isPublic(theInterface.getModifiers())) {
if (debug) {
System.out.println("** Looking in public interface: " + theInterface);
}
// if (debug) {
// System.out.println("** Looking in public interface: " + theInterface);
// }
try {
Method method = theInterface.getDeclaredMethod(functionName,paramTypes);
if (Modifier.isPublic(method.getModifiers())) {
if (debug) {
System.out.println("** Public method found: " + functionName);
}
// if (debug) {
// System.out.println("** Public method found: " + functionName);
// }
return method;
}
} catch (NoSuchMethodException e) {
if (debug) {
System.out.println("** The method has no public declaration in the interface: "+ functionName);
}
// if (debug) {
// System.out.println("** The method has no public declaration in the interface: "+ functionName);
// }
// throw new ProgrammingError("The method has no public declaration in a public class: "+ functionName);
} catch (SecurityException e) {
throw new ProgrammingError("Access error inspecting method "+ functionName + ": " + e);
}
} else {
if (debug) {
System.out.println("** Interface " + theInterface + " is not public - not searching for method");
}
// if (debug) {
// System.out.println("** Interface " + theInterface + " is not public - not searching for method");
// }
}
// Not found, try super interfaces
Class [] superInterfaces = theInterface.getInterfaces();
Method method = getInInterfaces(functionName, superInterfaces, paramTypes);
if (method!=null) {
if (debug) System.out.println("** Method found in super interfaces");
// if (debug) System.out.println("** Method found in super interfaces");
return method;
}
}
if (debug) {
System.out.println("** No method found in interface and super interfaces");
}
// if (debug) {
// System.out.println("** No method found in interface and super interfaces");
// }
return null;
}
@ -337,26 +337,26 @@ public class ClassInfo {
* @return The list of methods or null in case of error or if none found.
*/
private Method [] cachedPublicMethodLookup(String functionName, Class cls) throws EcmaScriptException {
boolean debug = ESLoader.isDebugJavaAccess();
// boolean debug = ESLoader.isDebugJavaAccess();
if (publicMethods != null) {
if (debug) System.out.println("** Method descriptor for class '" +
cls + "' found in cache");
// if (debug) System.out.println("** Method descriptor for class '" +
// cls + "' found in cache");
Method [] methods = (Method []) publicMethods.get(functionName);
if (methods!= null) {
if (debug) System.out.println("** " + methods.length +
" method(s) named '" + functionName + "' found in cache");
// if (debug) System.out.println("** " + methods.length +
// " method(s) named '" + functionName + "' found in cache");
return methods;
}
}
// Not in cache, find if any matching the same name can be found
if (debug) System.out.println("** No method named '" +
functionName + "' found in class cache, lookup started");
// if (debug) System.out.println("** No method named '" +
// functionName + "' found in class cache, lookup started");
Method [] allMethods = cls.getMethods();
Vector methodVector = new Vector(allMethods.length);
boolean wasFound = false;
for (int i=0; i<allMethods.length; i++) {
Method method = allMethods[i];
if (debug) System.out.println("** Method examined: " + method.toString());
// if (debug) System.out.println("** Method examined: " + method.toString());
if (!method.getName().equals(functionName)) continue;
// Method has same name, some closer examination is needed:
// If the class itself is not public, there is an access error if
@ -365,8 +365,8 @@ public class ClassInfo {
// I am not too sure of what happens if the method is defined in an
// interface...
if (!Modifier.isStatic(cls.getModifiers()) && !Modifier.isPublic(cls.getModifiers())) {
if (debug) System.out.println("** Class " + cls +
" is not public, examining superclasses and interfaces to find proper method descriptor");
// if (debug) System.out.println("** Class " + cls +
// " is not public, examining superclasses and interfaces to find proper method descriptor");
Class[] paramTypes = method.getParameterTypes();
SEARCHPUBLIC:
@ -383,31 +383,31 @@ public class ClassInfo {
// Look in the class
if (Modifier.isPublic(theClass.getModifiers())) {
if (debug) {
System.out.println("** Looking in public class: " + theClass);
}
// if (debug) {
// System.out.println("** Looking in public class: " + theClass);
// }
try {
m = theClass.getDeclaredMethod(functionName,paramTypes);
if (Modifier.isPublic(method.getModifiers())) {
if (debug) {
System.out.println("** Public method found: " + functionName);
}
// if (debug) {
// System.out.println("** Public method found: " + functionName);
// }
method = m;
wasFound = true;
break SEARCHPUBLIC;
}
} catch (NoSuchMethodException e) {
if (debug) {
System.out.println("** The method has no public declaration in the public class: "+ functionName);
}
// if (debug) {
// System.out.println("** The method has no public declaration in the public class: "+ functionName);
// }
// throw new ProgrammingError("The method has no public declaration in a public class: "+ functionName);
} catch (SecurityException e) {
throw new ProgrammingError("Access error inspecting method "+ functionName + ": " + e);
}
} else {
if (debug) {
System.out.println("** Class " + theClass + " is not public - not searching for method");
}
// if (debug) {
// System.out.println("** Class " + theClass + " is not public - not searching for method");
// }
}
} // for SEARCHPUBLIC
@ -427,7 +427,7 @@ public class ClassInfo {
Method [] methods = null;
int nmbMethods = methodVector.size();
if (nmbMethods>0) {
if (debug) System.out.println("** " + nmbMethods + " methods named: '" + functionName + "' + found, add to class cache");
// if (debug) System.out.println("** " + nmbMethods + " methods named: '" + functionName + "' + found, add to class cache");
methods = new Method[nmbMethods];
methodVector.copyInto(methods);
if (publicMethods==null) {
@ -435,7 +435,7 @@ public class ClassInfo {
}
publicMethods.put(functionName, methods);
} else {
if (debug) System.out.println("** No method named '" + functionName + "' found");
// if (debug) System.out.println("** No method named '" + functionName + "' found");
}
return methods;
}
@ -449,7 +449,7 @@ public class ClassInfo {
* @param cls The class of the method being looked up
* @return The method array or null if none found or in case of error
*/
synchronized public static Method[] lookupBeanMethod(String functionName, Class cls) {
public static Method[] lookupBeanMethod(String functionName, Class cls) {
ClassInfo classInfo = ClassInfo.ensureClassInfo(cls);
return classInfo.cachedBeanMethodLookup(functionName, cls);
}
@ -469,27 +469,27 @@ public class ClassInfo {
* @return The list of methods or null in case of error or if none found.
*/
private Method [] cachedBeanMethodLookup(String functionName, Class cls) {
boolean debug = ESLoader.isDebugJavaAccess();
// boolean debug = ESLoader.isDebugJavaAccess();
if (beanMethods != null) {
if (debug) System.out.println("** Method descriptor for bean '" +
cls + "' found in cache");
// if (debug) System.out.println("** Method descriptor for bean '" +
// cls + "' found in cache");
Method [] methods = (Method []) beanMethods.get(functionName);
if (methods!= null) {
if (debug) System.out.println("** " + methods.length +
" method(s) named '" + functionName + "' found in cache");
// if (debug) System.out.println("** " + methods.length +
// " method(s) named '" + functionName + "' found in cache");
return methods;
}
}
}
// Not in cache, find if any matching the same name can be found
if (debug) System.out.println("** No method named '" +
functionName + "' found in bean cache, lookup started");
// if (debug) System.out.println("** No method named '" +
// functionName + "' found in bean cache, lookup started");
// Do we have a cached BeanInfo ? create it if no
if (beanInfo == null) {
try {
beanInfo = Introspector.getBeanInfo(cls);
} catch (IntrospectionException e) {
if (debug) System.out.println(" ** Error getting beaninfo: " + e);
// if (debug) System.out.println(" ** Error getting beaninfo: " + e);
return null;
}
}
@ -498,7 +498,7 @@ public class ClassInfo {
Vector methodVector = new Vector(allDescriptors.length);
for (int i=0; i<allDescriptors.length; i++) {
Method method = allDescriptors[i].getMethod();
if (debug) System.out.println("** Method examined: " + method.toString());
// if (debug) System.out.println("** Method examined: " + method.toString());
if (!allDescriptors[i].getName().equals(functionName)) continue;
// Method has same name, some tuning neede:
// If the class itself is not public, there is an access error if
@ -507,21 +507,21 @@ public class ClassInfo {
// I am not too sure of what happens if the method is defined in an
// interface...
if (!Modifier.isStatic(cls.getModifiers()) && !Modifier.isPublic(cls.getModifiers())) {
if (debug) System.out.println("** Bean class " + cls +
" is not public, examining superclasses to find proper method descriptor");
// if (debug) System.out.println("** Bean class " + cls +
// " is not public, examining superclasses to find proper method descriptor");
SEARCHPUBLIC:
for (Class theClass=cls;theClass!=null;theClass=theClass.getSuperclass()) {
if (Modifier.isPublic(theClass.getModifiers())) {
if (debug) {
System.out.println("** Looking in public superlass: " + theClass);
}
// if (debug) {
// System.out.println("** Looking in public superlass: " + theClass);
// }
try {
Class[] paramTypes = method.getParameterTypes();
Method m = theClass.getDeclaredMethod(functionName,paramTypes);
if (Modifier.isPublic(method.getModifiers())) {
if (debug) {
System.out.println("** Public method found: " + functionName);
}
// if (debug) {
// System.out.println("** Public method found: " + functionName);
// }
method = m;
break SEARCHPUBLIC;
}
@ -531,9 +531,9 @@ public class ClassInfo {
throw new ProgrammingError("Acess error inspecting method "+ functionName + ": " + e);
}
} else {
if (debug) {
System.out.println("** Superlass " + theClass + " is not public");
}
// if (debug) {
// System.out.println("** Superlass " + theClass + " is not public");
// }
}
} // for
} // if class not public
@ -547,8 +547,8 @@ public class ClassInfo {
Method [] methods = null;
int nmbMethods = methodVector.size();
if (nmbMethods>0) {
if (debug) System.out.println("** " + nmbMethods + " methods named: '"
+ functionName + "' + found, add to bean cache");
// if (debug) System.out.println("** " + nmbMethods + " methods named: '"
// + functionName + "' + found, add to bean cache");
methods = new Method[nmbMethods];
methodVector.copyInto(methods);
if (beanMethods==null) {
@ -556,8 +556,8 @@ public class ClassInfo {
}
beanMethods.put(functionName, methods);
} else {
if (debug) System.out.println("** No bean method named: '" +
functionName + "' + found");
// if (debug) System.out.println("** No bean method named: '" +
// functionName + "' + found");
}
return methods;
}

View file

@ -32,6 +32,12 @@ public abstract class HelmaExtension {
*/
public abstract void applicationStopped (Application app);
/**
* called when an Application's properties are have been updated.
* note that this will be called at startup once *before* applicationStarted().
*/
public abstract void applicationUpdated (Application app);
/**
* called by the ScriptingEngine when it is initizalized. Throws a ConfigurationException
* when this type of ScriptingEngine is not supported. New methods and prototypes can be

View file

@ -43,6 +43,10 @@ public class DemoExtension extends HelmaExtension {
app.logEvent ("DemoExtension stopped on app " + app.getName () );
}
public void applicationUpdated (Application app) {
app.logEvent ("DemoExtension updated on app " + app.getName () );
}
public HashMap initScripting (Application app, ScriptingEngine engine) throws ConfigurationException {
if (!(engine instanceof FesiEngine))
throw new ConfigurationException ("scripting engine " + engine.toString () + " not supported in DemoExtension");

View file

@ -62,7 +62,7 @@ public class ResponseBean implements Serializable {
res.writeBinary (what);
}
public void debug (String message) {
public void debug (Object message) {
res.debug (message);
}

View file

@ -185,19 +185,15 @@ public final class ResponseTrans implements Externalizable {
}
/**
* Returns the number of characters written to the response buffer so far.
* Get the response buffer, creating it if it doesn't exist
*/
public int getBufferLength() {
public StringBuffer getBuffer () {
if (buffer == null)
return 0;
return buffer.length ();
}
public void setBufferLength(int l) {
if (buffer != null)
buffer.setLength (l);
buffer = new StringBuffer (INITIAL_BUFFER_SIZE);
return buffer;
}
/**
* Append a string to the response unchanged. This is often called
* at the end of a request to write out the whole page, so if buffer
@ -237,10 +233,13 @@ public final class ResponseTrans implements Externalizable {
* that buffer exists and its length is larger than offset. str may be null, in which
* case nothing happens.
*/
public void debug (String str) {
public void debug (Object message) {
if (debugBuffer == null)
debugBuffer = new StringBuffer ();
debugBuffer.append ("<p><span style=\"background: yellow; color: black\">"+str+"</span></p>");
String str = message == null ? "null" : message.toString ();
debugBuffer.append ("<p><span style=\"background: yellow; color: black\">");
debugBuffer.append (str);
debugBuffer.append ("</span></p>");
}
/**
@ -335,17 +334,25 @@ public final class ResponseTrans implements Externalizable {
if (charset == null)
charset = "ISO-8859-1";
boolean encodingError = false;
// only close if the response hasn't been closed yet
if (response == null) {
if (buffer != null) {
if (debugBuffer != null)
// if debug buffer exists, append it to main buffer
if (debugBuffer != null) {
if (buffer == null)
buffer = debugBuffer;
else
buffer.append (debugBuffer);
}
// get the buffer's bytes in the specified encoding
if (buffer != null) {
try {
response = buffer.toString ().getBytes (charset);
} catch (UnsupportedEncodingException uee) {
encodingError = true;
response = buffer.toString ().getBytes ();
}
buffer = null; // make sure this is done only once, even with more requsts attached
// make sure this is done only once, even with more requsts attached
buffer = null;
} else {
response = new byte[0];
}

View file

@ -228,6 +228,11 @@ public final class Application implements IPathElement, Runnable {
}
}
// read the sessions if wanted
if ("true".equalsIgnoreCase (getProperty("persistentSessions"))) {
loadSessionData (null);
}
typemgr = new TypeManager (this);
typemgr.createPrototypes ();
// logEvent ("Started type manager for "+name);
@ -319,6 +324,11 @@ public final class Application implements IPathElement, Runnable {
ext.applicationStopped (this);
}
// store the sessions if wanted
if ("true".equalsIgnoreCase (getProperty("persistentSessions"))) {
storeSessionData (null);
}
// stop logs if they exist
if (eventLog != null) {
eventLog.close ();
@ -840,34 +850,31 @@ public final class Application implements IPathElement, Runnable {
*/
public String getNodeHref (Object elem, String actionName) {
// Object root = getDataRoot ();
// check optional root prototype from app.properties
String rootProto = props.getProperty ("rootPrototype");
String divider = "/";
StringBuffer b = new StringBuffer ();
Object parent = null;
int loopWatch = 0;
StringBuffer b = new StringBuffer (baseURI);
while (elem != null && (parent = getParentElement (elem)) != null && elem != rootObject) {
if (rootProto != null && rootProto.equals (getPrototypeName (elem)))
break;
b.insert (0, divider);
b.insert (0, UrlEncoded.encode (getElementName (elem)));
// move down to the element's parent
elem = parent;
if (loopWatch++ > 20)
break;
}
composeHref (elem, b, rootProto, 0);
if (actionName != null)
b.append (UrlEncoded.encode (actionName));
return baseURI + b.toString ();
return b.toString ();
}
private final void composeHref (Object elem, StringBuffer b, String rootProto, int pathCount) {
if (elem == null || pathCount > 20)
return;
if (rootProto != null && rootProto.equals (getPrototypeName (elem)))
return;
Object parent = getParentElement (elem);
if (parent == null)
return;
composeHref (getParentElement (elem), b, rootProto, pathCount++);
b.append (UrlEncoded.encode (getElementName (elem)));
b.append ("/");
}
/**
* This method sets the base URL of this application which will be prepended to
@ -1112,9 +1119,8 @@ public final class Application implements IPathElement, Runnable {
NodeHandle userhandle = session.userHandle;
if (userhandle != null) {
try {
String[] str = new String [1];
str[0] = session.getSessionID ();
eval.invokeFunction (userhandle, "onLogout", str);
Object[] param = { session.getSessionID() };
eval.invokeFunction (userhandle, "onLogout", param);
} catch (Exception ignore) {}
}
destroySession(session);
@ -1143,7 +1149,7 @@ public final class Application implements IPathElement, Runnable {
}
// sleep until we have work to do
try {
try {
worker.sleep (Math.min (cleanupSleep, scheduleSleep));
} catch (InterruptedException x) {
logEvent ("Scheduler for "+name+" interrupted");
@ -1256,6 +1262,14 @@ public final class Application implements IPathElement, Runnable {
// if node manager exists, update it
if (nmgr != null)
nmgr.updateProperties (props);
// update extensions
Vector extensions = Server.getServer ().getExtensions ();
for (int i=0; i<extensions.size(); i++) {
HelmaExtension ext = (HelmaExtension)extensions.get(i);
try {
ext.applicationUpdated (this);
} catch (ConfigurationException e) { }
}
// set prop read timestamp
lastPropertyRead = props.lastModified ();
}
@ -1388,5 +1402,65 @@ public final class Application implements IPathElement, Runnable {
throw new Exception ("Method "+key+" is not callable via XML-RPC");
}
public void storeSessionData (File f) {
if (f==null)
f = new File(dbDir, "sessions");
try {
OutputStream ostream = new BufferedOutputStream (new FileOutputStream(f));
ObjectOutputStream p = new ObjectOutputStream(ostream);
synchronized (sessions) {
p.writeInt (sessions.size ());
for (Enumeration e=sessions.elements (); e.hasMoreElements ();) {
p.writeObject ((Session) e.nextElement ());
}
}
p.flush();
ostream.close();
logEvent ("stored " + sessions.size () + " sessions in file");
} catch (Exception e) {
logEvent ("error storing session data: " + e.toString ());
}
}
/**
* loads the serialized session table from a given file or from dbdir/sessions
*/
public void loadSessionData (File f) {
if (f==null)
f = new File(dbDir, "sessions");
// compute session timeout value
int sessionTimeout = 30;
try {
sessionTimeout = Math.max (0, Integer.parseInt (props.getProperty ("sessionTimeout", "30")));
} catch (Exception ignore) {
System.out.println(ignore.toString());
}
long now = System.currentTimeMillis ();
try {
// load the stored data:
InputStream istream = new BufferedInputStream (new FileInputStream(f));
ObjectInputStream p = new ObjectInputStream(istream);
int size = p.readInt ();
int ct = 0;
Hashtable newSessions = new Hashtable ();
while (ct < size) {
Session session = (Session) p.readObject ();
if (now - session.lastTouched () < sessionTimeout * 60000) {
session.setApp (this);
newSessions.put (session.getSessionID (), session);
}
ct++;
}
p.close ();
istream.close ();
sessions = newSessions;
logEvent ("loaded " + newSessions.size () + " sessions from file");
} catch (Exception e) {
logEvent ("error loading session data: " + e.toString ());
}
}
}

View file

@ -24,23 +24,27 @@ public class ApplicationBean implements Serializable {
app.clearCache ();
}
public void log (String msg) {
app.logEvent (msg);
public void log (Object msg) {
String str = msg == null ? "null" : msg.toString();
app.logEvent (str);
}
public void log (String logname, String msg) {
app.getLogger (logname).log (msg);
public void log (String logname, Object msg) {
String str = msg == null ? "null" : msg.toString();
app.getLogger (logname).log (str);
}
public void debug (String msg) {
public void debug (Object msg) {
if (app.debug()) {
app.logEvent (msg);
String str = msg == null ? "null" : msg.toString();
app.logEvent (str);
}
}
public void debug (String logname, String msg) {
public void debug (String logname, Object msg) {
if (app.debug()) {
app.getLogger (logname).log (msg);
String str = msg == null ? "null" : msg.toString();
app.getLogger (logname).log (str);
}
}

View file

@ -269,8 +269,6 @@ public final class RequestEvaluator implements Runnable {
scriptingEngine.invoke (currentElement, "onRequest", new Object[0], false);
} catch (RedirectException redir) {
throw redir;
} catch (Exception ignore) {
// function is not defined or caused an exception, ignore
}
// reset skin recursion detection counter
@ -351,7 +349,7 @@ public final class RequestEvaluator implements Runnable {
break;
case XMLRPC:
try {
localrtx.begin (app.getName()+":xmlrpc/"+method);
localrtx.begin (app.getName()+":xmlrpc:"+method);
root = app.getDataRoot ();
@ -386,23 +384,25 @@ public final class RequestEvaluator implements Runnable {
result = scriptingEngine.invoke (currentElement, method, args, true);
commitTransaction ();
} catch (Exception wrong) {
} catch (Exception x) {
abortTransaction (false);
app.logEvent ("Exception in "+Thread.currentThread()+": "+x);
// If the transactor thread has been killed by the invoker thread we don't have to
// bother for the error message, just quit.
if (localrtx != rtx) {
return;
}
this.exception = wrong;
this.exception = x;
}
break;
case INTERNAL:
// Just a human readable descriptor of this invocation
String funcdesc = app.getName()+":internal/"+method;
String funcdesc = app.getName()+":internal:"+method;
// if thisObject is an instance of NodeHandle, get the node object itself.
if (thisObject != null && thisObject instanceof NodeHandle) {
@ -438,17 +438,19 @@ public final class RequestEvaluator implements Runnable {
result = scriptingEngine.invoke (thisObject, method, args, false);
commitTransaction ();
} catch (Exception wrong) {
} catch (Exception x) {
abortTransaction (false);
app.logEvent ("Exception in "+Thread.currentThread()+": "+x);
// If the transactor thread has been killed by the invoker thread we don't have to
// bother for the error message, just quit.
if (localrtx != rtx) {
return;
}
this.exception = wrong;
this.exception = x;
}
break;

View file

@ -17,7 +17,7 @@ import helma.objectmodel.db.*;
public class Session implements Serializable {
Application app;
transient Application app;
String sessionID;
// the unique id (login name) for the user, if logged in
@ -98,6 +98,10 @@ public class Session implements Serializable {
return app;
}
public void setApp (Application app) {
this.app = app;
}
public String getSessionID () {
return sessionID;
}

View file

@ -20,7 +20,7 @@ import java.util.*;
public final class Skin {
private Macro[] parts;
private Macro[] macros;
private Application app;
private char[] source;
private int sourceLength;
@ -84,8 +84,8 @@ public final class Skin {
}
}
parts = new Macro[partBuffer.size()];
partBuffer.toArray (parts);
macros = new Macro[partBuffer.size()];
partBuffer.toArray (macros);
}
/**
@ -104,7 +104,7 @@ public final class Skin {
if (++reval.skinDepth > 50)
throw new RuntimeException ("Recursive skin invocation suspected");
if (parts == null) {
if (macros == null) {
reval.res.writeCharArray (source, 0, sourceLength);
reval.skinDepth--;
return;
@ -113,14 +113,14 @@ public final class Skin {
try {
int written = 0;
Map handlerCache = null;
if (parts.length > 3) {
if (macros.length > 3) {
handlerCache = new HashMap();
}
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, handlerCache);
written = parts[i].end;
for (int i=0; i<macros.length; i++) {
if (macros[i].start > written)
reval.res.writeCharArray (source, written, macros[i].start-written);
macros[i].render (reval, thisObject, paramObject, handlerCache);
written = macros[i].end;
}
if (written < sourceLength)
reval.res.writeCharArray (source, written, sourceLength-written);
@ -133,9 +133,9 @@ public final class Skin {
* 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];
for (int i=0; i<macros.length; i++) {
if (macros[i] instanceof Macro) {
Macro m = (Macro) macros[i];
if (macroname.equals (m.fullName))
return true;
}
@ -158,6 +158,13 @@ public final class Skin {
static final int PARAMNAME = 2;
static final int PARAMVALUE = 3;
static final int ENCODE_NONE = 0;
static final int ENCODE_HTML = 1;
static final int ENCODE_XML = 2;
static final int ENCODE_FORM = 3;
static final int ENCODE_URL = 4;
static final int ENCODE_ALL = 5;
class Macro {
final int start, end;
@ -166,8 +173,8 @@ public final class Skin {
String fullName;
String prefix;
String suffix;
String encoding;
String defaultValue;
int encoding = ENCODE_NONE;
Map parameters = null;
public Macro (int start, int end) {
@ -264,7 +271,7 @@ public final class Skin {
}
private boolean setSpecialParameter (String name, String value) {
if ("prefix".equals (name)) {
prefix = value;
@ -273,7 +280,16 @@ public final class Skin {
suffix = value;
return true;
} else if ("encoding".equals (name)) {
encoding = value;
if ("html".equalsIgnoreCase (value))
encoding = ENCODE_HTML;
else if ("xml".equalsIgnoreCase (value))
encoding = ENCODE_XML;
else if ("form".equalsIgnoreCase (value))
encoding = ENCODE_FORM;
else if ("url".equalsIgnoreCase (value))
encoding = ENCODE_URL;
else if ("all".equalsIgnoreCase (value))
encoding = ENCODE_ALL;
return true;
} else if ("default".equals (name)) {
defaultValue = value;
@ -347,16 +363,9 @@ public final class Skin {
}
if (handlerObject == null) {
// eiter because thisObject == null or the right object wasn't found in the object's parent path
// go check request path for an object with matching prototype
/* int l = reval.requestPath.size();
for (int i=l-1; i>=0; i--) {
Object pathelem = reval.requestPath.get (i);
if (handler.equals (app.getPrototypeName (pathelem))) {
handlerObject = pathelem;
break;
}
} */
// eiter because thisObject == null or the right object wasn't found
// in the object's parent path. Check if a matching macro handler
// is registered with the response object (res.handlers).
handlerObject = reval.res.getMacroHandlers().get (handler);
}
@ -380,12 +389,14 @@ public final class Skin {
String funcName = name+"_macro";
if (reval.scriptingEngine.hasFunction (handlerObject, funcName)) {
StringBuffer buffer = reval.res.getBuffer();
// remember length of response buffer before calling macro
int bufLength = reval.res.getBufferLength ();
int bufLength = buffer.length();
// remember length of buffer with prefix written out
int preLength = 0;
if (prefix != null) {
reval.res.write (prefix);
buffer.append (prefix);
preLength = prefix.length();
}
@ -396,24 +407,36 @@ public final class Skin {
// parameters = new HashMap ();
Object[] arguments = { parameters == null ?
new HashMap () :
new HashMap (parameters) };
new HashMap (parameters)
};
Object value = reval.scriptingEngine.invoke (handlerObject, funcName, arguments, false);
Object v = reval.scriptingEngine.invoke (handlerObject, funcName, arguments, false);
// check if macro wrote out to response buffer
if (reval.res.getBufferLength () == bufLength + preLength) {
// function didn't write out anything itself
if (buffer.length () == bufLength + preLength) {
// function didn't write out anything itself.
// erase previously written prefix
if (preLength > 0)
reval.res.setBufferLength (bufLength);
writeToResponse (v, reval.res, true);
buffer.setLength (bufLength);
// write out macro's return value
writeResponse (value, buffer, true);
} else {
if (suffix != null)
reval.res.write (suffix);
writeToResponse (v, reval.res, false);
if (encoding != ENCODE_NONE) {
// if an encoding is specified, re-encode the macro's output
String output = buffer.substring (bufLength + preLength);
buffer.setLength (bufLength);
writeResponse (output, buffer, false);
} else {
// no re-encoding needed, just append suffix
if (suffix != null)
buffer.append (suffix);
}
writeResponse (value, buffer, false);
}
} else {
// System.err.println ("Getting macro from property");
Object v = reval.scriptingEngine.get (handlerObject, name);
writeToResponse (v, reval.res, true);
Object value = reval.scriptingEngine.get (handlerObject, name);
writeResponse (value, reval.res.getBuffer(), true);
}
} else {
String msg = "[HopMacro unhandled: "+fullName+"]";
@ -445,21 +468,21 @@ public final class Skin {
value = reval.res.error;
if (value == null)
value = reval.res.get (name);
writeToResponse (value, reval.res, true);
writeResponse (value, reval.res.getBuffer(), true);
}
private void renderFromRequest (RequestEvaluator reval) {
if (reval.req == null)
return;
Object value = reval.req.get (name);
writeToResponse (value, reval.res, true);
writeResponse (value, reval.res.getBuffer(), true);
}
private void renderFromSession (RequestEvaluator reval) {
if (reval.session == null)
return;
Object value = reval.session.getCacheNode().getString (name);
writeToResponse (value, reval.res, true);
writeResponse (value, reval.res.getBuffer(), true);
}
private void renderFromParam (RequestEvaluator reval, Map paramObject) {
@ -467,14 +490,14 @@ public final class Skin {
reval.res.write ("[HopMacro error: Skin requires a parameter object]");
else {
Object value = paramObject.get (name);
writeToResponse (value, reval.res, true);
writeResponse (value, reval.res.getBuffer(), true);
}
}
/**
* Utility method for writing text out to the response object.
*/
void writeToResponse (Object value, ResponseTrans res, boolean useDefault) {
void writeResponse (Object value, StringBuffer buffer, boolean useDefault) {
String text;
if (value == null) {
if (useDefault)
@ -484,36 +507,39 @@ public final class Skin {
} else {
text = value.toString ();
}
if (text == null || text.length() == 0)
return;
if (encoding != null)
text = encode (text, encoding);
res.write (prefix);
res.write (text);
res.write (suffix);
}
/**
* Utility method for performing different kind of character
* encodings on the macro output.
*/
String encode (String text, String encoding) {
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;
if (text != null && text.length() > 0) {
if (prefix != null)
buffer.append (prefix);
switch (encoding) {
case ENCODE_NONE:
buffer.append (text);
break;
case ENCODE_HTML:
HtmlEncoder.encode (text, buffer);
break;
case ENCODE_XML:
HtmlEncoder.encodeXml (text, buffer);
break;
case ENCODE_FORM:
HtmlEncoder.encodeFormValue (text, buffer);
break;
case ENCODE_URL:
buffer.append (URLEncoder.encode (text));
break;
case ENCODE_ALL:
HtmlEncoder.encodeAll (text, buffer);
break;
}
if (suffix != null)
buffer.append (suffix);
}
}
public String toString () {
return "[HopMacro: "+fullName+"]";
}
/**
* Return the full name of the macro in handler.name notation

View file

@ -9,10 +9,10 @@ import java.net.URL;
import java.net.MalformedURLException;
/**
* This creates an invisible frame in order to be able to create images
* from Java. (Java needs a window context in order to user the Image class).
* Factory class for generating Image objects from various sources.
*
*/
public class ImageGenerator {
public ImageGenerator () {
@ -20,10 +20,9 @@ public class ImageGenerator {
}
public ImageWrapper createPaintableImage (int w, int h) {
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
BufferedImage img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics ();
ImageWrapper rimg = null;
rimg = new SunImageWrapper (img, g, w, h, this);
ImageWrapper rimg = new SunImageWrapper (img, g, w, h, this);
return rimg;
}
@ -31,13 +30,17 @@ public class ImageGenerator {
ImageWrapper rimg = null;
Image img1 = Toolkit.getDefaultToolkit ().createImage (src);
ImageLoader loader = new ImageLoader (img1);
loader.load ();
int w = loader.getWidth ();
int h = loader.getHeight ();
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics ();
g.drawImage (img1, 0, 0, null);
rimg = new SunImageWrapper (img, g, w, h, this);
try {
loader.getDimensions ();
int w = loader.getWidth ();
int h = loader.getHeight ();
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics ();
g.drawImage (img1, 0, 0, null);
rimg = new SunImageWrapper (img, g, w, h, this);
} finally {
loader.done();
}
return rimg;
}
@ -45,10 +48,14 @@ public class ImageGenerator {
ImageWrapper rimg = null;
Image img = Toolkit.getDefaultToolkit ().createImage (src);
ImageLoader loader = new ImageLoader (img);
loader.load ();
int w = loader.getWidth ();
int h = loader.getHeight ();
rimg = new SunImageWrapper (img, null, w, h, this);
try {
loader.getDimensions ();
int w = loader.getWidth ();
int h = loader.getHeight ();
rimg = new SunImageWrapper (img, null, w, h, this);
} finally {
loader.done();
}
return rimg;
}
@ -58,13 +65,17 @@ public class ImageGenerator {
URL url = new URL (urlstring);
Image img1 = Toolkit.getDefaultToolkit ().createImage (url);
ImageLoader loader = new ImageLoader (img1);
loader.load ();
int w = loader.getWidth ();
int h = loader.getHeight ();
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics ();
g.drawImage (img1, 0, 0, null);
rimg = new SunImageWrapper (img, g, w, h, this);
try {
loader.getDimensions ();
int w = loader.getWidth ();
int h = loader.getHeight ();
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics ();
g.drawImage (img1, 0, 0, null);
rimg = new SunImageWrapper (img, g, w, h, this);
} finally {
loader.done();
}
return rimg;
}
@ -73,13 +84,17 @@ public class ImageGenerator {
FilteredImageSource fis = new FilteredImageSource (iw.getSource(), filter);
Image img1 = Toolkit.getDefaultToolkit().createImage (fis);
ImageLoader loader = new ImageLoader (img1);
loader.load ();
int w = loader.getWidth ();
int h = loader.getHeight ();
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics ();
g.drawImage (img1, 0, 0, null);
rimg = new SunImageWrapper (img, g, w, h, this);
try {
loader.getDimensions ();
int w = loader.getWidth ();
int h = loader.getHeight ();
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = img.getGraphics ();
g.drawImage (img1, 0, 0, null);
rimg = new SunImageWrapper (img, g, w, h, this);
} finally {
loader.done();
}
return rimg;
}
@ -88,7 +103,8 @@ public class ImageGenerator {
Image img = null;
img = Toolkit.getDefaultToolkit ().createImage (filename);
ImageLoader loader = new ImageLoader (img);
loader.load ();
loader.getDimensions ();
loader.done();
return img;
}
@ -96,7 +112,8 @@ public class ImageGenerator {
Image img = null;
img = Toolkit.getDefaultToolkit ().createImage (producer);
ImageLoader loader = new ImageLoader (img);
loader.load ();
loader.getDimensions ();
loader.done();
return img;
}
@ -104,26 +121,27 @@ public class ImageGenerator {
Image img;
int w, h;
boolean waiting;
boolean firstFrameLoaded;
ImageLoader (Image img) {
this.img = img;
waiting = true;
firstFrameLoaded = false;
}
int getWidth () {
return w;
}
int getHeight () {
return h;
}
synchronized void load () {
synchronized void getDimensions () {
w = img.getWidth(this);
h = img.getHeight (this);
if (w == -1 || h == -1) try {
wait (30000);
} catch (InterruptedException x) {
return;
if (w == -1 || h == -1) {
try {
wait (45000);
} catch (InterruptedException x) {
waiting = false;
return;
} finally {
waiting = false;
}
}
// if width and height haven't been set, throw tantrum
if (w == -1 || h == -1) {
@ -131,6 +149,18 @@ public class ImageGenerator {
}
}
synchronized void done () {
waiting = false;
notifyAll ();
}
int getWidth () {
return w;
}
int getHeight () {
return h;
}
public synchronized boolean imageUpdate(Image img,
int infoflags,
@ -138,24 +168,24 @@ public class ImageGenerator {
int y,
int width,
int height) {
if (w == -1 && (infoflags & WIDTH) > 0)
w = width;
if (h == -1 && (infoflags & HEIGHT) > 0)
h = height;
if (h > -1 && w > -1 && (infoflags & ALLBITS) > 0) {
// we know all we want to know. notify waiting thread that
// the image is loaded and ready to be used.
notifyAll ();
return false;
}
// check if there was an error
if ((infoflags & ERROR) > 0) {
if (!waiting || (infoflags & ERROR) > 0 || (infoflags & ABORT) > 0) {
// we either timed out or there was an error.
notifyAll ();
return false;
}
// TODO: If image production was aborted, but no error was reported,
// we might want to start production again. For now, we just give up.
if ((infoflags & ABORT) > 0) {
if ((infoflags & WIDTH) > 0 || (infoflags & HEIGHT) > 0) {
if ((infoflags & WIDTH) > 0)
w = width;
if ((infoflags & HEIGHT) > 0)
h = height;
if (w > -1 && h > -1 && firstFrameLoaded) {
notifyAll ();
return false;
}
}
if ((infoflags & ALLBITS) > 0 || (infoflags & FRAMEBITS) > 0) {
firstFrameLoaded = true;
notifyAll ();
return false;
}

View file

@ -94,12 +94,16 @@ public abstract class ImageWrapper {
}
public void resize (int w, int h) {
// ImageFilter filter = new ReplicateScaleFilter (w, h);
// img = Toolkit.getDefaultToolkit ().createImage(new FilteredImageSource(img.getSource(), filter));
img = img.getScaledInstance (w, h, Image.SCALE_SMOOTH);
width = w;
height = h;
}
public void resizeFast (int w, int h) {
img = img.getScaledInstance (w, h, Image.SCALE_FAST);
width = w;
height = h;
}
public abstract void reduceColors (int colors);

View file

@ -25,7 +25,7 @@ import org.apache.xmlrpc.*;
public class Server implements IPathElement, Runnable {
public static final String version = "1.2 RC2 2002/12/05";
public static final String version = "1.2.2 (2003/02/04)";
public final long starttime;
// if true we only accept RMI and XML-RPC connections from
@ -90,6 +90,9 @@ import org.apache.xmlrpc.*;
// create new server instance
server = new Server (args);
// start the server main thread
server.start ();
}
/**
@ -137,8 +140,13 @@ import org.apache.xmlrpc.*;
} catch (Exception portx) {
usageError = true;
}
} else
} else if (args[i].equals ("-i") && i+1<args.length) {
// eat away the -i parameter which is meant for helma.main.launcher.Main
i++;
} else {
System.err.println ("Unknown command line token: "+args[i]);
usageError = true;
}
}
// get main property file from home dir or vice versa, depending on what we have.
@ -291,12 +299,18 @@ import org.apache.xmlrpc.*;
}
}
}
protected void start () {
// Start running, finishing setup and then entering a loop to check changes
// in the apps.properties file.
mainThread = new Thread (this);
mainThread.start ();
}
protected void stop () {
mainThread = null;
}
/**
* The main method of the Server. Basically, we set up Applications and than

View file

@ -4,6 +4,7 @@ package helma.main.launcher;
import java.net.URLClassLoader;
import java.net.URL;
import java.net.URLDecoder;
import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.Method;
@ -16,10 +17,20 @@ import java.security.Policy;
*/
public class Main {
public static final String[] jars = { "helma.jar", "jetty.jar", "crimson.jar", "xmlrpc.jar",
"village.jar", "servlet.jar", "regexp.jar", "mail.jar",
"activation.jar", "netcomponents.jar", "jimi.jar",
"apache-dom.jar", "jdom.jar"};
public static final String[] jars = {
"helma.jar",
"jetty.jar",
"crimson.jar",
"xmlrpc.jar",
"servlet.jar",
"regexp.jar",
"mail.jar",
"activation.jar",
"netcomponents.jar",
"jimi.jar",
"apache-dom.jar",
"jdom.jar"
};
public static void main (String[] args) throws Exception {
@ -54,9 +65,13 @@ public class Main {
} catch (Exception x) {
// unable to get Helma installation dir from launcher jar
System.err.println ("Unable to get Helma installation directory: "+x);
System.exit (2);
}
}
// decode installDir in case it is URL-encoded
installDir = URLDecoder.decode (installDir);
// set up the class path
File libdir = new File (installDir, "lib");
ArrayList jarlist = new ArrayList ();
@ -68,17 +83,20 @@ public class Main {
File extdir =new File (libdir, "ext");
File[] files = extdir.listFiles (new FilenameFilter() {
public boolean accept (File dir, String name) {
return name.toLowerCase().endsWith (".jar");
String n = name.toLowerCase();
return n.endsWith (".jar") || n.endsWith (".zip");
}
});
if (files != null)
for (int i=0;i<files.length; i++)
for (int i=0;i<files.length; i++) {
// WORKAROUND: add the files in lib/ext before
// lib/apache-dom.jar, since otherwise putting a full version
// of Xerces in lib/ext would cause a version conflict with the
// xerces classes in lib/apache-dom.jar. Generally, having some pieces
// of Xerces in lib/apache-dom.jar is kind of problematic.
jarlist.add (jars.length-3, new URL ("file:" + files[i].getAbsolutePath()));
System.err.println ("Adding to classpath: "+files[i].getAbsolutePath());
}
URL[] urls = new URL[jarlist.size()];
jarlist.toArray (urls);
FilteredClassLoader loader = new FilteredClassLoader (urls);

View file

@ -64,7 +64,7 @@ public final class Property implements IProperty, Serializable {
return null;
}
public void setStringValue (String value) throws ParseException {
public void setStringValue (String value) {
if (type == NODE)
this.nvalue = null;
if (type == JAVAOBJECT)
@ -116,6 +116,7 @@ public final class Property implements IProperty, Serializable {
this.nvalue = value;
}
public void setJavaObjectValue (Object value) {
if (type == NODE)
this.nvalue = null;
@ -124,7 +125,6 @@ public final class Property implements IProperty, Serializable {
}
public String getStringValue () {
switch (type) {
case STRING:
@ -151,32 +151,32 @@ public final class Property implements IProperty, Serializable {
}
public long getIntegerValue () {
if (type == INTEGER)
if (type == INTEGER)
return lvalue;
return 0;
}
public double getFloatValue () {
if (type == FLOAT)
if (type == FLOAT)
return dvalue;
return 0.0;
}
public Date getDateValue () {
if (type == DATE)
if (type == DATE)
return new Date (lvalue);
return null;
}
public boolean getBooleanValue () {
if (type == BOOLEAN)
if (type == BOOLEAN)
return bvalue;
return false;
}
public INode getNodeValue () {
if (type == NODE)
if (type == NODE)
return nvalue;
return null;
}

View file

@ -469,12 +469,8 @@ public class TransientNode implements INode, Serializable {
public void setString (String propname, String value) {
// IServer.getLogger().log ("setting String prop");
Property prop = initProperty (propname);
try {
prop.setStringValue (value);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
} catch (java.text.ParseException x) {
throw new RuntimeException ("Fehler beim Parsen des Datum-Strings");
}
prop.setStringValue (value);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis ();
}

View file

@ -20,6 +20,8 @@ public final class DbColumn {
this.name = name;
this.type = type;
this.relation = rel;
if (relation != null)
relation.setColumnType (type);
}
/**
@ -43,4 +45,4 @@ public final class DbColumn {
return relation;
}
}
}

View file

@ -11,7 +11,6 @@ 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
@ -58,8 +57,11 @@ public final class DbMapping implements Updatable {
DbColumn[] columns = null;
// Map of db columns by name
HashMap columnMap;
// pre-rendered select statement
String select = null;
String selectString = null;
String insertString = null;
String updateString = null;
// db field used as primary key
private String idField;
@ -81,13 +83,10 @@ public final class DbMapping implements Updatable {
// 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;
// init value is -1 so we know we have to run update once even if
// the underlying properties file is non-existent
long lastTypeChange = -1;
// timestamp of last modification of an object of this type
long lastDataChange;
@ -188,13 +187,10 @@ public final class DbMapping implements Updatable {
}
lastTypeChange = props.lastModified ();
// null the cached schema & keydef so it's rebuilt the next time around
schema = null;
keydef = null;
// same with columns and select string
// null the cached columns and select string
columns = null;
columnMap.clear();
select = null;
selectString = insertString = updateString = null;
if (extendsProto != null) {
@ -390,7 +386,9 @@ public final class DbMapping implements Updatable {
return null;
if (table == null && parentMapping != null)
return parentMapping.propertyToColumnName (propName);
Relation rel = (Relation) prop2db.get (propName);
// FIXME: prop2db stores keys in lower case, because it gets them
// from a SystemProperties object which converts keys to lower case.
Relation rel = (Relation) prop2db.get (propName.toLowerCase());
if (rel != null && (rel.reftype == Relation.PRIMITIVE || rel.reftype == Relation.REFERENCE))
return rel.columnName;
return null;
@ -415,7 +413,9 @@ public final class DbMapping implements Updatable {
return null;
if (table == null && parentMapping != null)
return parentMapping.propertyToRelation (propName);
return (Relation) prop2db.get (propName);
// FIXME: prop2db stores keys in lower case, because it gets them
// from a SystemProperties object which converts keys to lower case.
return (Relation) prop2db.get (propName.toLowerCase());
}
@ -558,22 +558,6 @@ public final class DbMapping implements Updatable {
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 an array of DbColumns for the relational table mapped by this DbMapping.
@ -630,14 +614,40 @@ public final class DbMapping implements Updatable {
}
public StringBuffer getSelect () throws SQLException, ClassNotFoundException {
String sel = select;
String sel = selectString;
if (sel != null)
return new StringBuffer (sel);
StringBuffer s = new StringBuffer ("SELECT * FROM ");
s.append (getTableName ());
s.append (" ");
// cache rendered string for later calls.
select = s.toString();
selectString = s.toString();
return s;
}
public StringBuffer getInsert () {
String ins = insertString;
if (ins != null)
return new StringBuffer (ins);
StringBuffer s = new StringBuffer ("INSERT INTO ");
s.append (getTableName ());
s.append (" ( ");
s.append (getIDField());
// cache rendered string for later calls.
insertString = s.toString();
return s;
}
public StringBuffer getUpdate () {
String upd = updateString;
if (upd != null)
return new StringBuffer (upd);
StringBuffer s = new StringBuffer ("UPDATE ");
s.append (getTableName ());
s.append (" SET ");
// cache rendered string for later calls.
updateString = s.toString();
return s;
}
@ -669,21 +679,6 @@ public final class DbMapping implements Updatable {
}
}
/**
* 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)

View file

@ -179,7 +179,7 @@ public final class Node implements INode, Serializable {
*/
public Node (String name, String id, String prototype, WrappedNodeManager nmgr) {
this.nmgr = nmgr;
this.id = id;
this.id = id;
this.name = name == null || "".equals (name) ? id : name;
if (prototype != null)
setPrototype (prototype);
@ -235,7 +235,7 @@ public final class Node implements INode, Serializable {
* Constructor used for nodes being stored in a relational database table.
*/
public Node (DbMapping dbm, ResultSet rs, DbColumn[] columns, WrappedNodeManager nmgr)
throws SQLException {
throws SQLException, IOException {
this.nmgr = nmgr;
// see what prototype/DbMapping this object should use
@ -302,13 +302,32 @@ public final class Node implements INode, Serializable {
newprop.setIntegerValue (num.longValue ());
break;
case Types.LONGVARBINARY:
case Types.VARBINARY:
case Types.BINARY:
newprop.setStringValue (rs.getString(columns[i].getName()));
break;
case Types.LONGVARBINARY:
case Types.LONGVARCHAR:
try {
newprop.setStringValue (rs.getString(columns[i].getName()));
} catch (SQLException x) {
Reader in = rs.getCharacterStream(columns[i].getName());
char[] buffer = new char[2048];
int read = 0, r = 0;
while ((r = in.read (buffer, read, buffer.length-read)) > -1) {
read += r;
if (read == buffer.length) {
// grow input buffer
char[] newBuffer = new char[buffer.length*2];
System.arraycopy (buffer, 0, newBuffer, 0, buffer.length);
buffer = newBuffer;
}
}
newprop.setStringValue (new String(buffer, 0, read));
}
break;
case Types.CHAR:
case Types.VARCHAR:
case Types.OTHER:
@ -435,9 +454,9 @@ public final class Node implements INode, Serializable {
Relation rel = getDbMapping ().getSubnodeRelation ();
if (rel != null) {
if (rel.usesPrimaryKey()) {
nmgr.evictKey (new DbKey (getDbMapping().getSubnodeMapping(), key));
nmgr.evictNodeByKey (new DbKey (getDbMapping().getSubnodeMapping(), key));
} else {
nmgr.evictKey (new SyntheticKey (getKey(), key));
nmgr.evictNodeByKey (new SyntheticKey (getKey(), key));
}
}
}
@ -493,7 +512,7 @@ public final class Node implements INode, Serializable {
} else {
anonymous = true;
}
} else if (p.contains (this) > -1) {
} else if (!anonymous && p.contains (this) > -1) {
anonymous = true;
}
} catch (Exception ignore) {
@ -873,13 +892,13 @@ public final class Node implements INode, Serializable {
public INode createNode (String nm, int where) {
checkWriteLock ();
boolean anon = false;
if (nm == null || "".equals (nm.trim ()))
boolean anon = false;
if (nm == null || "".equals (nm.trim ()))
anon = true;
Node n = new Node (nm, null, nmgr);
if (anon)
addNode (n, where);
else
else
setNode (nm, n);
return n;
}
@ -917,7 +936,7 @@ public final class Node implements INode, Serializable {
if (rel.otherType != null && rel.otherType.isRelational ())
return (IPathElement) nmgr.getNode (this, name, rel);
else
return (IPathElement) getNode (name);
return (IPathElement) getNode (name);
}
return (IPathElement) getSubnode (name);
} else {
@ -1748,11 +1767,20 @@ public final class Node implements INode, Serializable {
if (propMap == null)
return;
try {
Property p = (Property) propMap.remove (propname.toLowerCase ());
// if node is relational, leave a null property so that it is
// updated in the DB. Otherwise, remove the property.
Property p;
boolean relational = dbmap != null && dbmap.isRelational();
if (relational)
p = (Property) propMap.get (propname.toLowerCase ());
else
p = (Property) propMap.remove (propname.toLowerCase ());
if (p != null) {
checkWriteLock ();
if (p.getType() == Property.NODE)
p.unregisterNode ();
if (relational)
p.setStringValue (null);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis ();
if (state == CLEAN)

View file

@ -9,7 +9,6 @@ import helma.framework.core.Application;
import java.sql.*;
import java.io.*;
import java.util.*;
import com.workingdogs.village.*;
/**
* The NodeManager is responsible for fetching Nodes from the internal or
@ -360,8 +359,8 @@ public final class NodeManager {
}
/**
* Remove a node from the node cache. If at a later time it is accessed again, it will be
* refetched from the database.
* Remove a node from the node cache. If at a later time it is accessed again,
* it will be refetched from the database.
*/
public void evictNode (Node node) {
node.setState (INode.INVALID);
@ -369,7 +368,21 @@ public final class NodeManager {
}
/**
* Used when a key stops being valid for a node.
* Remove a node from the node cache. If at a later time it is accessed again,
* it will be refetched from the database.
*/
public void evictNodeByKey (Key key) {
Node n = (Node) cache.remove (key);
if (n != null) {
n.setState (INode.INVALID);
if (!(key instanceof DbKey))
cache.remove (n.getKey ());
}
}
/**
* Used when a key stops being valid for a node. The cached node itself
* remains valid, if it is present in the cache by other keys.
*/
public void evictKey (Key key) {
cache.remove (key);
@ -396,62 +409,129 @@ public final class NodeManager {
db.saveNode (txn, node.getID (), node);
} else {
// app.logEvent ("inserting relational node: "+node.getID ());
TableDataSet tds = null;
DbColumn[] columns = dbm.getColumns ();
StringBuffer b1 = dbm.getInsert ();
StringBuffer b2 = new StringBuffer (" ) VALUES ( ?");
String nameField = dbm.getNameField ();
String prototypeField = dbm.getPrototypeField ();
for (int i=0; i<columns.length; i++) {
Relation rel = columns[i].getRelation();
String name = columns[i].getName();
if ((rel != null && (rel.isPrimitive() || rel.isReference())) ||
name.equals (nameField) || name.equals (prototypeField))
{
b1.append (", "+columns[i].getName());
b2.append (", ?");
}
}
b1.append (b2.toString());
b1.append (" )");
Connection con = dbm.getConnection ();
PreparedStatement stmt = con.prepareStatement (b1.toString ());
if (logSql)
app.logEvent ("### insertNode: "+b1.toString ());
try {
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
Record rec = tds.addRecord ();
rec.setValue (dbm.getIDField (), node.getID ());
String nameField = dbm.getNameField ();
if (nameField != null)
rec.setValue (nameField, node.getName ());
int stmtNumber = 1;
stmt.setString (stmtNumber, node.getID());
for (Iterator i=dbm.getProp2DB().entrySet().iterator(); i.hasNext(); ) {
Map.Entry e = (Map.Entry) i.next ();
String propname = (String) e.getKey ();
Relation rel = (Relation) e.getValue ();
Property p = node.getProperty (propname);
Hashtable propMap = node.getPropMap ();
for (int i=0; i<columns.length; i++) {
Relation rel = columns[i].getRelation();
Property p = null;
if (rel != null && (rel.isPrimitive() || rel.isReference()))
p = (Property) propMap.get (rel.getPropName ());
String name = columns[i].getName ();
if (!(rel != null && (rel.isPrimitive() || rel.isReference())) && !name.equals (nameField) && !name.equals (prototypeField))
continue;
if (p != null && rel != null) {
switch (p.getType ()) {
case IProperty.STRING:
rec.setValue (rel.getDbField(), p.getStringValue ());
break;
case IProperty.BOOLEAN:
rec.setValue (rel.getDbField(), p.getBooleanValue ());
break;
case IProperty.DATE:
Timestamp t = new Timestamp (p.getDateValue ().getTime ());
rec.setValue (rel.getDbField(), t);
break;
case IProperty.INTEGER:
rec.setValue (rel.getDbField(), p.getIntegerValue ());
break;
case IProperty.FLOAT:
rec.setValue (rel.getDbField(), p.getFloatValue ());
break;
case IProperty.NODE:
if (rel.reftype == Relation.REFERENCE) {
// INode n = p.getNodeValue ();
// String foreignID = n == null ? null : n.getID ();
rec.setValue (rel.getDbField(), p.getStringValue ());
}
break;
stmtNumber++;
if (p != null) {
if (p.getValue() == null) {
stmt.setNull (stmtNumber, columns[i].getType ());
} else {
switch (columns[i].getType ()) {
case Types.BIT:
case Types.TINYINT:
case Types.BIGINT:
case Types.SMALLINT:
case Types.INTEGER:
stmt.setLong (stmtNumber, p.getIntegerValue());
break;
case Types.REAL:
case Types.FLOAT:
case Types.DOUBLE:
case Types.NUMERIC:
case Types.DECIMAL:
stmt.setDouble (stmtNumber, p.getFloatValue());
break;
case Types.VARBINARY:
case Types.BINARY:
case Types.BLOB:
stmt.setString (stmtNumber, p.getStringValue());
break;
case Types.LONGVARBINARY:
case Types.LONGVARCHAR:
try {
stmt.setString (stmtNumber, p.getStringValue());
} catch (SQLException x) {
String str = p.getStringValue();
Reader r = new StringReader (str);
stmt.setCharacterStream (stmtNumber, r, str.length());
}
break;
case Types.CHAR:
case Types.VARCHAR:
case Types.OTHER:
stmt.setString (stmtNumber, p.getStringValue());
break;
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
stmt.setTimestamp (stmtNumber, p.getTimestampValue());
break;
case Types.NULL:
stmt.setNull (stmtNumber, 0);
break;
default:
stmt.setString (stmtNumber, p.getStringValue());
break;
}
}
p.dirty = false;
} else if (rel != null && rel.getDbField() != null) {
rec.setValueNull (rel.getDbField());
} else {
if (name.equals (nameField))
stmt.setString (stmtNumber, node.getName());
else if (name.equals (prototypeField))
stmt.setString (stmtNumber, node.getPrototype ());
else
stmt.setNull (stmtNumber, columns[i].getType());
}
}
if (dbm.getPrototypeField () != null) {
rec.setValue (dbm.getPrototypeField (), node.getPrototype ());
}
rec.markForInsert ();
tds.save ();
stmt.executeUpdate ();
} catch (Exception x) {
x.printStackTrace ();
throw x;
} finally {
if (tds != null) try {
tds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
dbm.notifyDataChange ();
@ -475,82 +555,146 @@ public final class NodeManager {
db.saveNode (txn, node.getID (), node);
} else {
TableDataSet tds = null;
Hashtable propMap = node.getPropMap ();
Property[] props = new Property[propMap.size()];
propMap.values().toArray (props);
// make sure table meta info is loaded by dbmapping
dbm.getColumns ();
StringBuffer b = dbm.getUpdate ();
boolean comma = false;
for (int i=0; i<props.length; i++) {
// skip clean properties
if (props[i] == null || !props[i].dirty) {
// null out clean property so we don't consider it later
props[i] = null;
continue;
}
Relation rel = dbm.propertyToRelation (props[i].getName());
// skip readonly, virtual and collection relations
if (rel == null || rel.readonly || rel.virtual ||
(rel.reftype != Relation.REFERENCE && rel.reftype != Relation.PRIMITIVE))
{
// null out property so we don't consider it later
props[i] = null;
continue;
}
if (comma)
b.append (", ");
else
comma = true;
b.append (rel.getDbField());
b.append (" = ?");
}
// if no columns were updated, return
if (!comma)
return;
b.append (" WHERE ");
b.append (dbm.getIDField ());
b.append (" = ");
if (dbm.needsQuotes (dbm.getIDField ())) {
b.append ("'");
b.append (escape(node.getID()));
b.append ("'");
} else {
b.append (node.getID());
}
Connection con = dbm.getConnection ();
PreparedStatement stmt = con.prepareStatement (b.toString ());
if (logSql)
app.logEvent ("### updateNode: "+b.toString ());
int stmtNumber = 0;
try {
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
Record rec = tds.addRecord ();
rec.setValue (dbm.getIDField (), node.getID ());
int updated = 0;
for (Iterator i=dbm.getProp2DB().entrySet().iterator(); i.hasNext(); ) {
Map.Entry e = (Map.Entry) i.next ();
String propname = (String) e.getKey ();
Relation rel = (Relation) e.getValue ();
// skip properties that don't need to be updated before fetching them
if (rel != null && (rel.readonly || rel.virtual ||
(rel.reftype != Relation.REFERENCE && rel.reftype != Relation.PRIMITIVE)))
for (int i=0; i<props.length; i++) {
Property p = props[i];
if (p == null)
continue;
Relation rel = dbm.propertyToRelation (p.getName());
Property p = node.getProperty (propname);
stmtNumber++;
if (p != null && rel != null) {
if (p.getValue() == null) {
stmt.setNull (stmtNumber, rel.getColumnType ());
} else {
switch (rel.getColumnType ()) {
case Types.BIT:
case Types.TINYINT:
case Types.BIGINT:
case Types.SMALLINT:
case Types.INTEGER:
stmt.setLong (stmtNumber, p.getIntegerValue());
break;
if (p.dirty) {
switch (p.getType ()) {
case IProperty.STRING:
updated++;
rec.setValue (rel.getDbField(), p.getStringValue ());
break;
case IProperty.BOOLEAN:
updated++;
rec.setValue (rel.getDbField(), p.getBooleanValue ());
break;
case IProperty.DATE:
updated++;
Timestamp t = new Timestamp (p.getDateValue ().getTime ());
rec.setValue (rel.getDbField(), t);
break;
case IProperty.INTEGER:
updated++;
rec.setValue (rel.getDbField(), p.getIntegerValue ());
break;
case IProperty.FLOAT:
updated++;
rec.setValue (rel.getDbField(), p.getFloatValue ());
break;
case IProperty.NODE:
if (!rel.virtual && rel.reftype == Relation.REFERENCE) {
// INode n = p.getNodeValue ();
// String foreignID = n == null ? null : n.getID ();
updated++;
rec.setValue (rel.getDbField(), p.getStringValue ());
case Types.REAL:
case Types.FLOAT:
case Types.DOUBLE:
case Types.NUMERIC:
case Types.DECIMAL:
stmt.setDouble (stmtNumber, p.getFloatValue());
break;
case Types.VARBINARY:
case Types.BINARY:
case Types.BLOB:
stmt.setString (stmtNumber, p.getStringValue());
break;
case Types.LONGVARBINARY:
case Types.LONGVARCHAR:
try {
stmt.setString (stmtNumber, p.getStringValue());
} catch (SQLException x) {
String str = p.getStringValue();
Reader r = new StringReader (str);
stmt.setCharacterStream (stmtNumber, r, str.length());
}
break;
}
p.dirty = false;
if (!rel.isPrivate())
markMappingAsUpdated = true;
case Types.CHAR:
case Types.VARCHAR:
case Types.OTHER:
stmt.setString (stmtNumber, p.getStringValue());
break;
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
stmt.setTimestamp (stmtNumber, p.getTimestampValue());
break;
case Types.NULL:
stmt.setNull (stmtNumber, 0);
break;
default:
stmt.setString (stmtNumber, p.getStringValue());
break;
}
} else if (rel != null && rel.getDbField() != null) {
updated++;
rec.setValueNull (rel.getDbField());
}
p.dirty = false;
if (!rel.isPrivate())
markMappingAsUpdated = true;
}
if (updated > 0) {
// mark the key value as clean so no try is made to update it
rec.markValueClean (dbm.getIDField ());
rec.markForUpdate ();
tds.save ();
}
stmt.executeUpdate ();
} catch (Exception x) {
x.printStackTrace ();
throw x;
} finally {
if (tds != null) try {
tds.close ();
if (stmt != null) try {
stmt.close ();
} catch (Exception ignore) {}
}
if (markMappingAsUpdated)
dbm.notifyDataChange ();
}
@ -579,14 +723,17 @@ public final class NodeManager {
Statement st = null;
try {
Connection con = dbm.getConnection ();
st = con.createStatement ();
st.executeUpdate (new StringBuffer ("DELETE FROM ")
String str = new StringBuffer ("DELETE FROM ")
.append(dbm.getTableName ())
.append(" WHERE ")
.append(dbm.getIDField())
.append(" = ")
.append(node.getID())
.toString());
.toString();
st = con.createStatement ();
st.executeUpdate (str);
if (logSql)
app.logEvent ("### deleteNode: "+str);
} finally {
if (st != null) try {
st.close ();
@ -1084,7 +1231,13 @@ public final class NodeManager {
q.append ("WHERE ");
q.append (idfield);
q.append (" = ");
q.append (kstr);
if (dbm.needsQuotes (idfield)) {
q.append ("'");
q.append (escape(kstr));
q.append ("'");
} else {
q.append (kstr);
}
if (logSql)
app.logEvent ("### getNodeByKey: "+q.toString());

View file

@ -8,6 +8,7 @@ import java.util.*;
import java.io.*;
import java.text.*;
import helma.objectmodel.*;
import java.sql.Timestamp;
/**
* A property implementation for Nodes stored inside a database. Basically
@ -19,13 +20,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
private String propname;
private Node node;
private String svalue;
private boolean bvalue;
private long lvalue;
private double dvalue;
// protected String nvalueID;
private NodeHandle nhandle;
private Object jvalue;
private Object value;
private int type;
@ -42,29 +37,31 @@ public final class Property implements IProperty, Serializable, Cloneable {
case STRING:
// try to convert from old format
if (node.version < 7)
svalue = in.readUTF ();
value = in.readUTF ();
else
svalue = (String) in.readObject ();
value = in.readObject ();
break;
case BOOLEAN:
bvalue = in.readBoolean ();
value = in.readBoolean () ? Boolean.TRUE : Boolean.FALSE;
break;
case INTEGER:
value = new Long (in.readLong ());
break;
case DATE:
lvalue = in.readLong ();
value = new Date (in.readLong ());
break;
case FLOAT:
dvalue = in.readDouble ();
value = new Double (in.readDouble ());
break;
case NODE:
// try to convert from old format
if (node.version > 4)
nhandle = (NodeHandle) in.readObject ();
value = (NodeHandle) in.readObject ();
else
nhandle = new NodeHandle (new DbKey (null, in.readUTF ()));
value = new NodeHandle (new DbKey (null, in.readUTF ()));
break;
case JAVAOBJECT:
jvalue = in.readObject ();
value = in.readObject ();
break;
}
} catch (ClassNotFoundException x) {
@ -78,26 +75,28 @@ public final class Property implements IProperty, Serializable, Cloneable {
out.writeInt (type);
switch (type) {
case STRING:
out.writeObject (svalue);
out.writeObject (value);
break;
case BOOLEAN:
out.writeBoolean (bvalue);
out.writeBoolean (((Boolean) value).booleanValue());
break;
case INTEGER:
out.writeLong (((Long) value).longValue());
break;
case DATE:
out.writeLong (lvalue);
out.writeLong (((Date) value).getTime());
break;
case FLOAT:
out.writeDouble (dvalue);
out.writeDouble (((Double) value).doubleValue());
break;
case NODE:
out.writeObject (nhandle);
out.writeObject (value);
break;
case JAVAOBJECT:
if (jvalue != null && !(jvalue instanceof Serializable))
if (value != null && !(value instanceof Serializable))
out.writeObject (null);
else
out.writeObject (jvalue);
out.writeObject (value);
break;
}
}
@ -114,10 +113,10 @@ public final class Property implements IProperty, Serializable, Cloneable {
dirty = true;
}
public Property (String propname, Node node, Node value) {
public Property (String propname, Node node, Node valueNode) {
this (propname, node);
type = NODE;
nhandle = value == null ? null : value.getHandle ();
value = valueNode == null ? null : valueNode.getHandle ();
dirty = true;
}
@ -126,141 +125,115 @@ public final class Property implements IProperty, Serializable, Cloneable {
}
public Object getValue () {
switch (type) {
case STRING:
return svalue;
case BOOLEAN:
return new Boolean (bvalue);
case INTEGER:
return new Long (lvalue);
case FLOAT:
return new Double (dvalue);
case DATE:
return new Date (lvalue);
case NODE:
return null;
case JAVAOBJECT:
return jvalue;
}
return null;
return value;
}
public void setStringValue (String value) {
public int getType () {
return type;
}
public void setStringValue (String str) {
if (type == NODE)
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
type = STRING;
this.svalue = value;
value = str;
dirty = true;
}
public void setIntegerValue (long value) {
public void setIntegerValue (long l) {
if (type == NODE)
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
type = INTEGER;
this.lvalue = value;
value = new Long(l);
dirty = true;
}
public void setFloatValue (double value) {
public void setFloatValue (double d) {
if (type == NODE)
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
type = FLOAT;
this.dvalue = value;
value = new Double(d);
dirty = true;
}
public void setDateValue (Date value) {
public void setDateValue (Date date) {
if (type == NODE)
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
type = DATE;
this.lvalue = value == null ? 0 : value.getTime();
value = date;
dirty = true;
}
public void setBooleanValue (boolean value) {
public void setBooleanValue (boolean bool) {
if (type == NODE)
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
type = BOOLEAN;
this.bvalue = value;
value = bool ? Boolean.TRUE : Boolean.FALSE;
dirty = true;
}
public void setNodeValue (Node value) {
public void setNodeValue (Node node) {
// value.checkWriteLock ();
if (type == NODE)
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
// registerNode (value);
type = NODE;
nhandle = value.getHandle ();
value = node == null ? null : node.getHandle ();
dirty = true;
}
public void setNodeHandle (NodeHandle value) {
public void setNodeHandle (NodeHandle handle) {
if (type == NODE)
unregisterNode ();
if (type == JAVAOBJECT)
this.jvalue = null;
// registerNode (value);
type = NODE;
nhandle = value;
value = handle;
dirty = true;
}
public NodeHandle getNodeHandle () {
return nhandle;
if (type == NODE)
return (NodeHandle) value;
return null;
}
public void convertToNodeReference (DbMapping dbm) {
String id = getStringValue ();
if (id == null)
nhandle = null;
else
nhandle = new NodeHandle (new DbKey (dbm, id));
if (value != null && !(value instanceof NodeHandle))
value = new NodeHandle (new DbKey (dbm, value.toString ()));
type = NODE;
}
public void setJavaObjectValue (Object value) {
public void setJavaObjectValue (Object obj) {
if (type == NODE)
unregisterNode ();
type = JAVAOBJECT;
this.jvalue = value;
value = obj;
}
/**
* tell a the value node that it is no longer used as a property.
* tell a the value node that it is no longer used as a property.
* 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);
if (value == null || !(value instanceof NodeHandle))
return;
NodeHandle nhandle = (NodeHandle) value;
Node 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
@ -281,22 +254,20 @@ public final class Property implements IProperty, Serializable, Cloneable {
public String getStringValue () {
if (value == null)
return null;
switch (type) {
case STRING:
return svalue;
case BOOLEAN:
return bvalue ? "true" : "false";
case DATE:
SimpleDateFormat format = new SimpleDateFormat ("dd.MM.yy HH:mm");
return format.format (new Date (lvalue));
case INTEGER:
return Long.toString (lvalue);
case FLOAT:
return Double.toString (dvalue);
case NODE:
return nhandle == null ? null : nhandle.getID ();
case JAVAOBJECT:
return jvalue == null ? null : jvalue.toString ();
return value.toString ();
case DATE:
SimpleDateFormat format = new SimpleDateFormat ("dd.MM.yy hh:mm:ss");
return format.format ((Date) value);
case NODE:
return ((NodeHandle) value).getID ();
}
return "";
}
@ -306,51 +277,66 @@ public final class Property implements IProperty, Serializable, Cloneable {
}
public long getIntegerValue () {
if (type == INTEGER)
return lvalue;
return 0;
if (type == INTEGER)
return ((Long) value).longValue ();
if (type == FLOAT)
return ((Double) value).longValue ();
if (type == BOOLEAN)
return ((Boolean) value).booleanValue() ? 1 : 0;
try {
return Long.parseLong (getStringValue());
} catch (Exception x) {
return 0;
}
}
public double getFloatValue () {
if (type == FLOAT)
return dvalue;
return 0.0;
if (type == FLOAT)
return ((Double) value).doubleValue();
if (type == INTEGER)
return ((Long) value).doubleValue ();
try {
return Double.parseDouble (getStringValue());
} catch (Exception x) {
return 0.0;
}
}
public Date getDateValue () {
if (type == DATE)
return new Date (lvalue);
if (type == DATE)
return (Date) value;
return null;
}
public Timestamp getTimestampValue () {
if (type == DATE && value != null)
return new Timestamp (((Date) value).getTime());
return null;
}
public boolean getBooleanValue () {
if (type == BOOLEAN)
return bvalue;
if (type == BOOLEAN)
return ((Boolean) value).booleanValue();
if (type == INTEGER)
return !(0 == getIntegerValue());
return false;
}
public INode getNodeValue () {
if (nhandle != null) {
Node n = nhandle.getNode (node.nmgr);
if (n != null) return n;
if (type == NODE && value != null) {
NodeHandle nhandle = (NodeHandle) value;
return nhandle.getNode (node.nmgr);
}
return null;
}
public Object getJavaObjectValue () {
if (type == JAVAOBJECT)
return jvalue;
return value;
return null;
}
public int getType () {
return type;
}
}

View file

@ -110,6 +110,10 @@ import java.util.Vector;
nmgr.evictNode (node);
}
public void evictNodeByKey (Key key) {
nmgr.evictNodeByKey (key);
}
public void evictKey (Key key) {
nmgr.evictKey (key);
}

View file

@ -6,6 +6,7 @@ import java.util.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import helma.objectmodel.*;
import helma.util.SystemProperties;
@ -75,6 +76,15 @@ public class XmlConverter implements XmlConstants {
}
}
public INode convertFromString( String xml, INode helmaNode ) throws RuntimeException {
Document document = XmlUtil.parse (new InputSource (new StringReader (xml)));
if ( document!=null && document.getDocumentElement()!=null ) {
return convert( document.getDocumentElement(), helmaNode, new HashMap() );
} else {
return helmaNode;
}
}
public INode convert( Element element, INode helmaNode, Map nodeCache ) {
offset++;
// previousNode is used to cache previous nodes with the same prototype
@ -82,17 +92,16 @@ public class XmlConverter implements XmlConstants {
Object previousNode = null;
if (DEBUG)
debug("reading " + element.getNodeName() );
helmaNode.setName( element.getNodeName() );
String prototype = props.getProperty(element.getNodeName()+"._prototype");
if ( prototype == null && !sparse )
prototype = "HopObject";
// if we have a prototype (either explicit or implicit "hopobject"),
// if we have a prototype (either explicit or implicit "hopobject"),
// set it on the Helma node and store it in the node cache.
if ( prototype != null ) {
helmaNode.setName( element.getNodeName() );
helmaNode.setPrototype( prototype );
previousNode = nodeCache.put (prototype, helmaNode);
}
// check attributes of the current element
attributes(element, helmaNode, nodeCache);
// check child nodes of the current element
@ -113,7 +122,7 @@ public class XmlConverter implements XmlConstants {
private INode children( Element element, helma.objectmodel.INode helmaNode, Map nodeCache ) {
NodeList list = element.getChildNodes();
int len = list.getLength();
boolean nodeHasPrototype = helmaNode.getPrototype() != null;
boolean nodeIsInitialized = !nodeCache.isEmpty();
StringBuffer textcontent = new StringBuffer();
String domKey, helmaKey;
for ( int i=0; i<len; i++ ) {
@ -121,9 +130,9 @@ public class XmlConverter implements XmlConstants {
// loop through the list of children
org.w3c.dom.Node childNode = list.item(i);
// if the current node hasn't been initialized yet, try if it can
// if the current node hasn't been initialized yet, try if it can
// be initialized and converted from one of the child elements.
if (!nodeHasPrototype) {
if (!nodeIsInitialized) {
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
convert ((Element) childNode, helmaNode, nodeCache);
if (helmaNode.getPrototype() != null)
@ -162,8 +171,9 @@ public class XmlConverter implements XmlConstants {
String prototype = helmaKey.substring (0, dot);
INode node = (INode) nodeCache.get (prototype);
helmaKey = helmaKey.substring (dot+1);
if (node != null && node.getString(helmaKey)==null)
if (node != null && node.getString(helmaKey)==null) {
node.setString (helmaKey, XmlUtil.getTextContent (childNode));
}
} else if ( helmaNode.getString(helmaKey)==null ) {
helmaNode.setString( helmaKey, XmlUtil.getTextContent(childNode) );
if (DEBUG)
@ -220,7 +230,8 @@ public class XmlConverter implements XmlConstants {
if (helmaKey == null) {
// we don't map this child element itself since we do
// sparse parsing, but there may be something of interest
// in the child's child elements.
// in the child's attributes and child elements.
attributes (childElement, helmaNode, nodeCache);
children (childElement, helmaNode, nodeCache);
continue;
}
@ -295,8 +306,9 @@ public class XmlConverter implements XmlConstants {
if (dot > -1) {
String prototype = helmaKey.substring (0, dot);
INode node = (INode) nodeCache.get (prototype);
if (node != null)
if (node != null) {
node.setString (helmaKey.substring(dot+1), attr.getNodeValue());
}
} else if (helmaNode.getPrototype() != null) {
helmaNode.setString( helmaKey, attr.getNodeValue() );
}

View file

@ -97,7 +97,8 @@ public class XmlUtil {
int ct = childlist.getLength();
for ( int j=0; j<ct; j++ ) {
org.w3c.dom.Node childNode = childlist.item(j);
if ( childNode.getNodeType()==org.w3c.dom.Node.TEXT_NODE ) {
if ( childNode.getNodeType() == Node.TEXT_NODE ||
childNode.getNodeType() == Node.CDATA_SECTION_NODE) {
childtext.append(childNode.getNodeValue().trim() );
}
}

View file

@ -123,6 +123,8 @@ public class FesiEngine implements ScriptingEngine {
* necessary to bootstrap the rest is parsed.
*/
private void initialize () {
// set the thread filed in the FESI evaluator
evaluator.thread = Thread.currentThread ();
Collection protos = app.getPrototypes();
for (Iterator i=protos.iterator(); i.hasNext(); ) {
Prototype proto = (Prototype) i.next ();
@ -132,13 +134,14 @@ public class FesiEngine implements ScriptingEngine {
// we always need it and there's no chance to trigger
// creation on demand.
getPrototype ("global");
evaluator.thread = null;
}
/**
* Initialize a prototype without fully parsing its script files.
*/
void initPrototype (Prototype prototype) {
// System.err.println ("FESI INIT PROTO "+prototype);
// System.err.println ("FESI INIT PROTO "+prototype);
ObjectPrototype op = null;
// get the prototype's prototype if possible and necessary
@ -193,7 +196,7 @@ public class FesiEngine implements ScriptingEngine {
* Set up a prototype, parsing and compiling all its script files.
*/
void evaluatePrototype (Prototype prototype) {
// System.err.println ("FESI EVALUATE PROTO "+prototype+" FOR "+this);
// System.err.println ("FESI EVALUATE PROTO "+prototype+" FOR "+this);
ObjectPrototype op = null;
// get the prototype's prototype if possible and necessary
@ -230,8 +233,8 @@ public class FesiEngine implements ScriptingEngine {
}
// Register a constructor for all types except global.
// This will first create a new prototyped hopobject and then calls
// the actual (scripted) constructor on it.
// This will first create a new prototyped hopobject and then calls
// the actual (scripted) constructor on it.
if (!"global".equalsIgnoreCase (name) && !"root".equalsIgnoreCase (name)) {
try {
FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
@ -263,11 +266,13 @@ public class FesiEngine implements ScriptingEngine {
}
}
/**
* This method is called before an execution context is entered to let the
/**
* This method is called before an execution context is entered to let the
* engine know it should update its prototype information.
*/
public void updatePrototypes () {
// set the thread filed in the FESI evaluator
evaluator.thread = Thread.currentThread ();
Collection protos = app.getPrototypes();
for (Iterator i=protos.iterator(); i.hasNext(); ) {
Prototype proto = (Prototype) i.next ();

View file

@ -54,11 +54,17 @@ public class NodeConstructor extends BuiltinFunctionObject {
// 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)
if (op.getProperty ("constructor",
"constructor".hashCode())
instanceof ConstructedFunctionObject)
node.doIndirectCall (engine.getEvaluator(), node, "constructor", arguments);
else
else if (op.getProperty (typename,
typename.hashCode())
instanceof ConstructedFunctionObject)
node.doIndirectCall (engine.getEvaluator(), node, typename, arguments);
} catch (Exception ignore) {}
} catch (Exception x) {
throw new EcmaScriptException (x.toString());
}
}
return node;
}

View file

@ -39,6 +39,7 @@ public class DomExtension extends Extension {
globalXml.putHiddenProperty ("write", new XmlWrite ("write", evaluator, fp));
globalXml.putHiddenProperty ("writeToString", new XmlWriteToString ("writeToString", evaluator, fp));
globalXml.putHiddenProperty ("get", new XmlGet ("get", evaluator, fp));
globalXml.putHiddenProperty ("getFromString", new XmlGetFromString ("getFromString", evaluator, fp));
go.putHiddenProperty ("Xml", globalXml);
}
@ -175,6 +176,31 @@ public class DomExtension extends Extension {
}
}
class XmlGetFromString extends BuiltinFunctionObject {
XmlGetFromString(String name, Evaluator evaluator, FunctionPrototype fp) {
super(fp, evaluator, name, 1);
}
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if ( arguments==null || arguments.length==0 )
throw new EcmaScriptException("Xml.getFromString() needs an XML string as parameter");
try {
XmlConverter converter;
if ( arguments.length>1 ) {
converter = new XmlConverter (arguments[1].toString());
} else {
converter = new XmlConverter ();
}
INode node = new helma.objectmodel.db.Node ( (String)null, (String)null, this.evaluator.engine.getApplication().getWrappedNodeManager() );
INode result = converter.convertFromString (arguments[0].toString(),node);
return this.evaluator.engine.getNodeWrapper(result);
} catch ( NoClassDefFoundError e ) {
throw new EcmaScriptException("Can't load dom-capable xml parser.");
} catch ( RuntimeException f ) {
throw new EcmaScriptException(f.toString());
}
}
}
}

View file

@ -49,6 +49,8 @@ public abstract class AbstractServletClient extends HttpServlet {
uploadLimit = upstr == null ? 1024 : Integer.parseInt (upstr);
// get cookie domain
cookieDomain = init.getInitParameter ("cookieDomain");
if (cookieDomain != null)
cookieDomain = cookieDomain.toLowerCase();
// get default encoding
defaultEncoding = init.getInitParameter ("charset");
debug = ("true".equalsIgnoreCase (init.getInitParameter ("debug")));
@ -73,7 +75,6 @@ public abstract class AbstractServletClient extends HttpServlet {
protected void execute (HttpServletRequest request,
HttpServletResponse response,
byte method) {
Cookie[] cookies = request.getCookies();
RequestTrans reqtrans = new RequestTrans (method);
// get app and path from original request path
@ -120,11 +121,12 @@ public abstract class AbstractServletClient extends HttpServlet {
}
// read cookies
if (cookies != null) {
for (int i=0; i < cookies.length;i++) try {
Cookie[] reqCookies = request.getCookies();
if (reqCookies != null) {
for (int i=0; i < reqCookies.length;i++) try {
// get Cookies
String nextKey = cookies[i].getName ();
String nextPart = cookies[i].getValue ();
String nextKey = reqCookies[i].getName ();
String nextPart = reqCookies[i].getValue ();
if ("HopSession".equals (nextKey))
reqtrans.session = nextPart;
else
@ -157,6 +159,14 @@ public abstract class AbstractServletClient extends HttpServlet {
if (remotehost != null)
reqtrans.set ("http_remotehost", remotehost);
// get the cookie domain to use for this response, if any.
String resCookieDomain = cookieDomain;
if (resCookieDomain != null) {
// check if cookieDomain is valid for this response.
// (note: cookieDomain is guaranteed to be lower case)
if (host != null && host.toLowerCase().indexOf (cookieDomain) == -1)
resCookieDomain = null;
}
// check if we need to create a session id. also handle the
// case that the session id doesn't match the remote host address
if (reqtrans.session == null || !reqtrans.session.startsWith (remotehost)) {
@ -165,8 +175,8 @@ public abstract class AbstractServletClient extends HttpServlet {
System.currentTimeMillis (), 36);
Cookie c = new Cookie("HopSession", reqtrans.session);
c.setPath ("/");
if (cookieDomain != null)
c.setDomain (cookieDomain);
if (resCookieDomain != null)
c.setDomain (resCookieDomain);
response.addCookie(c);
}
@ -183,6 +193,16 @@ public abstract class AbstractServletClient extends HttpServlet {
reqtrans.path = getPathInfo (request);
ResponseTrans restrans = execute (reqtrans);
// set cookies
int ncookies = restrans.countCookies();
if (restrans.countCookies() > 0) {
CookieTrans[] resCookies = restrans.getCookies ();
for (int i = 0; i < resCookies.length; i++) try {
Cookie c = resCookies[i].getCookie ("/", resCookieDomain);
response.addCookie(c);
} catch (Exception ignore) {}
}
// write response
writeResponse (request, response, restrans);
} catch (Exception x) {
@ -210,15 +230,6 @@ public abstract class AbstractServletClient extends HttpServlet {
HttpServletResponse res,
ResponseTrans hopres) {
int ncookies = hopres.countCookies();
if (hopres.countCookies() > 0) {
CookieTrans[] cookies = hopres.getCookies ();
for (int i = 0; i < cookies.length; i++) try {
Cookie c = cookies[i].getCookie ("/", cookieDomain);
res.addCookie(c);
} catch (Exception ignore) {}
}
if (hopres.getETag() != null) {
res.setHeader ("ETag", hopres.getETag());
}

View file

@ -363,11 +363,14 @@ public final class HtmlEncoder {
if (i < l-2) {
if (!insideMacroTag && '%' == str.charAt(i+1)) {
// this is the beginning of a Helma macro tag
insideMacroTag = insideTag = true;
macroQuoteChar = '\u0000';
if (!insideCodeTag) {
insideMacroTag = insideTag = true;
macroQuoteChar = '\u0000';
}
} else if ('!' == str.charAt(i+1) && '-' == str.charAt(i+2)) {
// the beginning of an HTML comment?
insideComment = insideTag = (i<l-3 && '-' == str.charAt(i+3));
if (!insideCodeTag)
insideComment = insideTag = (i<l-3 && '-' == str.charAt(i+3));
} else if (!insideTag) {
// check if this is a HTML tag.
boolean insideCloseTag = ('/' == str.charAt(i+1));
@ -480,6 +483,7 @@ public final class HtmlEncoder {
}
}
/**
*
*/
@ -494,6 +498,13 @@ public final class HtmlEncoder {
return ret.toString();
}
/**
*
*/
public final static void encodeFormValue (String str, StringBuffer ret) {
encodeAll (str, ret, false);
}
/**
*
@ -512,9 +523,8 @@ public final class HtmlEncoder {
/**
*
*/
public final static String encodeAll (String str, StringBuffer ret) {
public final static void encodeAll (String str, StringBuffer ret) {
encodeAll (str, ret, true);
return ret.toString();
}