Merged changes from helma_1_2 (between helma_1_2_5 and helma_1_2_5_merge_1)

This commit is contained in:
hns 2003-06-26 14:10:04 +00:00
parent 61b8a4a35a
commit fd2882e21d
7 changed files with 130 additions and 38 deletions

View file

@ -140,9 +140,9 @@ public final class Application implements IPathElement, Runnable {
// the name under which this app serves XML-RPC requests. Defaults to the app name
private String xmlrpcHandlerName;
// the list of cron jobs
// the list of currently active cron jobs
private Map activeCronJobs = null;
private Vector cronJobs = null;
// the list of custom cron jobs
Hashtable customCronJobs = null;
/**
@ -342,7 +342,7 @@ public final class Application implements IPathElement, Runnable {
public void start() {
starttime = System.currentTimeMillis();
worker = new Thread(this, "Worker-" + name);
// worker.setPriority(Thread.NORM_PRIORITY + 2);
worker.setPriority(Thread.NORM_PRIORITY + 1);
worker.start();
// logEvent ("session cleanup and scheduler thread started");
@ -1328,6 +1328,10 @@ public final class Application implements IPathElement, Runnable {
}
}
// loop-local cron job data
List cronJobs = null;
long lastCronParse = 0;
while (Thread.currentThread() == worker) {
long now = System.currentTimeMillis();
@ -1374,13 +1378,14 @@ public final class Application implements IPathElement, Runnable {
}
}
if ((cronJobs == null) || (props.lastModified() > lastPropertyRead)) {
if ((cronJobs == null) || (props.lastModified() > lastCronParse)) {
updateProperties();
cronJobs = CronJob.parse(props);
lastCronParse = props.lastModified();
}
Date d = new Date();
List jobs = (List) cronJobs.clone();
List jobs = new ArrayList(cronJobs);
jobs.addAll(customCronJobs.values());
CronJob.sort(jobs);
@ -1559,6 +1564,9 @@ public final class Application implements IPathElement, Runnable {
private synchronized void updateProperties() {
// if so property file has been updated, re-read props.
if (props.lastModified() > lastPropertyRead) {
// force property update
props.update();
// character encoding to be used for responses
charset = props.getProperty("charset", "ISO-8859-1");

View file

@ -378,6 +378,11 @@ public final class TypeManager {
for (int i = 0; i < list.length; i++) {
String fn = list[i].getName();
// ignore files starting with ".".
if (fn.startsWith(".")) {
continue;
}
if (!proto.updatables.containsKey(fn)) {
if (fn.endsWith(templateExtension) || fn.endsWith(scriptExtension) ||
fn.endsWith(actionExtension) || fn.endsWith(skinExtension) ||

View file

@ -1646,12 +1646,12 @@ public final class Node implements INode, Serializable {
}
// the property does not exist in our propmap - see if we should create it on the fly,
// either because it is mapped to an object from relational database or defined as
// either because it is mapped to an object from relational database or defined as
// collection aka virtual node
if ((prop == null) && (dbmap != null)) {
Relation propRel = dbmap.getPropertyRelation(propname);
// if no property relation is defined for this specific property name,
// if no property relation is defined for this specific property name,
// use the generic property relation, if one is defined.
if (propRel == null) {
propRel = dbmap.getPropertyRelation();
@ -1668,12 +1668,8 @@ public final class Node implements INode, Serializable {
pn.setDbMapping(propRel.getVirtualMapping());
pn.setParent(this);
if (propRel.needsPersistence()) {
setNode(propname, pn);
prop = (Property) propMap.get(propname);
} else {
prop = new Property(propname, this, pn);
}
setNode(propname, pn);
prop = (Property) propMap.get(propname);
}
// if this is from relational database only fetch if this node
// is itself persistent.
@ -2408,6 +2404,14 @@ public final class Node implements INode, Serializable {
IProperty next = get((String) e.nextElement());
if ((next != null) && (next.getType() == IProperty.NODE)) {
// check if this property actually needs to be persisted.
if (dbmap != null) {
Relation rel = dbmap.getExactPropertyRelation(next.getName());
if (rel != null && !rel.needsPersistence()) {
continue;
}
}
Node n = (Node) next.getNodeValue();
if ((n != null) && (n.state == TRANSIENT)) {

View file

@ -120,7 +120,6 @@ public abstract class AbstractServletClient extends HttpServlet {
protected void execute(HttpServletRequest request, HttpServletResponse response,
byte method) {
RequestTrans reqtrans = new RequestTrans(method);
// get app and path from original request path
// String pathInfo = request.getPathInfo ();
// String appID = getAppID (pathInfo);
@ -236,23 +235,8 @@ public abstract class AbstractServletClient extends HttpServlet {
}
}
// 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)) {
reqtrans.session = remotehost + "." +
Long.toString(Math.round(Math.random() * Long.MAX_VALUE) -
System.currentTimeMillis(), 36);
Cookie c = new Cookie("HopSession", reqtrans.session);
c.setPath("/");
if (resCookieDomain != null) {
c.setDomain(resCookieDomain);
}
response.addCookie(c);
}
// check if session cookie is present and valid, creating it if not.
checkSessionCookie(request, response, reqtrans, resCookieDomain);
String browser = request.getHeader("User-Agent");
@ -448,6 +432,52 @@ public abstract class AbstractServletClient extends HttpServlet {
return upload.getParts().get(name);
}
/**
* Check if the session cookie is set and valid for this request.
* If not, create a new one.
*/
private void checkSessionCookie(HttpServletRequest request, HttpServletResponse response,
RequestTrans reqtrans, String resCookieDomain) {
// check if we need to create a session id. also handle the
// case that the session id doesn't match the remote host address
StringBuffer b = new StringBuffer();
addIPAddress(b, request.getRemoteAddr());
addIPAddress(b, request.getHeader("X-Forwarded-For"));
addIPAddress(b, request.getHeader("Client-ip"));
if ((reqtrans.session == null) || !reqtrans.session.startsWith(b.toString())) {
b.append (Long.toString(Math.round(Math.random() * Long.MAX_VALUE) -
System.currentTimeMillis(), 36));
reqtrans.session = b.toString();
Cookie c = new Cookie("HopSession", reqtrans.session);
c.setPath("/");
if (resCookieDomain != null) {
c.setDomain(resCookieDomain);
}
response.addCookie(c);
}
}
/**
* Adds an the 3 most significant bytes of an IP address to the
* session cookie id.
*/
private void addIPAddress(StringBuffer b, String addr) {
if (addr != null) {
int cut = addr.lastIndexOf(".");
if (cut == -1) {
cut = addr.lastIndexOf(":");
}
if (cut > -1) {
b.append(addr.substring(0, cut+1));
}
}
}
/**
* Put name value pair in map.
*

View file

@ -87,7 +87,7 @@ public class CronJob {
private String name = null;
private String function = null;
private long timeout = 20000;
private long timeout = 600000;
/** A method for parsing properties. It looks through the properties
* file for entries that look like this:
@ -182,7 +182,7 @@ public class CronJob {
}
public static Vector parse(Properties props) {
public static List parse(Properties props) {
Hashtable jobs = new Hashtable ();
Enumeration e = props.keys ();
while (e.hasMoreElements ()) {
@ -222,8 +222,8 @@ public class CronJob {
} catch (NoSuchElementException nsee) {
}
}
Vector jobVec = new Vector (jobs.values ());
return (Vector) sort (jobVec);
List jobVec = new ArrayList (jobs.values ());
return sort (jobVec);
}
public static List sort (List list) {

View file

@ -342,6 +342,11 @@ public final class HtmlEncoder {
emptyTags.add("param");
}
final static byte TAG_NAME = 0;
final static byte TAG_SPACE = 1;
final static byte TAG_ATT_NAME = 2;
final static byte TAG_ATT_VAL = 3;
/**
* Do "smart" encodging on a string. This means that valid HTML entities and tags,
@ -397,6 +402,8 @@ public final class HtmlEncoder {
// are we inside an HTML tag?
boolean insideHtmlTag = false;
boolean insideCloseTag = false;
byte htmlTagMode = TAG_NAME;
// if we are inside a <code> tag, we encode everything to make
// documentation work easier
@ -445,7 +452,7 @@ public final class HtmlEncoder {
}
} else if (!insideTag) {
// check if this is a HTML tag.
boolean insideCloseTag = ('/' == str.charAt(i + 1));
insideCloseTag = ('/' == str.charAt(i + 1));
int tagStart = insideCloseTag ? (i + 2) : (i + 1);
int j = tagStart;
@ -464,6 +471,7 @@ public final class HtmlEncoder {
allTags.contains(tagName) && !insideCodeTag) {
insideHtmlTag = insideTag = true;
htmlQuoteChar = '\u0000';
htmlTagMode = TAG_NAME;
// set ignoreNewline on some tags, depending on wheather they're
// being opened or closed.
@ -610,6 +618,7 @@ public final class HtmlEncoder {
escape = false;
} else if (htmlQuoteChar == c) {
htmlQuoteChar = '\u0000';
htmlTagMode = TAG_SPACE;
} else if (htmlQuoteChar == '\u0000') {
htmlQuoteChar = c;
}
@ -650,7 +659,11 @@ public final class HtmlEncoder {
// Check if this is an empty tag so we don't generate an
// additional </close> tag.
if (str.charAt(i - 1) == '/') {
openTags.pop();
// this is to avoid misinterpreting tags like
// <a href=http://foo/> as empty
if (htmlTagMode != TAG_ATT_VAL && htmlTagMode != TAG_ATT_NAME) {
openTags.pop();
}
}
} else {
ret.append("&gt;");
@ -663,7 +676,32 @@ public final class HtmlEncoder {
default:
// ret.append (c);
if (insideHtmlTag && !insideCloseTag) {
switch(htmlTagMode) {
case TAG_NAME:
if (!Character.isLetterOrDigit(c)) {
htmlTagMode = TAG_SPACE;
}
break;
case TAG_SPACE:
if (Character.isLetterOrDigit(c)) {
htmlTagMode = TAG_ATT_NAME;
}
break;
case TAG_ATT_NAME:
if (c == '=') {
htmlTagMode = TAG_ATT_VAL;
} else if (c == ' ') {
htmlTagMode = TAG_SPACE;
}
break;
case TAG_ATT_VAL:
if (Character.isWhitespace(c) && htmlQuoteChar == '\u0000') {
htmlTagMode = TAG_SPACE;
}
break;
}
}
if (c < 128) {
ret.append(c);
} else if ((c >= 128) && (c < 256)) {

View file

@ -101,6 +101,13 @@ public final class SystemProperties extends Properties {
return Math.max(file.lastModified(), lastadd);
}
/**
* Update/re-read the properties from file if necessary.
*/
public void update () {
checkFile();
}
/**
* Return a checksum that changes when something in the properties changes.
*/