You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lh...@apache.org on 2010/04/24 23:30:30 UTC

svn commit: r937704 - in /incubator/shiro/trunk/core/src: main/java/org/apache/shiro/config/ test/java/org/apache/shiro/config/

Author: lhazlewood
Date: Sat Apr 24 21:30:30 2010
New Revision: 937704

URL: http://svn.apache.org/viewvc?rev=937704&view=rev
Log:
SHIRO-152 - added ability to configure sets, lists and maps. Added test cases for validation

Modified:
    incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
    incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/CompositeBean.java
    incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/ReflectionBuilderTest.java
    incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/SimpleBean.java

Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java?rev=937704&r1=937703&r2=937704&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java Sat Apr 24 21:30:30 2010
@@ -22,12 +22,12 @@ import org.apache.commons.beanutils.Bean
 import org.apache.commons.beanutils.PropertyUtils;
 import org.apache.shiro.util.ClassUtils;
 import org.apache.shiro.util.Nameable;
+import org.apache.shiro.util.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.beans.PropertyDescriptor;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
 
 
 /**
@@ -49,6 +49,7 @@ public class ReflectionBuilder {
     private static final String OBJECT_REFERENCE_BEGIN_TOKEN = "$";
     private static final String ESCAPED_OBJECT_REFERENCE_BEGIN_TOKEN = "\\$";
     private static final String GLOBAL_PROPERTY_PREFIX = "shiro";
+    private static final char MAP_KEY_VALUE_DELIMITER = ':';
 
 
     protected Map objects;
@@ -170,7 +171,7 @@ public class ReflectionBuilder {
         } else if (instance == null) {
             String msg = "Configuration error.  Specified object [" + name + "] with property [" +
                     property + "] without first defining that object's class.  Please first " +
-                    "specify the class property first, e.g. myObject.class = fully_qualified_class_name " +
+                    "specify the class property first, e.g. myObject = fully_qualified_class_name " +
                     "and then define additional properties.";
             throw new IllegalArgumentException(msg);
 
@@ -205,17 +206,129 @@ public class ReflectionBuilder {
         return value;
     }
 
-    protected void applyProperty(Object object, String propertyName, String stringValue) {
+    protected Object resolveReference(String reference) {
+        String id = getId(reference);
+        log.debug("Encountered object reference '{}'.  Looking up object with id '{}'", reference, id);
+        return getReferencedObject(id);
+    }
 
-        Object value;
+    protected boolean isSetProperty(Object object, String propertyName) {
+        try {
+            PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(object, propertyName);
+            Class clazz = descriptor.getPropertyType();
+            return Set.class.isAssignableFrom(clazz);
+        } catch (Exception e) {
+            String msg = "Unable to determine if property [" + propertyName + "] represents a java.util.Set";
+            throw new ConfigurationException(msg, e);
+        }
+    }
+
+    protected Set<?> toSet(String sValue) {
+        String[] tokens = StringUtils.split(sValue);
+        if (tokens == null || tokens.length <= 0) {
+            return null;
+        }
+        Set<String> setTokens = new LinkedHashSet<String>(Arrays.asList(tokens));
+
+        //now convert into correct values and/or references:
+        Set<Object> values = new LinkedHashSet<Object>(setTokens.size());
+        for (String token : setTokens) {
+            Object value = resolveValue(token);
+            values.add(value);
+        }
+        return values;
+    }
 
+    protected boolean isListProperty(Object object, String propertyName) {
+        try {
+            PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(object, propertyName);
+            Class clazz = descriptor.getPropertyType();
+            return List.class.isAssignableFrom(clazz);
+        } catch (Exception e) {
+            String msg = "Unable to determine if property [" + propertyName + "] represents a java.util.List";
+            throw new ConfigurationException(msg, e);
+        }
+    }
+
+    protected List<?> toList(String sValue) {
+        String[] tokens = StringUtils.split(sValue);
+        if (tokens == null || tokens.length <= 0) {
+            return null;
+        }
+
+        //now convert into correct values and/or references:
+        List<Object> values = new ArrayList<Object>(tokens.length);
+        for (String token : tokens) {
+            Object value = resolveValue(token);
+            values.add(value);
+        }
+        return values;
+    }
+
+    protected boolean isMapProperty(Object object, String propertyName) {
+        try {
+            PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(object, propertyName);
+            Class clazz = descriptor.getPropertyType();
+            return Map.class.isAssignableFrom(clazz);
+        } catch (Exception e) {
+            String msg = "Unable to determine if property [" + propertyName + "] represents a java.util.Map";
+            throw new ConfigurationException(msg, e);
+        }
+    }
+
+    protected Map<?, ?> toMap(String sValue) {
+        String[] tokens = StringUtils.split(sValue, StringUtils.DEFAULT_DELIMITER_CHAR,
+                StringUtils.DEFAULT_QUOTE_CHAR, StringUtils.DEFAULT_QUOTE_CHAR, true, true);
+        if (tokens == null || tokens.length <= 0) {
+            return null;
+        }
+
+        Map<String, String> mapTokens = new LinkedHashMap<String, String>(tokens.length);
+        for (String token : tokens) {
+            String[] kvPair = StringUtils.split(token, ':');
+            if (kvPair == null || kvPair.length != 2) {
+                String msg = "Map property value [" + sValue + "] contained key-value pair token [" +
+                        token + "] that does not properly split to a single key and pair.  This must be the " +
+                        "case for all map entries.";
+                throw new ConfigurationException(msg);
+            }
+            mapTokens.put(kvPair[0], kvPair[1]);
+        }
+
+        //now convert into correct values and/or references:
+        Map<Object, Object> map = new LinkedHashMap<Object, Object>(mapTokens.size());
+        for (Map.Entry<String, String> entry : mapTokens.entrySet()) {
+            Object key = resolveValue(entry.getKey());
+            Object value = resolveValue(entry.getValue());
+            map.put(key, value);
+        }
+        return map;
+    }
+
+    protected Object resolveValue(String stringValue) {
+        Object value;
         if (isReference(stringValue)) {
-            String id = getId(stringValue);
-            log.debug("Encountered object reference '{}'.  Looking up object with id '{}'", stringValue, id);
-            value = getReferencedObject(id);
+            value = resolveReference(stringValue);
         } else {
             value = unescapeIfNecessary(stringValue);
         }
+        return value;
+    }
+
+
+    protected void applyProperty(Object object, String propertyName, String stringValue) {
+
+        Object value;
+
+        if (isSetProperty(object, propertyName)) {
+            value = toSet(stringValue);
+        } else if (isListProperty(object, propertyName)) {
+            value = toList(stringValue);
+        } else if (isMapProperty(object, propertyName)) {
+            value = toMap(stringValue);
+        } else {
+            value = resolveValue(stringValue);
+        }
 
         try {
             if (log.isTraceEnabled()) {

Modified: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/CompositeBean.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/CompositeBean.java?rev=937704&r1=937703&r2=937704&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/CompositeBean.java (original)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/CompositeBean.java Sat Apr 24 21:30:30 2010
@@ -18,17 +18,25 @@
  */
 package org.apache.shiro.config;
 
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 /**
  * @author Les Hazlewood
  * @since Aug 5, 2008 10:17:37 AM
  */
-public class CompositeBean
-{
+public class CompositeBean {
+
     private String stringProp;
     private boolean booleanProp;
     private int intProp;
     private SimpleBean simpleBean;
 
+    private Set<SimpleBean> simpleBeanSet;
+    private List<SimpleBean> simpleBeanList;
+    private Map<String, SimpleBean> simpleBeanMap;
+
     public CompositeBean() {
     }
 
@@ -63,4 +71,28 @@ public class CompositeBean
     public void setSimpleBean(SimpleBean simpleBean) {
         this.simpleBean = simpleBean;
     }
+
+    public Set<SimpleBean> getSimpleBeanSet() {
+        return simpleBeanSet;
+    }
+
+    public void setSimpleBeanSet(Set<SimpleBean> simpleBeanSet) {
+        this.simpleBeanSet = simpleBeanSet;
+    }
+
+    public List<SimpleBean> getSimpleBeanList() {
+        return simpleBeanList;
+    }
+
+    public void setSimpleBeanList(List<SimpleBean> simpleBeanList) {
+        this.simpleBeanList = simpleBeanList;
+    }
+
+    public Map<String, SimpleBean> getSimpleBeanMap() {
+        return simpleBeanMap;
+    }
+
+    public void setSimpleBeanMap(Map<String, SimpleBean> simpleBeanMap) {
+        this.simpleBeanMap = simpleBeanMap;
+    }
 }

Modified: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/ReflectionBuilderTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/ReflectionBuilderTest.java?rev=937704&r1=937703&r2=937704&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/ReflectionBuilderTest.java (original)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/ReflectionBuilderTest.java Sat Apr 24 21:30:30 2010
@@ -18,14 +18,15 @@
  */
 package org.apache.shiro.config;
 
+import org.apache.shiro.util.CollectionUtils;
+import org.junit.Test;
+
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.junit.Assert.*;
-import org.junit.Test;
-import org.apache.shiro.config.ConfigurationException;
-import org.apache.shiro.config.ReflectionBuilder;
-import org.apache.shiro.config.UnresolveableReferenceException;
 
 /**
  * @author Les Hazlewood
@@ -105,4 +106,81 @@ public class ReflectionBuilderTest {
         ReflectionBuilder builder = new ReflectionBuilder();
         builder.buildObjects(defs);
     }
+
+    @Test
+    public void testSetProperty() {
+        Map<String, String> defs = new LinkedHashMap<String, String>();
+        defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
+        defs.put("simpleBean2", "org.apache.shiro.config.SimpleBean");
+        defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
+        defs.put("compositeBean.simpleBeanSet", "$simpleBean1, $simpleBean2, $simpleBean2");
+        ReflectionBuilder builder = new ReflectionBuilder();
+        Map objects = builder.buildObjects(defs);
+        assertFalse(CollectionUtils.isEmpty(objects));
+        CompositeBean cBean = (CompositeBean) objects.get("compositeBean");
+        assertNotNull(cBean);
+        Set<SimpleBean> simpleBeans = cBean.getSimpleBeanSet();
+        assertNotNull(simpleBeans);
+        assertEquals(2, simpleBeans.size());
+    }
+
+    @Test
+    public void testListProperty() {
+        Map<String, String> defs = new LinkedHashMap<String, String>();
+        defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
+        defs.put("simpleBean2", "org.apache.shiro.config.SimpleBean");
+        defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
+        defs.put("compositeBean.simpleBeanList", "$simpleBean1, $simpleBean2, $simpleBean2");
+        ReflectionBuilder builder = new ReflectionBuilder();
+        Map objects = builder.buildObjects(defs);
+        assertFalse(CollectionUtils.isEmpty(objects));
+        CompositeBean cBean = (CompositeBean) objects.get("compositeBean");
+        assertNotNull(cBean);
+        List<SimpleBean> simpleBeans = cBean.getSimpleBeanList();
+        assertNotNull(simpleBeans);
+        assertEquals(3, simpleBeans.size());
+    }
+
+    @Test
+    public void testMapProperty() {
+        Map<String, String> defs = new LinkedHashMap<String, String>();
+        defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
+        defs.put("simpleBean2", "org.apache.shiro.config.SimpleBean");
+        defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
+        defs.put("compositeBean.simpleBeanMap", "simpleBean1:$simpleBean1, simpleBean2:$simpleBean2");
+        ReflectionBuilder builder = new ReflectionBuilder();
+        Map objects = builder.buildObjects(defs);
+        assertFalse(CollectionUtils.isEmpty(objects));
+        CompositeBean cBean = (CompositeBean) objects.get("compositeBean");
+        assertNotNull(cBean);
+        Map map = cBean.getSimpleBeanMap();
+        assertNotNull(map);
+        assertEquals(2, map.size());
+        Object value = map.get("simpleBean1");
+        assertTrue(value instanceof SimpleBean);
+        value = map.get("simpleBean2");
+        assertTrue(value instanceof SimpleBean);
+    }
+
+    @Test
+    public void testNestedListProperty() {
+        Map<String, String> defs = new LinkedHashMap<String, String>();
+        defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
+        defs.put("simpleBean2", "org.apache.shiro.config.SimpleBean");
+        defs.put("simpleBean3", "org.apache.shiro.config.SimpleBean");
+        defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
+        defs.put("compositeBean.simpleBean", "$simpleBean1");
+        defs.put("compositeBean.simpleBean.simpleBeans", "$simpleBean2, $simpleBean3");
+        ReflectionBuilder builder = new ReflectionBuilder();
+        Map objects = builder.buildObjects(defs);
+        assertFalse(CollectionUtils.isEmpty(objects));
+        CompositeBean cBean = (CompositeBean) objects.get("compositeBean");
+        assertNotNull(cBean);
+        SimpleBean nested = cBean.getSimpleBean();
+        assertNotNull(nested);
+        List<SimpleBean> children = nested.getSimpleBeans();
+        assertNotNull(children);
+        assertEquals(2, children.size());
+    }
+
 }

Modified: incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/SimpleBean.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/SimpleBean.java?rev=937704&r1=937703&r2=937704&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/SimpleBean.java (original)
+++ incubator/shiro/trunk/core/src/test/java/org/apache/shiro/config/SimpleBean.java Sat Apr 24 21:30:30 2010
@@ -18,16 +18,19 @@
  */
 package org.apache.shiro.config;
 
+import java.util.List;
+
 /**
  * @author Les Hazlewood
  * @since Aug 5, 2008 10:18:01 AM
  */
-public class SimpleBean
-{
+public class SimpleBean {
 
     private String stringProp = null;
     private int intProp;
 
+    private List<SimpleBean> simpleBeans;
+
     public SimpleBean() {
     }
 
@@ -46,4 +49,12 @@ public class SimpleBean
     public void setIntProp(int intProp) {
         this.intProp = intProp;
     }
+
+    public List<SimpleBean> getSimpleBeans() {
+        return simpleBeans;
+    }
+
+    public void setSimpleBeans(List<SimpleBean> simpleBeans) {
+        this.simpleBeans = simpleBeans;
+    }
 }