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

View file

@ -32,6 +32,12 @@ public abstract class HelmaExtension {
*/ */
public abstract void applicationStopped (Application app); 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 * 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 * 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 () ); 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 { public HashMap initScripting (Application app, ScriptingEngine engine) throws ConfigurationException {
if (!(engine instanceof FesiEngine)) if (!(engine instanceof FesiEngine))
throw new ConfigurationException ("scripting engine " + engine.toString () + " not supported in DemoExtension"); 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); res.writeBinary (what);
} }
public void debug (String message) { public void debug (Object message) {
res.debug (message); res.debug (message);
} }

View file

@ -185,18 +185,14 @@ 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) if (buffer == null)
return 0; buffer = new StringBuffer (INITIAL_BUFFER_SIZE);
return buffer.length (); return buffer;
} }
public void setBufferLength(int l) {
if (buffer != null)
buffer.setLength (l);
}
/** /**
* Append a string to the response unchanged. This is often called * Append a string to the response unchanged. This is often called
@ -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 * that buffer exists and its length is larger than offset. str may be null, in which
* case nothing happens. * case nothing happens.
*/ */
public void debug (String str) { public void debug (Object message) {
if (debugBuffer == null) if (debugBuffer == null)
debugBuffer = new StringBuffer (); 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) if (charset == null)
charset = "ISO-8859-1"; charset = "ISO-8859-1";
boolean encodingError = false; boolean encodingError = false;
// only close if the response hasn't been closed yet
if (response == null) { if (response == null) {
if (buffer != null) { // if debug buffer exists, append it to main buffer
if (debugBuffer != null) if (debugBuffer != null) {
if (buffer == null)
buffer = debugBuffer;
else
buffer.append (debugBuffer); buffer.append (debugBuffer);
}
// get the buffer's bytes in the specified encoding
if (buffer != null) {
try { try {
response = buffer.toString ().getBytes (charset); response = buffer.toString ().getBytes (charset);
} catch (UnsupportedEncodingException uee) { } catch (UnsupportedEncodingException uee) {
encodingError = true; encodingError = true;
response = buffer.toString ().getBytes (); 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 { } else {
response = new byte[0]; 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 = new TypeManager (this);
typemgr.createPrototypes (); typemgr.createPrototypes ();
// logEvent ("Started type manager for "+name); // logEvent ("Started type manager for "+name);
@ -319,6 +324,11 @@ public final class Application implements IPathElement, Runnable {
ext.applicationStopped (this); ext.applicationStopped (this);
} }
// store the sessions if wanted
if ("true".equalsIgnoreCase (getProperty("persistentSessions"))) {
storeSessionData (null);
}
// stop logs if they exist // stop logs if they exist
if (eventLog != null) { if (eventLog != null) {
eventLog.close (); eventLog.close ();
@ -840,34 +850,31 @@ public final class Application implements IPathElement, Runnable {
*/ */
public String getNodeHref (Object elem, String actionName) { public String getNodeHref (Object elem, String actionName) {
// Object root = getDataRoot (); // Object root = getDataRoot ();
// check optional root prototype from app.properties // check optional root prototype from app.properties
String rootProto = props.getProperty ("rootPrototype"); String rootProto = props.getProperty ("rootPrototype");
String divider = "/"; StringBuffer b = new StringBuffer (baseURI);
StringBuffer b = new StringBuffer ();
Object parent = null;
int loopWatch = 0;
while (elem != null && (parent = getParentElement (elem)) != null && elem != rootObject) { composeHref (elem, b, rootProto, 0);
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;
}
if (actionName != null) if (actionName != null)
b.append (UrlEncoded.encode (actionName)); 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 * 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; NodeHandle userhandle = session.userHandle;
if (userhandle != null) { if (userhandle != null) {
try { try {
String[] str = new String [1]; Object[] param = { session.getSessionID() };
str[0] = session.getSessionID (); eval.invokeFunction (userhandle, "onLogout", param);
eval.invokeFunction (userhandle, "onLogout", str);
} catch (Exception ignore) {} } catch (Exception ignore) {}
} }
destroySession(session); destroySession(session);
@ -1256,6 +1262,14 @@ public final class Application implements IPathElement, Runnable {
// if node manager exists, update it // if node manager exists, update it
if (nmgr != null) if (nmgr != null)
nmgr.updateProperties (props); 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 // set prop read timestamp
lastPropertyRead = props.lastModified (); 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"); 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 (); app.clearCache ();
} }
public void log (String msg) { public void log (Object msg) {
app.logEvent (msg); String str = msg == null ? "null" : msg.toString();
app.logEvent (str);
} }
public void log (String logname, String msg) { public void log (String logname, Object msg) {
app.getLogger (logname).log (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()) { 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()) { 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); scriptingEngine.invoke (currentElement, "onRequest", new Object[0], false);
} catch (RedirectException redir) { } catch (RedirectException redir) {
throw redir; throw redir;
} catch (Exception ignore) {
// function is not defined or caused an exception, ignore
} }
// reset skin recursion detection counter // reset skin recursion detection counter
@ -351,7 +349,7 @@ public final class RequestEvaluator implements Runnable {
break; break;
case XMLRPC: case XMLRPC:
try { try {
localrtx.begin (app.getName()+":xmlrpc/"+method); localrtx.begin (app.getName()+":xmlrpc:"+method);
root = app.getDataRoot (); root = app.getDataRoot ();
@ -386,23 +384,25 @@ public final class RequestEvaluator implements Runnable {
result = scriptingEngine.invoke (currentElement, method, args, true); result = scriptingEngine.invoke (currentElement, method, args, true);
commitTransaction (); commitTransaction ();
} catch (Exception wrong) { } catch (Exception x) {
abortTransaction (false); 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 // If the transactor thread has been killed by the invoker thread we don't have to
// bother for the error message, just quit. // bother for the error message, just quit.
if (localrtx != rtx) { if (localrtx != rtx) {
return; return;
} }
this.exception = wrong; this.exception = x;
} }
break; break;
case INTERNAL: case INTERNAL:
// Just a human readable descriptor of this invocation // 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 is an instance of NodeHandle, get the node object itself.
if (thisObject != null && thisObject instanceof NodeHandle) { if (thisObject != null && thisObject instanceof NodeHandle) {
@ -438,17 +438,19 @@ public final class RequestEvaluator implements Runnable {
result = scriptingEngine.invoke (thisObject, method, args, false); result = scriptingEngine.invoke (thisObject, method, args, false);
commitTransaction (); commitTransaction ();
} catch (Exception wrong) { } catch (Exception x) {
abortTransaction (false); 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 // If the transactor thread has been killed by the invoker thread we don't have to
// bother for the error message, just quit. // bother for the error message, just quit.
if (localrtx != rtx) { if (localrtx != rtx) {
return; return;
} }
this.exception = wrong; this.exception = x;
} }
break; break;

View file

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

View file

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

View file

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

View file

@ -94,13 +94,17 @@ public abstract class ImageWrapper {
} }
public void resize (int w, int h) { 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); img = img.getScaledInstance (w, h, Image.SCALE_SMOOTH);
width = w; width = w;
height = h; 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); public abstract void reduceColors (int colors);
public abstract void saveAs (String filename); public abstract void saveAs (String filename);

View file

@ -25,7 +25,7 @@ import org.apache.xmlrpc.*;
public class Server implements IPathElement, Runnable { 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; public final long starttime;
// if true we only accept RMI and XML-RPC connections from // if true we only accept RMI and XML-RPC connections from
@ -90,6 +90,9 @@ import org.apache.xmlrpc.*;
// create new server instance // create new server instance
server = new Server (args); server = new Server (args);
// start the server main thread
server.start ();
} }
/** /**
@ -137,9 +140,14 @@ import org.apache.xmlrpc.*;
} catch (Exception portx) { } catch (Exception portx) {
usageError = true; 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; usageError = true;
} }
}
// get main property file from home dir or vice versa, depending on what we have. // get main property file from home dir or vice versa, depending on what we have.
// get property file from hopHome // get property file from hopHome
@ -291,12 +299,18 @@ import org.apache.xmlrpc.*;
} }
} }
}
protected void start () {
// Start running, finishing setup and then entering a loop to check changes // Start running, finishing setup and then entering a loop to check changes
// in the apps.properties file. // in the apps.properties file.
mainThread = new Thread (this); mainThread = new Thread (this);
mainThread.start (); mainThread.start ();
} }
protected void stop () {
mainThread = null;
}
/** /**
* The main method of the Server. Basically, we set up Applications and than * 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.URLClassLoader;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder;
import java.io.File; import java.io.File;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -16,10 +17,20 @@ import java.security.Policy;
*/ */
public class Main { public class Main {
public static final String[] jars = { "helma.jar", "jetty.jar", "crimson.jar", "xmlrpc.jar", public static final String[] jars = {
"village.jar", "servlet.jar", "regexp.jar", "mail.jar", "helma.jar",
"activation.jar", "netcomponents.jar", "jimi.jar", "jetty.jar",
"apache-dom.jar", "jdom.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 { public static void main (String[] args) throws Exception {
@ -54,9 +65,13 @@ public class Main {
} catch (Exception x) { } catch (Exception x) {
// unable to get Helma installation dir from launcher jar // unable to get Helma installation dir from launcher jar
System.err.println ("Unable to get Helma installation directory: "+x); 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 // set up the class path
File libdir = new File (installDir, "lib"); File libdir = new File (installDir, "lib");
ArrayList jarlist = new ArrayList (); ArrayList jarlist = new ArrayList ();
@ -68,17 +83,20 @@ public class Main {
File extdir =new File (libdir, "ext"); File extdir =new File (libdir, "ext");
File[] files = extdir.listFiles (new FilenameFilter() { File[] files = extdir.listFiles (new FilenameFilter() {
public boolean accept (File dir, String name) { 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) 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 // WORKAROUND: add the files in lib/ext before
// lib/apache-dom.jar, since otherwise putting a full version // lib/apache-dom.jar, since otherwise putting a full version
// of Xerces in lib/ext would cause a version conflict with the // of Xerces in lib/ext would cause a version conflict with the
// xerces classes in lib/apache-dom.jar. Generally, having some pieces // xerces classes in lib/apache-dom.jar. Generally, having some pieces
// of Xerces in lib/apache-dom.jar is kind of problematic. // of Xerces in lib/apache-dom.jar is kind of problematic.
jarlist.add (jars.length-3, new URL ("file:" + files[i].getAbsolutePath())); 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()]; URL[] urls = new URL[jarlist.size()];
jarlist.toArray (urls); jarlist.toArray (urls);
FilteredClassLoader loader = new FilteredClassLoader (urls); FilteredClassLoader loader = new FilteredClassLoader (urls);

View file

@ -64,7 +64,7 @@ public final class Property implements IProperty, Serializable {
return null; return null;
} }
public void setStringValue (String value) throws ParseException { public void setStringValue (String value) {
if (type == NODE) if (type == NODE)
this.nvalue = null; this.nvalue = null;
if (type == JAVAOBJECT) if (type == JAVAOBJECT)
@ -116,6 +116,7 @@ public final class Property implements IProperty, Serializable {
this.nvalue = value; this.nvalue = value;
} }
public void setJavaObjectValue (Object value) { public void setJavaObjectValue (Object value) {
if (type == NODE) if (type == NODE)
this.nvalue = null; this.nvalue = null;
@ -124,7 +125,6 @@ public final class Property implements IProperty, Serializable {
} }
public String getStringValue () { public String getStringValue () {
switch (type) { switch (type) {
case STRING: case STRING:

View file

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

View file

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

View file

@ -11,7 +11,6 @@ import java.util.Enumeration;
import java.util.Iterator; import java.util.Iterator;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.sql.*; import java.sql.*;
import com.workingdogs.village.*;
/** /**
* A DbMapping describes how a certain type of Nodes is to mapped to a * 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; DbColumn[] columns = null;
// Map of db columns by name // Map of db columns by name
HashMap columnMap; HashMap columnMap;
// pre-rendered select statement // pre-rendered select statement
String select = null; String selectString = null;
String insertString = null;
String updateString = null;
// db field used as primary key // db field used as primary key
private String idField; private String idField;
@ -81,13 +83,10 @@ public final class DbMapping implements Updatable {
// remember last key generated for this table // remember last key generated for this table
long lastID; 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) // 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 // timestamp of last modification of an object of this type
long lastDataChange; long lastDataChange;
@ -188,13 +187,10 @@ public final class DbMapping implements Updatable {
} }
lastTypeChange = props.lastModified (); lastTypeChange = props.lastModified ();
// null the cached schema & keydef so it's rebuilt the next time around // null the cached columns and select string
schema = null;
keydef = null;
// same with columns and select string
columns = null; columns = null;
columnMap.clear(); columnMap.clear();
select = null; selectString = insertString = updateString = null;
if (extendsProto != null) { if (extendsProto != null) {
@ -390,7 +386,9 @@ public final class DbMapping implements Updatable {
return null; return null;
if (table == null && parentMapping != null) if (table == null && parentMapping != null)
return parentMapping.propertyToColumnName (propName); 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)) if (rel != null && (rel.reftype == Relation.PRIMITIVE || rel.reftype == Relation.REFERENCE))
return rel.columnName; return rel.columnName;
return null; return null;
@ -415,7 +413,9 @@ public final class DbMapping implements Updatable {
return null; return null;
if (table == null && parentMapping != null) if (table == null && parentMapping != null)
return parentMapping.propertyToRelation (propName); 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 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. * 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 { public StringBuffer getSelect () throws SQLException, ClassNotFoundException {
String sel = select; String sel = selectString;
if (sel != null) if (sel != null)
return new StringBuffer (sel); return new StringBuffer (sel);
StringBuffer s = new StringBuffer ("SELECT * FROM "); StringBuffer s = new StringBuffer ("SELECT * FROM ");
s.append (getTableName ()); s.append (getTableName ());
s.append (" "); s.append (" ");
// cache rendered string for later calls. // 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; 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 () { public String toString () {
if (typename == null) if (typename == null)

View file

@ -235,7 +235,7 @@ public final class Node implements INode, Serializable {
* Constructor used for nodes being stored in a relational database table. * Constructor used for nodes being stored in a relational database table.
*/ */
public Node (DbMapping dbm, ResultSet rs, DbColumn[] columns, WrappedNodeManager nmgr) public Node (DbMapping dbm, ResultSet rs, DbColumn[] columns, WrappedNodeManager nmgr)
throws SQLException { throws SQLException, IOException {
this.nmgr = nmgr; this.nmgr = nmgr;
// see what prototype/DbMapping this object should use // see what prototype/DbMapping this object should use
@ -302,13 +302,32 @@ public final class Node implements INode, Serializable {
newprop.setIntegerValue (num.longValue ()); newprop.setIntegerValue (num.longValue ());
break; break;
case Types.LONGVARBINARY:
case Types.VARBINARY: case Types.VARBINARY:
case Types.BINARY: case Types.BINARY:
newprop.setStringValue (rs.getString(columns[i].getName())); newprop.setStringValue (rs.getString(columns[i].getName()));
break; break;
case Types.LONGVARBINARY:
case Types.LONGVARCHAR: 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.CHAR:
case Types.VARCHAR: case Types.VARCHAR:
case Types.OTHER: case Types.OTHER:
@ -435,9 +454,9 @@ public final class Node implements INode, Serializable {
Relation rel = getDbMapping ().getSubnodeRelation (); Relation rel = getDbMapping ().getSubnodeRelation ();
if (rel != null) { if (rel != null) {
if (rel.usesPrimaryKey()) { if (rel.usesPrimaryKey()) {
nmgr.evictKey (new DbKey (getDbMapping().getSubnodeMapping(), key)); nmgr.evictNodeByKey (new DbKey (getDbMapping().getSubnodeMapping(), key));
} else { } 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 { } else {
anonymous = true; anonymous = true;
} }
} else if (p.contains (this) > -1) { } else if (!anonymous && p.contains (this) > -1) {
anonymous = true; anonymous = true;
} }
} catch (Exception ignore) { } catch (Exception ignore) {
@ -1748,11 +1767,20 @@ public final class Node implements INode, Serializable {
if (propMap == null) if (propMap == null)
return; return;
try { 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) { if (p != null) {
checkWriteLock (); checkWriteLock ();
if (p.getType() == Property.NODE) if (p.getType() == Property.NODE)
p.unregisterNode (); p.unregisterNode ();
if (relational)
p.setStringValue (null);
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED)); // Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
lastmodified = System.currentTimeMillis (); lastmodified = System.currentTimeMillis ();
if (state == CLEAN) if (state == CLEAN)

View file

@ -9,7 +9,6 @@ import helma.framework.core.Application;
import java.sql.*; import java.sql.*;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
import com.workingdogs.village.*;
/** /**
* The NodeManager is responsible for fetching Nodes from the internal or * 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 * Remove a node from the node cache. If at a later time it is accessed again,
* refetched from the database. * it will be refetched from the database.
*/ */
public void evictNode (Node node) { public void evictNode (Node node) {
node.setState (INode.INVALID); 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) { public void evictKey (Key key) {
cache.remove (key); cache.remove (key);
@ -396,62 +409,129 @@ public final class NodeManager {
db.saveNode (txn, node.getID (), node); db.saveNode (txn, node.getID (), node);
} else { } else {
// app.logEvent ("inserting relational node: "+node.getID ()); // app.logEvent ("inserting relational node: "+node.getID ());
TableDataSet tds = null;
try { DbColumn[] columns = dbm.getColumns ();
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
Record rec = tds.addRecord (); StringBuffer b1 = dbm.getInsert ();
rec.setValue (dbm.getIDField (), node.getID ()); StringBuffer b2 = new StringBuffer (" ) VALUES ( ?");
String nameField = dbm.getNameField (); String nameField = dbm.getNameField ();
if (nameField != null) String prototypeField = dbm.getPrototypeField ();
rec.setValue (nameField, node.getName ());
for (Iterator i=dbm.getProp2DB().entrySet().iterator(); i.hasNext(); ) { for (int i=0; i<columns.length; i++) {
Map.Entry e = (Map.Entry) i.next (); Relation rel = columns[i].getRelation();
String propname = (String) e.getKey (); String name = columns[i].getName();
Relation rel = (Relation) e.getValue (); if ((rel != null && (rel.isPrimitive() || rel.isReference())) ||
Property p = node.getProperty (propname); name.equals (nameField) || name.equals (prototypeField))
{
if (p != null && rel != null) { b1.append (", "+columns[i].getName());
switch (p.getType ()) { b2.append (", ?");
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;
}
p.dirty = false;
} else if (rel != null && rel.getDbField() != null) {
rec.setValueNull (rel.getDbField());
} }
} }
if (dbm.getPrototypeField () != null) { b1.append (b2.toString());
rec.setValue (dbm.getPrototypeField (), node.getPrototype ()); b1.append (" )");
Connection con = dbm.getConnection ();
PreparedStatement stmt = con.prepareStatement (b1.toString ());
if (logSql)
app.logEvent ("### insertNode: "+b1.toString ());
try {
int stmtNumber = 1;
stmt.setString (stmtNumber, node.getID());
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;
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());
} }
rec.markForInsert (); break;
tds.save ();
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 (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());
}
}
stmt.executeUpdate ();
} catch (Exception x) {
x.printStackTrace ();
throw x;
} finally { } finally {
if (tds != null) try { if (stmt != null) try {
tds.close (); stmt.close ();
} catch (Exception ignore) {} } catch (Exception ignore) {}
} }
dbm.notifyDataChange (); dbm.notifyDataChange ();
@ -475,82 +555,146 @@ public final class NodeManager {
db.saveNode (txn, node.getID (), node); db.saveNode (txn, node.getID (), node);
} else { } else {
TableDataSet tds = null; Hashtable propMap = node.getPropMap ();
try { Property[] props = new Property[propMap.size()];
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ()); propMap.values().toArray (props);
Record rec = tds.addRecord ();
rec.setValue (dbm.getIDField (), node.getID ());
int updated = 0; // make sure table meta info is loaded by dbmapping
dbm.getColumns ();
for (Iterator i=dbm.getProp2DB().entrySet().iterator(); i.hasNext(); ) { StringBuffer b = dbm.getUpdate ();
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 boolean comma = false;
if (rel != null && (rel.readonly || rel.virtual || for (int i=0; i<props.length; i++) {
(rel.reftype != Relation.REFERENCE && rel.reftype != Relation.PRIMITIVE))) // 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; 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 (" = ?");
Property p = node.getProperty (propname); }
// if no columns were updated, return
if (!comma)
return;
if (p != null && rel != null) { 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());
}
if (p.dirty) { Connection con = dbm.getConnection ();
switch (p.getType ()) { PreparedStatement stmt = con.prepareStatement (b.toString ());
case IProperty.STRING:
updated++; if (logSql)
rec.setValue (rel.getDbField(), p.getStringValue ()); app.logEvent ("### updateNode: "+b.toString ());
int stmtNumber = 0;
try {
for (int i=0; i<props.length; i++) {
Property p = props[i];
if (p == null)
continue;
Relation rel = dbm.propertyToRelation (p.getName());
stmtNumber++;
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; break;
case IProperty.BOOLEAN:
updated++; case Types.REAL:
rec.setValue (rel.getDbField(), p.getBooleanValue ()); case Types.FLOAT:
case Types.DOUBLE:
case Types.NUMERIC:
case Types.DECIMAL:
stmt.setDouble (stmtNumber, p.getFloatValue());
break; break;
case IProperty.DATE:
updated++; case Types.VARBINARY:
Timestamp t = new Timestamp (p.getDateValue ().getTime ()); case Types.BINARY:
rec.setValue (rel.getDbField(), t); case Types.BLOB:
stmt.setString (stmtNumber, p.getStringValue());
break; break;
case IProperty.INTEGER:
updated++; case Types.LONGVARBINARY:
rec.setValue (rel.getDbField(), p.getIntegerValue ()); case Types.LONGVARCHAR:
break; try {
case IProperty.FLOAT: stmt.setString (stmtNumber, p.getStringValue());
updated++; } catch (SQLException x) {
rec.setValue (rel.getDbField(), p.getFloatValue ()); String str = p.getStringValue();
break; Reader r = new StringReader (str);
case IProperty.NODE: stmt.setCharacterStream (stmtNumber, r, str.length());
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 ());
} }
break; 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; p.dirty = false;
if (!rel.isPrivate()) if (!rel.isPrivate())
markMappingAsUpdated = true; markMappingAsUpdated = true;
} }
} else if (rel != null && rel.getDbField() != null) { stmt.executeUpdate ();
updated++; } catch (Exception x) {
rec.setValueNull (rel.getDbField()); x.printStackTrace ();
} throw x;
}
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 ();
}
} finally { } finally {
if (tds != null) try { if (stmt != null) try {
tds.close (); stmt.close ();
} catch (Exception ignore) {} } catch (Exception ignore) {}
} }
if (markMappingAsUpdated) if (markMappingAsUpdated)
dbm.notifyDataChange (); dbm.notifyDataChange ();
} }
@ -579,14 +723,17 @@ public final class NodeManager {
Statement st = null; Statement st = null;
try { try {
Connection con = dbm.getConnection (); Connection con = dbm.getConnection ();
st = con.createStatement (); String str = new StringBuffer ("DELETE FROM ")
st.executeUpdate (new StringBuffer ("DELETE FROM ")
.append(dbm.getTableName ()) .append(dbm.getTableName ())
.append(" WHERE ") .append(" WHERE ")
.append(dbm.getIDField()) .append(dbm.getIDField())
.append(" = ") .append(" = ")
.append(node.getID()) .append(node.getID())
.toString()); .toString();
st = con.createStatement ();
st.executeUpdate (str);
if (logSql)
app.logEvent ("### deleteNode: "+str);
} finally { } finally {
if (st != null) try { if (st != null) try {
st.close (); st.close ();
@ -1084,7 +1231,13 @@ public final class NodeManager {
q.append ("WHERE "); q.append ("WHERE ");
q.append (idfield); q.append (idfield);
q.append (" = "); q.append (" = ");
if (dbm.needsQuotes (idfield)) {
q.append ("'");
q.append (escape(kstr));
q.append ("'");
} else {
q.append (kstr); q.append (kstr);
}
if (logSql) if (logSql)
app.logEvent ("### getNodeByKey: "+q.toString()); app.logEvent ("### getNodeByKey: "+q.toString());

View file

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

View file

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

View file

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

View file

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

View file

@ -123,6 +123,8 @@ public class FesiEngine implements ScriptingEngine {
* necessary to bootstrap the rest is parsed. * necessary to bootstrap the rest is parsed.
*/ */
private void initialize () { private void initialize () {
// set the thread filed in the FESI evaluator
evaluator.thread = Thread.currentThread ();
Collection protos = app.getPrototypes(); Collection protos = app.getPrototypes();
for (Iterator i=protos.iterator(); i.hasNext(); ) { for (Iterator i=protos.iterator(); i.hasNext(); ) {
Prototype proto = (Prototype) i.next (); Prototype proto = (Prototype) i.next ();
@ -132,6 +134,7 @@ public class FesiEngine implements ScriptingEngine {
// we always need it and there's no chance to trigger // we always need it and there's no chance to trigger
// creation on demand. // creation on demand.
getPrototype ("global"); getPrototype ("global");
evaluator.thread = null;
} }
/** /**
@ -268,6 +271,8 @@ public class FesiEngine implements ScriptingEngine {
* engine know it should update its prototype information. * engine know it should update its prototype information.
*/ */
public void updatePrototypes () { public void updatePrototypes () {
// set the thread filed in the FESI evaluator
evaluator.thread = Thread.currentThread ();
Collection protos = app.getPrototypes(); Collection protos = app.getPrototypes();
for (Iterator i=protos.iterator(); i.hasNext(); ) { for (Iterator i=protos.iterator(); i.hasNext(); ) {
Prototype proto = (Prototype) i.next (); Prototype proto = (Prototype) i.next ();

View file

@ -54,11 +54,17 @@ public class NodeConstructor extends BuiltinFunctionObject {
// with the name of the type. // with the name of the type.
// HACK: There is an incompatibility problem here, because the property // HACK: There is an incompatibility problem here, because the property
// constructor is defined as the constructor of the object by EcmaScript. // 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); node.doIndirectCall (engine.getEvaluator(), node, "constructor", arguments);
else else if (op.getProperty (typename,
typename.hashCode())
instanceof ConstructedFunctionObject)
node.doIndirectCall (engine.getEvaluator(), node, typename, arguments); node.doIndirectCall (engine.getEvaluator(), node, typename, arguments);
} catch (Exception ignore) {} } catch (Exception x) {
throw new EcmaScriptException (x.toString());
}
} }
return node; return node;
} }

View file

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

View file

@ -363,10 +363,13 @@ public final class HtmlEncoder {
if (i < l-2) { if (i < l-2) {
if (!insideMacroTag && '%' == str.charAt(i+1)) { if (!insideMacroTag && '%' == str.charAt(i+1)) {
// this is the beginning of a Helma macro tag // this is the beginning of a Helma macro tag
if (!insideCodeTag) {
insideMacroTag = insideTag = true; insideMacroTag = insideTag = true;
macroQuoteChar = '\u0000'; macroQuoteChar = '\u0000';
}
} else if ('!' == str.charAt(i+1) && '-' == str.charAt(i+2)) { } else if ('!' == str.charAt(i+1) && '-' == str.charAt(i+2)) {
// the beginning of an HTML comment? // the beginning of an HTML comment?
if (!insideCodeTag)
insideComment = insideTag = (i<l-3 && '-' == str.charAt(i+3)); insideComment = insideTag = (i<l-3 && '-' == str.charAt(i+3));
} else if (!insideTag) { } else if (!insideTag) {
// check if this is a HTML tag. // check if this is a HTML tag.
@ -480,6 +483,7 @@ public final class HtmlEncoder {
} }
} }
/** /**
* *
*/ */
@ -494,6 +498,13 @@ public final class HtmlEncoder {
return ret.toString(); 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); encodeAll (str, ret, true);
return ret.toString();
} }