* Implement subskins
* Fix skin failmode levels * Add Resource.getOverloadedResource() * Implement ScriptingEngine.isTypedObject(Object) * Fix skin length bug with non-ASCII characters
This commit is contained in:
parent
0b363a4b96
commit
4531ef6e4b
9 changed files with 315 additions and 87 deletions
|
@ -324,10 +324,36 @@ public final class Prototype {
|
||||||
/**
|
/**
|
||||||
* Get a skin for this prototype. This only works for skins
|
* Get a skin for this prototype. This only works for skins
|
||||||
* residing in the prototype directory, not for skins files in
|
* residing in the prototype directory, not for skins files in
|
||||||
* other locations or database stored skins.
|
* other locations or database stored skins. If parentName and
|
||||||
|
* subName are defined, the skin may be a subskin of another skin.
|
||||||
*/
|
*/
|
||||||
public Skin getSkin(String skinName) throws IOException {
|
public Skin getSkin(String skinName, String parentName, String subName)
|
||||||
return skinMap.getSkin(skinName);
|
throws IOException {
|
||||||
|
Skin skin = null;
|
||||||
|
Resource res = skinMap.getResource(skinName);
|
||||||
|
while (res != null) {
|
||||||
|
skin = Skin.getSkin(res, app);
|
||||||
|
if (skin.hasMainskin())
|
||||||
|
break;
|
||||||
|
res = res.getOverloadedResource();
|
||||||
|
}
|
||||||
|
if (parentName != null) {
|
||||||
|
Skin parentSkin = null;
|
||||||
|
Resource parent = skinMap.getResource(parentName);
|
||||||
|
while (parent != null) {
|
||||||
|
parentSkin = Skin.getSkin(parent, app);
|
||||||
|
if (parentSkin.hasSubskin(subName))
|
||||||
|
break;
|
||||||
|
parent = parent.getOverloadedResource();
|
||||||
|
}
|
||||||
|
if (parent != null) {
|
||||||
|
if (res != null && app.getResourceComparator().compare(res, parent) > 0)
|
||||||
|
return skin;
|
||||||
|
else
|
||||||
|
return parentSkin.getSubskin(subName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return skin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -494,6 +520,10 @@ public final class Prototype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Resource getResource(Object key) {
|
||||||
|
return (Resource) get(key);
|
||||||
|
}
|
||||||
|
|
||||||
public Object get(Object key) {
|
public Object get(Object key) {
|
||||||
checkForUpdates();
|
checkForUpdates();
|
||||||
return super.get(key);
|
return super.get(key);
|
||||||
|
@ -559,7 +589,8 @@ public final class Prototype {
|
||||||
// load Skins
|
// load Skins
|
||||||
for (Iterator i = skins.iterator(); i.hasNext();) {
|
for (Iterator i = skins.iterator(); i.hasNext();) {
|
||||||
Resource res = (Resource) i.next();
|
Resource res = (Resource) i.next();
|
||||||
super.put(res.getBaseName(), res);
|
Resource prev = (Resource) super.put(res.getBaseName(), res);
|
||||||
|
res.setOverloadedResource(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if skinpath is not null, overload/add skins from there
|
// if skinpath is not null, overload/add skins from there
|
||||||
|
@ -594,7 +625,9 @@ public final class Prototype {
|
||||||
String name = skinNames[i].substring(0, skinNames[i].length() - 5);
|
String name = skinNames[i].substring(0, skinNames[i].length() - 5);
|
||||||
File file = new File(dir, skinNames[i]);
|
File file = new File(dir, skinNames[i]);
|
||||||
|
|
||||||
super.put(name, (new FileResource(file)));
|
Resource res = new FileResource(file);
|
||||||
|
Resource prev = (Resource) super.put(name, res);
|
||||||
|
res.setOverloadedResource(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,15 @@ import java.io.IOException;
|
||||||
* from the RequestEvaluator object to resolve Macro handlers by type name.
|
* from the RequestEvaluator object to resolve Macro handlers by type name.
|
||||||
*/
|
*/
|
||||||
public final class Skin {
|
public final class Skin {
|
||||||
|
|
||||||
|
private Macro[] macros;
|
||||||
|
private Application app;
|
||||||
|
private char[] source;
|
||||||
|
private int offset, length; // start and end index of skin content
|
||||||
|
private HashSet sandbox;
|
||||||
|
private HashMap subskins;
|
||||||
|
private Skin parentSkin = this;
|
||||||
|
|
||||||
static private final int PARSE_MACRONAME = 0;
|
static private final int PARSE_MACRONAME = 0;
|
||||||
static private final int PARSE_PARAM = 1;
|
static private final int PARSE_PARAM = 1;
|
||||||
static private final int PARSE_DONE = 2;
|
static private final int PARSE_DONE = 2;
|
||||||
|
@ -52,20 +61,19 @@ public final class Skin {
|
||||||
static private final int HANDLER_THIS = 5;
|
static private final int HANDLER_THIS = 5;
|
||||||
static private final int HANDLER_OTHER = 6;
|
static private final int HANDLER_OTHER = 6;
|
||||||
|
|
||||||
private Macro[] macros;
|
static private final int FAIL_DEFAULT = 0;
|
||||||
private Application app;
|
static private final int FAIL_SILENT = 1;
|
||||||
private char[] source;
|
static private final int FAIL_VERBOSE = 2;
|
||||||
private int sourceLength;
|
|
||||||
private HashSet sandbox;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a skin without any restrictions on which macros are allowed to be called from it
|
* Create a skin without any restrictions on which macros are allowed to be called from it
|
||||||
*/
|
*/
|
||||||
public Skin(String content, Application app) {
|
public Skin(String content, Application app) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
sandbox = null;
|
this.sandbox = null;
|
||||||
source = content.toCharArray();
|
this.source = content.toCharArray();
|
||||||
sourceLength = source.length;
|
this.offset = 0;
|
||||||
|
this.length = source.length;
|
||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,8 +83,9 @@ public final class Skin {
|
||||||
public Skin(String content, Application app, HashSet sandbox) {
|
public Skin(String content, Application app, HashSet sandbox) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.sandbox = sandbox;
|
this.sandbox = sandbox;
|
||||||
source = content.toCharArray();
|
this.source = content.toCharArray();
|
||||||
sourceLength = source.length;
|
this.offset = 0;
|
||||||
|
length = source.length;
|
||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +95,23 @@ public final class Skin {
|
||||||
public Skin(char[] content, int length, Application app) {
|
public Skin(char[] content, int length, Application app) {
|
||||||
this.app = app;
|
this.app = app;
|
||||||
this.sandbox = null;
|
this.sandbox = null;
|
||||||
source = content;
|
this.source = content;
|
||||||
sourceLength = length;
|
this.offset = 0;
|
||||||
|
this.length = length;
|
||||||
|
parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subskin constructor.
|
||||||
|
*/
|
||||||
|
private Skin(Skin parentSkin, Macro anchorMacro) {
|
||||||
|
this.parentSkin = parentSkin;
|
||||||
|
this.app = parentSkin.app;
|
||||||
|
this.sandbox = parentSkin.sandbox;
|
||||||
|
this.source = parentSkin.source;
|
||||||
|
this.offset = anchorMacro.end;
|
||||||
|
this.length = parentSkin.length;
|
||||||
|
parentSkin.addSubskin(anchorMacro.name, this);
|
||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +137,7 @@ public final class Skin {
|
||||||
} finally {
|
} finally {
|
||||||
reader.close();
|
reader.close();
|
||||||
}
|
}
|
||||||
return new Skin(characterBuffer, length, app);
|
return new Skin(characterBuffer, read, app);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,11 +147,17 @@ public final class Skin {
|
||||||
ArrayList partBuffer = new ArrayList();
|
ArrayList partBuffer = new ArrayList();
|
||||||
|
|
||||||
boolean escape = false;
|
boolean escape = false;
|
||||||
for (int i = 0; i < (sourceLength - 1); i++) {
|
for (int i = offset; i < (length - 1); i++) {
|
||||||
if (source[i] == '<' && source[i + 1] == '%' && !escape) {
|
if (source[i] == '<' && source[i + 1] == '%' && !escape) {
|
||||||
// found macro start tag
|
// found macro start tag
|
||||||
Macro macro = new Macro(i, 2);
|
Macro macro = new Macro(i, 2);
|
||||||
partBuffer.add(macro);
|
if (macro.isSubskinMacro) {
|
||||||
|
new Skin(parentSkin, macro);
|
||||||
|
length = i;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
partBuffer.add(macro);
|
||||||
|
}
|
||||||
i = macro.end - 1;
|
i = macro.end - 1;
|
||||||
} else {
|
} else {
|
||||||
escape = source[i] == '\\' && !escape;
|
escape = source[i] == '\\' && !escape;
|
||||||
|
@ -138,11 +168,54 @@ public final class Skin {
|
||||||
partBuffer.toArray(macros);
|
partBuffer.toArray(macros);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addSubskin(String name, Skin subskin) {
|
||||||
|
if (subskins == null) {
|
||||||
|
subskins = new HashMap();
|
||||||
|
}
|
||||||
|
subskins.put(name, subskin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this skin has a main skin, as opposed to consisting just of subskins
|
||||||
|
* @return true if this skin contains a main skin
|
||||||
|
*/
|
||||||
|
public boolean hasMainskin() {
|
||||||
|
return length - offset > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this skin contains a subskin with the given name
|
||||||
|
* @param name a subskin name
|
||||||
|
* @return true if the given subskin exists
|
||||||
|
*/
|
||||||
|
public boolean hasSubskin(String name) {
|
||||||
|
return subskins != null && subskins.containsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a subskin by name
|
||||||
|
* @param name the subskin name
|
||||||
|
* @return the subskin
|
||||||
|
*/
|
||||||
|
public Skin getSubskin(String name) {
|
||||||
|
return subskins == null ? null : (Skin) subskins.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array of subskin names defined in this skin
|
||||||
|
* @return a string array containing this skin's substrings
|
||||||
|
*/
|
||||||
|
public String[] getSubskinNames() {
|
||||||
|
return subskins == null ?
|
||||||
|
new String[0] :
|
||||||
|
(String[]) subskins.keySet().toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the raw source text this skin was parsed from
|
* Get the raw source text this skin was parsed from
|
||||||
*/
|
*/
|
||||||
public String getSource() {
|
public String getSource() {
|
||||||
return new String(source, 0, sourceLength);
|
return new String(source, offset, length - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,9 +248,8 @@ public final class Skin {
|
||||||
ResponseTrans res = reval.getResponse();
|
ResponseTrans res = reval.getResponse();
|
||||||
|
|
||||||
if (macros == null) {
|
if (macros == null) {
|
||||||
res.write(source, 0, sourceLength);
|
res.write(source, offset, length - offset);
|
||||||
reval.skinDepth--;
|
reval.skinDepth--;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +258,7 @@ public final class Skin {
|
||||||
Object previousParam = handlers.put("param", paramObject);
|
Object previousParam = handlers.put("param", paramObject);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int written = 0;
|
int written = offset;
|
||||||
Map handlerCache = null;
|
Map handlerCache = null;
|
||||||
|
|
||||||
if (macros.length > 3) {
|
if (macros.length > 3) {
|
||||||
|
@ -202,8 +274,8 @@ public final class Skin {
|
||||||
written = macros[i].end;
|
written = macros[i].end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (written < sourceLength) {
|
if (written < length) {
|
||||||
res.write(source, written, sourceLength - written);
|
res.write(source, written, length - written);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
reval.skinDepth--;
|
reval.skinDepth--;
|
||||||
|
@ -276,6 +348,8 @@ public final class Skin {
|
||||||
|
|
||||||
// comment macros are silently dropped during rendering
|
// comment macros are silently dropped during rendering
|
||||||
boolean isCommentMacro = false;
|
boolean isCommentMacro = false;
|
||||||
|
// subskin macros delimits the beginning of a new subskin
|
||||||
|
boolean isSubskinMacro = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and parse a new macro.
|
* Create and parse a new macro.
|
||||||
|
@ -293,7 +367,7 @@ public final class Skin {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
for (i = start + offset; i < sourceLength - 1; i++) {
|
for (i = start + offset; i < length - 1; i++) {
|
||||||
|
|
||||||
switch (source[i]) {
|
switch (source[i]) {
|
||||||
|
|
||||||
|
@ -330,7 +404,7 @@ public final class Skin {
|
||||||
if (state == PARSE_MACRONAME && "//".equals(b.toString())) {
|
if (state == PARSE_MACRONAME && "//".equals(b.toString())) {
|
||||||
isCommentMacro = true;
|
isCommentMacro = true;
|
||||||
// search macro end tag
|
// search macro end tag
|
||||||
while (i < sourceLength - 1 &&
|
while (i < length - 1 &&
|
||||||
(source[i] != '%' || source[i + 1] != '>')) {
|
(source[i] != '%' || source[i + 1] != '>')) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -339,6 +413,16 @@ public final class Skin {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '#':
|
||||||
|
|
||||||
|
if (state == PARSE_MACRONAME && b.length() == 0) {
|
||||||
|
// this is a subskin/skinlet
|
||||||
|
isSubskinMacro = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
b.append(source[i]);
|
||||||
|
escape = false;
|
||||||
|
|
||||||
case '|':
|
case '|':
|
||||||
|
|
||||||
if (!escape && quotechar == '\u0000') {
|
if (!escape && quotechar == '\u0000') {
|
||||||
|
@ -431,7 +515,17 @@ public final class Skin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.end = Math.min(sourceLength, i + 2);
|
i += 2;
|
||||||
|
if (isSubskinMacro) {
|
||||||
|
if (i + 1 < length && source[i] == '\r' && source[i + 1] == '\n')
|
||||||
|
end = Math.min(length, i + 2);
|
||||||
|
else if (i < length && (source[i] == '\r' || source[i] == '\n'))
|
||||||
|
end = Math.min(length, i + 1);
|
||||||
|
else
|
||||||
|
end = Math.min(length, i);
|
||||||
|
} else {
|
||||||
|
end = Math.min(length, i);
|
||||||
|
}
|
||||||
|
|
||||||
if (b.length() > 0) {
|
if (b.length() > 0) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
|
@ -462,11 +556,6 @@ public final class Skin {
|
||||||
handler = HANDLER_PARAM;
|
handler = HANDLER_PARAM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set default failmode unless explicitly set:
|
|
||||||
// silent for default handlers, verbose
|
|
||||||
if (namedParams == null || !namedParams.containsKey("failmode")) {
|
|
||||||
standardParams.silentFailMode = (handler < HANDLER_GLOBAL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addParameter(String name, Object value) {
|
private void addParameter(String name, Object value) {
|
||||||
|
@ -607,8 +696,8 @@ public final class Skin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// display error message unless silent failmode is on
|
// display error message unless silent failmode is on
|
||||||
if (handlerObject == null || !hasProperty(handlerObject, propName, reval)) {
|
if (handlerObject == null || !reval.scriptingEngine.hasProperty(handlerObject, propName)) {
|
||||||
if (!standardParams.silentFailMode) {
|
if (standardParams.verboseFailmode(handlerObject, reval)) {
|
||||||
String msg = "[Macro unhandled: " + name + "]";
|
String msg = "[Macro unhandled: " + name + "]";
|
||||||
reval.getResponse().write(" " + msg + " ");
|
reval.getResponse().write(" " + msg + " ");
|
||||||
app.logEvent(msg);
|
app.logEvent(msg);
|
||||||
|
@ -616,13 +705,13 @@ public final class Skin {
|
||||||
writeResponse(null, reval, thisObject, handlerCache, standardParams, true);
|
writeResponse(null, reval, thisObject, handlerCache, standardParams, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Object value = getProperty(handlerObject, propName, reval);
|
Object value = reval.scriptingEngine.getProperty(handlerObject, propName);
|
||||||
writeResponse(value, reval, thisObject, handlerCache, standardParams, true);
|
writeResponse(value, reval, thisObject, handlerCache, standardParams, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!standardParams.silentFailMode) {
|
if (standardParams.verboseFailmode(handlerObject, reval)) {
|
||||||
String msg = "[Macro unhandled: " + name + "]";
|
String msg = "[Macro unhandled: " + name + "]";
|
||||||
reval.getResponse().write(" " + msg + " ");
|
reval.getResponse().write(" " + msg + " ");
|
||||||
app.logEvent(msg);
|
app.logEvent(msg);
|
||||||
|
@ -770,12 +859,12 @@ public final class Skin {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object resolvePath(Object handler, RequestEvaluator reval) {
|
private Object resolvePath(Object handler, RequestEvaluator reval) {
|
||||||
if (!app.allowDeepMacros && path.length > 2) {
|
if (path.length > 2 && !app.allowDeepMacros) {
|
||||||
throw new RuntimeException("allowDeepMacros property must be true " +
|
throw new RuntimeException("allowDeepMacros property must be true " +
|
||||||
"in order to enable deep macro paths.");
|
"in order to enable deep macro paths.");
|
||||||
}
|
}
|
||||||
for (int i = 1; i < path.length - 1; i++) {
|
for (int i = 1; i < path.length - 1; i++) {
|
||||||
handler = getProperty(handler, path[i], reval);
|
handler = reval.scriptingEngine.getProperty(handler, path[i]);
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -783,23 +872,6 @@ public final class Skin {
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object getProperty(Object obj, String name,
|
|
||||||
RequestEvaluator reval) {
|
|
||||||
if (obj instanceof Map) {
|
|
||||||
return ((Map) obj).get(name);
|
|
||||||
} else {
|
|
||||||
return reval.getScriptingEngine().getProperty(obj, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasProperty(Object obj, String name, RequestEvaluator reval) {
|
|
||||||
if (obj instanceof Map) {
|
|
||||||
return ((Map) obj).containsKey(name);
|
|
||||||
} else {
|
|
||||||
return reval.getScriptingEngine().hasProperty(obj, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility method for writing text out to the response object.
|
* Utility method for writing text out to the response object.
|
||||||
*/
|
*/
|
||||||
|
@ -822,7 +894,7 @@ public final class Skin {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
text = reval.getScriptingEngine().toString(value);
|
text = reval.scriptingEngine.toString(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((text != null) && (text.length() > 0)) {
|
if ((text != null) && (text.length() > 0)) {
|
||||||
|
@ -887,7 +959,7 @@ public final class Skin {
|
||||||
Object prefix = null;
|
Object prefix = null;
|
||||||
Object suffix = null;
|
Object suffix = null;
|
||||||
Object defaultValue = null;
|
Object defaultValue = null;
|
||||||
boolean silentFailMode = false;
|
int failmode = FAIL_DEFAULT;
|
||||||
|
|
||||||
StandardParams() {}
|
StandardParams() {}
|
||||||
|
|
||||||
|
@ -895,7 +967,6 @@ public final class Skin {
|
||||||
prefix = map.get("prefix");
|
prefix = map.get("prefix");
|
||||||
suffix = map.get("suffix");
|
suffix = map.get("suffix");
|
||||||
defaultValue = map.get("default");
|
defaultValue = map.get("default");
|
||||||
silentFailMode = "silent".equals(map.get("failmode"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean containsMacros() {
|
boolean containsMacros() {
|
||||||
|
@ -906,13 +977,18 @@ public final class Skin {
|
||||||
|
|
||||||
void setFailMode(Object value) {
|
void setFailMode(Object value) {
|
||||||
if ("silent".equals(value))
|
if ("silent".equals(value))
|
||||||
silentFailMode = true;
|
failmode = FAIL_SILENT;
|
||||||
else if ("verbose".equals(value))
|
else if ("verbose".equals(value))
|
||||||
silentFailMode = false;
|
failmode = FAIL_VERBOSE;
|
||||||
else
|
else if (value != null)
|
||||||
app.logEvent("unrecognized failmode value: " + value);
|
app.logEvent("unrecognized failmode value: " + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean verboseFailmode(Object handler, RequestEvaluator reval) {
|
||||||
|
return (failmode == FAIL_VERBOSE) ||
|
||||||
|
(failmode == FAIL_DEFAULT && reval.scriptingEngine.isTypedObject(handler));
|
||||||
|
}
|
||||||
|
|
||||||
StandardParams render(RequestEvaluator reval, Object thisObj, Map handlerCache)
|
StandardParams render(RequestEvaluator reval, Object thisObj, Map handlerCache)
|
||||||
throws UnsupportedEncodingException {
|
throws UnsupportedEncodingException {
|
||||||
if (!containsMacros())
|
if (!containsMacros())
|
||||||
|
|
|
@ -42,12 +42,22 @@ public final class SkinManager implements FilenameFilter {
|
||||||
skinExtension = ".skin";
|
skinExtension = ".skin";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Skin getSkin(Prototype proto, String skinname, Object[] skinpath) throws IOException {
|
protected Skin getSkin(Prototype prototype, String skinname, Object[] skinpath)
|
||||||
if (proto == null) {
|
throws IOException {
|
||||||
|
if (prototype == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Skin skin = null;
|
Skin skin;
|
||||||
|
Prototype proto = prototype;
|
||||||
|
|
||||||
|
// if name contains dot, this might be a substring of some other string
|
||||||
|
String parentName = null, subskinName = null;
|
||||||
|
int hash = skinname.indexOf('#');
|
||||||
|
if (hash > -1) {
|
||||||
|
parentName = skinname.substring(0, hash);
|
||||||
|
subskinName = skinname.substring(hash + 1);
|
||||||
|
}
|
||||||
|
|
||||||
// First check if the skin has been already used within the execution of this request
|
// First check if the skin has been already used within the execution of this request
|
||||||
// check for skinsets set via res.skinpath property
|
// check for skinsets set via res.skinpath property
|
||||||
|
@ -55,16 +65,23 @@ public final class SkinManager implements FilenameFilter {
|
||||||
if (skinpath != null) {
|
if (skinpath != null) {
|
||||||
for (int i = 0; i < skinpath.length; i++) {
|
for (int i = 0; i < skinpath.length; i++) {
|
||||||
skin = getSkinInPath(skinpath[i], proto.getName(), skinname);
|
skin = getSkinInPath(skinpath[i], proto.getName(), skinname);
|
||||||
|
if (skin != null && skin.hasMainskin()) {
|
||||||
if (skin != null) {
|
// check if skin skin contains main skin
|
||||||
return skin;
|
return skin;
|
||||||
|
} else if (parentName != null) {
|
||||||
|
// get parent skin
|
||||||
|
skin = getSkinInPath(skinpath[i], proto.getName(), parentName);
|
||||||
|
// check if it contains subskin
|
||||||
|
if (skin != null && skin.hasSubskin(subskinName)) {
|
||||||
|
return skin.getSubskin(subskinName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// skin for this prototype wasn't found in the skinsets.
|
// skin for this prototype wasn't found in the skinsets.
|
||||||
// the next step is to look if it is defined as skin file in the application directory
|
// the next step is to look if it is defined as skin file in the application directory
|
||||||
skin = proto.getSkin(skinname);
|
skin = proto.getSkin(skinname, parentName, subskinName);
|
||||||
|
|
||||||
if (skin != null) {
|
if (skin != null) {
|
||||||
return skin;
|
return skin;
|
||||||
|
@ -78,7 +95,7 @@ public final class SkinManager implements FilenameFilter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Skin getSkinInPath(Object skinset, String prototype, String skinname) throws IOException {
|
private Skin getSkinInPath(Object skinset, String prototype, String skinname) throws IOException {
|
||||||
if ((prototype == null) || (skinset == null)) {
|
if ((prototype == null) || (skinset == null)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
43
src/helma/framework/repository/AbstractResource.java
Normal file
43
src/helma/framework/repository/AbstractResource.java
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.framework.repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract resource base class that implents get/setOverloadedResource.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractResource implements Resource {
|
||||||
|
|
||||||
|
protected Resource overloaded = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for registering a Resource this Resource is overloading
|
||||||
|
*
|
||||||
|
* @param res the overloaded resource
|
||||||
|
*/
|
||||||
|
public void setOverloadedResource(Resource res) {
|
||||||
|
overloaded = res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a Resource this Resource is overloading
|
||||||
|
*
|
||||||
|
* @return the overloaded resource
|
||||||
|
*/
|
||||||
|
public Resource getOverloadedResource() {
|
||||||
|
return overloaded;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ package helma.framework.repository;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
public class FileResource implements Resource {
|
public class FileResource extends AbstractResource {
|
||||||
|
|
||||||
File file;
|
File file;
|
||||||
Repository repository;
|
Repository repository;
|
||||||
|
|
|
@ -41,25 +41,29 @@ public interface Resource {
|
||||||
/**
|
/**
|
||||||
* Returns the lengh of the resource's content
|
* Returns the lengh of the resource's content
|
||||||
* @return content length
|
* @return content length
|
||||||
|
* @throws IOException I/O related problem
|
||||||
*/
|
*/
|
||||||
public long getLength() throws IOException;
|
public long getLength() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an input stream to the content of the resource
|
* Returns an input stream to the content of the resource
|
||||||
* @return content input stream
|
* @return content input stream
|
||||||
|
* @throws IOException I/O related problem
|
||||||
*/
|
*/
|
||||||
public InputStream getInputStream() throws IOException;
|
public InputStream getInputStream() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the content of the resource in a given encoding
|
* Returns the content of the resource in a given encoding
|
||||||
* @param encoding
|
* @param encoding the character encoding
|
||||||
* @return content
|
* @return content
|
||||||
|
* @throws IOException I/O related problem
|
||||||
*/
|
*/
|
||||||
public String getContent(String encoding) throws IOException;
|
public String getContent(String encoding) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the content of the resource
|
* Returns the content of the resource
|
||||||
* @return content
|
* @return content
|
||||||
|
* @throws IOException I/O related problem
|
||||||
*/
|
*/
|
||||||
public String getContent() throws IOException;
|
public String getContent() throws IOException;
|
||||||
|
|
||||||
|
@ -88,9 +92,22 @@ public interface Resource {
|
||||||
* Returns an url to the resource if the repository of this resource is
|
* Returns an url to the resource if the repository of this resource is
|
||||||
* able to provide urls
|
* able to provide urls
|
||||||
* @return url to the resource
|
* @return url to the resource
|
||||||
|
* @throws UnsupportedOperationException if resource does not support URL schema
|
||||||
*/
|
*/
|
||||||
public URL getUrl() throws UnsupportedOperationException;
|
public URL getUrl() throws UnsupportedOperationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a Resource this Resource is overloading
|
||||||
|
* @return the overloaded resource
|
||||||
|
*/
|
||||||
|
public Resource getOverloadedResource();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for registering a Resource this Resource is overloading
|
||||||
|
* @param res the overloaded resource
|
||||||
|
*/
|
||||||
|
public void setOverloadedResource(Resource res);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the repository the resource does belong to
|
* Returns the repository the resource does belong to
|
||||||
* @return upper repository
|
* @return upper repository
|
||||||
|
|
|
@ -21,7 +21,7 @@ import java.net.URL;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
public final class ZipResource implements Resource {
|
public final class ZipResource extends AbstractResource {
|
||||||
|
|
||||||
private String entryName;
|
private String entryName;
|
||||||
private ZipRepository repository;
|
private ZipRepository repository;
|
||||||
|
|
|
@ -110,10 +110,10 @@ public interface ScriptingEngine {
|
||||||
/**
|
/**
|
||||||
* Get a property on an object
|
* Get a property on an object
|
||||||
* @param thisObject the object
|
* @param thisObject the object
|
||||||
* @param key the property name
|
* @param propertyName the property name
|
||||||
* @return true the property value, or null
|
* @return true the property value, or null
|
||||||
*/
|
*/
|
||||||
public Object getProperty(Object thisObject, String key);
|
public Object getProperty(Object thisObject, String propertyName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if a function by that name is defined for that object.
|
* Return true if a function by that name is defined for that object.
|
||||||
|
@ -131,6 +131,13 @@ public interface ScriptingEngine {
|
||||||
*/
|
*/
|
||||||
public boolean hasProperty(Object thisObject, String propertyName);
|
public boolean hasProperty(Object thisObject, String propertyName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is mapped to a type of the scripting engine
|
||||||
|
* @param obj an object
|
||||||
|
* @return true if the object is mapped to a type
|
||||||
|
*/
|
||||||
|
public boolean isTypedObject(Object obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a string representation for the given object
|
* Return a string representation for the given object
|
||||||
* @param obj an object
|
* @param obj an object
|
||||||
|
|
|
@ -346,28 +346,31 @@ public class RhinoEngine implements ScriptingEngine {
|
||||||
// references/child objects just to check for function properties.
|
// references/child objects just to check for function properties.
|
||||||
if (obj instanceof INode) {
|
if (obj instanceof INode) {
|
||||||
String protoname = ((INode) obj).getPrototype();
|
String protoname = ((INode) obj).getPrototype();
|
||||||
return core.hasFunction(protoname, fname);
|
if (protoname != null && core.hasFunction(protoname, fname))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scriptable op = obj == null ? global : Context.toObject(obj, global);
|
Scriptable op = obj == null ? global : Context.toObject(obj, global);
|
||||||
|
return ScriptableObject.getProperty(op, fname) instanceof Callable;
|
||||||
Object func = ScriptableObject.getProperty(op, fname);
|
|
||||||
|
|
||||||
return func instanceof Callable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if an object has a value property defined with that name.
|
* Check if an object has a value property defined with that name.
|
||||||
*/
|
*/
|
||||||
public boolean hasProperty(Object obj, String propname) {
|
public boolean hasProperty(Object obj, String propname) {
|
||||||
if ((obj == null) || (propname == null)) {
|
if (obj == null || propname == null) {
|
||||||
return false;
|
return false;
|
||||||
|
} else if (obj instanceof Map) {
|
||||||
|
return ((Map) obj).containsKey(propname);
|
||||||
}
|
}
|
||||||
|
|
||||||
String prototypeName = app.getPrototypeName(obj);
|
String prototypeName = app.getPrototypeName(obj);
|
||||||
|
|
||||||
if ("user".equalsIgnoreCase(prototypeName)
|
if ("user".equalsIgnoreCase(prototypeName)
|
||||||
&& "password".equalsIgnoreCase(propname)) {
|
&& "password".equalsIgnoreCase(propname)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is a HopObject, check if the property is defined
|
// if this is a HopObject, check if the property is defined
|
||||||
// in the type.properties db-mapping.
|
// in the type.properties db-mapping.
|
||||||
if (obj instanceof INode && ! "hopobject".equalsIgnoreCase(prototypeName)) {
|
if (obj instanceof INode && ! "hopobject".equalsIgnoreCase(prototypeName)) {
|
||||||
|
@ -386,22 +389,36 @@ public class RhinoEngine implements ScriptingEngine {
|
||||||
* is a java object) with that name.
|
* is a java object) with that name.
|
||||||
*/
|
*/
|
||||||
public Object getProperty(Object obj, String propname) {
|
public Object getProperty(Object obj, String propname) {
|
||||||
if ((obj == null) || (propname == null))
|
if (obj == null || propname == null) {
|
||||||
return null;
|
return null;
|
||||||
|
} else if (obj instanceof Map) {
|
||||||
|
Object prop = ((Map) obj).get(propname);
|
||||||
|
// Do not return functions as properties as this
|
||||||
|
// is a potential security problem
|
||||||
|
return (prop instanceof Function) ? null : prop;
|
||||||
|
} else if (obj instanceof INode) {
|
||||||
|
IProperty prop = ((INode) obj).get(propname);
|
||||||
|
if (prop == null) return null;
|
||||||
|
Object value = prop.getValue();
|
||||||
|
return (value instanceof Function) ? null : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use Rhino wrappers and methods to get property
|
||||||
Scriptable so = Context.toObject(obj, global);
|
Scriptable so = Context.toObject(obj, global);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object prop = so.get(propname, so);
|
Object prop = so.get(propname, so);
|
||||||
|
|
||||||
if ((prop == null)
|
if (prop == null
|
||||||
|| (prop == Undefined.instance)
|
|| prop == Undefined.instance
|
||||||
|| (prop == ScriptableObject.NOT_FOUND)) {
|
|| prop == ScriptableObject.NOT_FOUND) {
|
||||||
return null;
|
return null;
|
||||||
} else if (prop instanceof Wrapper) {
|
} else if (prop instanceof Wrapper) {
|
||||||
return ((Wrapper) prop).unwrap();
|
return ((Wrapper) prop).unwrap();
|
||||||
} else {
|
} else {
|
||||||
return prop;
|
// Do not return functions as properties as this
|
||||||
|
// is a potential security problem
|
||||||
|
return (prop instanceof Function) ? null : prop;
|
||||||
}
|
}
|
||||||
} catch (Exception esx) {
|
} catch (Exception esx) {
|
||||||
app.logError("Error getting property " + propname + ": " + esx);
|
app.logError("Error getting property " + propname + ": " + esx);
|
||||||
|
@ -410,6 +427,22 @@ public class RhinoEngine implements ScriptingEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is mapped to a type of the scripting engine
|
||||||
|
* @param obj an object
|
||||||
|
* @return true if the object is mapped to a type
|
||||||
|
*/
|
||||||
|
public boolean isTypedObject(Object obj) {
|
||||||
|
if (obj == null || obj instanceof Map || obj instanceof NativeObject)
|
||||||
|
return false;
|
||||||
|
if (obj instanceof INode) {
|
||||||
|
String protoName = app.getPrototypeName(obj);
|
||||||
|
return protoName != null && !"hopobject".equalsIgnoreCase(protoName);
|
||||||
|
}
|
||||||
|
// assume java object is typed
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a string representation for the given object
|
* Return a string representation for the given object
|
||||||
* @param obj an object
|
* @param obj an object
|
||||||
|
@ -544,7 +577,9 @@ public class RhinoEngine implements ScriptingEngine {
|
||||||
* Try to get a skin from the parameter object.
|
* Try to get a skin from the parameter object.
|
||||||
*/
|
*/
|
||||||
public Skin toSkin(Object skinobj, String protoName) throws IOException {
|
public Skin toSkin(Object skinobj, String protoName) throws IOException {
|
||||||
if (skinobj instanceof Wrapper) {
|
if (skinobj == null) {
|
||||||
|
return null;
|
||||||
|
} else if (skinobj instanceof Wrapper) {
|
||||||
skinobj = ((Wrapper) skinobj).unwrap();
|
skinobj = ((Wrapper) skinobj).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue