shiro-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bdem...@apache.org
Subject [01/13] shiro git commit: SHIRO-364: Adding initial implementation of bean listeners
Date Mon, 11 Jul 2016 21:04:28 GMT
Repository: shiro
Updated Branches:
  refs/heads/1.3.x dbfacf1f5 -> bd8c31415


SHIRO-364: Adding initial implementation of bean listeners

git-svn-id: https://svn.apache.org/repos/asf/shiro/trunk@1351930 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/shiro/repo
Commit: http://git-wip-us.apache.org/repos/asf/shiro/commit/0a886db6
Tree: http://git-wip-us.apache.org/repos/asf/shiro/tree/0a886db6
Diff: http://git-wip-us.apache.org/repos/asf/shiro/diff/0a886db6

Branch: refs/heads/1.3.x
Commit: 0a886db69ae665c0f29c3513e032f72c1b65095e
Parents: dbfacf1
Author: Jared Bunting <jbunting@apache.org>
Authored: Wed Jun 20 04:03:28 2012 +0000
Committer: Brian Demers <bdemers@apache.org>
Committed: Fri Jul 8 13:49:21 2016 -0400

----------------------------------------------------------------------
 .../shiro/config/IniSecurityManagerFactory.java |   6 +
 .../apache/shiro/config/ReflectionBuilder.java  |  79 ++++++-
 .../apache/shiro/config/event/BeanEvent.java    |  29 +++
 .../apache/shiro/config/event/BeanListener.java |  14 ++
 .../shiro/config/event/BeanListenerSupport.java |  31 +++
 .../shiro/config/event/ConfiguredBeanEvent.java |   9 +
 .../shiro/config/event/DestroyedBeanEvent.java  |   9 +
 .../config/event/InstantiatedBeanEvent.java     |   9 +
 .../shiro/config/event/LoggingBeanListener.java |  32 +++
 .../shiro/config/ReflectionBuilderTest.groovy   | 213 +++++++------------
 .../shiro/config/RecordingBeanListener.java     |  51 +++++
 samples/web/src/main/webapp/WEB-INF/shiro.ini   |   2 +
 12 files changed, 349 insertions(+), 135 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/main/java/org/apache/shiro/config/IniSecurityManagerFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/config/IniSecurityManagerFactory.java b/core/src/main/java/org/apache/shiro/config/IniSecurityManagerFactory.java
index 5101b35..6a30f0a 100644
--- a/core/src/main/java/org/apache/shiro/config/IniSecurityManagerFactory.java
+++ b/core/src/main/java/org/apache/shiro/config/IniSecurityManagerFactory.java
@@ -73,6 +73,12 @@ public class IniSecurityManagerFactory extends IniFactorySupport<SecurityManager
         return this.builder != null ? Collections.unmodifiableMap(builder.getObjects()) :
null;
     }
 
+    public void destroy() {
+        if(this.builder != null) {
+            builder.destroy();
+        }
+    }
+
     private SecurityManager getSecurityManagerBean() {
         return builder.getBean(SECURITY_MANAGER_NAME, SecurityManager.class);
     }

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java b/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
index 6ca49c0..3d15f9a 100644
--- a/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
+++ b/core/src/main/java/org/apache/shiro/config/ReflectionBuilder.java
@@ -22,6 +22,7 @@ import org.apache.commons.beanutils.BeanUtils;
 import org.apache.commons.beanutils.PropertyUtils;
 import org.apache.shiro.codec.Base64;
 import org.apache.shiro.codec.Hex;
+import org.apache.shiro.config.event.*;
 import org.apache.shiro.util.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -57,22 +58,41 @@ public class ReflectionBuilder {
     private static final char MAP_PROPERTY_BEGIN_TOKEN = '[';
     private static final char MAP_PROPERTY_END_TOKEN = ']';
 
-    private Map<String, ?> objects;
+    private final Map<String, Object> objects;
+    private final List<BeanListener> listeners = new ArrayList<BeanListener>();
+    private final BeanListener compositeListener = new BeanListener() {
+        public void onBeanEvent(BeanEvent beanEvent) {
+            for(BeanListener listener: listeners) {
+                listener.onBeanEvent(beanEvent);
+            }
+        }
+    };
 
     public ReflectionBuilder() {
         this.objects = new LinkedHashMap<String, Object>();
     }
 
     public ReflectionBuilder(Map<String, ?> defaults) {
-        this.objects = CollectionUtils.isEmpty(defaults) ? new LinkedHashMap<String, Object>()
: defaults;
+        this.objects = new LinkedHashMap<String, Object>();
+        if(!CollectionUtils.isEmpty(defaults)) {
+            this.objects.putAll(defaults);
+        }
     }
 
     public Map<String, ?> getObjects() {
         return objects;
     }
 
+    /**
+     * @deprecated Use of this method will break the event contract.  We recommend not using
it.
+     * @param objects
+     */
+    @Deprecated
     public void setObjects(Map<String, ?> objects) {
-        this.objects = CollectionUtils.isEmpty(objects) ? new LinkedHashMap<String, Object>()
: objects;
+        this.objects.clear();
+        if(!CollectionUtils.isEmpty(objects)) {
+            this.objects.putAll(objects);
+        }
     }
 
     public Object getBean(String id) {
@@ -119,10 +139,43 @@ public class ReflectionBuilder {
                 createNewInstance((Map<String, Object>) objects, entry.getKey(), entry.getValue());
             }
 
+            // Set properties on listeners
+            Iterator<Map.Entry<String, String>> entryIterator = propertyMap.entrySet().iterator();
+            while(entryIterator.hasNext()) {
+                Map.Entry<String, String> entry = entryIterator.next();
+                if(isListenerProperty(entry.getKey())) {
+                    applyProperty(entry.getKey(), entry.getValue(), objects);
+                    entryIterator.remove();
+                }
+            }
+
+            Map<String, Object> immutableObjects = Collections.unmodifiableMap(objects);
+
+            // Add listeners to listener set, notifying events on them as we go - order is
important here
+            for(Map.Entry<String, ?> entry: objects.entrySet()) {
+                if(entry.getValue() instanceof BeanListener) {
+                    compositeListener.onBeanEvent(new ConfiguredBeanEvent(entry.getKey(),
entry.getValue(), immutableObjects));
+                    listeners.add((BeanListener) entry.getValue());
+                }
+            }
+
+            // notify instantiated event on non-listeners
+            for(Map.Entry<String, ?> entry: objects.entrySet()) {
+                if(!(entry.getValue() instanceof BeanListener)) {
+                    compositeListener.onBeanEvent(new InstantiatedBeanEvent(entry.getKey(),
entry.getValue(), immutableObjects));
+                }
+            }
+
             // Set all properties
             for (Map.Entry<String, String> entry : propertyMap.entrySet()) {
                 applyProperty(entry.getKey(), entry.getValue(), objects);
             }
+
+            for(Map.Entry<String, ?> entry: objects.entrySet()) {
+                if(!(entry.getValue() instanceof BeanListener)) {
+                    compositeListener.onBeanEvent(new ConfiguredBeanEvent(entry.getKey(),
entry.getValue(), immutableObjects));
+                }
+            }
         }
 
         //SHIRO-413: init method must be called for constructed objects that are Initializable
@@ -131,6 +184,26 @@ public class ReflectionBuilder {
         return objects;
     }
 
+    public void destroy() {
+        final Map<String, Object> immutableObjects = Collections.unmodifiableMap(objects);
+        for(Map.Entry<String, ?> entry: objects.entrySet()) {
+            compositeListener.onBeanEvent(new DestroyedBeanEvent(entry.getKey(), entry.getValue(),
immutableObjects));
+        }
+    }
+
+    private boolean isListenerProperty(String key) {
+        int index = key.indexOf('.');
+
+        if (index >= 0) {
+            String name = key.substring(0, index);
+
+            return objects.containsKey(name) && objects.get(name) instanceof BeanListener;
+        } else {
+            throw new IllegalArgumentException("All property keys must contain a '.' character.
" +
+                    "(e.g. myBean.property = value)  These should already be separated out
by buildObjects().");
+        }
+    }
+
     protected void createNewInstance(Map<String, Object> objects, String name, String
value) {
 
         Object currentInstance = objects.get(name);

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/main/java/org/apache/shiro/config/event/BeanEvent.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/config/event/BeanEvent.java b/core/src/main/java/org/apache/shiro/config/event/BeanEvent.java
new file mode 100644
index 0000000..108c8eb
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/config/event/BeanEvent.java
@@ -0,0 +1,29 @@
+package org.apache.shiro.config.event;
+
+import java.util.EventObject;
+import java.util.Map;
+
+public class BeanEvent extends EventObject {
+    private String beanName;
+    private Object bean;
+    private final Map<String, Object> beanContext;
+
+    public BeanEvent(final String beanName, final Object bean, final Map<String, Object>
beanContext) {
+        super(bean);
+        this.beanName = beanName;
+        this.bean = bean;
+        this.beanContext = beanContext;
+    }
+
+    public String getBeanName() {
+        return beanName;
+    }
+
+    public Object getBean() {
+        return bean;
+    }
+
+    public Map<String, Object> getBeanContext() {
+        return beanContext;
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/main/java/org/apache/shiro/config/event/BeanListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/config/event/BeanListener.java b/core/src/main/java/org/apache/shiro/config/event/BeanListener.java
new file mode 100644
index 0000000..1f0a448
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/config/event/BeanListener.java
@@ -0,0 +1,14 @@
+package org.apache.shiro.config.event;
+
+/**
+ * Extension point that provides for notification of lifecycle events in the bean configuration
process.  This is an
+ * extension point of the (typically) ini-based bean instantiation strategy used by default
by shiro.  It is intended
+ * as a bare-bones corollary to the more advanced lifecycle facilities offered in full-fledged
dependency injection
+ * frameworks.
+ *
+ * The type of event is determined by the type of the beanEvent object.  Use of {@see BeanListenerSupport}
is
+ * recommended.
+ */
+public interface BeanListener {
+    void onBeanEvent(BeanEvent beanEvent);
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/main/java/org/apache/shiro/config/event/BeanListenerSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/config/event/BeanListenerSupport.java b/core/src/main/java/org/apache/shiro/config/event/BeanListenerSupport.java
new file mode 100644
index 0000000..60fc3d5
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/config/event/BeanListenerSupport.java
@@ -0,0 +1,31 @@
+package org.apache.shiro.config.event;
+
+public abstract class BeanListenerSupport implements BeanListener {
+    public void onBeanEvent(final BeanEvent beanEvent) {
+        if (beanEvent instanceof InstantiatedBeanEvent) {
+            this.onInstantiatedBeanEvent((InstantiatedBeanEvent) beanEvent);
+        } else if (beanEvent instanceof ConfiguredBeanEvent) {
+            this.onConfiguredBeanEvent((ConfiguredBeanEvent) beanEvent);
+        } else if (beanEvent instanceof DestroyedBeanEvent) {
+            this.onDestroyedBeanEvent((DestroyedBeanEvent) beanEvent);
+        } else {
+            this.onUnhandledBeanEvent(beanEvent);
+        }
+    }
+
+    protected void onUnhandledBeanEvent(final BeanEvent beanEvent) {
+        // do nothing
+    }
+
+    protected void onInstantiatedBeanEvent(final InstantiatedBeanEvent beanEvent) {
+        // do nothing
+    }
+
+    protected void onConfiguredBeanEvent(final ConfiguredBeanEvent beanEvent) {
+        // do nothing
+    }
+
+    protected void onDestroyedBeanEvent(final DestroyedBeanEvent beanEvent) {
+        // do nothing
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/main/java/org/apache/shiro/config/event/ConfiguredBeanEvent.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/config/event/ConfiguredBeanEvent.java b/core/src/main/java/org/apache/shiro/config/event/ConfiguredBeanEvent.java
new file mode 100644
index 0000000..f183a6b
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/config/event/ConfiguredBeanEvent.java
@@ -0,0 +1,9 @@
+package org.apache.shiro.config.event;
+
+import java.util.Map;
+
+public class ConfiguredBeanEvent extends BeanEvent {
+    public ConfiguredBeanEvent(final String beanName, final Object bean, final Map<String,
Object> beanContext) {
+        super(beanName, bean, beanContext);
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/main/java/org/apache/shiro/config/event/DestroyedBeanEvent.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/config/event/DestroyedBeanEvent.java b/core/src/main/java/org/apache/shiro/config/event/DestroyedBeanEvent.java
new file mode 100644
index 0000000..a92cc2f
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/config/event/DestroyedBeanEvent.java
@@ -0,0 +1,9 @@
+package org.apache.shiro.config.event;
+
+import java.util.Map;
+
+public class DestroyedBeanEvent extends BeanEvent {
+    public DestroyedBeanEvent(final String beanName, final Object bean, final Map<String,
Object> beanContext) {
+        super(beanName, bean, beanContext);
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/main/java/org/apache/shiro/config/event/InstantiatedBeanEvent.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/config/event/InstantiatedBeanEvent.java b/core/src/main/java/org/apache/shiro/config/event/InstantiatedBeanEvent.java
new file mode 100644
index 0000000..75d2ccf
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/config/event/InstantiatedBeanEvent.java
@@ -0,0 +1,9 @@
+package org.apache.shiro.config.event;
+
+import java.util.Map;
+
+public class InstantiatedBeanEvent extends BeanEvent {
+    public InstantiatedBeanEvent(final String beanName, final Object bean, final Map<String,
Object> beanContext) {
+        super(beanName, bean, beanContext);
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/main/java/org/apache/shiro/config/event/LoggingBeanListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/shiro/config/event/LoggingBeanListener.java b/core/src/main/java/org/apache/shiro/config/event/LoggingBeanListener.java
new file mode 100644
index 0000000..5a230e6
--- /dev/null
+++ b/core/src/main/java/org/apache/shiro/config/event/LoggingBeanListener.java
@@ -0,0 +1,32 @@
+package org.apache.shiro.config.event;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A stock bean listener implementation that logs all events via the standard logging mechanism.
+ */
+public class LoggingBeanListener extends BeanListenerSupport {
+
+    private static final Logger logger = LoggerFactory.getLogger(LoggingBeanListener.class);
+
+    @Override
+    protected void onUnhandledBeanEvent(BeanEvent beanEvent) {
+        logger.warn("UNHANDLED EVENT :: {} :: {}", beanEvent.getBeanName(), beanEvent.getBean());
+    }
+
+    @Override
+    protected void onInstantiatedBeanEvent(InstantiatedBeanEvent beanEvent) {
+        logger.info("INSTANTIATED :: {} :: {}", beanEvent.getBeanName(), beanEvent.getBean());
+    }
+
+    @Override
+    protected void onConfiguredBeanEvent(ConfiguredBeanEvent beanEvent) {
+        logger.info("CONFIGURED :: {} :: {}", beanEvent.getBeanName(), beanEvent.getBean());
+    }
+
+    @Override
+    protected void onDestroyedBeanEvent(DestroyedBeanEvent beanEvent) {
+        logger.info("DESTROYED :: {} :: {}", beanEvent.getBeanName(), beanEvent.getBean());
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy b/core/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy
index e5431bd..39957a9 100644
--- a/core/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy
+++ b/core/src/test/groovy/org/apache/shiro/config/ReflectionBuilderTest.groovy
@@ -23,15 +23,13 @@ import org.apache.shiro.codec.CodecSupport
 import org.apache.shiro.codec.Hex
 import org.apache.shiro.realm.ldap.JndiLdapRealm
 import org.apache.shiro.util.CollectionUtils
-import org.junit.Test
-import static org.junit.Assert.*
+import org.apache.shiro.config.event.BeanEvent
 
 /**
  * Unit tests for the {@link ReflectionBuilder} implementation.
  */
-class ReflectionBuilderTest {
+class ReflectionBuilderTest extends GroovyTestCase {
 
-    @Test
     void testStandardPropertyAssignment() {
         ReflectionBuilder builder = new ReflectionBuilder();
 
@@ -46,8 +44,7 @@ class ReflectionBuilderTest {
         assertTrue cBean.intProp == 42
         assertTrue cBean.simpleBean instanceof SimpleBean
     }
-
-    @Test
+    
     void testMapEntryAssignment() {
         ReflectionBuilder builder = new ReflectionBuilder();
 
@@ -59,7 +56,6 @@ class ReflectionBuilderTest {
         assertTrue cBean.simpleBeanMap['simpleBean2'] instanceof SimpleBean
     }
 
-    @Test
     void testArrayEntryAssignment() {
         ReflectionBuilder builder = new ReflectionBuilder();
 
@@ -71,7 +67,6 @@ class ReflectionBuilderTest {
         assertTrue cBean.compositeBeanArray[0] instanceof CompositeBean
     }
 
-    @Test
     void testNestedPathAssignment() {
         ReflectionBuilder builder = new ReflectionBuilder();
 
@@ -86,7 +81,6 @@ class ReflectionBuilderTest {
         assertTrue cbean1.compositeBeanMap['cbean2'].compositeBeanArray[0].simpleBean.name
== 'sbean1'
     }
 
-    @Test
     //asserts SHIRO-305: https://issues.apache.org/jira/browse/SHIRO-305
     void testNestedMapAssignmentWithPeriodDelimitedKeys() {
         def ini = new Ini()
@@ -106,7 +100,6 @@ class ReflectionBuilderTest {
         assertEquals 'plain ssl', ldapRealm.contextFactory.environment['com.sun.jndi.ldap.connect.pool.protocol']
     }
 
-    @Test
     void testSimpleConfig() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
@@ -124,7 +117,6 @@ class ReflectionBuilderTest {
         assertEquals(compositeBean.getIntProp(), 42);
     }
 
-    @Test
     void testWithConfiguredNullValue() {
         Map<String,Object> defaults = new LinkedHashMap<String,Object>();
         CompositeBean cBean = new CompositeBean();
@@ -148,7 +140,6 @@ class ReflectionBuilderTest {
         assertNull(compositeBean.getSimpleBean());
     }
 
-    @Test
     void testWithConfiguredNullLiteralValue() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
@@ -166,7 +157,6 @@ class ReflectionBuilderTest {
         assertEquals("null", compositeBean.getStringProp());
     }
 
-    @Test
     void testWithConfiguredEmptyStringValue() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
@@ -184,7 +174,6 @@ class ReflectionBuilderTest {
         assertEquals("", compositeBean.getStringProp());
     }
 
-    @Test
     void testWithConfiguredEmptyStringLiteralValue() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
@@ -202,7 +191,6 @@ class ReflectionBuilderTest {
         assertEquals("\"\"", compositeBean.getStringProp());
     }
 
-    @Test
     void testSimpleConfigWithDollarSignStringValue() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
@@ -215,7 +203,6 @@ class ReflectionBuilderTest {
         assertEquals(compositeBean.getStringProp(), '$500');
     }
 
-    @Test
     void testObjectReferenceConfig() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("simpleBean", "org.apache.shiro.config.SimpleBean");
@@ -237,7 +224,6 @@ class ReflectionBuilderTest {
         assertEquals(simpleBean.getIntProp(), 101);
     }
 
-    @Test
     void testObjectReferenceConfigWithTypeMismatch() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("simpleBean", "org.apache.shiro.config.SimpleBean");
@@ -251,7 +237,6 @@ class ReflectionBuilderTest {
         }
     }
 
-    @Test
     void testObjectReferenceConfigWithInvalidReference() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("simpleBean", "org.apache.shiro.config.SimpleBean");
@@ -265,7 +250,6 @@ class ReflectionBuilderTest {
         }
     }
 
-    @Test
     void testSetProperty() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
@@ -282,31 +266,6 @@ class ReflectionBuilderTest {
         assertEquals(2, simpleBeans.size());
     }
 
-    @Test
-    //SHIRO-423
-    void testSetPropertyWithReferencedSet() {
-        def set = [new SimpleBean('foo'), new SimpleBean('bar')] as Set
-
-        def defs = [
-            compositeBean: 'org.apache.shiro.config.CompositeBean',
-            'compositeBean.simpleBeanSet': '$set'
-        ]
-
-        ReflectionBuilder builder = new ReflectionBuilder(['set': set]);
-        Map objects = builder.buildObjects(defs);
-        assertFalse(CollectionUtils.isEmpty(objects));
-        CompositeBean cBean = (CompositeBean) objects.get("compositeBean");
-        assertNotNull(cBean);
-        Set<SimpleBean> simpleBeans = cBean.getSimpleBeanSet();
-        assertNotNull(simpleBeans);
-        assertSame set, simpleBeans
-        assertEquals(2, simpleBeans.size());
-        def i = simpleBeans.iterator()
-        assertEquals 'foo', i.next().name
-        assertEquals 'bar', i.next().name
-    }
-
-    @Test
     void testListProperty() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
@@ -323,30 +282,6 @@ class ReflectionBuilderTest {
         assertEquals(3, simpleBeans.size());
     }
 
-    @Test
-    //SHIRO-423
-    void testListPropertyWithReferencedList() {
-        List list = [new SimpleBean('foo'), new SimpleBean('bar')] as List
-
-        def defs = [
-            compositeBean: 'org.apache.shiro.config.CompositeBean',
-            'compositeBean.simpleBeanList': '$list'
-        ]
-
-        ReflectionBuilder builder = new ReflectionBuilder(['list': list]);
-        Map objects = builder.buildObjects(defs);
-        assertFalse(CollectionUtils.isEmpty(objects));
-        CompositeBean cBean = (CompositeBean) objects.get("compositeBean");
-        assertNotNull(cBean);
-        def simpleBeans = cBean.getSimpleBeanList();
-        assertNotNull(simpleBeans);
-        assertSame list, simpleBeans
-        assertEquals(2, simpleBeans.size());
-        assertEquals 'foo', simpleBeans[0].name
-        assertEquals 'bar', simpleBeans[1].name
-    }
-
-    @Test
     void testCollectionProperty() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
@@ -364,31 +299,6 @@ class ReflectionBuilderTest {
         assertEquals(3, simpleBeans.size());
     }
 
-    @Test
-    //SHIRO-423
-    void testCollectionPropertyWithReferencedCollection() {
-        def c = [new SimpleBean('foo'), new SimpleBean('bar')]
-
-        def defs = [
-            compositeBean: 'org.apache.shiro.config.CompositeBean',
-            'compositeBean.simpleBeanCollection': '$collection'
-        ]
-
-        ReflectionBuilder builder = new ReflectionBuilder(['collection': c]);
-        Map objects = builder.buildObjects(defs);
-        assertFalse(CollectionUtils.isEmpty(objects));
-        CompositeBean cBean = (CompositeBean) objects.get("compositeBean");
-        assertNotNull(cBean);
-        def simpleBeans = cBean.getSimpleBeanCollection();
-        assertNotNull(simpleBeans);
-        assertSame c, simpleBeans
-        assertEquals(2, simpleBeans.size());
-        def i  = simpleBeans.iterator()
-        assertEquals 'foo', i.next().name
-        assertEquals 'bar', i.next().name
-    }
-
-    @Test
     void testByteArrayHexProperty() {
         String source = "Hello, world.";
         byte[] bytes = CodecSupport.toBytes(source);
@@ -409,7 +319,6 @@ class ReflectionBuilderTest {
         assertEquals(source, reconstituted);
     }
 
-    @Test
     void testByteArrayBase64Property() {
         String source = "Hello, world.";
         byte[] bytes = CodecSupport.toBytes(source);
@@ -428,7 +337,6 @@ class ReflectionBuilderTest {
         assertEquals(reconstituted, source);
     }
 
-    @Test
     void testMapProperty() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
@@ -449,30 +357,6 @@ class ReflectionBuilderTest {
         assertTrue(value instanceof SimpleBean);
     }
 
-    @Test
-    //SHIRO-423
-    void testMapPropertyWithReferencedMap() {
-        def map = ['foo': new SimpleBean('foo'), 'bar': new SimpleBean('bar')]
-
-        def defs = [
-            compositeBean: 'org.apache.shiro.config.CompositeBean',
-            'compositeBean.simpleBeanMap': '$map'
-        ]
-
-        ReflectionBuilder builder = new ReflectionBuilder(['map': map]);
-        Map objects = builder.buildObjects(defs);
-        assertFalse(CollectionUtils.isEmpty(objects));
-        CompositeBean cBean = (CompositeBean) objects.get("compositeBean");
-        assertNotNull(cBean);
-        def simpleBeansMap = cBean.getSimpleBeanMap();
-        assertNotNull(simpleBeansMap);
-        assertSame map, simpleBeansMap
-        assertEquals(2, simpleBeansMap.size());
-        assertEquals 'foo', simpleBeansMap['foo'].name
-        assertEquals 'bar', simpleBeansMap['bar'].name
-    }
-
-    @Test
     void testNestedListProperty() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("simpleBean1", "org.apache.shiro.config.SimpleBean");
@@ -493,19 +377,6 @@ class ReflectionBuilderTest {
         assertEquals(2, children.size());
     }
 
-    @Test
-    //asserts SHIRO-413
-    void testInitializable() {
-        def defs = [
-                initializableBean: 'org.apache.shiro.config.InitializableBean'
-        ]
-        def builder = new ReflectionBuilder()
-        def objects = builder.buildObjects(defs)
-        def bean = objects.get('initializableBean') as InitializableBean
-        assertTrue bean.isInitialized()
-    }
-
-    @Test
     void testFactoryInstantiation() {
         Map<String, String> defs = new LinkedHashMap<String, String>();
         defs.put("simpleBeanFactory", "org.apache.shiro.config.SimpleBeanFactory");
@@ -523,4 +394,82 @@ class ReflectionBuilderTest {
         assertEquals(5, bean.getIntProp());
         assertEquals("someString", bean.getStringProp());
     }
+
+    void testBeanListeners() {
+        Map<String, String> defs = new LinkedHashMap<String, String>();
+        defs.put("listenerOne", RecordingBeanListener.class.getName());
+        defs.put("listenerTwo", RecordingBeanListener.class.getName());
+
+        defs.put("simpleBeanFactory", "org.apache.shiro.config.SimpleBeanFactory");
+        defs.put("simpleBeanFactory.factoryInt", "5");
+        defs.put("simpleBeanFactory.factoryString", "someString");
+        defs.put("compositeBean", "org.apache.shiro.config.CompositeBean");
+        defs.put("compositeBean.simpleBean", '$simpleBeanFactory');
+
+        ReflectionBuilder builder = new ReflectionBuilder();
+        Map<String, ?> objects = builder.buildObjects(defs);
+        assertFalse(CollectionUtils.isEmpty(objects));
+
+        assertInstantiatedEvents("listenerOne", objects);
+        assertConfiguredEvents("listenerOne", objects, true);
+        assertInstantiatedEvents("listenerTwo", objects);
+        assertConfiguredEvents("listenerTwo", objects, false);
+
+        builder.destroy();
+
+        assertDestroyedEvents("listenerOne", objects);
+        assertDestroyedEvents("listenerTwo", objects);
+    }
+
+    void assertInstantiatedEvents(String name, Map<String, ?> objects) {
+        Object bean = objects.get(name);
+        assertTrue("Bean " + name + " is not a " + RecordingBeanListener.class.getSimpleName(),
+                bean instanceof RecordingBeanListener);
+        List<BeanEvent> instantiatedEvents = bean.getInstantiateEvents();
+        assertEquals(2, instantiatedEvents.size())
+
+        checkType(name, instantiatedEvents, "simpleBeanFactory", SimpleBeanFactory.class);
+        checkType(name, instantiatedEvents, "compositeBean", CompositeBean.class);
+
+        // instantiate notifications do not occur for listeners
+    }
+
+    void assertConfiguredEvents(String name, Map<String, ?> objects, boolean includeListener)
{
+        Object bean = objects.get(name);
+        assertTrue("Bean " + name + " is not a " + RecordingBeanListener.class.getSimpleName(),
+                bean instanceof RecordingBeanListener);
+        List<BeanEvent> configuredEvents = bean.getConfiguredEvents();
+        assertEquals(includeListener ? 3 : 2, configuredEvents.size())
+
+        checkType(name, configuredEvents, "simpleBeanFactory", SimpleBeanFactory.class);
+        checkType(name, configuredEvents, "compositeBean", CompositeBean.class);
+        if(includeListener) {
+            checkType(name, configuredEvents, "listenerTwo", RecordingBeanListener.class);
+        }
+    }
+
+    void assertDestroyedEvents(String name, Map<String, ?> objects) {
+        Object bean = objects.get(name);
+        assertTrue("Bean " + name + " is not a " + RecordingBeanListener.class.getSimpleName(),
+                bean instanceof RecordingBeanListener);
+        List<BeanEvent> configuredEvents = bean.getDestroyedEvents();
+        assertEquals(4, configuredEvents.size())
+
+        checkType(name, configuredEvents, "simpleBeanFactory", SimpleBeanFactory.class);
+        checkType(name, configuredEvents, "compositeBean", CompositeBean.class);
+        checkType(name, configuredEvents, "listenerOne", RecordingBeanListener.class);
+        checkType(name, configuredEvents, "listenerTwo", RecordingBeanListener.class);
+    }
+
+    void checkType(String instanceName, List<BeanEvent> events, String name, Class<?>
expectedType) {
+        for(BeanEvent event: events) {
+            if(event.getBeanName().equals(name)) {
+                assertTrue("Notification for bean " + name + " did not provide an instance
of " + expectedType
+                        + " to listener " + instanceName,
+                expectedType.isInstance(event.getBean()))
+                return;
+            }
+        }
+        fail("No bean named " + name + " was ever notified to listener " + instanceName +
".");
+    }
 }

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/core/src/test/java/org/apache/shiro/config/RecordingBeanListener.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/shiro/config/RecordingBeanListener.java b/core/src/test/java/org/apache/shiro/config/RecordingBeanListener.java
new file mode 100644
index 0000000..82a2f13
--- /dev/null
+++ b/core/src/test/java/org/apache/shiro/config/RecordingBeanListener.java
@@ -0,0 +1,51 @@
+package org.apache.shiro.config;
+
+import org.apache.shiro.config.event.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RecordingBeanListener extends BeanListenerSupport {
+
+    private List<InstantiatedBeanEvent> instantiateEvents = new ArrayList<InstantiatedBeanEvent>();
+    private List<ConfiguredBeanEvent> configuredEvents = new ArrayList<ConfiguredBeanEvent>();
+    private List<DestroyedBeanEvent> destroyedEvents = new ArrayList<DestroyedBeanEvent>();
+
+    private List<BeanEvent> unhandledEvents = new ArrayList<BeanEvent>();
+
+    @Override
+    protected void onUnhandledBeanEvent(BeanEvent beanEvent) {
+        this.unhandledEvents.add(beanEvent);
+    }
+
+    @Override
+    protected void onInstantiatedBeanEvent(InstantiatedBeanEvent beanEvent) {
+        this.instantiateEvents.add(beanEvent);
+    }
+
+    @Override
+    protected void onConfiguredBeanEvent(ConfiguredBeanEvent beanEvent) {
+        this.configuredEvents.add(beanEvent);
+    }
+
+    @Override
+    protected void onDestroyedBeanEvent(DestroyedBeanEvent beanEvent) {
+        this.destroyedEvents.add(beanEvent);
+    }
+
+    public List<InstantiatedBeanEvent> getInstantiateEvents() {
+        return instantiateEvents;
+    }
+
+    public List<ConfiguredBeanEvent> getConfiguredEvents() {
+        return configuredEvents;
+    }
+
+    public List<DestroyedBeanEvent> getDestroyedEvents() {
+        return destroyedEvents;
+    }
+
+    public List<BeanEvent> getUnhandledEvents() {
+        return unhandledEvents;
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/0a886db6/samples/web/src/main/webapp/WEB-INF/shiro.ini
----------------------------------------------------------------------
diff --git a/samples/web/src/main/webapp/WEB-INF/shiro.ini b/samples/web/src/main/webapp/WEB-INF/shiro.ini
index 60ff990..46d1e1b 100644
--- a/samples/web/src/main/webapp/WEB-INF/shiro.ini
+++ b/samples/web/src/main/webapp/WEB-INF/shiro.ini
@@ -21,6 +21,8 @@
 # http://shiro.apache.org/web.html for more.
 
 [main]
+listener = org.apache.shiro.config.event.LoggingBeanListener
+
 shiro.loginUrl = /login.jsp
 
 # We need to set the cipherKey, if you want the rememberMe cookie to work after restarting
or on multiple nodes.


Mime
View raw message