Revision: 1011
          http://stripes.svn.sourceforge.net/stripes/?rev=1011&view=rev
Author:   bengunter
Date:     2008-11-25 20:06:56 +0000 (Tue, 25 Nov 2008)

Log Message:
-----------
STS-617: Added the ability to remove an ActionBean's URL binding to support 
projects like Freddy's Stripes Reload.

Modified Paths:
--------------
    
trunk/stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java
    trunk/stripes/src/net/sourceforge/stripes/controller/UrlBindingFactory.java

Modified: 
trunk/stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java
===================================================================
--- 
trunk/stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java
      2008-11-24 21:24:22 UTC (rev 1010)
+++ 
trunk/stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java
      2008-11-25 20:06:56 UTC (rev 1011)
@@ -116,7 +116,6 @@
         }
     }
 
-
     /**
      * Adds an ActionBean class to the set that this resolver can resolve. 
Identifies
      * the URL binding and the events managed by the class and stores them in 
Maps
@@ -161,6 +160,20 @@
     }
 
     /**
+     * Removes an ActionBean class from the set that this resolver can 
resolve. The URL binding
+     * and the events managed by the class are removed from the cache.
+     *
+     * @param clazz a class that implements ActionBean
+     */
+    protected void removeActionBean(Class<? extends ActionBean> clazz) {
+        String binding = getUrlBinding(clazz);
+        if (binding != null) {
+            UrlBindingFactory.getInstance().removeBinding(clazz);
+        }
+        eventMappings.remove(clazz);
+    }
+
+    /**
      * Returns the URL binding that is a substring of the path provided. For 
example, if there
      * is an ActionBean bound to [EMAIL PROTECTED] /user/Profile.action} the 
path
      * [EMAIL PROTECTED] /user/Profile.action/view} would return [EMAIL 
PROTECTED] /user/Profile.action}.

Modified: 
trunk/stripes/src/net/sourceforge/stripes/controller/UrlBindingFactory.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/controller/UrlBindingFactory.java 
2008-11-24 21:24:22 UTC (rev 1010)
+++ trunk/stripes/src/net/sourceforge/stripes/controller/UrlBindingFactory.java 
2008-11-25 20:06:56 UTC (rev 1011)
@@ -22,6 +22,7 @@
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -339,35 +340,112 @@
      * @param binding the URL binding
      */
     public void addBinding(Class<? extends ActionBean> beanType, UrlBinding 
binding) {
-        // The binding path with trailing slash, used several times below
-        String pathPlusSlash = binding.getPath();
-        if (!pathPlusSlash.endsWith("/"))
-            pathPlusSlash = pathPlusSlash + '/';
+        for (String path : getCachedPaths(binding)) {
+            cachePath(path, binding);
+        }
+        for (String prefix : getCachedPrefixes(binding)) {
+            cachePrefix(prefix, binding);
+        }
+        classCache.put(beanType, binding);
+    }
 
+    /**
+     * Removes an [EMAIL PROTECTED] ActionBean}'s URL binding.
+     * 
+     * @param beanType the [EMAIL PROTECTED] ActionBean} class
+     */
+    public synchronized void removeBinding(Class<? extends ActionBean> 
beanType) {
+        UrlBinding binding = classCache.get(beanType);
+        if (binding == null)
+            return;
+
+        Set<UrlBinding> resolvedConflicts = null;
+        for (String path : getCachedPaths(binding)) {
+            log.debug("Clearing cached path ", path, " for ", binding);
+            pathCache.remove(path);
+
+            List<String> conflicts = pathConflicts.get(path);
+            if (conflicts != null) {
+                log.debug("Removing ", binding, " from conflicts list ", 
conflicts);
+                conflicts.remove(binding.toString());
+
+                if (conflicts.size() == 1) {
+                    if (resolvedConflicts == null) {
+                        resolvedConflicts = new LinkedHashSet<UrlBinding>();
+                    }
+
+                    resolvedConflicts.add(pathCache.get(conflicts.get(0)));
+                    conflicts.clear();
+                }
+
+                if (conflicts.isEmpty())
+                    pathConflicts.remove(path);
+            }
+        }
+
+        for (String prefix : getCachedPrefixes(binding)) {
+            Set<UrlBinding> bindings = prefixCache.get(prefix);
+            if (bindings != null) {
+                log.debug("Clearing cached prefix ", prefix, " for ", binding);
+                bindings.remove(binding);
+                if (bindings.isEmpty())
+                    prefixCache.remove(prefix);
+            }
+        }
+
+        classCache.remove(beanType);
+
+        if (resolvedConflicts != null) {
+            log.debug("Resolved conflicts with ", resolvedConflicts);
+
+            for (UrlBinding conflict : resolvedConflicts) {
+                removeBinding(conflict.getBeanType());
+                addBinding(conflict.getBeanType(), conflict);
+            }
+        }
+    }
+
+    /**
+     * Get a list of the request paths that will be wired directly to an 
ActionBean. In some cases,
+     * a single path might be valid for more than one ActionBean. In such a 
case, a warning will be
+     * logged at startup and an exception will be thrown if the conflicting 
path is requested.
+     */
+    protected Set<String> getCachedPaths(UrlBinding binding) {
+        Set<String> paths = new TreeSet<String>();
+
         // Wire some paths directly to the ActionBean (path, path + /, path + 
suffix, etc.)
-        cachePath(binding.getPath(), binding);
-        if (!binding.getPath().equals(pathPlusSlash))
-            cachePath(pathPlusSlash, binding);
+        paths.add(binding.getPath());
+        paths.add(binding.toString());
+        if (!binding.getPath().endsWith("/"))
+            paths.add(binding.getPath() + '/');
         if (binding.getSuffix() != null)
-            cachePath(binding.getPath() + binding.getSuffix(), binding);
-        if (!binding.toString().equals(binding.getPath()))
-            cachePath(binding.toString(), binding);
+            paths.add(binding.getPath() + binding.getSuffix());
 
-        // Pick out the first component if it is a literal
-        String leadingLiteral = null;
+        return paths;
+    }
+
+    /**
+     * Get a list of the request path prefixes that <em>could</em> map to an 
ActionBean. A single
+     * prefix may map to multiple ActionBeans. In such a case, we attempt to 
determine the best
+     * match based on the literal strings and parameters defined in the 
ActionBeans' URL bindings.
+     * If no single ActionBean is determined to be a best match, then an 
exception is thrown to
+     * report the conflict.
+     */
+    protected Set<String> getCachedPrefixes(UrlBinding binding) {
+        Set<String> prefixes = new TreeSet<String>();
+
+        // Add binding as a candidate for some prefixes (path + /, path + 
leading literal, etc.)
+        if (binding.getPath().endsWith("/"))
+            prefixes.add(binding.getPath());
+        else
+            prefixes.add(binding.getPath() + '/');
+
         List<Object> components = binding.getComponents();
-        if (components != null && !components.isEmpty() && components.get(0) 
instanceof String)
-            leadingLiteral = (String) components.get(0);
+        if (components != null && !components.isEmpty() && components.get(0) 
instanceof String) {
+            prefixes.add(binding.getPath() + components.get(0));
+        }
 
-        // Map some prefixes to the binding
-        String pathPlusLiteral = binding.getPath() + leadingLiteral;
-        if (leadingLiteral != null)
-            cachePrefix(pathPlusLiteral, binding);
-        if (!pathPlusSlash.equals(pathPlusLiteral))
-            cachePrefix(pathPlusSlash, binding);
-
-        // Map the ActionBean to its binding
-        classCache.put(beanType, binding);
+        return prefixes;
     }
 
     /**


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to