From 6902a8373c02ddd7d555ee19bcdda9918dfa3b88 Mon Sep 17 00:00:00 2001
From: cramakri <cramakri>
Date: Tue, 9 Nov 2010 12:11:09 +0000
Subject: [PATCH] LMS-1767 Refactored the escaper.

SVN: 18602
---
 .../utilities/ReflectingStringEscaper.java    | 136 +++++++++++++++---
 .../ReflectingStringEscaperTest.java          |  52 ++++++-
 2 files changed, 164 insertions(+), 24 deletions(-)

diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaper.java b/common/source/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaper.java
index 30c2635cf53..fee68b0dde0 100644
--- a/common/source/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaper.java
+++ b/common/source/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaper.java
@@ -23,31 +23,98 @@ import java.util.HashSet;
 import org.apache.commons.lang.StringEscapeUtils;
 
 /**
- * Performs HTML escaping the string fields of an object. Restricts itself to the properties
- * specified by the invoker.
+ * Performs HTML escaping the string fields of an object. If desired, users can restrict the fields
+ * that are escaped by the invoker. Support for controlling the behavior of the escaper by using
+ * annotations may come in the future.
  * 
  * @author Chandrasekhar Ramakrishnan
  */
-public class ReflectingStringEscaper<T>
+public class ReflectingStringEscaper
 {
-    public static <T> T escapeShallow(T bean, String... escapedProperties)
+
+    /**
+     * Escape all the string fields on the bean.
+     */
+    public static <T> T escapeShallow(T bean)
+    {
+        ReflectingStringEscaperUnrestricted<T> escaper =
+                new ReflectingStringEscaperUnrestricted<T>(false, bean);
+        return escaper.escape();
+    }
+
+    /**
+     * Escape all the string fields on the bean and all fields of objects referred to by the bean.
+     */
+    public static <T> T escapeDeep(T bean)
+    {
+        ReflectingStringEscaperUnrestricted<T> escaper =
+                new ReflectingStringEscaperUnrestricted<T>(true, bean);
+        return escaper.escape();
+    }
+
+    /**
+     * Escape the specified string fields on the bean.
+     */
+    public static <T> T escapeShallowRestricted(T bean, String... escapedProperties)
     {
-        ReflectingStringEscaper<T> escaper =
-                new ReflectingStringEscaper<T>(false, bean, escapedProperties);
+        ReflectingStringEscaperRestricted<T> escaper =
+                new ReflectingStringEscaperRestricted<T>(false, bean, escapedProperties);
         return escaper.escape();
     }
 
-    public static <T> T escapeDeep(T bean, String... escapedProperties)
+    /**
+     * Escape all the string fields on the bean and all fields of objects referred to by the bean,
+     * restricting the field names to those specified.
+     */
+    public static <T> T escapeDeepRestricted(T bean, String... escapedProperties)
     {
-        ReflectingStringEscaper<T> escaper =
-                new ReflectingStringEscaper<T>(true, bean, escapedProperties);
+        ReflectingStringEscaperRestricted<T> escaper =
+                new ReflectingStringEscaperRestricted<T>(true, bean, escapedProperties);
         return escaper.escape();
     }
+}
+
+/**
+ * @author Chandrasekhar Ramakrishnan
+ */
+class ReflectingStringEscaperImpl<T>
+{
+
+    protected final boolean isDeep;
+
+    protected final T bean;
+
+    /**
+     *
+     *
+     */
+    protected ReflectingStringEscaperImpl(boolean isDeep, T bean)
+    {
+        this.isDeep = isDeep;
+        this.bean = bean;
+    }
 
-    private final boolean isDeep;
+    protected T escape(ReflectionStringTraverser.ReflectionFieldVisitor visitor)
+    {
+        if (isDeep)
+        {
+            ReflectionStringTraverser.traverseDeep(bean, visitor);
+        } else
+        {
+            ReflectionStringTraverser.traverseShallow(bean, visitor);
+        }
+        return bean;
+    }
 
-    private final T bean;
+}
 
+/**
+ * Utility Class that preforms the restricted escaping.
+ * 
+ * @author Chandrasekhar Ramakrishnan
+ */
+class ReflectingStringEscaperRestricted<T> extends ReflectingStringEscaperImpl<T>
+{
     private final HashSet<String> escapedProperties;
 
     private class Visitor implements ReflectionStringTraverser.ReflectionFieldVisitor
@@ -66,23 +133,50 @@ public class ReflectingStringEscaper<T>
         }
     }
 
-    private ReflectingStringEscaper(boolean isDeep, T bean, String... escapedProperties)
+    ReflectingStringEscaperRestricted(boolean isDeep, T bean, String... escapedProperties)
     {
-        this.isDeep = isDeep;
-        this.bean = bean;
+        super(isDeep, bean);
         this.escapedProperties = new HashSet<String>();
         Collections.addAll(this.escapedProperties, escapedProperties);
     }
 
-    private T escape()
+    T escape()
     {
-        if (isDeep)
-        {
-            ReflectionStringTraverser.traverseDeep(bean, new Visitor());
-        } else
+        return escape(new Visitor());
+    }
+}
+
+/**
+ * Utility Class that preforms the unrestricted escaping.
+ * 
+ * @author Chandrasekhar Ramakrishnan
+ */
+class ReflectingStringEscaperUnrestricted<T> extends ReflectingStringEscaperImpl<T>
+{
+
+    private static class Visitor implements ReflectionStringTraverser.ReflectionFieldVisitor
+    {
+
+        public String tryVisit(String value, Object object, Field fieldOrNull)
         {
-            ReflectionStringTraverser.traverseShallow(bean, new Visitor());
+            // Only change the value if the name of the field is in the list provided
+            if (null == fieldOrNull)
+            {
+                return null;
+            }
+
+            return StringEscapeUtils.escapeHtml(value);
+
         }
-        return bean;
+    }
+
+    ReflectingStringEscaperUnrestricted(boolean isDeep, T bean)
+    {
+        super(isDeep, bean);
+    }
+
+    T escape()
+    {
+        return escape(new Visitor());
     }
 }
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaperTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaperTest.java
index 03a6b0c4273..d50f77a981f 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaperTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/utilities/ReflectingStringEscaperTest.java
@@ -47,10 +47,10 @@ public class ReflectingStringEscaperTest extends AssertJUnit
         bean.wrappedBean.bar = "<b>bar</b>";
         bean.wrappedBean.baz = "<i>baz</i>";
 
-        TestBean escaped = ReflectingStringEscaper.escapeShallow(bean, "foo", "baz");
+        TestBean escaped = ReflectingStringEscaper.escapeShallow(bean);
         assertEquals(bean, escaped);
         assertEquals("&lt;a&gt;foo&lt;/a&gt;", bean.foo);
-        assertEquals("<b>bar</b>", bean.bar);
+        assertEquals("&lt;b&gt;bar&lt;/b&gt;", bean.bar);
         assertEquals("&lt;i&gt;baz&lt;/i&gt;", bean.baz);
 
         assertEquals("<a>foo</a>", bean.wrappedBean.foo);
@@ -70,7 +70,53 @@ public class ReflectingStringEscaperTest extends AssertJUnit
         bean.wrappedBean.bar = "<b>bar</b>";
         bean.wrappedBean.baz = "<i>baz</i>";
 
-        TestBean escaped = ReflectingStringEscaper.escapeDeep(bean, "foo", "baz");
+        TestBean escaped = ReflectingStringEscaper.escapeDeep(bean);
+        assertEquals(bean, escaped);
+        assertEquals("&lt;a&gt;foo&lt;/a&gt;", bean.foo);
+        assertEquals("&lt;b&gt;bar&lt;/b&gt;", bean.bar);
+        assertEquals("&lt;i&gt;baz&lt;/i&gt;", bean.baz);
+
+        assertEquals("&lt;a&gt;foo&lt;/a&gt;", bean.wrappedBean.foo);
+        assertEquals("&lt;b&gt;bar&lt;/b&gt;", bean.wrappedBean.bar);
+        assertEquals("&lt;i&gt;baz&lt;/i&gt;", bean.wrappedBean.baz);
+    }
+
+    @Test
+    public void testShallowEscaperRestricted()
+    {
+        TestBean bean = new TestBean();
+        bean.foo = "<a>foo</a>";
+        bean.bar = "<b>bar</b>";
+        bean.baz = "<i>baz</i>";
+        bean.wrappedBean = new TestBean();
+        bean.wrappedBean.foo = "<a>foo</a>";
+        bean.wrappedBean.bar = "<b>bar</b>";
+        bean.wrappedBean.baz = "<i>baz</i>";
+
+        TestBean escaped = ReflectingStringEscaper.escapeShallowRestricted(bean, "foo", "baz");
+        assertEquals(bean, escaped);
+        assertEquals("&lt;a&gt;foo&lt;/a&gt;", bean.foo);
+        assertEquals("<b>bar</b>", bean.bar);
+        assertEquals("&lt;i&gt;baz&lt;/i&gt;", bean.baz);
+
+        assertEquals("<a>foo</a>", bean.wrappedBean.foo);
+        assertEquals("<b>bar</b>", bean.wrappedBean.bar);
+        assertEquals("<i>baz</i>", bean.wrappedBean.baz);
+    }
+
+    @Test
+    public void testDeepEscaperRestricted()
+    {
+        TestBean bean = new TestBean();
+        bean.foo = "<a>foo</a>";
+        bean.bar = "<b>bar</b>";
+        bean.baz = "<i>baz</i>";
+        bean.wrappedBean = new TestBean();
+        bean.wrappedBean.foo = "<a>foo</a>";
+        bean.wrappedBean.bar = "<b>bar</b>";
+        bean.wrappedBean.baz = "<i>baz</i>";
+
+        TestBean escaped = ReflectingStringEscaper.escapeDeepRestricted(bean, "foo", "baz");
         assertEquals(bean, escaped);
         assertEquals("&lt;a&gt;foo&lt;/a&gt;", bean.foo);
         assertEquals("<b>bar</b>", bean.bar);
-- 
GitLab