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:
hns 2003-02-04 14:15:46 +00:00
parent 30098b723e
commit d53076291d

View file

@ -20,7 +20,7 @@ import java.util.*;
public final class Skin { public final class Skin {
private Macro[] parts; private Macro[] macros;
private Application app; private Application app;
private char[] source; private char[] source;
private int sourceLength; private int sourceLength;
@ -84,8 +84,8 @@ public final class Skin {
} }
} }
parts = new Macro[partBuffer.size()]; macros = new Macro[partBuffer.size()];
partBuffer.toArray (parts); partBuffer.toArray (macros);
} }
/** /**
@ -104,7 +104,7 @@ public final class Skin {
if (++reval.skinDepth > 50) if (++reval.skinDepth > 50)
throw new RuntimeException ("Recursive skin invocation suspected"); throw new RuntimeException ("Recursive skin invocation suspected");
if (parts == null) { if (macros == null) {
reval.res.writeCharArray (source, 0, sourceLength); reval.res.writeCharArray (source, 0, sourceLength);
reval.skinDepth--; reval.skinDepth--;
return; return;
@ -113,14 +113,14 @@ public final class Skin {
try { try {
int written = 0; int written = 0;
Map handlerCache = null; Map handlerCache = null;
if (parts.length > 3) { if (macros.length > 3) {
handlerCache = new HashMap(); handlerCache = new HashMap();
} }
for (int i=0; i<parts.length; i++) { for (int i=0; i<macros.length; i++) {
if (parts[i].start > written) if (macros[i].start > written)
reval.res.writeCharArray (source, written, parts[i].start-written); reval.res.writeCharArray (source, written, macros[i].start-written);
parts[i].render (reval, thisObject, paramObject, handlerCache); macros[i].render (reval, thisObject, paramObject, handlerCache);
written = parts[i].end; written = macros[i].end;
} }
if (written < sourceLength) if (written < sourceLength)
reval.res.writeCharArray (source, written, sourceLength-written); reval.res.writeCharArray (source, written, sourceLength-written);
@ -133,9 +133,9 @@ public final class Skin {
* Check if a certain macro is present in this skin. The macro name is in handler.name notation * Check if a certain macro is present in this skin. The macro name is in handler.name notation
*/ */
public boolean containsMacro (String macroname) { public boolean containsMacro (String macroname) {
for (int i=0; i<parts.length; i++) { for (int i=0; i<macros.length; i++) {
if (parts[i] instanceof Macro) { if (macros[i] instanceof Macro) {
Macro m = (Macro) parts[i]; Macro m = (Macro) macros[i];
if (macroname.equals (m.fullName)) if (macroname.equals (m.fullName))
return true; return true;
} }
@ -158,6 +158,13 @@ public final class Skin {
static final int PARAMNAME = 2; static final int PARAMNAME = 2;
static final int PARAMVALUE = 3; static final int PARAMVALUE = 3;
static final int ENCODE_NONE = 0;
static final int ENCODE_HTML = 1;
static final int ENCODE_XML = 2;
static final int ENCODE_FORM = 3;
static final int ENCODE_URL = 4;
static final int ENCODE_ALL = 5;
class Macro { class Macro {
final int start, end; final int start, end;
@ -166,8 +173,8 @@ public final class Skin {
String fullName; String fullName;
String prefix; String prefix;
String suffix; String suffix;
String encoding;
String defaultValue; String defaultValue;
int encoding = ENCODE_NONE;
Map parameters = null; Map parameters = null;
public Macro (int start, int end) { public Macro (int start, int end) {
@ -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