Various minor optimizations.
This commit is contained in:
parent
c796392946
commit
063b42744c
1 changed files with 128 additions and 75 deletions
|
@ -21,9 +21,9 @@ import java.util.*;
|
||||||
public final class Skin {
|
public final class Skin {
|
||||||
|
|
||||||
private Macro[] parts;
|
private Macro[] parts;
|
||||||
private Application app;
|
private final Application app;
|
||||||
private char[] source;
|
private final char[] source;
|
||||||
private int sourceLength;
|
private final int sourceLength;
|
||||||
private HashSet sandbox;
|
private HashSet sandbox;
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,20 +98,28 @@ public final class Skin {
|
||||||
/**
|
/**
|
||||||
* Render this skin
|
* Render this skin
|
||||||
*/
|
*/
|
||||||
public void render (RequestEvaluator reval, Object thisObject, HashMap paramObject) throws RedirectException {
|
public void render (RequestEvaluator reval, Object thisObject, Map paramObject) throws RedirectException {
|
||||||
|
|
||||||
if (parts == null)
|
|
||||||
reval.res.writeCharArray (source, 0, sourceLength);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// check for endless skin recursion
|
// check for endless skin recursion
|
||||||
if (++reval.skinDepth > 50)
|
if (++reval.skinDepth > 50)
|
||||||
throw new RuntimeException ("Recursive skin invocation suspected");
|
throw new RuntimeException ("Recursive skin invocation suspected");
|
||||||
|
|
||||||
|
if (parts == null) {
|
||||||
|
reval.res.writeCharArray (source, 0, sourceLength);
|
||||||
|
reval.skinDepth--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
int written = 0;
|
int written = 0;
|
||||||
|
Map handlerCache = null;
|
||||||
|
if (parts.length > 3) {
|
||||||
|
handlerCache = new HashMap();
|
||||||
|
}
|
||||||
for (int i=0; i<parts.length; i++) {
|
for (int i=0; i<parts.length; i++) {
|
||||||
if (parts[i].start > written)
|
if (parts[i].start > written)
|
||||||
reval.res.writeCharArray (source, written, parts[i].start-written);
|
reval.res.writeCharArray (source, written, parts[i].start-written);
|
||||||
parts[i].render (reval, thisObject, paramObject);
|
parts[i].render (reval, thisObject, paramObject, handlerCache);
|
||||||
written = parts[i].end;
|
written = parts[i].end;
|
||||||
}
|
}
|
||||||
if (written < sourceLength)
|
if (written < sourceLength)
|
||||||
|
@ -152,20 +160,20 @@ public final class Skin {
|
||||||
|
|
||||||
class Macro {
|
class Macro {
|
||||||
|
|
||||||
int start, end;
|
final int start, end;
|
||||||
String handler;
|
String handler;
|
||||||
String name;
|
String name;
|
||||||
String prefix;
|
String prefix;
|
||||||
String suffix;
|
String suffix;
|
||||||
HashMap parameters;
|
String encoding;
|
||||||
|
String defaultValue;
|
||||||
|
Map parameters = null;
|
||||||
|
|
||||||
public Macro (int start, int end) {
|
public Macro (int start, int end) {
|
||||||
|
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
|
|
||||||
parameters = new HashMap ();
|
|
||||||
|
|
||||||
int state = HANDLER;
|
int state = HANDLER;
|
||||||
boolean escape = false;
|
boolean escape = false;
|
||||||
char quotechar = '\u0000';
|
char quotechar = '\u0000';
|
||||||
|
@ -191,7 +199,9 @@ public final class Skin {
|
||||||
case '\'':
|
case '\'':
|
||||||
if (!escape && state == PARAMVALUE) {
|
if (!escape && state == PARAMVALUE) {
|
||||||
if (quotechar == source[i]) {
|
if (quotechar == source[i]) {
|
||||||
parameters.put (lastParamName, b.toString());
|
String paramValue = b.toString();
|
||||||
|
if (!setSpecialParameter (lastParamName, paramValue))
|
||||||
|
addGenericParameter (lastParamName, paramValue);
|
||||||
lastParamName = null;
|
lastParamName = null;
|
||||||
b.setLength (0);
|
b.setLength (0);
|
||||||
state = PARAMNAME;
|
state = PARAMNAME;
|
||||||
|
@ -215,7 +225,9 @@ public final class Skin {
|
||||||
b.setLength (0);
|
b.setLength (0);
|
||||||
state = PARAMNAME;
|
state = PARAMNAME;
|
||||||
} else if (state == PARAMVALUE && quotechar == '\u0000') {
|
} else if (state == PARAMVALUE && quotechar == '\u0000') {
|
||||||
parameters.put (lastParamName, b.toString());
|
String paramValue = b.toString();
|
||||||
|
if (!setSpecialParameter (lastParamName, paramValue))
|
||||||
|
addGenericParameter (lastParamName, paramValue);
|
||||||
lastParamName = null;
|
lastParamName = null;
|
||||||
b.setLength (0);
|
b.setLength (0);
|
||||||
state = PARAMNAME;
|
state = PARAMNAME;
|
||||||
|
@ -238,21 +250,43 @@ public final class Skin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (b.length() > 0) {
|
if (b.length() > 0) {
|
||||||
if (lastParamName != null && b.length() > 0)
|
if (lastParamName != null && b.length() > 0) {
|
||||||
parameters.put (lastParamName, b.toString());
|
String paramValue = b.toString();
|
||||||
else if (state <= MACRO)
|
if (!setSpecialParameter (lastParamName, paramValue))
|
||||||
|
addGenericParameter (lastParamName, paramValue);
|
||||||
|
} else if (state <= MACRO)
|
||||||
name = b.toString().trim();
|
name = b.toString().trim();
|
||||||
}
|
}
|
||||||
// get prefix and suffix from parameters
|
|
||||||
prefix = (String) parameters.get ("prefix");
|
|
||||||
suffix = (String) parameters.get ("suffix");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean setSpecialParameter (String name, String value) {
|
||||||
|
if ("prefix".equals (name)) {
|
||||||
|
prefix = value;
|
||||||
|
return true;
|
||||||
|
} else if ("suffix".equals (name)) {
|
||||||
|
suffix = value;
|
||||||
|
return true;
|
||||||
|
} else if ("encoding".equals (name)) {
|
||||||
|
encoding = value;
|
||||||
|
return true;
|
||||||
|
} else if ("default".equals (name)) {
|
||||||
|
defaultValue = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addGenericParameter (String name, String value) {
|
||||||
|
if (parameters == null)
|
||||||
|
parameters = new HashMap ();
|
||||||
|
parameters.put (name, value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the macro given a handler object
|
* Render the macro given a handler object
|
||||||
*/
|
*/
|
||||||
public void render (RequestEvaluator reval, Object thisObject, HashMap paramObject) throws RedirectException {
|
public void render (RequestEvaluator reval, Object thisObject, Map paramObject, Map handlerCache) throws RedirectException {
|
||||||
|
|
||||||
if (sandbox != null && !sandbox.contains (getFullName ())) {
|
if (sandbox != null && !sandbox.contains (getFullName ())) {
|
||||||
String h = handler == null ? "global" : handler;
|
String h = handler == null ? "global" : handler;
|
||||||
|
@ -273,24 +307,26 @@ public final class Skin {
|
||||||
|
|
||||||
Object handlerObject = null;
|
Object handlerObject = null;
|
||||||
|
|
||||||
Object[] arguments = new Object[1];
|
|
||||||
// pass a clone of the parameter map so if the script changes it,
|
|
||||||
// we still keep the original version.
|
|
||||||
arguments[0] = parameters.clone ();
|
|
||||||
|
|
||||||
// flag to tell whether we found our invocation target object
|
// flag to tell whether we found our invocation target object
|
||||||
boolean objectFound = true;
|
boolean objectFound = true;
|
||||||
|
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
if (thisObject != null) {
|
// try to get handler from handlerCache first
|
||||||
|
if (handlerCache != null)
|
||||||
|
handlerObject = handlerCache.get (handler);
|
||||||
|
|
||||||
|
if (handlerObject == null) {
|
||||||
|
|
||||||
|
// if handler object wasn't found in cache retrieve it
|
||||||
|
if (handlerObject == null && thisObject != null) {
|
||||||
// not a global macro - need to find handler object
|
// not a global macro - need to find handler object
|
||||||
// was called with this object - check it or its parents for matching prototype
|
// was called with this object - check it or its parents for matching prototype
|
||||||
if (!handler.equalsIgnoreCase ("this") && !handler.equalsIgnoreCase (app.getPrototypeName (thisObject))) {
|
if (!handler.equals ("this") && !handler.equals (app.getPrototypeName (thisObject))) {
|
||||||
// the handler object is not what we want
|
// the handler object is not what we want
|
||||||
Object n = thisObject;
|
Object n = app.getParentElement (thisObject);
|
||||||
// walk down parent chain to find handler object
|
// walk down parent chain to find handler object
|
||||||
while (n != null) {
|
while (n != null) {
|
||||||
if (handler.equalsIgnoreCase (app.getPrototypeName (n))) {
|
if (handler.equals (app.getPrototypeName (n))) {
|
||||||
handlerObject = n;
|
handlerObject = n;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -308,7 +344,7 @@ public final class Skin {
|
||||||
int l = reval.requestPath.size();
|
int l = reval.requestPath.size();
|
||||||
for (int i=l-1; i>=0; i--) {
|
for (int i=l-1; i>=0; i--) {
|
||||||
Object pathelem = reval.requestPath.get (i);
|
Object pathelem = reval.requestPath.get (i);
|
||||||
if (handler.equalsIgnoreCase (app.getPrototypeName (pathelem))) {
|
if (handler.equals (app.getPrototypeName (pathelem))) {
|
||||||
handlerObject = pathelem;
|
handlerObject = pathelem;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -318,6 +354,10 @@ public final class Skin {
|
||||||
// the macro handler object couldn't be found
|
// the macro handler object couldn't be found
|
||||||
if (handlerObject == null)
|
if (handlerObject == null)
|
||||||
objectFound = false;
|
objectFound = false;
|
||||||
|
// else put the found handler object into the cache so we don't have to look again
|
||||||
|
else if (handlerCache != null)
|
||||||
|
handlerCache.put (handler, handlerObject);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// this is a global macro with no handler specified
|
// this is a global macro with no handler specified
|
||||||
|
@ -329,21 +369,35 @@ public final class Skin {
|
||||||
// if so, the macro evaluates to the function. Otherwise,
|
// if so, the macro evaluates to the function. Otherwise,
|
||||||
// a property/field with the name is used, if defined.
|
// a property/field with the name is used, if defined.
|
||||||
|
|
||||||
|
String funcName = name+"_macro";
|
||||||
|
if (reval.scriptingEngine.hasFunction (handlerObject, funcName)) {
|
||||||
// remember length of response buffer before calling macro
|
// remember length of response buffer before calling macro
|
||||||
int oldLength = reval.res.getBufferLength ();
|
int bufLength = reval.res.getBufferLength ();
|
||||||
if (reval.scriptingEngine.hasFunction (handlerObject, name+"_macro")) {
|
// remember length of buffer with prefix written out
|
||||||
|
int preLength = 0;
|
||||||
|
if (prefix != null) {
|
||||||
|
reval.res.write (prefix);
|
||||||
|
preLength = prefix.length();
|
||||||
|
}
|
||||||
|
|
||||||
// System.err.println ("Getting macro from function");
|
// System.err.println ("Getting macro from function");
|
||||||
Object v = reval.scriptingEngine.invoke (handlerObject, name+"_macro", arguments, false);
|
// pass a clone of the parameter map so if the script changes it,
|
||||||
|
// Map param = ;
|
||||||
|
Object[] arguments = { parameters == null ?
|
||||||
|
new HashMap () :
|
||||||
|
new HashMap (parameters) };
|
||||||
|
|
||||||
|
Object v = reval.scriptingEngine.invoke (handlerObject, funcName, arguments, false);
|
||||||
// check if macro wrote out to response buffer
|
// check if macro wrote out to response buffer
|
||||||
if (reval.res.getBufferLength () > oldLength) {
|
if (reval.res.getBufferLength () == bufLength + preLength) {
|
||||||
// insert prefix and append suffix
|
// function didn't write out anything itself
|
||||||
if (prefix != null)
|
if (preLength > 0)
|
||||||
reval.res.insert (oldLength, prefix);
|
reval.res.setBufferLength (bufLength);
|
||||||
|
writeToResponse (v, reval.res, true);
|
||||||
|
} else {
|
||||||
if (suffix != null)
|
if (suffix != null)
|
||||||
reval.res.write (suffix);
|
reval.res.write (suffix);
|
||||||
writeToResponse (v, reval.res, false);
|
writeToResponse (v, reval.res, false);
|
||||||
} else {
|
|
||||||
writeToResponse (v, reval.res, true);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// System.err.println ("Getting macro from property");
|
// System.err.println ("Getting macro from property");
|
||||||
|
@ -392,7 +446,7 @@ public final class Skin {
|
||||||
writeToResponse (value, reval.res, true);
|
writeToResponse (value, reval.res, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderFromParam (RequestEvaluator reval, HashMap paramObject) {
|
private void renderFromParam (RequestEvaluator reval, Map paramObject) {
|
||||||
if (paramObject == null)
|
if (paramObject == null)
|
||||||
reval.res.write ("[HopMacro error: Skin requires a parameter object]");
|
reval.res.write ("[HopMacro error: Skin requires a parameter object]");
|
||||||
else {
|
else {
|
||||||
|
@ -408,7 +462,7 @@ public final class Skin {
|
||||||
String text;
|
String text;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
if (useDefault)
|
if (useDefault)
|
||||||
text = (String) parameters.get ("default");
|
text = defaultValue;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -416,9 +470,10 @@ public final class Skin {
|
||||||
}
|
}
|
||||||
if (text == null || text.length() == 0)
|
if (text == null || text.length() == 0)
|
||||||
return;
|
return;
|
||||||
String encoding = (String) parameters.get ("encoding");
|
if (encoding != null)
|
||||||
|
text = encode (text, encoding);
|
||||||
res.write (prefix);
|
res.write (prefix);
|
||||||
res.write (encode (text, encoding));
|
res.write (text);
|
||||||
res.write (suffix);
|
res.write (suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,8 +482,6 @@ public final class Skin {
|
||||||
* encodings on the macro output.
|
* encodings on the macro output.
|
||||||
*/
|
*/
|
||||||
String encode (String text, String encoding) {
|
String encode (String text, String encoding) {
|
||||||
if (encoding == null || text == null)
|
|
||||||
return text;
|
|
||||||
if ("html".equalsIgnoreCase (encoding))
|
if ("html".equalsIgnoreCase (encoding))
|
||||||
return HtmlEncoder.encode (text);
|
return HtmlEncoder.encode (text);
|
||||||
if ("xml".equalsIgnoreCase (encoding))
|
if ("xml".equalsIgnoreCase (encoding))
|
||||||
|
|
Loading…
Add table
Reference in a new issue