* 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
|
||||
* 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 {
|
||||
return skinMap.getSkin(skinName);
|
||||
public Skin getSkin(String skinName, String parentName, String subName)
|
||||
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) {
|
||||
checkForUpdates();
|
||||
return super.get(key);
|
||||
|
@ -559,7 +589,8 @@ public final class Prototype {
|
|||
// load Skins
|
||||
for (Iterator i = skins.iterator(); i.hasNext();) {
|
||||
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
|
||||
|
@ -594,7 +625,9 @@ public final class Prototype {
|
|||
String name = skinNames[i].substring(0, skinNames[i].length() - 5);
|
||||
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.
|
||||
*/
|
||||
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_PARAM = 1;
|
||||
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_OTHER = 6;
|
||||
|
||||
private Macro[] macros;
|
||||
private Application app;
|
||||
private char[] source;
|
||||
private int sourceLength;
|
||||
private HashSet sandbox;
|
||||
static private final int FAIL_DEFAULT = 0;
|
||||
static private final int FAIL_SILENT = 1;
|
||||
static private final int FAIL_VERBOSE = 2;
|
||||
|
||||
/**
|
||||
* Create a skin without any restrictions on which macros are allowed to be called from it
|
||||
*/
|
||||
public Skin(String content, Application app) {
|
||||
this.app = app;
|
||||
sandbox = null;
|
||||
source = content.toCharArray();
|
||||
sourceLength = source.length;
|
||||
this.sandbox = null;
|
||||
this.source = content.toCharArray();
|
||||
this.offset = 0;
|
||||
this.length = source.length;
|
||||
parse();
|
||||
}
|
||||
|
||||
|
@ -75,8 +83,9 @@ public final class Skin {
|
|||
public Skin(String content, Application app, HashSet sandbox) {
|
||||
this.app = app;
|
||||
this.sandbox = sandbox;
|
||||
source = content.toCharArray();
|
||||
sourceLength = source.length;
|
||||
this.source = content.toCharArray();
|
||||
this.offset = 0;
|
||||
length = source.length;
|
||||
parse();
|
||||
}
|
||||
|
||||
|
@ -86,8 +95,23 @@ public final class Skin {
|
|||
public Skin(char[] content, int length, Application app) {
|
||||
this.app = app;
|
||||
this.sandbox = null;
|
||||
source = content;
|
||||
sourceLength = length;
|
||||
this.source = content;
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -113,7 +137,7 @@ public final class Skin {
|
|||
} finally {
|
||||
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();
|
||||
|
||||
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) {
|
||||
// found macro start tag
|
||||
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;
|
||||
} else {
|
||||
escape = source[i] == '\\' && !escape;
|
||||
|
@ -138,11 +168,54 @@ public final class Skin {
|
|||
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
|
||||
*/
|
||||
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();
|
||||
|
||||
if (macros == null) {
|
||||
res.write(source, 0, sourceLength);
|
||||
res.write(source, offset, length - offset);
|
||||
reval.skinDepth--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -186,7 +258,7 @@ public final class Skin {
|
|||
Object previousParam = handlers.put("param", paramObject);
|
||||
|
||||
try {
|
||||
int written = 0;
|
||||
int written = offset;
|
||||
Map handlerCache = null;
|
||||
|
||||
if (macros.length > 3) {
|
||||
|
@ -202,8 +274,8 @@ public final class Skin {
|
|||
written = macros[i].end;
|
||||
}
|
||||
|
||||
if (written < sourceLength) {
|
||||
res.write(source, written, sourceLength - written);
|
||||
if (written < length) {
|
||||
res.write(source, written, length - written);
|
||||
}
|
||||
} finally {
|
||||
reval.skinDepth--;
|
||||
|
@ -276,6 +348,8 @@ public final class Skin {
|
|||
|
||||
// comment macros are silently dropped during rendering
|
||||
boolean isCommentMacro = false;
|
||||
// subskin macros delimits the beginning of a new subskin
|
||||
boolean isSubskinMacro = false;
|
||||
|
||||
/**
|
||||
* Create and parse a new macro.
|
||||
|
@ -293,7 +367,7 @@ public final class Skin {
|
|||
int i;
|
||||
|
||||
loop:
|
||||
for (i = start + offset; i < sourceLength - 1; i++) {
|
||||
for (i = start + offset; i < length - 1; i++) {
|
||||
|
||||
switch (source[i]) {
|
||||
|
||||
|
@ -330,7 +404,7 @@ public final class Skin {
|
|||
if (state == PARSE_MACRONAME && "//".equals(b.toString())) {
|
||||
isCommentMacro = true;
|
||||
// search macro end tag
|
||||
while (i < sourceLength - 1 &&
|
||||
while (i < length - 1 &&
|
||||
(source[i] != '%' || source[i + 1] != '>')) {
|
||||
i++;
|
||||
}
|
||||
|
@ -339,6 +413,16 @@ public final class Skin {
|
|||
}
|
||||
break;
|
||||
|
||||
case '#':
|
||||
|
||||
if (state == PARSE_MACRONAME && b.length() == 0) {
|
||||
// this is a subskin/skinlet
|
||||
isSubskinMacro = true;
|
||||
break;
|
||||
}
|
||||
b.append(source[i]);
|
||||
escape = false;
|
||||
|
||||
case '|':
|
||||
|
||||
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 (name == null) {
|
||||
|
@ -462,11 +556,6 @@ public final class Skin {
|
|||
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) {
|
||||
|
@ -607,8 +696,8 @@ public final class Skin {
|
|||
}
|
||||
}
|
||||
// display error message unless silent failmode is on
|
||||
if (handlerObject == null || !hasProperty(handlerObject, propName, reval)) {
|
||||
if (!standardParams.silentFailMode) {
|
||||
if (handlerObject == null || !reval.scriptingEngine.hasProperty(handlerObject, propName)) {
|
||||
if (standardParams.verboseFailmode(handlerObject, reval)) {
|
||||
String msg = "[Macro unhandled: " + name + "]";
|
||||
reval.getResponse().write(" " + msg + " ");
|
||||
app.logEvent(msg);
|
||||
|
@ -616,13 +705,13 @@ public final class Skin {
|
|||
writeResponse(null, reval, thisObject, handlerCache, standardParams, true);
|
||||
}
|
||||
} else {
|
||||
Object value = getProperty(handlerObject, propName, reval);
|
||||
Object value = reval.scriptingEngine.getProperty(handlerObject, propName);
|
||||
writeResponse(value, reval, thisObject, handlerCache, standardParams, true);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!standardParams.silentFailMode) {
|
||||
if (standardParams.verboseFailmode(handlerObject, reval)) {
|
||||
String msg = "[Macro unhandled: " + name + "]";
|
||||
reval.getResponse().write(" " + msg + " ");
|
||||
app.logEvent(msg);
|
||||
|
@ -770,12 +859,12 @@ public final class Skin {
|
|||
}
|
||||
|
||||
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 " +
|
||||
"in order to enable deep macro paths.");
|
||||
}
|
||||
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) {
|
||||
break;
|
||||
}
|
||||
|
@ -783,23 +872,6 @@ public final class Skin {
|
|||
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.
|
||||
*/
|
||||
|
@ -822,7 +894,7 @@ public final class Skin {
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
text = reval.getScriptingEngine().toString(value);
|
||||
text = reval.scriptingEngine.toString(value);
|
||||
}
|
||||
|
||||
if ((text != null) && (text.length() > 0)) {
|
||||
|
@ -887,7 +959,7 @@ public final class Skin {
|
|||
Object prefix = null;
|
||||
Object suffix = null;
|
||||
Object defaultValue = null;
|
||||
boolean silentFailMode = false;
|
||||
int failmode = FAIL_DEFAULT;
|
||||
|
||||
StandardParams() {}
|
||||
|
||||
|
@ -895,7 +967,6 @@ public final class Skin {
|
|||
prefix = map.get("prefix");
|
||||
suffix = map.get("suffix");
|
||||
defaultValue = map.get("default");
|
||||
silentFailMode = "silent".equals(map.get("failmode"));
|
||||
}
|
||||
|
||||
boolean containsMacros() {
|
||||
|
@ -906,13 +977,18 @@ public final class Skin {
|
|||
|
||||
void setFailMode(Object value) {
|
||||
if ("silent".equals(value))
|
||||
silentFailMode = true;
|
||||
failmode = FAIL_SILENT;
|
||||
else if ("verbose".equals(value))
|
||||
silentFailMode = false;
|
||||
else
|
||||
failmode = FAIL_VERBOSE;
|
||||
else if (value != null)
|
||||
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)
|
||||
throws UnsupportedEncodingException {
|
||||
if (!containsMacros())
|
||||
|
|
|
@ -42,12 +42,22 @@ public final class SkinManager implements FilenameFilter {
|
|||
skinExtension = ".skin";
|
||||
}
|
||||
|
||||
protected Skin getSkin(Prototype proto, String skinname, Object[] skinpath) throws IOException {
|
||||
if (proto == null) {
|
||||
protected Skin getSkin(Prototype prototype, String skinname, Object[] skinpath)
|
||||
throws IOException {
|
||||
if (prototype == 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
|
||||
// check for skinsets set via res.skinpath property
|
||||
|
@ -55,16 +65,23 @@ public final class SkinManager implements FilenameFilter {
|
|||
if (skinpath != null) {
|
||||
for (int i = 0; i < skinpath.length; i++) {
|
||||
skin = getSkinInPath(skinpath[i], proto.getName(), skinname);
|
||||
|
||||
if (skin != null) {
|
||||
if (skin != null && skin.hasMainskin()) {
|
||||
// check if skin skin contains main 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.
|
||||
// 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) {
|
||||
return skin;
|
||||
|
@ -78,7 +95,7 @@ public final class SkinManager implements FilenameFilter {
|
|||
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)) {
|
||||
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.io.*;
|
||||
|
||||
public class FileResource implements Resource {
|
||||
public class FileResource extends AbstractResource {
|
||||
|
||||
File file;
|
||||
Repository repository;
|
||||
|
|
|
@ -41,25 +41,29 @@ public interface Resource {
|
|||
/**
|
||||
* Returns the lengh of the resource's content
|
||||
* @return content length
|
||||
* @throws IOException I/O related problem
|
||||
*/
|
||||
public long getLength() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns an input stream to the content of the resource
|
||||
* @return content input stream
|
||||
* @throws IOException I/O related problem
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the content of the resource in a given encoding
|
||||
* @param encoding
|
||||
* @param encoding the character encoding
|
||||
* @return content
|
||||
* @throws IOException I/O related problem
|
||||
*/
|
||||
public String getContent(String encoding) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the content of the resource
|
||||
* @return content
|
||||
* @throws IOException I/O related problem
|
||||
*/
|
||||
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
|
||||
* able to provide urls
|
||||
* @return url to the resource
|
||||
* @throws UnsupportedOperationException if resource does not support URL schema
|
||||
*/
|
||||
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
|
||||
* @return upper repository
|
||||
|
|
|
@ -21,7 +21,7 @@ import java.net.URL;
|
|||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public final class ZipResource implements Resource {
|
||||
public final class ZipResource extends AbstractResource {
|
||||
|
||||
private String entryName;
|
||||
private ZipRepository repository;
|
||||
|
|
|
@ -110,10 +110,10 @@ public interface ScriptingEngine {
|
|||
/**
|
||||
* Get a property on an object
|
||||
* @param thisObject the object
|
||||
* @param key the property name
|
||||
* @param propertyName the property name
|
||||
* @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.
|
||||
|
@ -131,6 +131,13 @@ public interface ScriptingEngine {
|
|||
*/
|
||||
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
|
||||
* @param obj an object
|
||||
|
|
|
@ -346,28 +346,31 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
// references/child objects just to check for function properties.
|
||||
if (obj instanceof INode) {
|
||||
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);
|
||||
|
||||
Object func = ScriptableObject.getProperty(op, fname);
|
||||
|
||||
return func instanceof Callable;
|
||||
return ScriptableObject.getProperty(op, fname) instanceof Callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an object has a value property defined with that name.
|
||||
*/
|
||||
public boolean hasProperty(Object obj, String propname) {
|
||||
if ((obj == null) || (propname == null)) {
|
||||
if (obj == null || propname == null) {
|
||||
return false;
|
||||
} else if (obj instanceof Map) {
|
||||
return ((Map) obj).containsKey(propname);
|
||||
}
|
||||
|
||||
String prototypeName = app.getPrototypeName(obj);
|
||||
|
||||
if ("user".equalsIgnoreCase(prototypeName)
|
||||
&& "password".equalsIgnoreCase(propname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if this is a HopObject, check if the property is defined
|
||||
// in the type.properties db-mapping.
|
||||
if (obj instanceof INode && ! "hopobject".equalsIgnoreCase(prototypeName)) {
|
||||
|
@ -386,22 +389,36 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
* is a java object) with that name.
|
||||
*/
|
||||
public Object getProperty(Object obj, String propname) {
|
||||
if ((obj == null) || (propname == null))
|
||||
if (obj == null || propname == 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);
|
||||
|
||||
try {
|
||||
Object prop = so.get(propname, so);
|
||||
|
||||
if ((prop == null)
|
||||
|| (prop == Undefined.instance)
|
||||
|| (prop == ScriptableObject.NOT_FOUND)) {
|
||||
if (prop == null
|
||||
|| prop == Undefined.instance
|
||||
|| prop == ScriptableObject.NOT_FOUND) {
|
||||
return null;
|
||||
} else if (prop instanceof Wrapper) {
|
||||
return ((Wrapper) prop).unwrap();
|
||||
} 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) {
|
||||
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
|
||||
* @param obj an object
|
||||
|
@ -544,7 +577,9 @@ public class RhinoEngine implements ScriptingEngine {
|
|||
* Try to get a skin from the parameter object.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue