Merged in changes from helma_1_2 branch
This commit is contained in:
parent
9d73c836ed
commit
ed15173b8c
32 changed files with 1056 additions and 632 deletions
|
@ -8,7 +8,7 @@
|
|||
<target name="init">
|
||||
<property name="Name" value="helma"/>
|
||||
<property name="year" value="1998-${year}"/>
|
||||
<property name="version" value="1.2-rc2"/>
|
||||
<property name="version" value="1.2.2"/>
|
||||
<property name="project" value="helma"/>
|
||||
<property name="build.compiler" value="classic"/>
|
||||
|
||||
|
|
BIN
lib/village.jar
BIN
lib/village.jar
Binary file not shown.
|
@ -432,11 +432,7 @@ public abstract class ESLoader extends ESObject {
|
|||
debugInfo = " rejected (not widening numbers)";
|
||||
}
|
||||
// Handle String of length 1 as a Char, which can be converted to a number
|
||||
} else if ((targetClass == Character.class ||
|
||||
targetClass == Integer.class ||
|
||||
targetClass == Long.class ||
|
||||
targetClass == Float.class ||
|
||||
targetClass == Double.class)
|
||||
} else if (targetClass == Character.class
|
||||
&& params[i] instanceof String) {
|
||||
if (((String) params[i]).length()==1) {
|
||||
accepted = true; // will require conversion of parameter
|
||||
|
|
|
@ -74,11 +74,11 @@ public class ClassInfo {
|
|||
* @return the ClassInfo of cls, added to the cache if needed
|
||||
*/
|
||||
private static ClassInfo ensureClassInfo(Class cls) {
|
||||
boolean debug = ESLoader.isDebugJavaAccess();
|
||||
// boolean debug = ESLoader.isDebugJavaAccess();
|
||||
ClassInfo classInfo = (ClassInfo) allClassInfo.get(cls);
|
||||
if (classInfo == null) {
|
||||
if (debug) System.out.println("** Class info for class '" +
|
||||
cls + "' not found in cache, created");
|
||||
// if (debug) System.out.println("** Class info for class '" +
|
||||
// cls + "' not found in cache, created");
|
||||
classInfo = new ClassInfo();
|
||||
allClassInfo.put(cls, classInfo);
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public class ClassInfo {
|
|||
* @param cls The class for which we look for the property.
|
||||
* @return The PropertyDescriptor or null if not found or in case of error
|
||||
*/
|
||||
synchronized public static PropertyDescriptor lookupBeanField(String fieldName, Class cls) {
|
||||
public static PropertyDescriptor lookupBeanField(String fieldName, Class cls) {
|
||||
ClassInfo classInfo = ClassInfo.ensureClassInfo(cls);
|
||||
return classInfo.cachedBeanFieldLookup(fieldName, cls);
|
||||
}
|
||||
|
@ -110,29 +110,29 @@ public class ClassInfo {
|
|||
* @return The PropertyDescriptor or null if not found or in case of error
|
||||
*/
|
||||
private PropertyDescriptor cachedBeanFieldLookup(String propertyName, Class cls) {
|
||||
boolean debug = ESLoader.isDebugJavaAccess();
|
||||
// boolean debug = ESLoader.isDebugJavaAccess();
|
||||
|
||||
// Check that there is a bean properties cache, chech if the property was cached
|
||||
if (beanProperties != null) {
|
||||
if (debug) System.out.println("** Bean properties for class '" +
|
||||
cls + "' found in cache");
|
||||
// if (debug) System.out.println("** Bean properties for class '" +
|
||||
// cls + "' found in cache");
|
||||
PropertyDescriptor descriptor =
|
||||
(PropertyDescriptor) beanProperties.get(propertyName);
|
||||
if (descriptor!= null) {
|
||||
if (debug) System.out.println("** property descriptor '" + propertyName + "' found in cache");
|
||||
// if (debug) System.out.println("** property descriptor '" + propertyName + "' found in cache");
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
// Not in cache
|
||||
if (debug) System.out.println("** No property named '" +
|
||||
propertyName + "' found in cache, lookup started");
|
||||
// if (debug) System.out.println("** No property named '" +
|
||||
// propertyName + "' found in cache, lookup started");
|
||||
|
||||
// Do we have a cached BeanInfo ? create it if no
|
||||
if (beanInfo == null) {
|
||||
try {
|
||||
beanInfo = Introspector.getBeanInfo(cls);
|
||||
} catch (IntrospectionException e) {
|
||||
if (debug) System.out.println(" ** Error getting beaninfo: " + e);
|
||||
// if (debug) System.out.println(" ** Error getting beaninfo: " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ public class ClassInfo {
|
|||
PropertyDescriptor descriptor = null; // none found
|
||||
for (int i=0; i<allProperties.length; i++) {
|
||||
PropertyDescriptor property = allProperties[i];
|
||||
if (debug) System.out.println("** Property examined: " + property.getName());
|
||||
// if (debug) System.out.println("** Property examined: " + property.getName());
|
||||
if (!property.getName().equals(propertyName)) continue;
|
||||
descriptor = property;
|
||||
break;
|
||||
|
@ -238,13 +238,13 @@ public class ClassInfo {
|
|||
}
|
||||
|
||||
// Add to cache
|
||||
if (debug) System.out.println("** property '" + propertyName + "' + found, add to cache");
|
||||
// if (debug) System.out.println("** property '" + propertyName + "' + found, add to cache");
|
||||
if (beanProperties==null) {
|
||||
beanProperties = new Hashtable();
|
||||
}
|
||||
beanProperties.put(propertyName, descriptor);
|
||||
} else {
|
||||
if (debug) System.out.println("** No method named '" + propertyName + "' found");
|
||||
// if (debug) System.out.println("** No method named '" + propertyName + "' found");
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
|
@ -258,7 +258,7 @@ public class ClassInfo {
|
|||
* @param cls The class of the method being looked up
|
||||
* @return The method array or null if none found or in case of error
|
||||
*/
|
||||
synchronized public static Method[] lookupPublicMethod(String functionName, Class cls) throws EcmaScriptException {
|
||||
public static Method[] lookupPublicMethod(String functionName, Class cls) throws EcmaScriptException {
|
||||
ClassInfo classInfo = ClassInfo.ensureClassInfo(cls);
|
||||
return classInfo.cachedPublicMethodLookup(functionName, cls);
|
||||
}
|
||||
|
@ -274,52 +274,52 @@ public class ClassInfo {
|
|||
* @return The method if found, null otherwise
|
||||
*/
|
||||
private Method getInInterfaces(String functionName, Class [] interfaces, Class[] paramTypes) {
|
||||
boolean debug = ESLoader.isDebugJavaAccess();
|
||||
// boolean debug = ESLoader.isDebugJavaAccess();
|
||||
|
||||
if (debug && interfaces.length>0) {
|
||||
System.out.println("** Looking in " + interfaces.length + " interfaces");
|
||||
}
|
||||
// if (debug && interfaces.length>0) {
|
||||
// System.out.println("** Looking in " + interfaces.length + " interfaces");
|
||||
// }
|
||||
SEARCHININTERFACE:
|
||||
for (int ix=0; ix<interfaces.length; ix++) {
|
||||
Class theInterface=interfaces[ix];
|
||||
if (Modifier.isPublic(theInterface.getModifiers())) {
|
||||
if (debug) {
|
||||
System.out.println("** Looking in public interface: " + theInterface);
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** Looking in public interface: " + theInterface);
|
||||
// }
|
||||
try {
|
||||
Method method = theInterface.getDeclaredMethod(functionName,paramTypes);
|
||||
if (Modifier.isPublic(method.getModifiers())) {
|
||||
if (debug) {
|
||||
System.out.println("** Public method found: " + functionName);
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** Public method found: " + functionName);
|
||||
// }
|
||||
return method;
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
if (debug) {
|
||||
System.out.println("** The method has no public declaration in the interface: "+ functionName);
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** The method has no public declaration in the interface: "+ functionName);
|
||||
// }
|
||||
// throw new ProgrammingError("The method has no public declaration in a public class: "+ functionName);
|
||||
} catch (SecurityException e) {
|
||||
throw new ProgrammingError("Access error inspecting method "+ functionName + ": " + e);
|
||||
}
|
||||
} else {
|
||||
if (debug) {
|
||||
System.out.println("** Interface " + theInterface + " is not public - not searching for method");
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** Interface " + theInterface + " is not public - not searching for method");
|
||||
// }
|
||||
}
|
||||
|
||||
// Not found, try super interfaces
|
||||
Class [] superInterfaces = theInterface.getInterfaces();
|
||||
Method method = getInInterfaces(functionName, superInterfaces, paramTypes);
|
||||
if (method!=null) {
|
||||
if (debug) System.out.println("** Method found in super interfaces");
|
||||
// if (debug) System.out.println("** Method found in super interfaces");
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
System.out.println("** No method found in interface and super interfaces");
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** No method found in interface and super interfaces");
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -337,26 +337,26 @@ public class ClassInfo {
|
|||
* @return The list of methods or null in case of error or if none found.
|
||||
*/
|
||||
private Method [] cachedPublicMethodLookup(String functionName, Class cls) throws EcmaScriptException {
|
||||
boolean debug = ESLoader.isDebugJavaAccess();
|
||||
// boolean debug = ESLoader.isDebugJavaAccess();
|
||||
if (publicMethods != null) {
|
||||
if (debug) System.out.println("** Method descriptor for class '" +
|
||||
cls + "' found in cache");
|
||||
// if (debug) System.out.println("** Method descriptor for class '" +
|
||||
// cls + "' found in cache");
|
||||
Method [] methods = (Method []) publicMethods.get(functionName);
|
||||
if (methods!= null) {
|
||||
if (debug) System.out.println("** " + methods.length +
|
||||
" method(s) named '" + functionName + "' found in cache");
|
||||
// if (debug) System.out.println("** " + methods.length +
|
||||
// " method(s) named '" + functionName + "' found in cache");
|
||||
return methods;
|
||||
}
|
||||
}
|
||||
// Not in cache, find if any matching the same name can be found
|
||||
if (debug) System.out.println("** No method named '" +
|
||||
functionName + "' found in class cache, lookup started");
|
||||
// if (debug) System.out.println("** No method named '" +
|
||||
// functionName + "' found in class cache, lookup started");
|
||||
Method [] allMethods = cls.getMethods();
|
||||
Vector methodVector = new Vector(allMethods.length);
|
||||
boolean wasFound = false;
|
||||
for (int i=0; i<allMethods.length; i++) {
|
||||
Method method = allMethods[i];
|
||||
if (debug) System.out.println("** Method examined: " + method.toString());
|
||||
// if (debug) System.out.println("** Method examined: " + method.toString());
|
||||
if (!method.getName().equals(functionName)) continue;
|
||||
// Method has same name, some closer examination is needed:
|
||||
// If the class itself is not public, there is an access error if
|
||||
|
@ -365,8 +365,8 @@ public class ClassInfo {
|
|||
// I am not too sure of what happens if the method is defined in an
|
||||
// interface...
|
||||
if (!Modifier.isStatic(cls.getModifiers()) && !Modifier.isPublic(cls.getModifiers())) {
|
||||
if (debug) System.out.println("** Class " + cls +
|
||||
" is not public, examining superclasses and interfaces to find proper method descriptor");
|
||||
// if (debug) System.out.println("** Class " + cls +
|
||||
// " is not public, examining superclasses and interfaces to find proper method descriptor");
|
||||
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
SEARCHPUBLIC:
|
||||
|
@ -383,31 +383,31 @@ public class ClassInfo {
|
|||
|
||||
// Look in the class
|
||||
if (Modifier.isPublic(theClass.getModifiers())) {
|
||||
if (debug) {
|
||||
System.out.println("** Looking in public class: " + theClass);
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** Looking in public class: " + theClass);
|
||||
// }
|
||||
try {
|
||||
m = theClass.getDeclaredMethod(functionName,paramTypes);
|
||||
if (Modifier.isPublic(method.getModifiers())) {
|
||||
if (debug) {
|
||||
System.out.println("** Public method found: " + functionName);
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** Public method found: " + functionName);
|
||||
// }
|
||||
method = m;
|
||||
wasFound = true;
|
||||
break SEARCHPUBLIC;
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
if (debug) {
|
||||
System.out.println("** The method has no public declaration in the public class: "+ functionName);
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** The method has no public declaration in the public class: "+ functionName);
|
||||
// }
|
||||
// throw new ProgrammingError("The method has no public declaration in a public class: "+ functionName);
|
||||
} catch (SecurityException e) {
|
||||
throw new ProgrammingError("Access error inspecting method "+ functionName + ": " + e);
|
||||
}
|
||||
} else {
|
||||
if (debug) {
|
||||
System.out.println("** Class " + theClass + " is not public - not searching for method");
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** Class " + theClass + " is not public - not searching for method");
|
||||
// }
|
||||
}
|
||||
|
||||
} // for SEARCHPUBLIC
|
||||
|
@ -427,7 +427,7 @@ public class ClassInfo {
|
|||
Method [] methods = null;
|
||||
int nmbMethods = methodVector.size();
|
||||
if (nmbMethods>0) {
|
||||
if (debug) System.out.println("** " + nmbMethods + " methods named: '" + functionName + "' + found, add to class cache");
|
||||
// if (debug) System.out.println("** " + nmbMethods + " methods named: '" + functionName + "' + found, add to class cache");
|
||||
methods = new Method[nmbMethods];
|
||||
methodVector.copyInto(methods);
|
||||
if (publicMethods==null) {
|
||||
|
@ -435,7 +435,7 @@ public class ClassInfo {
|
|||
}
|
||||
publicMethods.put(functionName, methods);
|
||||
} else {
|
||||
if (debug) System.out.println("** No method named '" + functionName + "' found");
|
||||
// if (debug) System.out.println("** No method named '" + functionName + "' found");
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
@ -449,7 +449,7 @@ public class ClassInfo {
|
|||
* @param cls The class of the method being looked up
|
||||
* @return The method array or null if none found or in case of error
|
||||
*/
|
||||
synchronized public static Method[] lookupBeanMethod(String functionName, Class cls) {
|
||||
public static Method[] lookupBeanMethod(String functionName, Class cls) {
|
||||
ClassInfo classInfo = ClassInfo.ensureClassInfo(cls);
|
||||
return classInfo.cachedBeanMethodLookup(functionName, cls);
|
||||
}
|
||||
|
@ -469,27 +469,27 @@ public class ClassInfo {
|
|||
* @return The list of methods or null in case of error or if none found.
|
||||
*/
|
||||
private Method [] cachedBeanMethodLookup(String functionName, Class cls) {
|
||||
boolean debug = ESLoader.isDebugJavaAccess();
|
||||
// boolean debug = ESLoader.isDebugJavaAccess();
|
||||
if (beanMethods != null) {
|
||||
if (debug) System.out.println("** Method descriptor for bean '" +
|
||||
cls + "' found in cache");
|
||||
// if (debug) System.out.println("** Method descriptor for bean '" +
|
||||
// cls + "' found in cache");
|
||||
Method [] methods = (Method []) beanMethods.get(functionName);
|
||||
if (methods!= null) {
|
||||
if (debug) System.out.println("** " + methods.length +
|
||||
" method(s) named '" + functionName + "' found in cache");
|
||||
// if (debug) System.out.println("** " + methods.length +
|
||||
// " method(s) named '" + functionName + "' found in cache");
|
||||
return methods;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Not in cache, find if any matching the same name can be found
|
||||
if (debug) System.out.println("** No method named '" +
|
||||
functionName + "' found in bean cache, lookup started");
|
||||
// if (debug) System.out.println("** No method named '" +
|
||||
// functionName + "' found in bean cache, lookup started");
|
||||
|
||||
// Do we have a cached BeanInfo ? create it if no
|
||||
if (beanInfo == null) {
|
||||
try {
|
||||
beanInfo = Introspector.getBeanInfo(cls);
|
||||
} catch (IntrospectionException e) {
|
||||
if (debug) System.out.println(" ** Error getting beaninfo: " + e);
|
||||
// if (debug) System.out.println(" ** Error getting beaninfo: " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -498,7 +498,7 @@ public class ClassInfo {
|
|||
Vector methodVector = new Vector(allDescriptors.length);
|
||||
for (int i=0; i<allDescriptors.length; i++) {
|
||||
Method method = allDescriptors[i].getMethod();
|
||||
if (debug) System.out.println("** Method examined: " + method.toString());
|
||||
// if (debug) System.out.println("** Method examined: " + method.toString());
|
||||
if (!allDescriptors[i].getName().equals(functionName)) continue;
|
||||
// Method has same name, some tuning neede:
|
||||
// If the class itself is not public, there is an access error if
|
||||
|
@ -507,21 +507,21 @@ public class ClassInfo {
|
|||
// I am not too sure of what happens if the method is defined in an
|
||||
// interface...
|
||||
if (!Modifier.isStatic(cls.getModifiers()) && !Modifier.isPublic(cls.getModifiers())) {
|
||||
if (debug) System.out.println("** Bean class " + cls +
|
||||
" is not public, examining superclasses to find proper method descriptor");
|
||||
// if (debug) System.out.println("** Bean class " + cls +
|
||||
// " is not public, examining superclasses to find proper method descriptor");
|
||||
SEARCHPUBLIC:
|
||||
for (Class theClass=cls;theClass!=null;theClass=theClass.getSuperclass()) {
|
||||
if (Modifier.isPublic(theClass.getModifiers())) {
|
||||
if (debug) {
|
||||
System.out.println("** Looking in public superlass: " + theClass);
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** Looking in public superlass: " + theClass);
|
||||
// }
|
||||
try {
|
||||
Class[] paramTypes = method.getParameterTypes();
|
||||
Method m = theClass.getDeclaredMethod(functionName,paramTypes);
|
||||
if (Modifier.isPublic(method.getModifiers())) {
|
||||
if (debug) {
|
||||
System.out.println("** Public method found: " + functionName);
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** Public method found: " + functionName);
|
||||
// }
|
||||
method = m;
|
||||
break SEARCHPUBLIC;
|
||||
}
|
||||
|
@ -531,9 +531,9 @@ public class ClassInfo {
|
|||
throw new ProgrammingError("Acess error inspecting method "+ functionName + ": " + e);
|
||||
}
|
||||
} else {
|
||||
if (debug) {
|
||||
System.out.println("** Superlass " + theClass + " is not public");
|
||||
}
|
||||
// if (debug) {
|
||||
// System.out.println("** Superlass " + theClass + " is not public");
|
||||
// }
|
||||
}
|
||||
} // for
|
||||
} // if class not public
|
||||
|
@ -547,8 +547,8 @@ public class ClassInfo {
|
|||
Method [] methods = null;
|
||||
int nmbMethods = methodVector.size();
|
||||
if (nmbMethods>0) {
|
||||
if (debug) System.out.println("** " + nmbMethods + " methods named: '"
|
||||
+ functionName + "' + found, add to bean cache");
|
||||
// if (debug) System.out.println("** " + nmbMethods + " methods named: '"
|
||||
// + functionName + "' + found, add to bean cache");
|
||||
methods = new Method[nmbMethods];
|
||||
methodVector.copyInto(methods);
|
||||
if (beanMethods==null) {
|
||||
|
@ -556,8 +556,8 @@ public class ClassInfo {
|
|||
}
|
||||
beanMethods.put(functionName, methods);
|
||||
} else {
|
||||
if (debug) System.out.println("** No bean method named: '" +
|
||||
functionName + "' + found");
|
||||
// if (debug) System.out.println("** No bean method named: '" +
|
||||
// functionName + "' + found");
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,12 @@ public abstract class HelmaExtension {
|
|||
*/
|
||||
public abstract void applicationStopped (Application app);
|
||||
|
||||
/**
|
||||
* called when an Application's properties are have been updated.
|
||||
* note that this will be called at startup once *before* applicationStarted().
|
||||
*/
|
||||
public abstract void applicationUpdated (Application app);
|
||||
|
||||
/**
|
||||
* called by the ScriptingEngine when it is initizalized. Throws a ConfigurationException
|
||||
* when this type of ScriptingEngine is not supported. New methods and prototypes can be
|
||||
|
|
|
@ -43,6 +43,10 @@ public class DemoExtension extends HelmaExtension {
|
|||
app.logEvent ("DemoExtension stopped on app " + app.getName () );
|
||||
}
|
||||
|
||||
public void applicationUpdated (Application app) {
|
||||
app.logEvent ("DemoExtension updated on app " + app.getName () );
|
||||
}
|
||||
|
||||
public HashMap initScripting (Application app, ScriptingEngine engine) throws ConfigurationException {
|
||||
if (!(engine instanceof FesiEngine))
|
||||
throw new ConfigurationException ("scripting engine " + engine.toString () + " not supported in DemoExtension");
|
||||
|
|
|
@ -62,7 +62,7 @@ public class ResponseBean implements Serializable {
|
|||
res.writeBinary (what);
|
||||
}
|
||||
|
||||
public void debug (String message) {
|
||||
public void debug (Object message) {
|
||||
res.debug (message);
|
||||
}
|
||||
|
||||
|
|
|
@ -185,19 +185,15 @@ public final class ResponseTrans implements Externalizable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the number of characters written to the response buffer so far.
|
||||
* Get the response buffer, creating it if it doesn't exist
|
||||
*/
|
||||
public int getBufferLength() {
|
||||
public StringBuffer getBuffer () {
|
||||
if (buffer == null)
|
||||
return 0;
|
||||
return buffer.length ();
|
||||
}
|
||||
|
||||
public void setBufferLength(int l) {
|
||||
if (buffer != null)
|
||||
buffer.setLength (l);
|
||||
buffer = new StringBuffer (INITIAL_BUFFER_SIZE);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append a string to the response unchanged. This is often called
|
||||
* at the end of a request to write out the whole page, so if buffer
|
||||
|
@ -237,10 +233,13 @@ public final class ResponseTrans implements Externalizable {
|
|||
* that buffer exists and its length is larger than offset. str may be null, in which
|
||||
* case nothing happens.
|
||||
*/
|
||||
public void debug (String str) {
|
||||
public void debug (Object message) {
|
||||
if (debugBuffer == null)
|
||||
debugBuffer = new StringBuffer ();
|
||||
debugBuffer.append ("<p><span style=\"background: yellow; color: black\">"+str+"</span></p>");
|
||||
String str = message == null ? "null" : message.toString ();
|
||||
debugBuffer.append ("<p><span style=\"background: yellow; color: black\">");
|
||||
debugBuffer.append (str);
|
||||
debugBuffer.append ("</span></p>");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -335,17 +334,25 @@ public final class ResponseTrans implements Externalizable {
|
|||
if (charset == null)
|
||||
charset = "ISO-8859-1";
|
||||
boolean encodingError = false;
|
||||
// only close if the response hasn't been closed yet
|
||||
if (response == null) {
|
||||
if (buffer != null) {
|
||||
if (debugBuffer != null)
|
||||
// if debug buffer exists, append it to main buffer
|
||||
if (debugBuffer != null) {
|
||||
if (buffer == null)
|
||||
buffer = debugBuffer;
|
||||
else
|
||||
buffer.append (debugBuffer);
|
||||
}
|
||||
// get the buffer's bytes in the specified encoding
|
||||
if (buffer != null) {
|
||||
try {
|
||||
response = buffer.toString ().getBytes (charset);
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
encodingError = true;
|
||||
response = buffer.toString ().getBytes ();
|
||||
}
|
||||
buffer = null; // make sure this is done only once, even with more requsts attached
|
||||
// make sure this is done only once, even with more requsts attached
|
||||
buffer = null;
|
||||
} else {
|
||||
response = new byte[0];
|
||||
}
|
||||
|
|
|
@ -228,6 +228,11 @@ public final class Application implements IPathElement, Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
// read the sessions if wanted
|
||||
if ("true".equalsIgnoreCase (getProperty("persistentSessions"))) {
|
||||
loadSessionData (null);
|
||||
}
|
||||
|
||||
typemgr = new TypeManager (this);
|
||||
typemgr.createPrototypes ();
|
||||
// logEvent ("Started type manager for "+name);
|
||||
|
@ -319,6 +324,11 @@ public final class Application implements IPathElement, Runnable {
|
|||
ext.applicationStopped (this);
|
||||
}
|
||||
|
||||
// store the sessions if wanted
|
||||
if ("true".equalsIgnoreCase (getProperty("persistentSessions"))) {
|
||||
storeSessionData (null);
|
||||
}
|
||||
|
||||
// stop logs if they exist
|
||||
if (eventLog != null) {
|
||||
eventLog.close ();
|
||||
|
@ -840,34 +850,31 @@ public final class Application implements IPathElement, Runnable {
|
|||
*/
|
||||
public String getNodeHref (Object elem, String actionName) {
|
||||
// Object root = getDataRoot ();
|
||||
|
||||
// check optional root prototype from app.properties
|
||||
String rootProto = props.getProperty ("rootPrototype");
|
||||
|
||||
String divider = "/";
|
||||
StringBuffer b = new StringBuffer ();
|
||||
Object parent = null;
|
||||
int loopWatch = 0;
|
||||
StringBuffer b = new StringBuffer (baseURI);
|
||||
|
||||
while (elem != null && (parent = getParentElement (elem)) != null && elem != rootObject) {
|
||||
|
||||
if (rootProto != null && rootProto.equals (getPrototypeName (elem)))
|
||||
break;
|
||||
b.insert (0, divider);
|
||||
b.insert (0, UrlEncoded.encode (getElementName (elem)));
|
||||
// move down to the element's parent
|
||||
elem = parent;
|
||||
|
||||
if (loopWatch++ > 20)
|
||||
break;
|
||||
}
|
||||
composeHref (elem, b, rootProto, 0);
|
||||
|
||||
if (actionName != null)
|
||||
b.append (UrlEncoded.encode (actionName));
|
||||
|
||||
return baseURI + b.toString ();
|
||||
return b.toString ();
|
||||
}
|
||||
|
||||
private final void composeHref (Object elem, StringBuffer b, String rootProto, int pathCount) {
|
||||
if (elem == null || pathCount > 20)
|
||||
return;
|
||||
if (rootProto != null && rootProto.equals (getPrototypeName (elem)))
|
||||
return;
|
||||
Object parent = getParentElement (elem);
|
||||
if (parent == null)
|
||||
return;
|
||||
composeHref (getParentElement (elem), b, rootProto, pathCount++);
|
||||
b.append (UrlEncoded.encode (getElementName (elem)));
|
||||
b.append ("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the base URL of this application which will be prepended to
|
||||
|
@ -1112,9 +1119,8 @@ public final class Application implements IPathElement, Runnable {
|
|||
NodeHandle userhandle = session.userHandle;
|
||||
if (userhandle != null) {
|
||||
try {
|
||||
String[] str = new String [1];
|
||||
str[0] = session.getSessionID ();
|
||||
eval.invokeFunction (userhandle, "onLogout", str);
|
||||
Object[] param = { session.getSessionID() };
|
||||
eval.invokeFunction (userhandle, "onLogout", param);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
destroySession(session);
|
||||
|
@ -1143,7 +1149,7 @@ public final class Application implements IPathElement, Runnable {
|
|||
}
|
||||
|
||||
// sleep until we have work to do
|
||||
try {
|
||||
try {
|
||||
worker.sleep (Math.min (cleanupSleep, scheduleSleep));
|
||||
} catch (InterruptedException x) {
|
||||
logEvent ("Scheduler for "+name+" interrupted");
|
||||
|
@ -1256,6 +1262,14 @@ public final class Application implements IPathElement, Runnable {
|
|||
// if node manager exists, update it
|
||||
if (nmgr != null)
|
||||
nmgr.updateProperties (props);
|
||||
// update extensions
|
||||
Vector extensions = Server.getServer ().getExtensions ();
|
||||
for (int i=0; i<extensions.size(); i++) {
|
||||
HelmaExtension ext = (HelmaExtension)extensions.get(i);
|
||||
try {
|
||||
ext.applicationUpdated (this);
|
||||
} catch (ConfigurationException e) { }
|
||||
}
|
||||
// set prop read timestamp
|
||||
lastPropertyRead = props.lastModified ();
|
||||
}
|
||||
|
@ -1388,5 +1402,65 @@ public final class Application implements IPathElement, Runnable {
|
|||
throw new Exception ("Method "+key+" is not callable via XML-RPC");
|
||||
}
|
||||
|
||||
public void storeSessionData (File f) {
|
||||
if (f==null)
|
||||
f = new File(dbDir, "sessions");
|
||||
try {
|
||||
OutputStream ostream = new BufferedOutputStream (new FileOutputStream(f));
|
||||
ObjectOutputStream p = new ObjectOutputStream(ostream);
|
||||
synchronized (sessions) {
|
||||
p.writeInt (sessions.size ());
|
||||
for (Enumeration e=sessions.elements (); e.hasMoreElements ();) {
|
||||
p.writeObject ((Session) e.nextElement ());
|
||||
}
|
||||
}
|
||||
p.flush();
|
||||
ostream.close();
|
||||
logEvent ("stored " + sessions.size () + " sessions in file");
|
||||
} catch (Exception e) {
|
||||
logEvent ("error storing session data: " + e.toString ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* loads the serialized session table from a given file or from dbdir/sessions
|
||||
*/
|
||||
public void loadSessionData (File f) {
|
||||
if (f==null)
|
||||
f = new File(dbDir, "sessions");
|
||||
// compute session timeout value
|
||||
int sessionTimeout = 30;
|
||||
try {
|
||||
sessionTimeout = Math.max (0, Integer.parseInt (props.getProperty ("sessionTimeout", "30")));
|
||||
} catch (Exception ignore) {
|
||||
System.out.println(ignore.toString());
|
||||
}
|
||||
long now = System.currentTimeMillis ();
|
||||
try {
|
||||
// load the stored data:
|
||||
InputStream istream = new BufferedInputStream (new FileInputStream(f));
|
||||
ObjectInputStream p = new ObjectInputStream(istream);
|
||||
int size = p.readInt ();
|
||||
int ct = 0;
|
||||
Hashtable newSessions = new Hashtable ();
|
||||
while (ct < size) {
|
||||
Session session = (Session) p.readObject ();
|
||||
if (now - session.lastTouched () < sessionTimeout * 60000) {
|
||||
session.setApp (this);
|
||||
newSessions.put (session.getSessionID (), session);
|
||||
}
|
||||
ct++;
|
||||
}
|
||||
p.close ();
|
||||
istream.close ();
|
||||
sessions = newSessions;
|
||||
logEvent ("loaded " + newSessions.size () + " sessions from file");
|
||||
} catch (Exception e) {
|
||||
logEvent ("error loading session data: " + e.toString ());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,23 +24,27 @@ public class ApplicationBean implements Serializable {
|
|||
app.clearCache ();
|
||||
}
|
||||
|
||||
public void log (String msg) {
|
||||
app.logEvent (msg);
|
||||
public void log (Object msg) {
|
||||
String str = msg == null ? "null" : msg.toString();
|
||||
app.logEvent (str);
|
||||
}
|
||||
|
||||
public void log (String logname, String msg) {
|
||||
app.getLogger (logname).log (msg);
|
||||
public void log (String logname, Object msg) {
|
||||
String str = msg == null ? "null" : msg.toString();
|
||||
app.getLogger (logname).log (str);
|
||||
}
|
||||
|
||||
public void debug (String msg) {
|
||||
public void debug (Object msg) {
|
||||
if (app.debug()) {
|
||||
app.logEvent (msg);
|
||||
String str = msg == null ? "null" : msg.toString();
|
||||
app.logEvent (str);
|
||||
}
|
||||
}
|
||||
|
||||
public void debug (String logname, String msg) {
|
||||
public void debug (String logname, Object msg) {
|
||||
if (app.debug()) {
|
||||
app.getLogger (logname).log (msg);
|
||||
String str = msg == null ? "null" : msg.toString();
|
||||
app.getLogger (logname).log (str);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -269,8 +269,6 @@ public final class RequestEvaluator implements Runnable {
|
|||
scriptingEngine.invoke (currentElement, "onRequest", new Object[0], false);
|
||||
} catch (RedirectException redir) {
|
||||
throw redir;
|
||||
} catch (Exception ignore) {
|
||||
// function is not defined or caused an exception, ignore
|
||||
}
|
||||
|
||||
// reset skin recursion detection counter
|
||||
|
@ -351,7 +349,7 @@ public final class RequestEvaluator implements Runnable {
|
|||
break;
|
||||
case XMLRPC:
|
||||
try {
|
||||
localrtx.begin (app.getName()+":xmlrpc/"+method);
|
||||
localrtx.begin (app.getName()+":xmlrpc:"+method);
|
||||
|
||||
root = app.getDataRoot ();
|
||||
|
||||
|
@ -386,23 +384,25 @@ public final class RequestEvaluator implements Runnable {
|
|||
result = scriptingEngine.invoke (currentElement, method, args, true);
|
||||
commitTransaction ();
|
||||
|
||||
} catch (Exception wrong) {
|
||||
} catch (Exception x) {
|
||||
|
||||
abortTransaction (false);
|
||||
|
||||
app.logEvent ("Exception in "+Thread.currentThread()+": "+x);
|
||||
|
||||
// If the transactor thread has been killed by the invoker thread we don't have to
|
||||
// bother for the error message, just quit.
|
||||
if (localrtx != rtx) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.exception = wrong;
|
||||
this.exception = x;
|
||||
}
|
||||
|
||||
break;
|
||||
case INTERNAL:
|
||||
// Just a human readable descriptor of this invocation
|
||||
String funcdesc = app.getName()+":internal/"+method;
|
||||
String funcdesc = app.getName()+":internal:"+method;
|
||||
|
||||
// if thisObject is an instance of NodeHandle, get the node object itself.
|
||||
if (thisObject != null && thisObject instanceof NodeHandle) {
|
||||
|
@ -438,17 +438,19 @@ public final class RequestEvaluator implements Runnable {
|
|||
result = scriptingEngine.invoke (thisObject, method, args, false);
|
||||
commitTransaction ();
|
||||
|
||||
} catch (Exception wrong) {
|
||||
} catch (Exception x) {
|
||||
|
||||
abortTransaction (false);
|
||||
|
||||
app.logEvent ("Exception in "+Thread.currentThread()+": "+x);
|
||||
|
||||
// If the transactor thread has been killed by the invoker thread we don't have to
|
||||
// bother for the error message, just quit.
|
||||
if (localrtx != rtx) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.exception = wrong;
|
||||
this.exception = x;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -17,7 +17,7 @@ import helma.objectmodel.db.*;
|
|||
|
||||
public class Session implements Serializable {
|
||||
|
||||
Application app;
|
||||
transient Application app;
|
||||
String sessionID;
|
||||
|
||||
// the unique id (login name) for the user, if logged in
|
||||
|
@ -98,6 +98,10 @@ public class Session implements Serializable {
|
|||
return app;
|
||||
}
|
||||
|
||||
public void setApp (Application app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getSessionID () {
|
||||
return sessionID;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.*;
|
|||
|
||||
public final class Skin {
|
||||
|
||||
private Macro[] parts;
|
||||
private Macro[] macros;
|
||||
private Application app;
|
||||
private char[] source;
|
||||
private int sourceLength;
|
||||
|
@ -84,8 +84,8 @@ public final class Skin {
|
|||
}
|
||||
}
|
||||
|
||||
parts = new Macro[partBuffer.size()];
|
||||
partBuffer.toArray (parts);
|
||||
macros = new Macro[partBuffer.size()];
|
||||
partBuffer.toArray (macros);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,7 +104,7 @@ public final class Skin {
|
|||
if (++reval.skinDepth > 50)
|
||||
throw new RuntimeException ("Recursive skin invocation suspected");
|
||||
|
||||
if (parts == null) {
|
||||
if (macros == null) {
|
||||
reval.res.writeCharArray (source, 0, sourceLength);
|
||||
reval.skinDepth--;
|
||||
return;
|
||||
|
@ -113,14 +113,14 @@ public final class Skin {
|
|||
try {
|
||||
int written = 0;
|
||||
Map handlerCache = null;
|
||||
if (parts.length > 3) {
|
||||
if (macros.length > 3) {
|
||||
handlerCache = new HashMap();
|
||||
}
|
||||
for (int i=0; i<parts.length; i++) {
|
||||
if (parts[i].start > written)
|
||||
reval.res.writeCharArray (source, written, parts[i].start-written);
|
||||
parts[i].render (reval, thisObject, paramObject, handlerCache);
|
||||
written = parts[i].end;
|
||||
for (int i=0; i<macros.length; i++) {
|
||||
if (macros[i].start > written)
|
||||
reval.res.writeCharArray (source, written, macros[i].start-written);
|
||||
macros[i].render (reval, thisObject, paramObject, handlerCache);
|
||||
written = macros[i].end;
|
||||
}
|
||||
if (written < sourceLength)
|
||||
reval.res.writeCharArray (source, written, sourceLength-written);
|
||||
|
@ -133,9 +133,9 @@ public final class Skin {
|
|||
* Check if a certain macro is present in this skin. The macro name is in handler.name notation
|
||||
*/
|
||||
public boolean containsMacro (String macroname) {
|
||||
for (int i=0; i<parts.length; i++) {
|
||||
if (parts[i] instanceof Macro) {
|
||||
Macro m = (Macro) parts[i];
|
||||
for (int i=0; i<macros.length; i++) {
|
||||
if (macros[i] instanceof Macro) {
|
||||
Macro m = (Macro) macros[i];
|
||||
if (macroname.equals (m.fullName))
|
||||
return true;
|
||||
}
|
||||
|
@ -158,6 +158,13 @@ public final class Skin {
|
|||
static final int PARAMNAME = 2;
|
||||
static final int PARAMVALUE = 3;
|
||||
|
||||
static final int ENCODE_NONE = 0;
|
||||
static final int ENCODE_HTML = 1;
|
||||
static final int ENCODE_XML = 2;
|
||||
static final int ENCODE_FORM = 3;
|
||||
static final int ENCODE_URL = 4;
|
||||
static final int ENCODE_ALL = 5;
|
||||
|
||||
class Macro {
|
||||
|
||||
final int start, end;
|
||||
|
@ -166,8 +173,8 @@ public final class Skin {
|
|||
String fullName;
|
||||
String prefix;
|
||||
String suffix;
|
||||
String encoding;
|
||||
String defaultValue;
|
||||
int encoding = ENCODE_NONE;
|
||||
Map parameters = null;
|
||||
|
||||
public Macro (int start, int end) {
|
||||
|
@ -264,7 +271,7 @@ public final class Skin {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private boolean setSpecialParameter (String name, String value) {
|
||||
if ("prefix".equals (name)) {
|
||||
prefix = value;
|
||||
|
@ -273,7 +280,16 @@ public final class Skin {
|
|||
suffix = value;
|
||||
return true;
|
||||
} else if ("encoding".equals (name)) {
|
||||
encoding = value;
|
||||
if ("html".equalsIgnoreCase (value))
|
||||
encoding = ENCODE_HTML;
|
||||
else if ("xml".equalsIgnoreCase (value))
|
||||
encoding = ENCODE_XML;
|
||||
else if ("form".equalsIgnoreCase (value))
|
||||
encoding = ENCODE_FORM;
|
||||
else if ("url".equalsIgnoreCase (value))
|
||||
encoding = ENCODE_URL;
|
||||
else if ("all".equalsIgnoreCase (value))
|
||||
encoding = ENCODE_ALL;
|
||||
return true;
|
||||
} else if ("default".equals (name)) {
|
||||
defaultValue = value;
|
||||
|
@ -347,16 +363,9 @@ public final class Skin {
|
|||
}
|
||||
|
||||
if (handlerObject == null) {
|
||||
// eiter because thisObject == null or the right object wasn't found in the object's parent path
|
||||
// go check request path for an object with matching prototype
|
||||
/* int l = reval.requestPath.size();
|
||||
for (int i=l-1; i>=0; i--) {
|
||||
Object pathelem = reval.requestPath.get (i);
|
||||
if (handler.equals (app.getPrototypeName (pathelem))) {
|
||||
handlerObject = pathelem;
|
||||
break;
|
||||
}
|
||||
} */
|
||||
// eiter because thisObject == null or the right object wasn't found
|
||||
// in the object's parent path. Check if a matching macro handler
|
||||
// is registered with the response object (res.handlers).
|
||||
handlerObject = reval.res.getMacroHandlers().get (handler);
|
||||
}
|
||||
|
||||
|
@ -380,12 +389,14 @@ public final class Skin {
|
|||
|
||||
String funcName = name+"_macro";
|
||||
if (reval.scriptingEngine.hasFunction (handlerObject, funcName)) {
|
||||
|
||||
StringBuffer buffer = reval.res.getBuffer();
|
||||
// remember length of response buffer before calling macro
|
||||
int bufLength = reval.res.getBufferLength ();
|
||||
int bufLength = buffer.length();
|
||||
// remember length of buffer with prefix written out
|
||||
int preLength = 0;
|
||||
if (prefix != null) {
|
||||
reval.res.write (prefix);
|
||||
buffer.append (prefix);
|
||||
preLength = prefix.length();
|
||||
}
|
||||
|
||||
|
@ -396,24 +407,36 @@ public final class Skin {
|
|||
// parameters = new HashMap ();
|
||||
Object[] arguments = { parameters == null ?
|
||||
new HashMap () :
|
||||
new HashMap (parameters) };
|
||||
new HashMap (parameters)
|
||||
};
|
||||
|
||||
Object value = reval.scriptingEngine.invoke (handlerObject, funcName, arguments, false);
|
||||
|
||||
Object v = reval.scriptingEngine.invoke (handlerObject, funcName, arguments, false);
|
||||
// check if macro wrote out to response buffer
|
||||
if (reval.res.getBufferLength () == bufLength + preLength) {
|
||||
// function didn't write out anything itself
|
||||
if (buffer.length () == bufLength + preLength) {
|
||||
// function didn't write out anything itself.
|
||||
// erase previously written prefix
|
||||
if (preLength > 0)
|
||||
reval.res.setBufferLength (bufLength);
|
||||
writeToResponse (v, reval.res, true);
|
||||
buffer.setLength (bufLength);
|
||||
// write out macro's return value
|
||||
writeResponse (value, buffer, true);
|
||||
} else {
|
||||
if (suffix != null)
|
||||
reval.res.write (suffix);
|
||||
writeToResponse (v, reval.res, false);
|
||||
if (encoding != ENCODE_NONE) {
|
||||
// if an encoding is specified, re-encode the macro's output
|
||||
String output = buffer.substring (bufLength + preLength);
|
||||
buffer.setLength (bufLength);
|
||||
writeResponse (output, buffer, false);
|
||||
} else {
|
||||
// no re-encoding needed, just append suffix
|
||||
if (suffix != null)
|
||||
buffer.append (suffix);
|
||||
}
|
||||
writeResponse (value, buffer, false);
|
||||
}
|
||||
} else {
|
||||
// System.err.println ("Getting macro from property");
|
||||
Object v = reval.scriptingEngine.get (handlerObject, name);
|
||||
writeToResponse (v, reval.res, true);
|
||||
Object value = reval.scriptingEngine.get (handlerObject, name);
|
||||
writeResponse (value, reval.res.getBuffer(), true);
|
||||
}
|
||||
} else {
|
||||
String msg = "[HopMacro unhandled: "+fullName+"]";
|
||||
|
@ -445,21 +468,21 @@ public final class Skin {
|
|||
value = reval.res.error;
|
||||
if (value == null)
|
||||
value = reval.res.get (name);
|
||||
writeToResponse (value, reval.res, true);
|
||||
writeResponse (value, reval.res.getBuffer(), true);
|
||||
}
|
||||
|
||||
private void renderFromRequest (RequestEvaluator reval) {
|
||||
if (reval.req == null)
|
||||
return;
|
||||
Object value = reval.req.get (name);
|
||||
writeToResponse (value, reval.res, true);
|
||||
writeResponse (value, reval.res.getBuffer(), true);
|
||||
}
|
||||
|
||||
private void renderFromSession (RequestEvaluator reval) {
|
||||
if (reval.session == null)
|
||||
return;
|
||||
Object value = reval.session.getCacheNode().getString (name);
|
||||
writeToResponse (value, reval.res, true);
|
||||
writeResponse (value, reval.res.getBuffer(), true);
|
||||
}
|
||||
|
||||
private void renderFromParam (RequestEvaluator reval, Map paramObject) {
|
||||
|
@ -467,14 +490,14 @@ public final class Skin {
|
|||
reval.res.write ("[HopMacro error: Skin requires a parameter object]");
|
||||
else {
|
||||
Object value = paramObject.get (name);
|
||||
writeToResponse (value, reval.res, true);
|
||||
writeResponse (value, reval.res.getBuffer(), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for writing text out to the response object.
|
||||
*/
|
||||
void writeToResponse (Object value, ResponseTrans res, boolean useDefault) {
|
||||
void writeResponse (Object value, StringBuffer buffer, boolean useDefault) {
|
||||
String text;
|
||||
if (value == null) {
|
||||
if (useDefault)
|
||||
|
@ -484,36 +507,39 @@ public final class Skin {
|
|||
} else {
|
||||
text = value.toString ();
|
||||
}
|
||||
if (text == null || text.length() == 0)
|
||||
return;
|
||||
if (encoding != null)
|
||||
text = encode (text, encoding);
|
||||
res.write (prefix);
|
||||
res.write (text);
|
||||
res.write (suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method for performing different kind of character
|
||||
* encodings on the macro output.
|
||||
*/
|
||||
String encode (String text, String encoding) {
|
||||
if ("html".equalsIgnoreCase (encoding))
|
||||
return HtmlEncoder.encode (text);
|
||||
if ("xml".equalsIgnoreCase (encoding))
|
||||
return HtmlEncoder.encodeXml (text);
|
||||
if ("form".equalsIgnoreCase (encoding))
|
||||
return HtmlEncoder.encodeFormValue (text);
|
||||
if ("url".equalsIgnoreCase (encoding))
|
||||
return URLEncoder.encode (text);
|
||||
return text;
|
||||
if (text != null && text.length() > 0) {
|
||||
if (prefix != null)
|
||||
buffer.append (prefix);
|
||||
switch (encoding) {
|
||||
case ENCODE_NONE:
|
||||
buffer.append (text);
|
||||
break;
|
||||
case ENCODE_HTML:
|
||||
HtmlEncoder.encode (text, buffer);
|
||||
break;
|
||||
case ENCODE_XML:
|
||||
HtmlEncoder.encodeXml (text, buffer);
|
||||
break;
|
||||
case ENCODE_FORM:
|
||||
HtmlEncoder.encodeFormValue (text, buffer);
|
||||
break;
|
||||
case ENCODE_URL:
|
||||
buffer.append (URLEncoder.encode (text));
|
||||
break;
|
||||
case ENCODE_ALL:
|
||||
HtmlEncoder.encodeAll (text, buffer);
|
||||
break;
|
||||
}
|
||||
if (suffix != null)
|
||||
buffer.append (suffix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString () {
|
||||
return "[HopMacro: "+fullName+"]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the full name of the macro in handler.name notation
|
||||
|
|
|
@ -9,10 +9,10 @@ import java.net.URL;
|
|||
import java.net.MalformedURLException;
|
||||
|
||||
/**
|
||||
* This creates an invisible frame in order to be able to create images
|
||||
* from Java. (Java needs a window context in order to user the Image class).
|
||||
* Factory class for generating Image objects from various sources.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
public class ImageGenerator {
|
||||
|
||||
public ImageGenerator () {
|
||||
|
@ -20,10 +20,9 @@ public class ImageGenerator {
|
|||
}
|
||||
|
||||
public ImageWrapper createPaintableImage (int w, int h) {
|
||||
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
|
||||
BufferedImage img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = img.getGraphics ();
|
||||
ImageWrapper rimg = null;
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
ImageWrapper rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
return rimg;
|
||||
}
|
||||
|
||||
|
@ -31,13 +30,17 @@ public class ImageGenerator {
|
|||
ImageWrapper rimg = null;
|
||||
Image img1 = Toolkit.getDefaultToolkit ().createImage (src);
|
||||
ImageLoader loader = new ImageLoader (img1);
|
||||
loader.load ();
|
||||
int w = loader.getWidth ();
|
||||
int h = loader.getHeight ();
|
||||
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = img.getGraphics ();
|
||||
g.drawImage (img1, 0, 0, null);
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
try {
|
||||
loader.getDimensions ();
|
||||
int w = loader.getWidth ();
|
||||
int h = loader.getHeight ();
|
||||
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = img.getGraphics ();
|
||||
g.drawImage (img1, 0, 0, null);
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
} finally {
|
||||
loader.done();
|
||||
}
|
||||
return rimg;
|
||||
}
|
||||
|
||||
|
@ -45,10 +48,14 @@ public class ImageGenerator {
|
|||
ImageWrapper rimg = null;
|
||||
Image img = Toolkit.getDefaultToolkit ().createImage (src);
|
||||
ImageLoader loader = new ImageLoader (img);
|
||||
loader.load ();
|
||||
int w = loader.getWidth ();
|
||||
int h = loader.getHeight ();
|
||||
rimg = new SunImageWrapper (img, null, w, h, this);
|
||||
try {
|
||||
loader.getDimensions ();
|
||||
int w = loader.getWidth ();
|
||||
int h = loader.getHeight ();
|
||||
rimg = new SunImageWrapper (img, null, w, h, this);
|
||||
} finally {
|
||||
loader.done();
|
||||
}
|
||||
return rimg;
|
||||
}
|
||||
|
||||
|
@ -58,13 +65,17 @@ public class ImageGenerator {
|
|||
URL url = new URL (urlstring);
|
||||
Image img1 = Toolkit.getDefaultToolkit ().createImage (url);
|
||||
ImageLoader loader = new ImageLoader (img1);
|
||||
loader.load ();
|
||||
int w = loader.getWidth ();
|
||||
int h = loader.getHeight ();
|
||||
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = img.getGraphics ();
|
||||
g.drawImage (img1, 0, 0, null);
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
try {
|
||||
loader.getDimensions ();
|
||||
int w = loader.getWidth ();
|
||||
int h = loader.getHeight ();
|
||||
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = img.getGraphics ();
|
||||
g.drawImage (img1, 0, 0, null);
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
} finally {
|
||||
loader.done();
|
||||
}
|
||||
return rimg;
|
||||
}
|
||||
|
||||
|
@ -73,13 +84,17 @@ public class ImageGenerator {
|
|||
FilteredImageSource fis = new FilteredImageSource (iw.getSource(), filter);
|
||||
Image img1 = Toolkit.getDefaultToolkit().createImage (fis);
|
||||
ImageLoader loader = new ImageLoader (img1);
|
||||
loader.load ();
|
||||
int w = loader.getWidth ();
|
||||
int h = loader.getHeight ();
|
||||
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = img.getGraphics ();
|
||||
g.drawImage (img1, 0, 0, null);
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
try {
|
||||
loader.getDimensions ();
|
||||
int w = loader.getWidth ();
|
||||
int h = loader.getHeight ();
|
||||
Image img = new BufferedImage (w, h, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = img.getGraphics ();
|
||||
g.drawImage (img1, 0, 0, null);
|
||||
rimg = new SunImageWrapper (img, g, w, h, this);
|
||||
} finally {
|
||||
loader.done();
|
||||
}
|
||||
return rimg;
|
||||
}
|
||||
|
||||
|
@ -88,7 +103,8 @@ public class ImageGenerator {
|
|||
Image img = null;
|
||||
img = Toolkit.getDefaultToolkit ().createImage (filename);
|
||||
ImageLoader loader = new ImageLoader (img);
|
||||
loader.load ();
|
||||
loader.getDimensions ();
|
||||
loader.done();
|
||||
return img;
|
||||
}
|
||||
|
||||
|
@ -96,7 +112,8 @@ public class ImageGenerator {
|
|||
Image img = null;
|
||||
img = Toolkit.getDefaultToolkit ().createImage (producer);
|
||||
ImageLoader loader = new ImageLoader (img);
|
||||
loader.load ();
|
||||
loader.getDimensions ();
|
||||
loader.done();
|
||||
return img;
|
||||
}
|
||||
|
||||
|
@ -104,26 +121,27 @@ public class ImageGenerator {
|
|||
|
||||
Image img;
|
||||
int w, h;
|
||||
boolean waiting;
|
||||
boolean firstFrameLoaded;
|
||||
|
||||
ImageLoader (Image img) {
|
||||
this.img = img;
|
||||
waiting = true;
|
||||
firstFrameLoaded = false;
|
||||
}
|
||||
|
||||
int getWidth () {
|
||||
return w;
|
||||
}
|
||||
|
||||
int getHeight () {
|
||||
return h;
|
||||
}
|
||||
|
||||
synchronized void load () {
|
||||
synchronized void getDimensions () {
|
||||
w = img.getWidth(this);
|
||||
h = img.getHeight (this);
|
||||
if (w == -1 || h == -1) try {
|
||||
wait (30000);
|
||||
} catch (InterruptedException x) {
|
||||
return;
|
||||
if (w == -1 || h == -1) {
|
||||
try {
|
||||
wait (45000);
|
||||
} catch (InterruptedException x) {
|
||||
waiting = false;
|
||||
return;
|
||||
} finally {
|
||||
waiting = false;
|
||||
}
|
||||
}
|
||||
// if width and height haven't been set, throw tantrum
|
||||
if (w == -1 || h == -1) {
|
||||
|
@ -131,6 +149,18 @@ public class ImageGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
synchronized void done () {
|
||||
waiting = false;
|
||||
notifyAll ();
|
||||
}
|
||||
|
||||
int getWidth () {
|
||||
return w;
|
||||
}
|
||||
|
||||
int getHeight () {
|
||||
return h;
|
||||
}
|
||||
|
||||
public synchronized boolean imageUpdate(Image img,
|
||||
int infoflags,
|
||||
|
@ -138,24 +168,24 @@ public class ImageGenerator {
|
|||
int y,
|
||||
int width,
|
||||
int height) {
|
||||
if (w == -1 && (infoflags & WIDTH) > 0)
|
||||
w = width;
|
||||
if (h == -1 && (infoflags & HEIGHT) > 0)
|
||||
h = height;
|
||||
if (h > -1 && w > -1 && (infoflags & ALLBITS) > 0) {
|
||||
// we know all we want to know. notify waiting thread that
|
||||
// the image is loaded and ready to be used.
|
||||
notifyAll ();
|
||||
return false;
|
||||
}
|
||||
// check if there was an error
|
||||
if ((infoflags & ERROR) > 0) {
|
||||
if (!waiting || (infoflags & ERROR) > 0 || (infoflags & ABORT) > 0) {
|
||||
// we either timed out or there was an error.
|
||||
notifyAll ();
|
||||
return false;
|
||||
}
|
||||
// TODO: If image production was aborted, but no error was reported,
|
||||
// we might want to start production again. For now, we just give up.
|
||||
if ((infoflags & ABORT) > 0) {
|
||||
if ((infoflags & WIDTH) > 0 || (infoflags & HEIGHT) > 0) {
|
||||
if ((infoflags & WIDTH) > 0)
|
||||
w = width;
|
||||
if ((infoflags & HEIGHT) > 0)
|
||||
h = height;
|
||||
if (w > -1 && h > -1 && firstFrameLoaded) {
|
||||
notifyAll ();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((infoflags & ALLBITS) > 0 || (infoflags & FRAMEBITS) > 0) {
|
||||
firstFrameLoaded = true;
|
||||
notifyAll ();
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -94,12 +94,16 @@ public abstract class ImageWrapper {
|
|||
}
|
||||
|
||||
public void resize (int w, int h) {
|
||||
// ImageFilter filter = new ReplicateScaleFilter (w, h);
|
||||
// img = Toolkit.getDefaultToolkit ().createImage(new FilteredImageSource(img.getSource(), filter));
|
||||
img = img.getScaledInstance (w, h, Image.SCALE_SMOOTH);
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
public void resizeFast (int w, int h) {
|
||||
img = img.getScaledInstance (w, h, Image.SCALE_FAST);
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
public abstract void reduceColors (int colors);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.apache.xmlrpc.*;
|
|||
|
||||
public class Server implements IPathElement, Runnable {
|
||||
|
||||
public static final String version = "1.2 RC2 2002/12/05";
|
||||
public static final String version = "1.2.2 (2003/02/04)";
|
||||
public final long starttime;
|
||||
|
||||
// if true we only accept RMI and XML-RPC connections from
|
||||
|
@ -90,6 +90,9 @@ import org.apache.xmlrpc.*;
|
|||
|
||||
// create new server instance
|
||||
server = new Server (args);
|
||||
|
||||
// start the server main thread
|
||||
server.start ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,8 +140,13 @@ import org.apache.xmlrpc.*;
|
|||
} catch (Exception portx) {
|
||||
usageError = true;
|
||||
}
|
||||
} else
|
||||
} else if (args[i].equals ("-i") && i+1<args.length) {
|
||||
// eat away the -i parameter which is meant for helma.main.launcher.Main
|
||||
i++;
|
||||
} else {
|
||||
System.err.println ("Unknown command line token: "+args[i]);
|
||||
usageError = true;
|
||||
}
|
||||
}
|
||||
|
||||
// get main property file from home dir or vice versa, depending on what we have.
|
||||
|
@ -291,12 +299,18 @@ import org.apache.xmlrpc.*;
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void start () {
|
||||
// Start running, finishing setup and then entering a loop to check changes
|
||||
// in the apps.properties file.
|
||||
mainThread = new Thread (this);
|
||||
mainThread.start ();
|
||||
}
|
||||
|
||||
|
||||
protected void stop () {
|
||||
mainThread = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method of the Server. Basically, we set up Applications and than
|
||||
|
|
|
@ -4,6 +4,7 @@ package helma.main.launcher;
|
|||
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -16,10 +17,20 @@ import java.security.Policy;
|
|||
*/
|
||||
public class Main {
|
||||
|
||||
public static final String[] jars = { "helma.jar", "jetty.jar", "crimson.jar", "xmlrpc.jar",
|
||||
"village.jar", "servlet.jar", "regexp.jar", "mail.jar",
|
||||
"activation.jar", "netcomponents.jar", "jimi.jar",
|
||||
"apache-dom.jar", "jdom.jar"};
|
||||
public static final String[] jars = {
|
||||
"helma.jar",
|
||||
"jetty.jar",
|
||||
"crimson.jar",
|
||||
"xmlrpc.jar",
|
||||
"servlet.jar",
|
||||
"regexp.jar",
|
||||
"mail.jar",
|
||||
"activation.jar",
|
||||
"netcomponents.jar",
|
||||
"jimi.jar",
|
||||
"apache-dom.jar",
|
||||
"jdom.jar"
|
||||
};
|
||||
|
||||
|
||||
public static void main (String[] args) throws Exception {
|
||||
|
@ -54,9 +65,13 @@ public class Main {
|
|||
} catch (Exception x) {
|
||||
// unable to get Helma installation dir from launcher jar
|
||||
System.err.println ("Unable to get Helma installation directory: "+x);
|
||||
System.exit (2);
|
||||
}
|
||||
}
|
||||
|
||||
// decode installDir in case it is URL-encoded
|
||||
installDir = URLDecoder.decode (installDir);
|
||||
|
||||
// set up the class path
|
||||
File libdir = new File (installDir, "lib");
|
||||
ArrayList jarlist = new ArrayList ();
|
||||
|
@ -68,17 +83,20 @@ public class Main {
|
|||
File extdir =new File (libdir, "ext");
|
||||
File[] files = extdir.listFiles (new FilenameFilter() {
|
||||
public boolean accept (File dir, String name) {
|
||||
return name.toLowerCase().endsWith (".jar");
|
||||
String n = name.toLowerCase();
|
||||
return n.endsWith (".jar") || n.endsWith (".zip");
|
||||
}
|
||||
});
|
||||
if (files != null)
|
||||
for (int i=0;i<files.length; i++)
|
||||
for (int i=0;i<files.length; i++) {
|
||||
// WORKAROUND: add the files in lib/ext before
|
||||
// lib/apache-dom.jar, since otherwise putting a full version
|
||||
// of Xerces in lib/ext would cause a version conflict with the
|
||||
// xerces classes in lib/apache-dom.jar. Generally, having some pieces
|
||||
// of Xerces in lib/apache-dom.jar is kind of problematic.
|
||||
jarlist.add (jars.length-3, new URL ("file:" + files[i].getAbsolutePath()));
|
||||
System.err.println ("Adding to classpath: "+files[i].getAbsolutePath());
|
||||
}
|
||||
URL[] urls = new URL[jarlist.size()];
|
||||
jarlist.toArray (urls);
|
||||
FilteredClassLoader loader = new FilteredClassLoader (urls);
|
||||
|
|
|
@ -64,7 +64,7 @@ public final class Property implements IProperty, Serializable {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void setStringValue (String value) throws ParseException {
|
||||
public void setStringValue (String value) {
|
||||
if (type == NODE)
|
||||
this.nvalue = null;
|
||||
if (type == JAVAOBJECT)
|
||||
|
@ -116,6 +116,7 @@ public final class Property implements IProperty, Serializable {
|
|||
this.nvalue = value;
|
||||
}
|
||||
|
||||
|
||||
public void setJavaObjectValue (Object value) {
|
||||
if (type == NODE)
|
||||
this.nvalue = null;
|
||||
|
@ -124,7 +125,6 @@ public final class Property implements IProperty, Serializable {
|
|||
}
|
||||
|
||||
|
||||
|
||||
public String getStringValue () {
|
||||
switch (type) {
|
||||
case STRING:
|
||||
|
@ -151,32 +151,32 @@ public final class Property implements IProperty, Serializable {
|
|||
}
|
||||
|
||||
public long getIntegerValue () {
|
||||
if (type == INTEGER)
|
||||
if (type == INTEGER)
|
||||
return lvalue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public double getFloatValue () {
|
||||
if (type == FLOAT)
|
||||
if (type == FLOAT)
|
||||
return dvalue;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
public Date getDateValue () {
|
||||
if (type == DATE)
|
||||
if (type == DATE)
|
||||
return new Date (lvalue);
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean getBooleanValue () {
|
||||
if (type == BOOLEAN)
|
||||
if (type == BOOLEAN)
|
||||
return bvalue;
|
||||
return false;
|
||||
}
|
||||
|
||||
public INode getNodeValue () {
|
||||
if (type == NODE)
|
||||
if (type == NODE)
|
||||
return nvalue;
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -469,12 +469,8 @@ public class TransientNode implements INode, Serializable {
|
|||
public void setString (String propname, String value) {
|
||||
// IServer.getLogger().log ("setting String prop");
|
||||
Property prop = initProperty (propname);
|
||||
try {
|
||||
prop.setStringValue (value);
|
||||
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||
} catch (java.text.ParseException x) {
|
||||
throw new RuntimeException ("Fehler beim Parsen des Datum-Strings");
|
||||
}
|
||||
prop.setStringValue (value);
|
||||
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||
lastmodified = System.currentTimeMillis ();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ public final class DbColumn {
|
|||
this.name = name;
|
||||
this.type = type;
|
||||
this.relation = rel;
|
||||
if (relation != null)
|
||||
relation.setColumnType (type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,4 +45,4 @@ public final class DbColumn {
|
|||
return relation;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import java.util.Enumeration;
|
|||
import java.util.Iterator;
|
||||
import java.util.StringTokenizer;
|
||||
import java.sql.*;
|
||||
import com.workingdogs.village.*;
|
||||
|
||||
/**
|
||||
* A DbMapping describes how a certain type of Nodes is to mapped to a
|
||||
|
@ -58,8 +57,11 @@ public final class DbMapping implements Updatable {
|
|||
DbColumn[] columns = null;
|
||||
// Map of db columns by name
|
||||
HashMap columnMap;
|
||||
|
||||
// pre-rendered select statement
|
||||
String select = null;
|
||||
String selectString = null;
|
||||
String insertString = null;
|
||||
String updateString = null;
|
||||
|
||||
// db field used as primary key
|
||||
private String idField;
|
||||
|
@ -81,13 +83,10 @@ public final class DbMapping implements Updatable {
|
|||
// remember last key generated for this table
|
||||
long lastID;
|
||||
|
||||
// the (village) schema of the database table
|
||||
Schema schema = null;
|
||||
// the (village) keydef of the db table
|
||||
KeyDef keydef = null;
|
||||
|
||||
// timestamp of last modification of the mapping (type.properties)
|
||||
long lastTypeChange;
|
||||
// init value is -1 so we know we have to run update once even if
|
||||
// the underlying properties file is non-existent
|
||||
long lastTypeChange = -1;
|
||||
// timestamp of last modification of an object of this type
|
||||
long lastDataChange;
|
||||
|
||||
|
@ -188,13 +187,10 @@ public final class DbMapping implements Updatable {
|
|||
}
|
||||
|
||||
lastTypeChange = props.lastModified ();
|
||||
// null the cached schema & keydef so it's rebuilt the next time around
|
||||
schema = null;
|
||||
keydef = null;
|
||||
// same with columns and select string
|
||||
// null the cached columns and select string
|
||||
columns = null;
|
||||
columnMap.clear();
|
||||
select = null;
|
||||
selectString = insertString = updateString = null;
|
||||
|
||||
|
||||
if (extendsProto != null) {
|
||||
|
@ -390,7 +386,9 @@ public final class DbMapping implements Updatable {
|
|||
return null;
|
||||
if (table == null && parentMapping != null)
|
||||
return parentMapping.propertyToColumnName (propName);
|
||||
Relation rel = (Relation) prop2db.get (propName);
|
||||
// FIXME: prop2db stores keys in lower case, because it gets them
|
||||
// from a SystemProperties object which converts keys to lower case.
|
||||
Relation rel = (Relation) prop2db.get (propName.toLowerCase());
|
||||
if (rel != null && (rel.reftype == Relation.PRIMITIVE || rel.reftype == Relation.REFERENCE))
|
||||
return rel.columnName;
|
||||
return null;
|
||||
|
@ -415,7 +413,9 @@ public final class DbMapping implements Updatable {
|
|||
return null;
|
||||
if (table == null && parentMapping != null)
|
||||
return parentMapping.propertyToRelation (propName);
|
||||
return (Relation) prop2db.get (propName);
|
||||
// FIXME: prop2db stores keys in lower case, because it gets them
|
||||
// from a SystemProperties object which converts keys to lower case.
|
||||
return (Relation) prop2db.get (propName.toLowerCase());
|
||||
}
|
||||
|
||||
|
||||
|
@ -558,22 +558,6 @@ public final class DbMapping implements Updatable {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Village Schema object for this DbMapping.
|
||||
*/
|
||||
public synchronized Schema getSchema () throws ClassNotFoundException, SQLException, DataSetException {
|
||||
if (!isRelational ())
|
||||
throw new SQLException ("Can't get Schema for non-relational data mapping");
|
||||
if (source == null && parentMapping != null)
|
||||
return parentMapping.getSchema ();
|
||||
// Use local variable s to avoid synchronization (schema may be nulled elsewhere)
|
||||
Schema s = schema;
|
||||
if (s != null)
|
||||
return s;
|
||||
schema = new Schema ().schema (getConnection (), table, "*");
|
||||
return schema;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an array of DbColumns for the relational table mapped by this DbMapping.
|
||||
|
@ -630,14 +614,40 @@ public final class DbMapping implements Updatable {
|
|||
}
|
||||
|
||||
public StringBuffer getSelect () throws SQLException, ClassNotFoundException {
|
||||
String sel = select;
|
||||
String sel = selectString;
|
||||
if (sel != null)
|
||||
return new StringBuffer (sel);
|
||||
StringBuffer s = new StringBuffer ("SELECT * FROM ");
|
||||
s.append (getTableName ());
|
||||
s.append (" ");
|
||||
// cache rendered string for later calls.
|
||||
select = s.toString();
|
||||
selectString = s.toString();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
public StringBuffer getInsert () {
|
||||
String ins = insertString;
|
||||
if (ins != null)
|
||||
return new StringBuffer (ins);
|
||||
StringBuffer s = new StringBuffer ("INSERT INTO ");
|
||||
s.append (getTableName ());
|
||||
s.append (" ( ");
|
||||
s.append (getIDField());
|
||||
// cache rendered string for later calls.
|
||||
insertString = s.toString();
|
||||
return s;
|
||||
}
|
||||
|
||||
public StringBuffer getUpdate () {
|
||||
String upd = updateString;
|
||||
if (upd != null)
|
||||
return new StringBuffer (upd);
|
||||
StringBuffer s = new StringBuffer ("UPDATE ");
|
||||
s.append (getTableName ());
|
||||
s.append (" SET ");
|
||||
// cache rendered string for later calls.
|
||||
updateString = s.toString();
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -669,21 +679,6 @@ public final class DbMapping implements Updatable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Village Schema object for this DbMapping.
|
||||
*/
|
||||
public synchronized KeyDef getKeyDef () {
|
||||
if (!isRelational ())
|
||||
throw new RuntimeException ("Can't get KeyDef for non-relational data mapping");
|
||||
if (source == null && parentMapping != null)
|
||||
return parentMapping.getKeyDef ();
|
||||
// Use local variable s to avoid synchronization (keydef may be nulled elsewhere)
|
||||
KeyDef k = keydef;
|
||||
if (k != null)
|
||||
return k;
|
||||
keydef = new KeyDef ().addAttrib (getIDField ());
|
||||
return keydef;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
if (typename == null)
|
||||
|
|
|
@ -179,7 +179,7 @@ public final class Node implements INode, Serializable {
|
|||
*/
|
||||
public Node (String name, String id, String prototype, WrappedNodeManager nmgr) {
|
||||
this.nmgr = nmgr;
|
||||
this.id = id;
|
||||
this.id = id;
|
||||
this.name = name == null || "".equals (name) ? id : name;
|
||||
if (prototype != null)
|
||||
setPrototype (prototype);
|
||||
|
@ -235,7 +235,7 @@ public final class Node implements INode, Serializable {
|
|||
* Constructor used for nodes being stored in a relational database table.
|
||||
*/
|
||||
public Node (DbMapping dbm, ResultSet rs, DbColumn[] columns, WrappedNodeManager nmgr)
|
||||
throws SQLException {
|
||||
throws SQLException, IOException {
|
||||
|
||||
this.nmgr = nmgr;
|
||||
// see what prototype/DbMapping this object should use
|
||||
|
@ -302,13 +302,32 @@ public final class Node implements INode, Serializable {
|
|||
newprop.setIntegerValue (num.longValue ());
|
||||
break;
|
||||
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.VARBINARY:
|
||||
case Types.BINARY:
|
||||
newprop.setStringValue (rs.getString(columns[i].getName()));
|
||||
break;
|
||||
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.LONGVARCHAR:
|
||||
try {
|
||||
newprop.setStringValue (rs.getString(columns[i].getName()));
|
||||
} catch (SQLException x) {
|
||||
Reader in = rs.getCharacterStream(columns[i].getName());
|
||||
char[] buffer = new char[2048];
|
||||
int read = 0, r = 0;
|
||||
while ((r = in.read (buffer, read, buffer.length-read)) > -1) {
|
||||
read += r;
|
||||
if (read == buffer.length) {
|
||||
// grow input buffer
|
||||
char[] newBuffer = new char[buffer.length*2];
|
||||
System.arraycopy (buffer, 0, newBuffer, 0, buffer.length);
|
||||
buffer = newBuffer;
|
||||
}
|
||||
}
|
||||
newprop.setStringValue (new String(buffer, 0, read));
|
||||
}
|
||||
break;
|
||||
|
||||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.OTHER:
|
||||
|
@ -435,9 +454,9 @@ public final class Node implements INode, Serializable {
|
|||
Relation rel = getDbMapping ().getSubnodeRelation ();
|
||||
if (rel != null) {
|
||||
if (rel.usesPrimaryKey()) {
|
||||
nmgr.evictKey (new DbKey (getDbMapping().getSubnodeMapping(), key));
|
||||
nmgr.evictNodeByKey (new DbKey (getDbMapping().getSubnodeMapping(), key));
|
||||
} else {
|
||||
nmgr.evictKey (new SyntheticKey (getKey(), key));
|
||||
nmgr.evictNodeByKey (new SyntheticKey (getKey(), key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -493,7 +512,7 @@ public final class Node implements INode, Serializable {
|
|||
} else {
|
||||
anonymous = true;
|
||||
}
|
||||
} else if (p.contains (this) > -1) {
|
||||
} else if (!anonymous && p.contains (this) > -1) {
|
||||
anonymous = true;
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
|
@ -873,13 +892,13 @@ public final class Node implements INode, Serializable {
|
|||
|
||||
public INode createNode (String nm, int where) {
|
||||
checkWriteLock ();
|
||||
boolean anon = false;
|
||||
if (nm == null || "".equals (nm.trim ()))
|
||||
boolean anon = false;
|
||||
if (nm == null || "".equals (nm.trim ()))
|
||||
anon = true;
|
||||
Node n = new Node (nm, null, nmgr);
|
||||
if (anon)
|
||||
addNode (n, where);
|
||||
else
|
||||
else
|
||||
setNode (nm, n);
|
||||
return n;
|
||||
}
|
||||
|
@ -917,7 +936,7 @@ public final class Node implements INode, Serializable {
|
|||
if (rel.otherType != null && rel.otherType.isRelational ())
|
||||
return (IPathElement) nmgr.getNode (this, name, rel);
|
||||
else
|
||||
return (IPathElement) getNode (name);
|
||||
return (IPathElement) getNode (name);
|
||||
}
|
||||
return (IPathElement) getSubnode (name);
|
||||
} else {
|
||||
|
@ -1748,11 +1767,20 @@ public final class Node implements INode, Serializable {
|
|||
if (propMap == null)
|
||||
return;
|
||||
try {
|
||||
Property p = (Property) propMap.remove (propname.toLowerCase ());
|
||||
// if node is relational, leave a null property so that it is
|
||||
// updated in the DB. Otherwise, remove the property.
|
||||
Property p;
|
||||
boolean relational = dbmap != null && dbmap.isRelational();
|
||||
if (relational)
|
||||
p = (Property) propMap.get (propname.toLowerCase ());
|
||||
else
|
||||
p = (Property) propMap.remove (propname.toLowerCase ());
|
||||
if (p != null) {
|
||||
checkWriteLock ();
|
||||
if (p.getType() == Property.NODE)
|
||||
p.unregisterNode ();
|
||||
if (relational)
|
||||
p.setStringValue (null);
|
||||
// Server.throwNodeEvent (new NodeEvent (this, NodeEvent.PROPERTIES_CHANGED));
|
||||
lastmodified = System.currentTimeMillis ();
|
||||
if (state == CLEAN)
|
||||
|
|
|
@ -9,7 +9,6 @@ import helma.framework.core.Application;
|
|||
import java.sql.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import com.workingdogs.village.*;
|
||||
|
||||
/**
|
||||
* The NodeManager is responsible for fetching Nodes from the internal or
|
||||
|
@ -360,8 +359,8 @@ public final class NodeManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove a node from the node cache. If at a later time it is accessed again, it will be
|
||||
* refetched from the database.
|
||||
* Remove a node from the node cache. If at a later time it is accessed again,
|
||||
* it will be refetched from the database.
|
||||
*/
|
||||
public void evictNode (Node node) {
|
||||
node.setState (INode.INVALID);
|
||||
|
@ -369,7 +368,21 @@ public final class NodeManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Used when a key stops being valid for a node.
|
||||
* Remove a node from the node cache. If at a later time it is accessed again,
|
||||
* it will be refetched from the database.
|
||||
*/
|
||||
public void evictNodeByKey (Key key) {
|
||||
Node n = (Node) cache.remove (key);
|
||||
if (n != null) {
|
||||
n.setState (INode.INVALID);
|
||||
if (!(key instanceof DbKey))
|
||||
cache.remove (n.getKey ());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when a key stops being valid for a node. The cached node itself
|
||||
* remains valid, if it is present in the cache by other keys.
|
||||
*/
|
||||
public void evictKey (Key key) {
|
||||
cache.remove (key);
|
||||
|
@ -396,62 +409,129 @@ public final class NodeManager {
|
|||
db.saveNode (txn, node.getID (), node);
|
||||
} else {
|
||||
// app.logEvent ("inserting relational node: "+node.getID ());
|
||||
TableDataSet tds = null;
|
||||
|
||||
DbColumn[] columns = dbm.getColumns ();
|
||||
|
||||
StringBuffer b1 = dbm.getInsert ();
|
||||
StringBuffer b2 = new StringBuffer (" ) VALUES ( ?");
|
||||
|
||||
String nameField = dbm.getNameField ();
|
||||
String prototypeField = dbm.getPrototypeField ();
|
||||
|
||||
for (int i=0; i<columns.length; i++) {
|
||||
Relation rel = columns[i].getRelation();
|
||||
String name = columns[i].getName();
|
||||
if ((rel != null && (rel.isPrimitive() || rel.isReference())) ||
|
||||
name.equals (nameField) || name.equals (prototypeField))
|
||||
{
|
||||
b1.append (", "+columns[i].getName());
|
||||
b2.append (", ?");
|
||||
}
|
||||
}
|
||||
|
||||
b1.append (b2.toString());
|
||||
b1.append (" )");
|
||||
|
||||
Connection con = dbm.getConnection ();
|
||||
PreparedStatement stmt = con.prepareStatement (b1.toString ());
|
||||
|
||||
if (logSql)
|
||||
app.logEvent ("### insertNode: "+b1.toString ());
|
||||
|
||||
try {
|
||||
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
|
||||
Record rec = tds.addRecord ();
|
||||
rec.setValue (dbm.getIDField (), node.getID ());
|
||||
|
||||
String nameField = dbm.getNameField ();
|
||||
if (nameField != null)
|
||||
rec.setValue (nameField, node.getName ());
|
||||
int stmtNumber = 1;
|
||||
stmt.setString (stmtNumber, node.getID());
|
||||
|
||||
for (Iterator i=dbm.getProp2DB().entrySet().iterator(); i.hasNext(); ) {
|
||||
Map.Entry e = (Map.Entry) i.next ();
|
||||
String propname = (String) e.getKey ();
|
||||
Relation rel = (Relation) e.getValue ();
|
||||
Property p = node.getProperty (propname);
|
||||
Hashtable propMap = node.getPropMap ();
|
||||
for (int i=0; i<columns.length; i++) {
|
||||
Relation rel = columns[i].getRelation();
|
||||
Property p = null;
|
||||
if (rel != null && (rel.isPrimitive() || rel.isReference()))
|
||||
p = (Property) propMap.get (rel.getPropName ());
|
||||
String name = columns[i].getName ();
|
||||
if (!(rel != null && (rel.isPrimitive() || rel.isReference())) && !name.equals (nameField) && !name.equals (prototypeField))
|
||||
continue;
|
||||
|
||||
if (p != null && rel != null) {
|
||||
switch (p.getType ()) {
|
||||
case IProperty.STRING:
|
||||
rec.setValue (rel.getDbField(), p.getStringValue ());
|
||||
break;
|
||||
case IProperty.BOOLEAN:
|
||||
rec.setValue (rel.getDbField(), p.getBooleanValue ());
|
||||
break;
|
||||
case IProperty.DATE:
|
||||
Timestamp t = new Timestamp (p.getDateValue ().getTime ());
|
||||
rec.setValue (rel.getDbField(), t);
|
||||
break;
|
||||
case IProperty.INTEGER:
|
||||
rec.setValue (rel.getDbField(), p.getIntegerValue ());
|
||||
break;
|
||||
case IProperty.FLOAT:
|
||||
rec.setValue (rel.getDbField(), p.getFloatValue ());
|
||||
break;
|
||||
case IProperty.NODE:
|
||||
if (rel.reftype == Relation.REFERENCE) {
|
||||
// INode n = p.getNodeValue ();
|
||||
// String foreignID = n == null ? null : n.getID ();
|
||||
rec.setValue (rel.getDbField(), p.getStringValue ());
|
||||
}
|
||||
break;
|
||||
stmtNumber++;
|
||||
if (p != null) {
|
||||
if (p.getValue() == null) {
|
||||
stmt.setNull (stmtNumber, columns[i].getType ());
|
||||
} else {
|
||||
switch (columns[i].getType ()) {
|
||||
|
||||
case Types.BIT:
|
||||
case Types.TINYINT:
|
||||
case Types.BIGINT:
|
||||
case Types.SMALLINT:
|
||||
case Types.INTEGER:
|
||||
stmt.setLong (stmtNumber, p.getIntegerValue());
|
||||
break;
|
||||
|
||||
case Types.REAL:
|
||||
case Types.FLOAT:
|
||||
case Types.DOUBLE:
|
||||
case Types.NUMERIC:
|
||||
case Types.DECIMAL:
|
||||
stmt.setDouble (stmtNumber, p.getFloatValue());
|
||||
break;
|
||||
|
||||
case Types.VARBINARY:
|
||||
case Types.BINARY:
|
||||
case Types.BLOB:
|
||||
stmt.setString (stmtNumber, p.getStringValue());
|
||||
break;
|
||||
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.LONGVARCHAR:
|
||||
try {
|
||||
stmt.setString (stmtNumber, p.getStringValue());
|
||||
} catch (SQLException x) {
|
||||
String str = p.getStringValue();
|
||||
Reader r = new StringReader (str);
|
||||
stmt.setCharacterStream (stmtNumber, r, str.length());
|
||||
}
|
||||
break;
|
||||
|
||||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.OTHER:
|
||||
stmt.setString (stmtNumber, p.getStringValue());
|
||||
break;
|
||||
|
||||
case Types.DATE:
|
||||
case Types.TIME:
|
||||
case Types.TIMESTAMP:
|
||||
stmt.setTimestamp (stmtNumber, p.getTimestampValue());
|
||||
break;
|
||||
|
||||
case Types.NULL:
|
||||
stmt.setNull (stmtNumber, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
stmt.setString (stmtNumber, p.getStringValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.dirty = false;
|
||||
} else if (rel != null && rel.getDbField() != null) {
|
||||
rec.setValueNull (rel.getDbField());
|
||||
} else {
|
||||
if (name.equals (nameField))
|
||||
stmt.setString (stmtNumber, node.getName());
|
||||
else if (name.equals (prototypeField))
|
||||
stmt.setString (stmtNumber, node.getPrototype ());
|
||||
else
|
||||
stmt.setNull (stmtNumber, columns[i].getType());
|
||||
}
|
||||
}
|
||||
|
||||
if (dbm.getPrototypeField () != null) {
|
||||
rec.setValue (dbm.getPrototypeField (), node.getPrototype ());
|
||||
}
|
||||
rec.markForInsert ();
|
||||
tds.save ();
|
||||
stmt.executeUpdate ();
|
||||
|
||||
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace ();
|
||||
throw x;
|
||||
} finally {
|
||||
if (tds != null) try {
|
||||
tds.close ();
|
||||
if (stmt != null) try {
|
||||
stmt.close ();
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
dbm.notifyDataChange ();
|
||||
|
@ -475,82 +555,146 @@ public final class NodeManager {
|
|||
db.saveNode (txn, node.getID (), node);
|
||||
} else {
|
||||
|
||||
TableDataSet tds = null;
|
||||
Hashtable propMap = node.getPropMap ();
|
||||
Property[] props = new Property[propMap.size()];
|
||||
propMap.values().toArray (props);
|
||||
|
||||
// make sure table meta info is loaded by dbmapping
|
||||
dbm.getColumns ();
|
||||
|
||||
StringBuffer b = dbm.getUpdate ();
|
||||
|
||||
boolean comma = false;
|
||||
for (int i=0; i<props.length; i++) {
|
||||
// skip clean properties
|
||||
if (props[i] == null || !props[i].dirty) {
|
||||
// null out clean property so we don't consider it later
|
||||
props[i] = null;
|
||||
continue;
|
||||
}
|
||||
Relation rel = dbm.propertyToRelation (props[i].getName());
|
||||
// skip readonly, virtual and collection relations
|
||||
if (rel == null || rel.readonly || rel.virtual ||
|
||||
(rel.reftype != Relation.REFERENCE && rel.reftype != Relation.PRIMITIVE))
|
||||
{
|
||||
// null out property so we don't consider it later
|
||||
props[i] = null;
|
||||
continue;
|
||||
}
|
||||
if (comma)
|
||||
b.append (", ");
|
||||
else
|
||||
comma = true;
|
||||
b.append (rel.getDbField());
|
||||
b.append (" = ?");
|
||||
|
||||
}
|
||||
// if no columns were updated, return
|
||||
if (!comma)
|
||||
return;
|
||||
|
||||
b.append (" WHERE ");
|
||||
b.append (dbm.getIDField ());
|
||||
b.append (" = ");
|
||||
if (dbm.needsQuotes (dbm.getIDField ())) {
|
||||
b.append ("'");
|
||||
b.append (escape(node.getID()));
|
||||
b.append ("'");
|
||||
} else {
|
||||
b.append (node.getID());
|
||||
}
|
||||
|
||||
Connection con = dbm.getConnection ();
|
||||
PreparedStatement stmt = con.prepareStatement (b.toString ());
|
||||
|
||||
if (logSql)
|
||||
app.logEvent ("### updateNode: "+b.toString ());
|
||||
|
||||
int stmtNumber = 0;
|
||||
try {
|
||||
tds = new TableDataSet (dbm.getConnection (), dbm.getSchema (), dbm.getKeyDef ());
|
||||
Record rec = tds.addRecord ();
|
||||
rec.setValue (dbm.getIDField (), node.getID ());
|
||||
|
||||
int updated = 0;
|
||||
|
||||
for (Iterator i=dbm.getProp2DB().entrySet().iterator(); i.hasNext(); ) {
|
||||
Map.Entry e = (Map.Entry) i.next ();
|
||||
String propname = (String) e.getKey ();
|
||||
Relation rel = (Relation) e.getValue ();
|
||||
|
||||
// skip properties that don't need to be updated before fetching them
|
||||
if (rel != null && (rel.readonly || rel.virtual ||
|
||||
(rel.reftype != Relation.REFERENCE && rel.reftype != Relation.PRIMITIVE)))
|
||||
for (int i=0; i<props.length; i++) {
|
||||
Property p = props[i];
|
||||
if (p == null)
|
||||
continue;
|
||||
Relation rel = dbm.propertyToRelation (p.getName());
|
||||
|
||||
Property p = node.getProperty (propname);
|
||||
stmtNumber++;
|
||||
|
||||
if (p != null && rel != null) {
|
||||
if (p.getValue() == null) {
|
||||
stmt.setNull (stmtNumber, rel.getColumnType ());
|
||||
} else {
|
||||
switch (rel.getColumnType ()) {
|
||||
case Types.BIT:
|
||||
case Types.TINYINT:
|
||||
case Types.BIGINT:
|
||||
case Types.SMALLINT:
|
||||
case Types.INTEGER:
|
||||
stmt.setLong (stmtNumber, p.getIntegerValue());
|
||||
break;
|
||||
|
||||
if (p.dirty) {
|
||||
switch (p.getType ()) {
|
||||
case IProperty.STRING:
|
||||
updated++;
|
||||
rec.setValue (rel.getDbField(), p.getStringValue ());
|
||||
break;
|
||||
case IProperty.BOOLEAN:
|
||||
updated++;
|
||||
rec.setValue (rel.getDbField(), p.getBooleanValue ());
|
||||
break;
|
||||
case IProperty.DATE:
|
||||
updated++;
|
||||
Timestamp t = new Timestamp (p.getDateValue ().getTime ());
|
||||
rec.setValue (rel.getDbField(), t);
|
||||
break;
|
||||
case IProperty.INTEGER:
|
||||
updated++;
|
||||
rec.setValue (rel.getDbField(), p.getIntegerValue ());
|
||||
break;
|
||||
case IProperty.FLOAT:
|
||||
updated++;
|
||||
rec.setValue (rel.getDbField(), p.getFloatValue ());
|
||||
break;
|
||||
case IProperty.NODE:
|
||||
if (!rel.virtual && rel.reftype == Relation.REFERENCE) {
|
||||
// INode n = p.getNodeValue ();
|
||||
// String foreignID = n == null ? null : n.getID ();
|
||||
updated++;
|
||||
rec.setValue (rel.getDbField(), p.getStringValue ());
|
||||
case Types.REAL:
|
||||
case Types.FLOAT:
|
||||
case Types.DOUBLE:
|
||||
case Types.NUMERIC:
|
||||
case Types.DECIMAL:
|
||||
stmt.setDouble (stmtNumber, p.getFloatValue());
|
||||
break;
|
||||
|
||||
case Types.VARBINARY:
|
||||
case Types.BINARY:
|
||||
case Types.BLOB:
|
||||
stmt.setString (stmtNumber, p.getStringValue());
|
||||
break;
|
||||
|
||||
case Types.LONGVARBINARY:
|
||||
case Types.LONGVARCHAR:
|
||||
try {
|
||||
stmt.setString (stmtNumber, p.getStringValue());
|
||||
} catch (SQLException x) {
|
||||
String str = p.getStringValue();
|
||||
Reader r = new StringReader (str);
|
||||
stmt.setCharacterStream (stmtNumber, r, str.length());
|
||||
}
|
||||
break;
|
||||
}
|
||||
p.dirty = false;
|
||||
if (!rel.isPrivate())
|
||||
markMappingAsUpdated = true;
|
||||
|
||||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.OTHER:
|
||||
stmt.setString (stmtNumber, p.getStringValue());
|
||||
break;
|
||||
|
||||
case Types.DATE:
|
||||
case Types.TIME:
|
||||
case Types.TIMESTAMP:
|
||||
stmt.setTimestamp (stmtNumber, p.getTimestampValue());
|
||||
break;
|
||||
|
||||
case Types.NULL:
|
||||
stmt.setNull (stmtNumber, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
stmt.setString (stmtNumber, p.getStringValue());
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (rel != null && rel.getDbField() != null) {
|
||||
|
||||
updated++;
|
||||
rec.setValueNull (rel.getDbField());
|
||||
}
|
||||
p.dirty = false;
|
||||
if (!rel.isPrivate())
|
||||
markMappingAsUpdated = true;
|
||||
|
||||
}
|
||||
if (updated > 0) {
|
||||
// mark the key value as clean so no try is made to update it
|
||||
rec.markValueClean (dbm.getIDField ());
|
||||
rec.markForUpdate ();
|
||||
tds.save ();
|
||||
}
|
||||
|
||||
stmt.executeUpdate ();
|
||||
|
||||
} catch (Exception x) {
|
||||
x.printStackTrace ();
|
||||
throw x;
|
||||
} finally {
|
||||
if (tds != null) try {
|
||||
tds.close ();
|
||||
if (stmt != null) try {
|
||||
stmt.close ();
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
if (markMappingAsUpdated)
|
||||
dbm.notifyDataChange ();
|
||||
}
|
||||
|
@ -579,14 +723,17 @@ public final class NodeManager {
|
|||
Statement st = null;
|
||||
try {
|
||||
Connection con = dbm.getConnection ();
|
||||
st = con.createStatement ();
|
||||
st.executeUpdate (new StringBuffer ("DELETE FROM ")
|
||||
String str = new StringBuffer ("DELETE FROM ")
|
||||
.append(dbm.getTableName ())
|
||||
.append(" WHERE ")
|
||||
.append(dbm.getIDField())
|
||||
.append(" = ")
|
||||
.append(node.getID())
|
||||
.toString());
|
||||
.toString();
|
||||
st = con.createStatement ();
|
||||
st.executeUpdate (str);
|
||||
if (logSql)
|
||||
app.logEvent ("### deleteNode: "+str);
|
||||
} finally {
|
||||
if (st != null) try {
|
||||
st.close ();
|
||||
|
@ -1084,7 +1231,13 @@ public final class NodeManager {
|
|||
q.append ("WHERE ");
|
||||
q.append (idfield);
|
||||
q.append (" = ");
|
||||
q.append (kstr);
|
||||
if (dbm.needsQuotes (idfield)) {
|
||||
q.append ("'");
|
||||
q.append (escape(kstr));
|
||||
q.append ("'");
|
||||
} else {
|
||||
q.append (kstr);
|
||||
}
|
||||
|
||||
if (logSql)
|
||||
app.logEvent ("### getNodeByKey: "+q.toString());
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.*;
|
|||
import java.io.*;
|
||||
import java.text.*;
|
||||
import helma.objectmodel.*;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* A property implementation for Nodes stored inside a database. Basically
|
||||
|
@ -19,13 +20,7 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
private String propname;
|
||||
private Node node;
|
||||
|
||||
private String svalue;
|
||||
private boolean bvalue;
|
||||
private long lvalue;
|
||||
private double dvalue;
|
||||
// protected String nvalueID;
|
||||
private NodeHandle nhandle;
|
||||
private Object jvalue;
|
||||
private Object value;
|
||||
|
||||
private int type;
|
||||
|
||||
|
@ -42,29 +37,31 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
case STRING:
|
||||
// try to convert from old format
|
||||
if (node.version < 7)
|
||||
svalue = in.readUTF ();
|
||||
value = in.readUTF ();
|
||||
else
|
||||
svalue = (String) in.readObject ();
|
||||
value = in.readObject ();
|
||||
break;
|
||||
case BOOLEAN:
|
||||
bvalue = in.readBoolean ();
|
||||
value = in.readBoolean () ? Boolean.TRUE : Boolean.FALSE;
|
||||
break;
|
||||
case INTEGER:
|
||||
value = new Long (in.readLong ());
|
||||
break;
|
||||
case DATE:
|
||||
lvalue = in.readLong ();
|
||||
value = new Date (in.readLong ());
|
||||
break;
|
||||
case FLOAT:
|
||||
dvalue = in.readDouble ();
|
||||
value = new Double (in.readDouble ());
|
||||
break;
|
||||
case NODE:
|
||||
// try to convert from old format
|
||||
if (node.version > 4)
|
||||
nhandle = (NodeHandle) in.readObject ();
|
||||
value = (NodeHandle) in.readObject ();
|
||||
else
|
||||
nhandle = new NodeHandle (new DbKey (null, in.readUTF ()));
|
||||
value = new NodeHandle (new DbKey (null, in.readUTF ()));
|
||||
break;
|
||||
case JAVAOBJECT:
|
||||
jvalue = in.readObject ();
|
||||
value = in.readObject ();
|
||||
break;
|
||||
}
|
||||
} catch (ClassNotFoundException x) {
|
||||
|
@ -78,26 +75,28 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
out.writeInt (type);
|
||||
switch (type) {
|
||||
case STRING:
|
||||
out.writeObject (svalue);
|
||||
out.writeObject (value);
|
||||
break;
|
||||
case BOOLEAN:
|
||||
out.writeBoolean (bvalue);
|
||||
out.writeBoolean (((Boolean) value).booleanValue());
|
||||
break;
|
||||
case INTEGER:
|
||||
out.writeLong (((Long) value).longValue());
|
||||
break;
|
||||
case DATE:
|
||||
out.writeLong (lvalue);
|
||||
out.writeLong (((Date) value).getTime());
|
||||
break;
|
||||
case FLOAT:
|
||||
out.writeDouble (dvalue);
|
||||
out.writeDouble (((Double) value).doubleValue());
|
||||
break;
|
||||
case NODE:
|
||||
out.writeObject (nhandle);
|
||||
out.writeObject (value);
|
||||
break;
|
||||
case JAVAOBJECT:
|
||||
if (jvalue != null && !(jvalue instanceof Serializable))
|
||||
if (value != null && !(value instanceof Serializable))
|
||||
out.writeObject (null);
|
||||
else
|
||||
out.writeObject (jvalue);
|
||||
out.writeObject (value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -114,10 +113,10 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
dirty = true;
|
||||
}
|
||||
|
||||
public Property (String propname, Node node, Node value) {
|
||||
public Property (String propname, Node node, Node valueNode) {
|
||||
this (propname, node);
|
||||
type = NODE;
|
||||
nhandle = value == null ? null : value.getHandle ();
|
||||
value = valueNode == null ? null : valueNode.getHandle ();
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
|
@ -126,141 +125,115 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
}
|
||||
|
||||
public Object getValue () {
|
||||
switch (type) {
|
||||
case STRING:
|
||||
return svalue;
|
||||
case BOOLEAN:
|
||||
return new Boolean (bvalue);
|
||||
case INTEGER:
|
||||
return new Long (lvalue);
|
||||
case FLOAT:
|
||||
return new Double (dvalue);
|
||||
case DATE:
|
||||
return new Date (lvalue);
|
||||
case NODE:
|
||||
return null;
|
||||
case JAVAOBJECT:
|
||||
return jvalue;
|
||||
}
|
||||
return null;
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setStringValue (String value) {
|
||||
public int getType () {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setStringValue (String str) {
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = STRING;
|
||||
this.svalue = value;
|
||||
value = str;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
|
||||
public void setIntegerValue (long value) {
|
||||
public void setIntegerValue (long l) {
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = INTEGER;
|
||||
this.lvalue = value;
|
||||
value = new Long(l);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public void setFloatValue (double value) {
|
||||
public void setFloatValue (double d) {
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = FLOAT;
|
||||
this.dvalue = value;
|
||||
value = new Double(d);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public void setDateValue (Date value) {
|
||||
public void setDateValue (Date date) {
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = DATE;
|
||||
this.lvalue = value == null ? 0 : value.getTime();
|
||||
value = date;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public void setBooleanValue (boolean value) {
|
||||
public void setBooleanValue (boolean bool) {
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
type = BOOLEAN;
|
||||
this.bvalue = value;
|
||||
value = bool ? Boolean.TRUE : Boolean.FALSE;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public void setNodeValue (Node value) {
|
||||
public void setNodeValue (Node node) {
|
||||
// value.checkWriteLock ();
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
|
||||
// registerNode (value);
|
||||
type = NODE;
|
||||
|
||||
nhandle = value.getHandle ();
|
||||
value = node == null ? null : node.getHandle ();
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public void setNodeHandle (NodeHandle value) {
|
||||
public void setNodeHandle (NodeHandle handle) {
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
if (type == JAVAOBJECT)
|
||||
this.jvalue = null;
|
||||
// registerNode (value);
|
||||
type = NODE;
|
||||
nhandle = value;
|
||||
value = handle;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public NodeHandle getNodeHandle () {
|
||||
return nhandle;
|
||||
if (type == NODE)
|
||||
return (NodeHandle) value;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void convertToNodeReference (DbMapping dbm) {
|
||||
String id = getStringValue ();
|
||||
if (id == null)
|
||||
nhandle = null;
|
||||
else
|
||||
nhandle = new NodeHandle (new DbKey (dbm, id));
|
||||
if (value != null && !(value instanceof NodeHandle))
|
||||
value = new NodeHandle (new DbKey (dbm, value.toString ()));
|
||||
type = NODE;
|
||||
}
|
||||
|
||||
public void setJavaObjectValue (Object value) {
|
||||
public void setJavaObjectValue (Object obj) {
|
||||
if (type == NODE)
|
||||
unregisterNode ();
|
||||
type = JAVAOBJECT;
|
||||
this.jvalue = value;
|
||||
value = obj;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tell a the value node that it is no longer used as a property.
|
||||
* tell a the value node that it is no longer used as a property.
|
||||
* If this was the "main" property for the node, also remove all other references.
|
||||
*/
|
||||
protected void unregisterNode () {
|
||||
Node nvalue = null;
|
||||
if (nhandle != null)
|
||||
nvalue = nhandle.getNode (node.nmgr);
|
||||
|
||||
if (value == null || !(value instanceof NodeHandle))
|
||||
return;
|
||||
NodeHandle nhandle = (NodeHandle) value;
|
||||
Node nvalue = nhandle.getNode (node.nmgr);
|
||||
|
||||
DbMapping nvmap = null;
|
||||
Relation nvrel = null;
|
||||
if (node.dbmap != null) {
|
||||
nvmap = node.dbmap.getPropertyMapping (propname);
|
||||
nvrel = node.dbmap.getPropertyRelation (propname);
|
||||
}
|
||||
|
||||
|
||||
if (nvalue == null)
|
||||
return;
|
||||
|
||||
|
||||
nvalue.checkWriteLock ();
|
||||
// check if the property node is also a subnode
|
||||
// BUG: this doesn't work because properties for subnode/properties are never stored and therefore
|
||||
|
@ -281,22 +254,20 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
|
||||
|
||||
public String getStringValue () {
|
||||
if (value == null)
|
||||
return null;
|
||||
switch (type) {
|
||||
case STRING:
|
||||
return svalue;
|
||||
case BOOLEAN:
|
||||
return bvalue ? "true" : "false";
|
||||
case DATE:
|
||||
SimpleDateFormat format = new SimpleDateFormat ("dd.MM.yy HH:mm");
|
||||
return format.format (new Date (lvalue));
|
||||
case INTEGER:
|
||||
return Long.toString (lvalue);
|
||||
case FLOAT:
|
||||
return Double.toString (dvalue);
|
||||
case NODE:
|
||||
return nhandle == null ? null : nhandle.getID ();
|
||||
case JAVAOBJECT:
|
||||
return jvalue == null ? null : jvalue.toString ();
|
||||
return value.toString ();
|
||||
case DATE:
|
||||
SimpleDateFormat format = new SimpleDateFormat ("dd.MM.yy hh:mm:ss");
|
||||
return format.format ((Date) value);
|
||||
case NODE:
|
||||
return ((NodeHandle) value).getID ();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -306,51 +277,66 @@ public final class Property implements IProperty, Serializable, Cloneable {
|
|||
}
|
||||
|
||||
public long getIntegerValue () {
|
||||
if (type == INTEGER)
|
||||
return lvalue;
|
||||
return 0;
|
||||
if (type == INTEGER)
|
||||
return ((Long) value).longValue ();
|
||||
if (type == FLOAT)
|
||||
return ((Double) value).longValue ();
|
||||
if (type == BOOLEAN)
|
||||
return ((Boolean) value).booleanValue() ? 1 : 0;
|
||||
try {
|
||||
return Long.parseLong (getStringValue());
|
||||
} catch (Exception x) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public double getFloatValue () {
|
||||
if (type == FLOAT)
|
||||
return dvalue;
|
||||
return 0.0;
|
||||
if (type == FLOAT)
|
||||
return ((Double) value).doubleValue();
|
||||
if (type == INTEGER)
|
||||
return ((Long) value).doubleValue ();
|
||||
try {
|
||||
return Double.parseDouble (getStringValue());
|
||||
} catch (Exception x) {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Date getDateValue () {
|
||||
if (type == DATE)
|
||||
return new Date (lvalue);
|
||||
if (type == DATE)
|
||||
return (Date) value;
|
||||
return null;
|
||||
}
|
||||
|
||||
public Timestamp getTimestampValue () {
|
||||
if (type == DATE && value != null)
|
||||
return new Timestamp (((Date) value).getTime());
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean getBooleanValue () {
|
||||
if (type == BOOLEAN)
|
||||
return bvalue;
|
||||
if (type == BOOLEAN)
|
||||
return ((Boolean) value).booleanValue();
|
||||
if (type == INTEGER)
|
||||
return !(0 == getIntegerValue());
|
||||
return false;
|
||||
}
|
||||
|
||||
public INode getNodeValue () {
|
||||
|
||||
if (nhandle != null) {
|
||||
Node n = nhandle.getNode (node.nmgr);
|
||||
if (n != null) return n;
|
||||
if (type == NODE && value != null) {
|
||||
NodeHandle nhandle = (NodeHandle) value;
|
||||
return nhandle.getNode (node.nmgr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getJavaObjectValue () {
|
||||
if (type == JAVAOBJECT)
|
||||
return jvalue;
|
||||
return value;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public int getType () {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -110,6 +110,10 @@ import java.util.Vector;
|
|||
nmgr.evictNode (node);
|
||||
}
|
||||
|
||||
public void evictNodeByKey (Key key) {
|
||||
nmgr.evictNodeByKey (key);
|
||||
}
|
||||
|
||||
public void evictKey (Key key) {
|
||||
nmgr.evictKey (key);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import java.util.*;
|
|||
|
||||
import javax.xml.parsers.*;
|
||||
import org.w3c.dom.*;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import helma.objectmodel.*;
|
||||
import helma.util.SystemProperties;
|
||||
|
@ -75,6 +76,15 @@ public class XmlConverter implements XmlConstants {
|
|||
}
|
||||
}
|
||||
|
||||
public INode convertFromString( String xml, INode helmaNode ) throws RuntimeException {
|
||||
Document document = XmlUtil.parse (new InputSource (new StringReader (xml)));
|
||||
if ( document!=null && document.getDocumentElement()!=null ) {
|
||||
return convert( document.getDocumentElement(), helmaNode, new HashMap() );
|
||||
} else {
|
||||
return helmaNode;
|
||||
}
|
||||
}
|
||||
|
||||
public INode convert( Element element, INode helmaNode, Map nodeCache ) {
|
||||
offset++;
|
||||
// previousNode is used to cache previous nodes with the same prototype
|
||||
|
@ -82,17 +92,16 @@ public class XmlConverter implements XmlConstants {
|
|||
Object previousNode = null;
|
||||
if (DEBUG)
|
||||
debug("reading " + element.getNodeName() );
|
||||
helmaNode.setName( element.getNodeName() );
|
||||
String prototype = props.getProperty(element.getNodeName()+"._prototype");
|
||||
if ( prototype == null && !sparse )
|
||||
prototype = "HopObject";
|
||||
// if we have a prototype (either explicit or implicit "hopobject"),
|
||||
// if we have a prototype (either explicit or implicit "hopobject"),
|
||||
// set it on the Helma node and store it in the node cache.
|
||||
if ( prototype != null ) {
|
||||
helmaNode.setName( element.getNodeName() );
|
||||
helmaNode.setPrototype( prototype );
|
||||
previousNode = nodeCache.put (prototype, helmaNode);
|
||||
}
|
||||
|
||||
// check attributes of the current element
|
||||
attributes(element, helmaNode, nodeCache);
|
||||
// check child nodes of the current element
|
||||
|
@ -113,7 +122,7 @@ public class XmlConverter implements XmlConstants {
|
|||
private INode children( Element element, helma.objectmodel.INode helmaNode, Map nodeCache ) {
|
||||
NodeList list = element.getChildNodes();
|
||||
int len = list.getLength();
|
||||
boolean nodeHasPrototype = helmaNode.getPrototype() != null;
|
||||
boolean nodeIsInitialized = !nodeCache.isEmpty();
|
||||
StringBuffer textcontent = new StringBuffer();
|
||||
String domKey, helmaKey;
|
||||
for ( int i=0; i<len; i++ ) {
|
||||
|
@ -121,9 +130,9 @@ public class XmlConverter implements XmlConstants {
|
|||
// loop through the list of children
|
||||
org.w3c.dom.Node childNode = list.item(i);
|
||||
|
||||
// if the current node hasn't been initialized yet, try if it can
|
||||
// if the current node hasn't been initialized yet, try if it can
|
||||
// be initialized and converted from one of the child elements.
|
||||
if (!nodeHasPrototype) {
|
||||
if (!nodeIsInitialized) {
|
||||
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
|
||||
convert ((Element) childNode, helmaNode, nodeCache);
|
||||
if (helmaNode.getPrototype() != null)
|
||||
|
@ -162,8 +171,9 @@ public class XmlConverter implements XmlConstants {
|
|||
String prototype = helmaKey.substring (0, dot);
|
||||
INode node = (INode) nodeCache.get (prototype);
|
||||
helmaKey = helmaKey.substring (dot+1);
|
||||
if (node != null && node.getString(helmaKey)==null)
|
||||
if (node != null && node.getString(helmaKey)==null) {
|
||||
node.setString (helmaKey, XmlUtil.getTextContent (childNode));
|
||||
}
|
||||
} else if ( helmaNode.getString(helmaKey)==null ) {
|
||||
helmaNode.setString( helmaKey, XmlUtil.getTextContent(childNode) );
|
||||
if (DEBUG)
|
||||
|
@ -220,7 +230,8 @@ public class XmlConverter implements XmlConstants {
|
|||
if (helmaKey == null) {
|
||||
// we don't map this child element itself since we do
|
||||
// sparse parsing, but there may be something of interest
|
||||
// in the child's child elements.
|
||||
// in the child's attributes and child elements.
|
||||
attributes (childElement, helmaNode, nodeCache);
|
||||
children (childElement, helmaNode, nodeCache);
|
||||
continue;
|
||||
}
|
||||
|
@ -295,8 +306,9 @@ public class XmlConverter implements XmlConstants {
|
|||
if (dot > -1) {
|
||||
String prototype = helmaKey.substring (0, dot);
|
||||
INode node = (INode) nodeCache.get (prototype);
|
||||
if (node != null)
|
||||
if (node != null) {
|
||||
node.setString (helmaKey.substring(dot+1), attr.getNodeValue());
|
||||
}
|
||||
} else if (helmaNode.getPrototype() != null) {
|
||||
helmaNode.setString( helmaKey, attr.getNodeValue() );
|
||||
}
|
||||
|
|
|
@ -97,7 +97,8 @@ public class XmlUtil {
|
|||
int ct = childlist.getLength();
|
||||
for ( int j=0; j<ct; j++ ) {
|
||||
org.w3c.dom.Node childNode = childlist.item(j);
|
||||
if ( childNode.getNodeType()==org.w3c.dom.Node.TEXT_NODE ) {
|
||||
if ( childNode.getNodeType() == Node.TEXT_NODE ||
|
||||
childNode.getNodeType() == Node.CDATA_SECTION_NODE) {
|
||||
childtext.append(childNode.getNodeValue().trim() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,8 @@ public class FesiEngine implements ScriptingEngine {
|
|||
* necessary to bootstrap the rest is parsed.
|
||||
*/
|
||||
private void initialize () {
|
||||
// set the thread filed in the FESI evaluator
|
||||
evaluator.thread = Thread.currentThread ();
|
||||
Collection protos = app.getPrototypes();
|
||||
for (Iterator i=protos.iterator(); i.hasNext(); ) {
|
||||
Prototype proto = (Prototype) i.next ();
|
||||
|
@ -132,13 +134,14 @@ public class FesiEngine implements ScriptingEngine {
|
|||
// we always need it and there's no chance to trigger
|
||||
// creation on demand.
|
||||
getPrototype ("global");
|
||||
evaluator.thread = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a prototype without fully parsing its script files.
|
||||
*/
|
||||
void initPrototype (Prototype prototype) {
|
||||
// System.err.println ("FESI INIT PROTO "+prototype);
|
||||
// System.err.println ("FESI INIT PROTO "+prototype);
|
||||
ObjectPrototype op = null;
|
||||
|
||||
// get the prototype's prototype if possible and necessary
|
||||
|
@ -193,7 +196,7 @@ public class FesiEngine implements ScriptingEngine {
|
|||
* Set up a prototype, parsing and compiling all its script files.
|
||||
*/
|
||||
void evaluatePrototype (Prototype prototype) {
|
||||
// System.err.println ("FESI EVALUATE PROTO "+prototype+" FOR "+this);
|
||||
// System.err.println ("FESI EVALUATE PROTO "+prototype+" FOR "+this);
|
||||
ObjectPrototype op = null;
|
||||
|
||||
// get the prototype's prototype if possible and necessary
|
||||
|
@ -230,8 +233,8 @@ public class FesiEngine implements ScriptingEngine {
|
|||
}
|
||||
|
||||
// Register a constructor for all types except global.
|
||||
// This will first create a new prototyped hopobject and then calls
|
||||
// the actual (scripted) constructor on it.
|
||||
// This will first create a new prototyped hopobject and then calls
|
||||
// the actual (scripted) constructor on it.
|
||||
if (!"global".equalsIgnoreCase (name) && !"root".equalsIgnoreCase (name)) {
|
||||
try {
|
||||
FunctionPrototype fp = (FunctionPrototype) evaluator.getFunctionPrototype();
|
||||
|
@ -263,11 +266,13 @@ public class FesiEngine implements ScriptingEngine {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called before an execution context is entered to let the
|
||||
/**
|
||||
* This method is called before an execution context is entered to let the
|
||||
* engine know it should update its prototype information.
|
||||
*/
|
||||
public void updatePrototypes () {
|
||||
// set the thread filed in the FESI evaluator
|
||||
evaluator.thread = Thread.currentThread ();
|
||||
Collection protos = app.getPrototypes();
|
||||
for (Iterator i=protos.iterator(); i.hasNext(); ) {
|
||||
Prototype proto = (Prototype) i.next ();
|
||||
|
|
|
@ -54,11 +54,17 @@ public class NodeConstructor extends BuiltinFunctionObject {
|
|||
// with the name of the type.
|
||||
// HACK: There is an incompatibility problem here, because the property
|
||||
// constructor is defined as the constructor of the object by EcmaScript.
|
||||
if (op.getProperty ("constructor", "constructor".hashCode()) instanceof ConstructedFunctionObject)
|
||||
if (op.getProperty ("constructor",
|
||||
"constructor".hashCode())
|
||||
instanceof ConstructedFunctionObject)
|
||||
node.doIndirectCall (engine.getEvaluator(), node, "constructor", arguments);
|
||||
else
|
||||
else if (op.getProperty (typename,
|
||||
typename.hashCode())
|
||||
instanceof ConstructedFunctionObject)
|
||||
node.doIndirectCall (engine.getEvaluator(), node, typename, arguments);
|
||||
} catch (Exception ignore) {}
|
||||
} catch (Exception x) {
|
||||
throw new EcmaScriptException (x.toString());
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ public class DomExtension extends Extension {
|
|||
globalXml.putHiddenProperty ("write", new XmlWrite ("write", evaluator, fp));
|
||||
globalXml.putHiddenProperty ("writeToString", new XmlWriteToString ("writeToString", evaluator, fp));
|
||||
globalXml.putHiddenProperty ("get", new XmlGet ("get", evaluator, fp));
|
||||
globalXml.putHiddenProperty ("getFromString", new XmlGetFromString ("getFromString", evaluator, fp));
|
||||
go.putHiddenProperty ("Xml", globalXml);
|
||||
}
|
||||
|
||||
|
@ -175,6 +176,31 @@ public class DomExtension extends Extension {
|
|||
}
|
||||
}
|
||||
|
||||
class XmlGetFromString extends BuiltinFunctionObject {
|
||||
XmlGetFromString(String name, Evaluator evaluator, FunctionPrototype fp) {
|
||||
super(fp, evaluator, name, 1);
|
||||
}
|
||||
public ESValue callFunction(ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
|
||||
if ( arguments==null || arguments.length==0 )
|
||||
throw new EcmaScriptException("Xml.getFromString() needs an XML string as parameter");
|
||||
try {
|
||||
XmlConverter converter;
|
||||
if ( arguments.length>1 ) {
|
||||
converter = new XmlConverter (arguments[1].toString());
|
||||
} else {
|
||||
converter = new XmlConverter ();
|
||||
}
|
||||
INode node = new helma.objectmodel.db.Node ( (String)null, (String)null, this.evaluator.engine.getApplication().getWrappedNodeManager() );
|
||||
INode result = converter.convertFromString (arguments[0].toString(),node);
|
||||
return this.evaluator.engine.getNodeWrapper(result);
|
||||
} catch ( NoClassDefFoundError e ) {
|
||||
throw new EcmaScriptException("Can't load dom-capable xml parser.");
|
||||
} catch ( RuntimeException f ) {
|
||||
throw new EcmaScriptException(f.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
uploadLimit = upstr == null ? 1024 : Integer.parseInt (upstr);
|
||||
// get cookie domain
|
||||
cookieDomain = init.getInitParameter ("cookieDomain");
|
||||
if (cookieDomain != null)
|
||||
cookieDomain = cookieDomain.toLowerCase();
|
||||
// get default encoding
|
||||
defaultEncoding = init.getInitParameter ("charset");
|
||||
debug = ("true".equalsIgnoreCase (init.getInitParameter ("debug")));
|
||||
|
@ -73,7 +75,6 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
protected void execute (HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
byte method) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
|
||||
RequestTrans reqtrans = new RequestTrans (method);
|
||||
// get app and path from original request path
|
||||
|
@ -120,11 +121,12 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
}
|
||||
|
||||
// read cookies
|
||||
if (cookies != null) {
|
||||
for (int i=0; i < cookies.length;i++) try {
|
||||
Cookie[] reqCookies = request.getCookies();
|
||||
if (reqCookies != null) {
|
||||
for (int i=0; i < reqCookies.length;i++) try {
|
||||
// get Cookies
|
||||
String nextKey = cookies[i].getName ();
|
||||
String nextPart = cookies[i].getValue ();
|
||||
String nextKey = reqCookies[i].getName ();
|
||||
String nextPart = reqCookies[i].getValue ();
|
||||
if ("HopSession".equals (nextKey))
|
||||
reqtrans.session = nextPart;
|
||||
else
|
||||
|
@ -157,6 +159,14 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
if (remotehost != null)
|
||||
reqtrans.set ("http_remotehost", remotehost);
|
||||
|
||||
// get the cookie domain to use for this response, if any.
|
||||
String resCookieDomain = cookieDomain;
|
||||
if (resCookieDomain != null) {
|
||||
// check if cookieDomain is valid for this response.
|
||||
// (note: cookieDomain is guaranteed to be lower case)
|
||||
if (host != null && host.toLowerCase().indexOf (cookieDomain) == -1)
|
||||
resCookieDomain = null;
|
||||
}
|
||||
// check if we need to create a session id. also handle the
|
||||
// case that the session id doesn't match the remote host address
|
||||
if (reqtrans.session == null || !reqtrans.session.startsWith (remotehost)) {
|
||||
|
@ -165,8 +175,8 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
System.currentTimeMillis (), 36);
|
||||
Cookie c = new Cookie("HopSession", reqtrans.session);
|
||||
c.setPath ("/");
|
||||
if (cookieDomain != null)
|
||||
c.setDomain (cookieDomain);
|
||||
if (resCookieDomain != null)
|
||||
c.setDomain (resCookieDomain);
|
||||
response.addCookie(c);
|
||||
}
|
||||
|
||||
|
@ -183,6 +193,16 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
reqtrans.path = getPathInfo (request);
|
||||
ResponseTrans restrans = execute (reqtrans);
|
||||
|
||||
// set cookies
|
||||
int ncookies = restrans.countCookies();
|
||||
if (restrans.countCookies() > 0) {
|
||||
CookieTrans[] resCookies = restrans.getCookies ();
|
||||
for (int i = 0; i < resCookies.length; i++) try {
|
||||
Cookie c = resCookies[i].getCookie ("/", resCookieDomain);
|
||||
response.addCookie(c);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
// write response
|
||||
writeResponse (request, response, restrans);
|
||||
|
||||
} catch (Exception x) {
|
||||
|
@ -210,15 +230,6 @@ public abstract class AbstractServletClient extends HttpServlet {
|
|||
HttpServletResponse res,
|
||||
ResponseTrans hopres) {
|
||||
|
||||
int ncookies = hopres.countCookies();
|
||||
if (hopres.countCookies() > 0) {
|
||||
CookieTrans[] cookies = hopres.getCookies ();
|
||||
for (int i = 0; i < cookies.length; i++) try {
|
||||
Cookie c = cookies[i].getCookie ("/", cookieDomain);
|
||||
res.addCookie(c);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
|
||||
if (hopres.getETag() != null) {
|
||||
res.setHeader ("ETag", hopres.getETag());
|
||||
}
|
||||
|
|
|
@ -363,11 +363,14 @@ public final class HtmlEncoder {
|
|||
if (i < l-2) {
|
||||
if (!insideMacroTag && '%' == str.charAt(i+1)) {
|
||||
// this is the beginning of a Helma macro tag
|
||||
insideMacroTag = insideTag = true;
|
||||
macroQuoteChar = '\u0000';
|
||||
if (!insideCodeTag) {
|
||||
insideMacroTag = insideTag = true;
|
||||
macroQuoteChar = '\u0000';
|
||||
}
|
||||
} else if ('!' == str.charAt(i+1) && '-' == str.charAt(i+2)) {
|
||||
// the beginning of an HTML comment?
|
||||
insideComment = insideTag = (i<l-3 && '-' == str.charAt(i+3));
|
||||
if (!insideCodeTag)
|
||||
insideComment = insideTag = (i<l-3 && '-' == str.charAt(i+3));
|
||||
} else if (!insideTag) {
|
||||
// check if this is a HTML tag.
|
||||
boolean insideCloseTag = ('/' == str.charAt(i+1));
|
||||
|
@ -480,6 +483,7 @@ public final class HtmlEncoder {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -494,6 +498,13 @@ public final class HtmlEncoder {
|
|||
return ret.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final static void encodeFormValue (String str, StringBuffer ret) {
|
||||
encodeAll (str, ret, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -512,9 +523,8 @@ public final class HtmlEncoder {
|
|||
/**
|
||||
*
|
||||
*/
|
||||
public final static String encodeAll (String str, StringBuffer ret) {
|
||||
public final static void encodeAll (String str, StringBuffer ret) {
|
||||
encodeAll (str, ret, true);
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue