You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by ja...@apache.org on 2011/02/02 21:28:21 UTC
svn commit: r1066613 - in /struts/struts2/trunk:
plugins/json/src/main/java/org/apache/struts2/json/
plugins/json/src/test/java/org/apache/struts2/json/
xwork-core/src/main/java/com/opensymphony/xwork2/util/
xwork-core/src/test/java/com/opensymphony/xw...
Author: jafl
Date: Wed Feb 2 20:28:20 2011
New Revision: 1066613
URL: http://svn.apache.org/viewvc?rev=1066613&view=rev
Log:
WW-3514 fix/enhance support for include/exclude parameters
Added:
struts/struts2/trunk/plugins/json/src/test/java/org/apache/struts2/json/JSONCleanerTest.java
- copied, changed from r1065873, struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java
struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/WildcardUtil.java
struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardUtilTest.java
- copied, changed from r1065873, struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java
Modified:
struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONCleaner.java
struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java
struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java
struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java
Modified: struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONCleaner.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONCleaner.java?rev=1066613&r1=1066612&r2=1066613&view=diff
==============================================================================
--- struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONCleaner.java (original)
+++ struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONCleaner.java Wed Feb 2 20:28:20 2011
@@ -21,14 +21,51 @@
package org.apache.struts2.json;
import java.util.Iterator;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
+import java.util.HashMap;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+import com.opensymphony.xwork2.util.TextParseUtil;
+import com.opensymphony.xwork2.util.WildcardUtil;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
/**
- * Isolate the process of cleaning JSON data from the Interceptor class itself.
+ * <p>Isolate the process of cleaning JSON data from the Interceptor class
+ * itself.</p>
+ *
+ * <p>The allowed and blocked wildcard patterns, combined with
+ * defaultBlock, let you filter out values that should not be injected, in
+ * the same way that ParameterFilterInterceptor does. Note that you can
+ * only remove values from a Map. Removing values from a List is dangerous
+ * because it could change the meaning of the data!</p>
*/
public abstract class JSONCleaner {
+ private static final Logger LOG = LoggerFactory.getLogger(JSONCleaner.class);
+
+ public static class Filter
+ {
+ public Pattern pattern;
+ public boolean allow;
+
+ public Filter(String pattern, boolean allow)
+ {
+ this.pattern = WildcardUtil.compileWildcardPattern(pattern);
+ this.allow = allow;
+ }
+ }
+
+ private boolean defaultBlock = false;
+ private Collection<String> allowed;
+ private Collection<String> blocked;
+ private Map<String, Filter> includesExcludesMap;
+
public Object clean(String ognlPrefix, Object data) throws JSONException {
if (data == null)
return null;
@@ -54,11 +91,172 @@ public abstract class JSONCleaner {
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry e = (Map.Entry) iter.next();
- e.setValue(clean((ognlPrefix.length() > 0 ? ognlPrefix + "." : "") + e.getKey(), e.getValue()));
+ String key = (ognlPrefix.length() > 0 ? ognlPrefix + "." : "") + e.getKey();
+ if (allow(key)) {
+ e.setValue(clean(key, e.getValue()));
+ } else {
+ LOG.debug("blocked: " + key);
+ iter.remove();
+ }
}
return map;
}
protected abstract Object cleanValue(String ognlName, Object data) throws JSONException;
+ private boolean allow(String ognl) {
+ Map<String, Filter> includesExcludesMap = getIncludesExcludesMap();
+
+ boolean allow = !isDefaultBlock();
+
+ if (includesExcludesMap != null) {
+ for (String currRule : includesExcludesMap.keySet()) {
+ Filter f = includesExcludesMap.get(currRule);
+ if (f.pattern.matcher(ognl).matches()) {
+ allow = f.allow;
+ }
+ }
+ }
+
+ return allow;
+ }
+
+ /**
+ * @return the compiled list of includes and excludes
+ */
+ public Map<String, Filter> getIncludesExcludesMap() {
+ if (allowed == null && blocked == null) {
+ return includesExcludesMap;
+ }
+
+ if (includesExcludesMap == null) {
+ includesExcludesMap = new TreeMap<String, Filter>();
+
+ Map<String, Boolean> existingExpr = new HashMap<String, Boolean>();
+
+ Map<String, Map<String, String>> includePatternData = JSONUtil.getIncludePatternData();
+ String splitPattern = includePatternData.get(JSONUtil.SPLIT_PATTERN).get(JSONUtil.WILDCARD_PATTERN);
+ String joinString = includePatternData.get(JSONUtil.JOIN_STRING).get(JSONUtil.WILDCARD_PATTERN);
+ String arrayBegin = includePatternData.get(JSONUtil.ARRAY_BEGIN_STRING).get(JSONUtil.WILDCARD_PATTERN);
+ String arrayEnd = includePatternData.get(JSONUtil.ARRAY_END_STRING).get(JSONUtil.WILDCARD_PATTERN);
+
+ if (allowed != null) {
+ for (String a : allowed) {
+ // Compile a pattern for each level of the object hierarchy
+ // so cleanMap() won't short-circuit too early.
+
+ String expr = "";
+ for (String piece : a.split(splitPattern)) {
+ if (expr.length() > 0) {
+ expr += joinString;
+ }
+ expr += piece;
+
+ if (!existingExpr.containsKey(expr)) {
+ existingExpr.put(expr, Boolean.TRUE);
+
+ String s = expr;
+ if (piece.endsWith(arrayEnd)) {
+ s = expr.substring(0, expr.lastIndexOf(arrayBegin));
+ }
+
+ if (s.length() > 0) {
+ includesExcludesMap.put(s, new Filter(s, true));
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Adding include wildcard expression: " + s);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (blocked != null) {
+ for (String b : blocked) {
+ includesExcludesMap.put(b, new Filter(b, false));
+ }
+ }
+ }
+
+ return includesExcludesMap;
+ }
+
+ /**
+ * Allow external caching of the compiled result.
+ *
+ * @param map the compiled list of includes and excludes
+ */
+ public void setIncludesExcludesMap(Map<String, Filter> map) {
+ includesExcludesMap = map;
+ }
+
+ /**
+ * @return value of defaultBlock
+ */
+ public boolean isDefaultBlock() {
+ return defaultBlock;
+ }
+
+ /**
+ * @param defaultExclude The defaultExclude to set.
+ */
+ public void setDefaultBlock(boolean defaultExclude) {
+ this.defaultBlock = defaultExclude;
+ }
+
+ /**
+ * @return list of blocked wildcard patterns
+ */
+ public Collection<String> getBlockedCollection() {
+ return blocked;
+ }
+
+ /**
+ * @param blocked The blocked to set.
+ */
+ public void setBlockedCollection(Collection<String> blocked) {
+ this.blocked = blocked;
+ }
+
+ /**
+ * @param blocked The blocked paramters as comma separated String.
+ */
+ public void setBlocked(String blocked) {
+ setBlockedCollection(asCollection(blocked));
+ }
+
+ /**
+ * @return list of allowed wildcard patterns
+ */
+ public Collection<String> getAllowedCollection() {
+ return allowed;
+ }
+
+ /**
+ * @param allowed The allowed to set.
+ */
+ public void setAllowedCollection(Collection<String> allowed) {
+ this.allowed = allowed;
+ }
+
+ /**
+ * @param allowed The allowed paramters as comma separated String.
+ */
+ public void setAllowed(String allowed) {
+ setAllowedCollection(asCollection(allowed));
+ }
+
+ /**
+ * Return a collection from the comma delimited String.
+ *
+ * @param commaDelim the comma delimited String.
+ * @return A collection from the comma delimited String. Returns <tt>null</tt> if the string is empty.
+ */
+ private Collection<String> asCollection(String commaDelim) {
+ if (commaDelim == null || commaDelim.trim().length() == 0) {
+ return null;
+ }
+ return TextParseUtil.commaDelimitedStringToSet(commaDelim);
+ }
+
}
Modified: struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java?rev=1066613&r1=1066612&r2=1066613&view=diff
==============================================================================
--- struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java (original)
+++ struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java Wed Feb 2 20:28:20 2011
@@ -25,8 +25,10 @@ import java.lang.reflect.InvocationTarge
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
@@ -45,6 +47,7 @@ import com.opensymphony.xwork2.ActionInv
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.WildcardUtil;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
@@ -142,14 +145,6 @@ public class JSONInterceptor extends Abs
rpcResponse.setError(new RPCError(message, RPCErrorCode.INVALID_PROCEDURE_CALL));
result = rpcResponse;
}
-
- String json = JSONUtil.serialize(result, excludeProperties, includeProperties,
- ignoreHierarchy, excludeNullProperties);
- json = addCallbackIfApplicable(request, json);
- JSONUtil.writeJSONToResponse(new SerializationParams(response, this.defaultEncoding,
- this.wrapWithComments, json, true, false, noCache, -1, -1, prefix, contentType));
-
- return Action.NONE;
} else {
String message = "Request with content type of 'application/json-rpc' was received but SMD is "
+ "not enabled for this interceptor. Set 'enableSMD' to true to enable it";
@@ -159,8 +154,8 @@ public class JSONInterceptor extends Abs
result = rpcResponse;
}
- String json = JSONUtil.serialize(result, excludeProperties, includeProperties, ignoreHierarchy,
- excludeNullProperties);
+ String json = JSONUtil.serialize(result, excludeProperties, getIncludeProperties(),
+ ignoreHierarchy, excludeNullProperties);
json = addCallbackIfApplicable(request, json);
boolean writeGzip = enableGZIP && JSONUtil.isGzipInRequest(request);
JSONUtil.writeJSONToResponse(new SerializationParams(response, this.defaultEncoding,
@@ -400,7 +395,7 @@ public class JSONInterceptor extends Abs
* A comma-delimited list of regular expressions
*/
public void setExcludeProperties(String commaDelim) {
- List<String> excludePatterns = JSONUtil.asList(commaDelim);
+ Set<String> excludePatterns = JSONUtil.asSet(commaDelim);
if (excludePatterns != null) {
this.excludeProperties = new ArrayList<Pattern>(excludePatterns.size());
for (String pattern : excludePatterns) {
@@ -417,12 +412,44 @@ public class JSONInterceptor extends Abs
* A comma-delimited list of regular expressions
*/
public void setIncludeProperties(String commaDelim) {
- List<String> includePatterns = JSONUtil.asList(commaDelim);
- if (includePatterns != null) {
- this.includeProperties = new ArrayList<Pattern>(includePatterns.size());
- for (String pattern : includePatterns) {
- this.includeProperties.add(Pattern.compile(pattern));
- }
+ includeProperties = JSONUtil.processIncludePatterns(JSONUtil.asSet(commaDelim), JSONUtil.REGEXP_PATTERN, JSONUtil.getIncludePatternData());
+ }
+
+ /**
+ * Sets a comma-delimited list of wildcard expressions to match
+ * properties that should be included from the JSON output. Since the
+ * patterns are only used for the JSON-RPC response, you only need to
+ * specify the elements inside your result object (and "result." is
+ * automatically prepended).
+ *
+ * @param commaDelim
+ * A comma-delimited list of regular expressions
+ */
+ public void setIncludeWildcards(String commaDelim) {
+ Map<String, Map<String, String>> includePatternData = JSONUtil.getIncludePatternData();
+ includePatternData.get(JSONUtil.PATTERN_PREFIX).put(JSONUtil.WILDCARD_PATTERN, "result.");
+ includeProperties = JSONUtil.processIncludePatterns(JSONUtil.asSet(commaDelim), JSONUtil.WILDCARD_PATTERN, includePatternData);
+
+ if (includeProperties != null) {
+ includeProperties.add(Pattern.compile("id"));
+ includeProperties.add(Pattern.compile("result"));
+ includeProperties.add(Pattern.compile("error"));
+ includeProperties.add(WildcardUtil.compileWildcardPattern("error.code"));
+ }
+ }
+
+ /**
+ * Returns the appropriate set of includes.
+ */
+ private List getIncludeProperties()
+ {
+ if (includeProperties != null && getDebug()) {
+ List<Pattern> list = new ArrayList<Pattern>(includeProperties);
+ list.add(WildcardUtil.compileWildcardPattern("error.*"));
+ return list;
+ }
+ else {
+ return includeProperties;
}
}
Modified: struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java?rev=1066613&r1=1066612&r2=1066613&view=diff
==============================================================================
--- struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java (original)
+++ struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONResult.java Wed Feb 2 20:28:20 2011
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.ActionInv
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.WildcardUtil;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import org.apache.struts2.StrutsConstants;
@@ -36,8 +37,8 @@ import javax.servlet.http.HttpServletRes
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
+import java.util.Set;
import java.util.Map;
import java.util.regex.Pattern;
@@ -108,7 +109,7 @@ public class JSONResult implements Resul
* @param commaDelim A comma-delimited list of regular expressions
*/
public void setExcludeProperties(String commaDelim) {
- List<String> excludePatterns = JSONUtil.asList(commaDelim);
+ Set<String> excludePatterns = JSONUtil.asSet(commaDelim);
if (excludePatterns != null) {
this.excludeProperties = new ArrayList<Pattern>(excludePatterns.size());
for (String pattern : excludePatterns) {
@@ -118,6 +119,22 @@ public class JSONResult implements Resul
}
/**
+ * Sets a comma-delimited list of wildcard expressions to match properties
+ * that should be excluded from the JSON output.
+ *
+ * @param commaDelim A comma-delimited list of wildcard patterns
+ */
+ public void setExcludeWildcards(String commaDelim) {
+ Set<String> excludePatterns = JSONUtil.asSet(commaDelim);
+ if (excludePatterns != null) {
+ this.excludeProperties = new ArrayList<Pattern>(excludePatterns.size());
+ for (String pattern : excludePatterns) {
+ this.excludeProperties.add(WildcardUtil.compileWildcardPattern(pattern));
+ }
+ }
+ }
+
+ /**
* @return the includeProperties
*/
public List<Pattern> getIncludePropertiesList() {
@@ -125,63 +142,23 @@ public class JSONResult implements Resul
}
/**
- * @param commaDelim comma delimited include string patterns
+ * Sets a comma-delimited list of regular expressions to match properties
+ * that should be included in the JSON output.
+ *
+ * @param commaDelim A comma-delimited list of regular expressions
*/
public void setIncludeProperties(String commaDelim) {
- List<String> includePatterns = JSONUtil.asList(commaDelim);
- if (includePatterns != null) {
- processIncludePatterns(includePatterns);
- }
- }
-
- private void processIncludePatterns(List<String> includePatterns) {
- includeProperties = new ArrayList<Pattern>(includePatterns.size());
- Map<String, String> existingPatterns = new HashMap<String, String>();
- for (String pattern : includePatterns) {
- processPattern(existingPatterns, pattern);
- }
- }
-
- private void processPattern(Map<String, String> existingPatterns, String pattern) {
- // Compile a pattern for each *unique* "level" of the object
- // hierarchy specified in the regex.
- String[] patternPieces = pattern.split("\\\\\\.");
-
- String patternExpr = "";
- for (String patternPiece : patternPieces) {
- patternExpr = processPatternPiece(existingPatterns, patternExpr, patternPiece);
- }
- }
-
- private String processPatternPiece(Map<String, String> existingPatterns, String patternExpr, String patternPiece) {
- if (patternExpr.length() > 0) {
- patternExpr += "\\.";
- }
- patternExpr += patternPiece;
-
- // Check for duplicate patterns so that there is no overlap.
- if (!existingPatterns.containsKey(patternExpr)) {
- existingPatterns.put(patternExpr, patternExpr);
- if (isIndexedProperty(patternPiece)) {
- addPattern(patternExpr.substring(0, patternExpr.lastIndexOf("\\[")));
- }
- addPattern(patternExpr);
- }
- return patternExpr;
+ includeProperties = JSONUtil.processIncludePatterns(JSONUtil.asSet(commaDelim), JSONUtil.REGEXP_PATTERN, JSONUtil.getIncludePatternData());
}
/**
- * Add a pattern that does not have the indexed property matching (ie. list\[\d+\] becomes list).
+ * Sets a comma-delimited list of wildcard expressions to match properties
+ * that should be included in the JSON output.
+ *
+ * @param commaDelim A comma-delimited list of wildcard patterns
*/
- private boolean isIndexedProperty(String patternPiece) {
- return patternPiece.endsWith("\\]");
- }
-
- private void addPattern(String pattern) {
- this.includeProperties.add(Pattern.compile(pattern));
- if (LOG.isDebugEnabled()) {
- LOG.debug("Adding include property expression: " + pattern);
- }
+ public void setIncludeWildcards(String commaDelim) {
+ includeProperties = JSONUtil.processIncludePatterns(JSONUtil.asSet(commaDelim), JSONUtil.WILDCARD_PATTERN, JSONUtil.getIncludePatternData());
}
public void execute(ActionInvocation invocation) throws Exception {
Modified: struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java?rev=1066613&r1=1066612&r2=1066613&view=diff
==============================================================================
--- struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java (original)
+++ struts/struts2/trunk/plugins/json/src/main/java/org/apache/struts2/json/JSONUtil.java Wed Feb 2 20:28:20 2011
@@ -31,7 +31,10 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.regex.Pattern;
import java.util.zip.GZIPOutputStream;
@@ -41,6 +44,8 @@ import javax.servlet.http.HttpServletRes
import org.apache.commons.lang.xwork.StringUtils;
import org.apache.struts2.json.annotations.SMDMethod;
+import com.opensymphony.xwork2.util.TextParseUtil;
+import com.opensymphony.xwork2.util.WildcardUtil;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
@@ -256,18 +261,10 @@ public class JSONUtil {
}
}
- public static List<String> asList(String commaDelim) {
+ public static Set<String> asSet(String commaDelim) {
if ((commaDelim == null) || (commaDelim.trim().length() == 0))
return null;
- List<String> list = new ArrayList<String>();
- String[] split = commaDelim.split(",");
- for (int i = 0; i < split.length; i++) {
- String trimmed = split[i].trim();
- if (trimmed.length() > 0) {
- list.add(trimmed);
- }
- }
- return list;
+ return TextParseUtil.commaDelimitedStringToSet(commaDelim);
}
/**
@@ -392,4 +389,103 @@ public class JSONUtil {
String header = request.getHeader("Accept-Encoding");
return (header != null) && (header.indexOf("gzip") >= 0);
}
+
+ /* package */ static final String REGEXP_PATTERN = "regexp";
+ /* package */ static final String WILDCARD_PATTERN = "wildcard";
+ /* package */ static final String SPLIT_PATTERN = "split";
+ /* package */ static final String JOIN_STRING = "join";
+ /* package */ static final String ARRAY_BEGIN_STRING = "array-begin";
+ /* package */ static final String ARRAY_END_STRING = "array-end";
+ /* package */ static final String PATTERN_PREFIX = "pattern-prefix";
+
+ /* package */ static Map<String, Map<String, String>> getIncludePatternData()
+ {
+ Map<String, Map<String, String>> includePatternData = new HashMap<String, Map<String, String>>();
+
+ Map<String, String> data = new HashMap<String, String>();
+ data.put(REGEXP_PATTERN, "\\\\\\.");
+ data.put(WILDCARD_PATTERN, "\\.");
+ includePatternData.put(SPLIT_PATTERN, data);
+
+ data = new HashMap<String, String>();
+ data.put(REGEXP_PATTERN, "\\.");
+ data.put(WILDCARD_PATTERN, ".");
+ includePatternData.put(JOIN_STRING, data);
+
+ data = new HashMap<String, String>();
+ data.put(REGEXP_PATTERN, "\\[");
+ data.put(WILDCARD_PATTERN, "[");
+ includePatternData.put(ARRAY_BEGIN_STRING, data);
+
+ data = new HashMap<String, String>();
+ data.put(REGEXP_PATTERN, "\\]");
+ data.put(WILDCARD_PATTERN, "]");
+ includePatternData.put(ARRAY_END_STRING, data);
+
+ data = new HashMap<String, String>();
+ data.put(REGEXP_PATTERN, "");
+ data.put(WILDCARD_PATTERN, "");
+ includePatternData.put(PATTERN_PREFIX, data);
+
+ return includePatternData;
+ }
+
+ /* package */ static List<Pattern> processIncludePatterns(Set<String> includePatterns, String type, Map<String, Map<String, String>> includePatternData) {
+ if (includePatterns != null) {
+ List<Pattern> results = new ArrayList<Pattern>(includePatterns.size());
+ Map<String, String> existingPatterns = new HashMap<String, String>();
+ for (String pattern : includePatterns) {
+ processPattern(results, existingPatterns, pattern, type, includePatternData);
+ }
+ return results;
+ } else {
+ return null;
+ }
+ }
+
+ private static void processPattern(List<Pattern> results, Map<String, String> existingPatterns, String pattern, String type, Map<String, Map<String, String>> includePatternData) {
+ // Compile a pattern for each *unique* "level" of the object
+ // hierarchy specified in the regex.
+ String[] patternPieces = pattern.split(includePatternData.get(SPLIT_PATTERN).get(type));
+
+ String patternExpr = "";
+ for (String patternPiece : patternPieces) {
+ patternExpr = processPatternPiece(results, existingPatterns, patternExpr, patternPiece, type, includePatternData);
+ }
+ }
+
+ private static String processPatternPiece(List<Pattern> results, Map<String, String> existingPatterns, String patternExpr, String patternPiece, String type, Map<String, Map<String, String>> includePatternData) {
+ if (patternExpr.length() > 0) {
+ patternExpr += includePatternData.get(JOIN_STRING).get(type);
+ }
+ patternExpr += patternPiece;
+
+ // Check for duplicate patterns so that there is no overlap.
+ if (!existingPatterns.containsKey(patternExpr)) {
+ existingPatterns.put(patternExpr, patternExpr);
+ if (isIndexedProperty(patternPiece, type, includePatternData)) {
+ addPattern(results, patternExpr.substring(0, patternExpr.lastIndexOf(includePatternData.get(ARRAY_BEGIN_STRING).get(type))), type, includePatternData);
+ }
+ addPattern(results, patternExpr, type, includePatternData);
+ }
+ return patternExpr;
+ }
+
+ /**
+ * Add a pattern that does not have the indexed property matching (ie. list\[\d+\] becomes list).
+ */
+ private static boolean isIndexedProperty(String patternPiece, String type, Map<String, Map<String, String>> includePatternData) {
+ return patternPiece.endsWith(includePatternData.get(ARRAY_END_STRING).get(type));
+ }
+
+ private static void addPattern(List<Pattern> results, String pattern, String type, Map<String, Map<String, String>> includePatternData) {
+ pattern = includePatternData.get(PATTERN_PREFIX).get(type) + pattern;
+ results.add(
+ type == REGEXP_PATTERN ?
+ Pattern.compile(pattern) :
+ WildcardUtil.compileWildcardPattern(pattern));
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Adding include " + (type == REGEXP_PATTERN ? "property" : "wildcard") + " expression: " + pattern);
+ }
+ }
}
Copied: struts/struts2/trunk/plugins/json/src/test/java/org/apache/struts2/json/JSONCleanerTest.java (from r1065873, struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java)
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/json/src/test/java/org/apache/struts2/json/JSONCleanerTest.java?p2=struts/struts2/trunk/plugins/json/src/test/java/org/apache/struts2/json/JSONCleanerTest.java&p1=struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java&r1=1065873&r2=1066613&rev=1066613&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java (original)
+++ struts/struts2/trunk/plugins/json/src/test/java/org/apache/struts2/json/JSONCleanerTest.java Wed Feb 2 20:28:20 2011
@@ -15,42 +15,119 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.opensymphony.xwork2.util;
+package org.apache.struts2.json;
-import com.opensymphony.xwork2.XWorkTestCase;
+import junit.framework.TestCase;
+import java.util.Map;
import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+public class JSONCleanerTest extends TestCase {
+
+ public void testDefaultBlock1() throws JSONException {
+
+ JSONCleaner cleaner = getCleaner();
+ cleaner.setDefaultBlock(true);
+ cleaner.setAllowed("a,c");
+
+ Map data = getData();
+ cleaner.clean("", data);
+ assertEquals(2, data.size());
+ assertEquals("x", data.get("a"));
+ assertNull(data.get("b"));
+ assertNotNull(data.get("c"));
+ assertNull(data.get("d"));
+
+ }
+
+ public void testDefaultBlock2() throws JSONException {
+
+ JSONCleaner cleaner = getCleaner();
+ cleaner.setDefaultBlock(true);
+ cleaner.setAllowed("a,c,d.x");
+
+ Map data = getData();
+ cleaner.clean("", data);
+ assertEquals(3, data.size());
+ assertEquals("x", data.get("a"));
+ assertNull(data.get("b"));
+ assertNotNull(data.get("c"));
+ assertNotNull(data.get("d"));
+ assertEquals(1, ((Map) data.get("d")).size());
+ assertEquals("a", ((Map) data.get("d")).get("x"));
+ assertNull(((Map) data.get("d")).get("y"));
+
+ }
+
+ public void testDefaultAllow1() throws JSONException {
+
+ JSONCleaner cleaner = getCleaner();
+ cleaner.setDefaultBlock(false);
+ cleaner.setBlocked("b,d");
+
+ Map data = getData();
+ cleaner.clean("", data);
+ assertEquals(2, data.size());
+ assertEquals("x", data.get("a"));
+ assertNull(data.get("b"));
+ assertNotNull(data.get("c"));
+ assertNull(data.get("d"));
+
+ }
+
+ public void testDefaultAllow2() throws JSONException {
+
+ JSONCleaner cleaner = getCleaner();
+ cleaner.setDefaultBlock(false);
+ cleaner.setBlocked("b,d.y");
+
+ Map data = getData();
+ cleaner.clean("", data);
+ assertEquals(3, data.size());
+ assertEquals("x", data.get("a"));
+ assertNull(data.get("b"));
+ assertNotNull(data.get("c"));
+ assertNotNull(data.get("d"));
+ assertEquals(1, ((Map) data.get("d")).size());
+ assertEquals("a", ((Map) data.get("d")).get("x"));
+ assertNull(((Map) data.get("d")).get("y"));
+
+ }
+
+ private JSONCleaner getCleaner() {
+
+ return new JSONCleaner() {
+ protected Object cleanValue(String ognlName, Object data) throws JSONException {
+ return data;
+ }
+ };
+
+ }
+
+ private Map getData() {
+
+ Map data = new HashMap();
+ data.put("a", "x");
+ data.put("b", "y");
+
+ List list = new ArrayList();
+ list.add("p");
+ list.add("q");
+ list.add("r");
+ data.put("c", list);
+
+ Map map = new HashMap();
+ map.put("x", "a");
+ map.put("y", "b");
+ data.put("d", map);
+
+ return data;
-public class WildcardHelperTest extends XWorkTestCase {
-
- public void testMatch() {
-
- WildcardHelper wild = new WildcardHelper();
- HashMap<String,String> matchedPatterns = new HashMap<String,String>();
- int[] pattern = wild.compilePattern("wes-rules");
- assertEquals(wild.match(matchedPatterns,"wes-rules", pattern), true);
- assertEquals(wild.match(matchedPatterns, "rules-wes", pattern), false);
-
- pattern = wild.compilePattern("wes-*");
- assertEquals(wild.match(matchedPatterns,"wes-rules", pattern), true);
- assertEquals("rules".equals(matchedPatterns.get("1")), true);
- assertEquals(wild.match(matchedPatterns, "rules-wes", pattern), false);
-
- pattern = wild.compilePattern("path/**/file");
- assertEquals(wild.match(matchedPatterns, "path/to/file", pattern), true);
- assertEquals("to".equals(matchedPatterns.get("1")), true);
- assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
- assertEquals("to/another/location/of".equals(matchedPatterns.get("1")), true);
-
- pattern = wild.compilePattern("path/*/file");
- assertEquals(wild.match(matchedPatterns, "path/to/file", pattern), true);
- assertEquals("to".equals(matchedPatterns.get("1")), true);
- assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), false);
-
- pattern = wild.compilePattern("path/*/another/**/file");
- assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
- assertEquals("to".equals(matchedPatterns.get("1")), true);
- assertEquals("location/of".equals(matchedPatterns.get("2")), true);
}
}
Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/WildcardUtil.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/WildcardUtil.java?rev=1066613&view=auto
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/WildcardUtil.java (added)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/WildcardUtil.java Wed Feb 2 20:28:20 2011
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010 Yahoo, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.opensymphony.xwork2.util;
+
+import java.util.regex.Pattern;
+
+/**
+ * Helper class to convert wildcard expression to regular expression
+ */
+public class WildcardUtil {
+
+ /**
+ * Convert wildcard pattern to Pattern
+ * @param pattern String containing wildcard pattern
+ * @return compiled regular expression as a Pattern
+ */
+ public static Pattern compileWildcardPattern(String pattern) {
+ StringBuilder buf = new StringBuilder(pattern);
+
+ for (int i=buf.length()-1; i>=0; i--)
+ {
+ char c = buf.charAt(i);
+ if (c == '*' && (i == 0 || buf.charAt(i-1) != '\\'))
+ {
+ buf.insert(i+1, '?');
+ buf.insert(i, '.');
+ }
+ else if (c == '*')
+ {
+ i--; // skip backslash, too
+ }
+ else if (needsBackslashToBeLiteralInRegex(c))
+ {
+ buf.insert(i, '\\');
+ }
+ }
+
+ return Pattern.compile(buf.toString());
+ }
+
+ /**
+ * @param c character to test
+ * @return true if the given character must be escaped to be a literal
+ * inside a regular expression.
+ */
+
+ private static final String theSpecialRegexCharList = ".[]\\?*+{}|()^$";
+
+ public static boolean needsBackslashToBeLiteralInRegex(
+ char c)
+ {
+ return (theSpecialRegexCharList.indexOf(c) >= 0);
+ }
+
+}
Copied: struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardUtilTest.java (from r1065873, struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java)
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardUtilTest.java?p2=struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardUtilTest.java&p1=struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java&r1=1065873&r2=1066613&rev=1066613&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardHelperTest.java (original)
+++ struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/WildcardUtilTest.java Wed Feb 2 20:28:20 2011
@@ -19,38 +19,39 @@ package com.opensymphony.xwork2.util;
import com.opensymphony.xwork2.XWorkTestCase;
-import java.util.HashMap;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
-public class WildcardHelperTest extends XWorkTestCase {
+public class WildcardUtilTest extends XWorkTestCase {
- public void testMatch() {
+ public void testPattern() {
- WildcardHelper wild = new WildcardHelper();
- HashMap<String,String> matchedPatterns = new HashMap<String,String>();
- int[] pattern = wild.compilePattern("wes-rules");
- assertEquals(wild.match(matchedPatterns,"wes-rules", pattern), true);
- assertEquals(wild.match(matchedPatterns, "rules-wes", pattern), false);
+ Pattern p = WildcardUtil.compileWildcardPattern("a*b");
+ assertTrue(p.matcher("ab").matches());
+ assertTrue(p.matcher("axyb").matches());
+ assertFalse(p.matcher("bxyb").matches());
- pattern = wild.compilePattern("wes-*");
- assertEquals(wild.match(matchedPatterns,"wes-rules", pattern), true);
- assertEquals("rules".equals(matchedPatterns.get("1")), true);
- assertEquals(wild.match(matchedPatterns, "rules-wes", pattern), false);
+ p = WildcardUtil.compileWildcardPattern("a\\*b");
+ assertFalse(p.matcher("ab").matches());
+ assertTrue(p.matcher("a*b").matches());
- pattern = wild.compilePattern("path/**/file");
- assertEquals(wild.match(matchedPatterns, "path/to/file", pattern), true);
- assertEquals("to".equals(matchedPatterns.get("1")), true);
- assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
- assertEquals("to/another/location/of".equals(matchedPatterns.get("1")), true);
+ p = WildcardUtil.compileWildcardPattern("a.*");
+ assertFalse(p.matcher("ab").matches());
+ assertFalse(p.matcher("ab.b").matches());
+ assertTrue(p.matcher("a.b").matches());
+ assertTrue(p.matcher("a.bc").matches());
+ assertTrue(p.matcher("a.b.c").matches());
- pattern = wild.compilePattern("path/*/file");
- assertEquals(wild.match(matchedPatterns, "path/to/file", pattern), true);
- assertEquals("to".equals(matchedPatterns.get("1")), true);
- assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), false);
+ p = WildcardUtil.compileWildcardPattern("a[*]");
+ assertFalse(p.matcher("ab").matches());
+ assertFalse(p.matcher("ab[b]").matches());
+ assertTrue(p.matcher("a[b]").matches());
+ assertTrue(p.matcher("a[bc]").matches());
+ assertFalse(p.matcher("a[b].c").matches());
- pattern = wild.compilePattern("path/*/another/**/file");
- assertEquals(wild.match(matchedPatterns, "path/to/another/location/of/file", pattern), true);
- assertEquals("to".equals(matchedPatterns.get("1")), true);
- assertEquals("location/of".equals(matchedPatterns.get("2")), true);
+ p = WildcardUtil.compileWildcardPattern("a[*].*");
+ assertTrue(p.matcher("a[b].c").matches());
+ assertTrue(p.matcher("a[bc].cd").matches());
}
}