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