Revision: 1019
http://stripes.svn.sourceforge.net/stripes/?rev=1019&view=rev
Author: bengunter
Date: 2008-12-23 16:24:56 +0000 (Tue, 23 Dec 2008)
Log Message:
-----------
Applied fix for STS-617 from trunk
Modified Paths:
--------------
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/StripesRequestWrapper.java
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/UrlBindingFactory.java
branches/1.5.x/stripes/src/net/sourceforge/stripes/util/UrlBuilder.java
Added Paths:
-----------
branches/1.5.x/stripes/src/net/sourceforge/stripes/exception/UrlBindingConflictException.java
Modified:
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java
===================================================================
---
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java
2008-12-23 16:01:51 UTC (rev 1018)
+++
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/AnnotatedClassActionResolver.java
2008-12-23 16:24:56 UTC (rev 1019)
@@ -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 {...@code /user/Profile.action} the path
* {...@code /user/Profile.action/view} would return {...@code
/user/Profile.action}.
@@ -172,7 +185,7 @@
*/
public String getUrlBindingFromPath(String path) {
UrlBinding mapping =
UrlBindingFactory.getInstance().getBindingPrototype(path);
- return mapping == null ? null : mapping.getPath();
+ return mapping == null ? null : mapping.toString();
}
/**
@@ -186,7 +199,7 @@
*/
public String getUrlBinding(Class<? extends ActionBean> clazz) {
UrlBinding mapping =
UrlBindingFactory.getInstance().getBindingPrototype(clazz);
- return mapping == null ? null : mapping.getPath();
+ return mapping == null ? null : mapping.toString();
}
/**
@@ -275,8 +288,7 @@
*/
public ActionBean getActionBean(ActionBeanContext context) throws
StripesServletException {
HttpServletRequest request = context.getRequest();
- UrlBinding binding =
UrlBindingFactory.getInstance().getBindingPrototype(request);
- String path = binding == null ? HttpUtil.getRequestedPath(request) :
binding.getPath();
+ String path = HttpUtil.getRequestedPath(request);
ActionBean bean = getActionBean(context, path);
request.setAttribute(RESOLVED_ACTION, getUrlBindingFromPath(path));
return bean;
@@ -524,7 +536,8 @@
ActionBeanContext context) {
Map<String,Method> mappings = this.eventMappings.get(bean);
String path = HttpUtil.getRequestedPath(context.getRequest());
- String binding = getUrlBindingFromPath(path);
+ UrlBinding prototype =
UrlBindingFactory.getInstance().getBindingPrototype(path);
+ String binding = prototype == null ? null : prototype.getPath();
if (binding != null && path.length() != binding.length()) {
String extra = path.substring(binding.length() + 1);
Modified:
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/StripesRequestWrapper.java
===================================================================
---
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/StripesRequestWrapper.java
2008-12-23 16:01:51 UTC (rev 1018)
+++
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/StripesRequestWrapper.java
2008-12-23 16:24:56 UTC (rev 1019)
@@ -35,6 +35,7 @@
import net.sourceforge.stripes.action.FileBean;
import net.sourceforge.stripes.controller.multipart.MultipartWrapper;
import net.sourceforge.stripes.exception.StripesServletException;
+import net.sourceforge.stripes.exception.UrlBindingConflictException;
/**
* HttpServletRequestWrapper that is used to make the file upload
functionality transparent.
@@ -466,8 +467,15 @@
* {...@link Map}. If no parameters are present in the URI, then return
null.
*/
Map<String, String[]> getUriParameters(HttpServletRequest request) {
+ UrlBinding binding = null;
+ try {
+ binding = UrlBindingFactory.getInstance().getBinding(request);
+ }
+ catch (UrlBindingConflictException e) {
+ // This can be safely ignored
+ }
+
Map<String, String[]> params = null;
- UrlBinding binding =
UrlBindingFactory.getInstance().getBinding(request);
if (binding != null && binding.getParameters().size() > 0) {
for (UrlBindingParameter p : binding.getParameters()) {
String name = p.getName();
Modified:
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/UrlBindingFactory.java
===================================================================
---
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/UrlBindingFactory.java
2008-12-23 16:01:51 UTC (rev 1018)
+++
branches/1.5.x/stripes/src/net/sourceforge/stripes/controller/UrlBindingFactory.java
2008-12-23 16:24:56 UTC (rev 1019)
@@ -22,16 +22,21 @@
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;
import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.exception.StripesRuntimeException;
+import net.sourceforge.stripes.exception.UrlBindingConflictException;
import net.sourceforge.stripes.util.HttpUtil;
+import net.sourceforge.stripes.util.Log;
import net.sourceforge.stripes.util.bean.ParseException;
/**
@@ -54,6 +59,8 @@
* @see UrlBindingParameter
*/
public class UrlBindingFactory {
+ private static final Log log = Log.getInstance(UrlBindingFactory.class);
+
/** Singleton instance */
private static final UrlBindingFactory instance = new UrlBindingFactory();
@@ -72,8 +79,11 @@
/** Maps simple paths to {...@link UrlBinding}s */
private final Map<String, UrlBinding> pathCache = new HashMap<String,
UrlBinding>();
+ /** Keeps a list of all the paths that could not be cached due to
conflicts between URL bindings */
+ private final Map<String, List<String>> pathConflicts = new
HashMap<String, List<String>>();
+
/** Holds the set of paths that are cached, sorted from longest to
shortest */
- private final Map<String, UrlBinding> prefixCache = new TreeMap<String,
UrlBinding>(
+ private final Map<String, Set<UrlBinding>> prefixCache = new
TreeMap<String, Set<UrlBinding>>(
new Comparator<String>() {
public int compare(String a, String b) {
int cmp = b.length() - a.length();
@@ -123,17 +133,82 @@
public UrlBinding getBindingPrototype(String uri) {
// Look for an exact match to the URI first
UrlBinding prototype = pathCache.get(uri);
- if (prototype != null)
+ if (prototype != null) {
+ log.debug("Matched ", uri, " to ", prototype);
return prototype;
+ }
+ else if (pathConflicts.containsKey(uri)) {
+ throw new UrlBindingConflictException(uri, pathConflicts.get(uri));
+ }
- // Then look for a matching prefix
- for (Entry<String, UrlBinding> entry : prefixCache.entrySet()) {
+ // Get all the bindings whose prefix matches the URI
+ Set<UrlBinding> candidates = null;
+ for (Entry<String, Set<UrlBinding>> entry : prefixCache.entrySet()) {
if (uri.startsWith(entry.getKey())) {
- prototype = entry.getValue();
+ candidates = entry.getValue();
break;
}
}
+ // If none matched or exactly one matched then return now
+ if (candidates == null) {
+ log.debug("No URL binding matches ", uri);
+ return null;
+ }
+ else if (candidates.size() == 1) {
+ log.debug("Matched ", uri, " to ", candidates);
+ return candidates.iterator().next();
+ }
+
+ // Now find the one that matches deepest into the URI with the fewest
components
+ int maxIndex = 0, minComponents = Integer.MAX_VALUE;
+ List<String> conflicts = null;
+ for (UrlBinding binding : candidates) {
+ int idx = binding.getPath().length();
+ List<Object> components = binding.getComponents();
+ int componentCount = components.size();
+
+ for (Object component : components) {
+ if (!(component instanceof String))
+ continue;
+
+ int at = uri.indexOf((String) component, idx);
+ if (at >= 0) {
+ idx = at + ((String) component).length();
+ }
+ else {
+ break;
+ }
+ }
+
+ if (idx == maxIndex) {
+ if (componentCount < minComponents) {
+ conflicts = null;
+ minComponents = componentCount;
+ prototype = binding;
+ }
+ else if (componentCount == minComponents) {
+ if (conflicts == null) {
+ conflicts = new ArrayList<String>(candidates.size());
+ conflicts.add(prototype.toString());
+ }
+ conflicts.add(binding.toString());
+ prototype = null;
+ }
+ }
+ else if (idx > maxIndex) {
+ conflicts = null;
+ minComponents = componentCount;
+ prototype = binding;
+ maxIndex = idx;
+ }
+ }
+
+ log.debug("Matched @", maxIndex, " ", uri, " to ", prototype == null ?
conflicts : prototype);
+ if (prototype == null) {
+ throw new UrlBindingConflictException(uri, conflicts);
+ }
+
return prototype;
}
@@ -265,17 +340,188 @@
* @param binding the URL binding
*/
public void addBinding(Class<? extends ActionBean> beanType, UrlBinding
binding) {
- pathCache.put(binding.getPath(), binding);
+ /*
+ * Search for a class that has already been added with the same name
as the class being
+ * added now. If one is found then remove its information first and
then proceed with adding
+ * it. I know this is not technically correct because two classes from
two different class
+ * loaders can have the same name, but this feature is valuable for
extensions that reload
+ * classes and I consider it highly unlikely to be a problem in
practice.
+ */
+ Class<? extends ActionBean> existing = null;
+ for (Class<? extends ActionBean> c : classCache.keySet()) {
+ if (c.getName().equals(beanType.getName())) {
+ existing = c;
+ break;
+ }
+ }
+ if (existing != null)
+ removeBinding(existing);
+
+ // And now we can safely add the class
+ for (String path : getCachedPaths(binding)) {
+ cachePath(path, binding);
+ }
+ for (String prefix : getCachedPrefixes(binding)) {
+ cachePrefix(prefix, binding);
+ }
+ classCache.put(beanType, binding);
+ }
+
+ /**
+ * Removes an {...@link ActionBean}'s URL binding.
+ *
+ * @param beanType the {...@link 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.)
+ paths.add(binding.getPath());
+ paths.add(binding.toString());
+ if (!binding.getPath().endsWith("/"))
+ paths.add(binding.getPath() + '/');
if (binding.getSuffix() != null)
- pathCache.put(binding.getPath() + binding.getSuffix(),
binding);
- prefixCache.put(binding.getPath() + '/', binding);
+ paths.add(binding.getPath() + binding.getSuffix());
+
+ 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)
- prefixCache.put(binding.getPath() + components.get(0), binding);
- classCache.put(beanType, binding);
+ if (components != null && !components.isEmpty() && components.get(0)
instanceof String) {
+ prefixes.add(binding.getPath() + components.get(0));
+ }
+
+ return prefixes;
}
/**
+ * Map a path directly to a binding. If the path matches more than one
binding, then a warning
+ * will be logged indicating such a condition, and the path will not be
cached for any binding.
+ *
+ * @param path The path to cache
+ * @param binding The binding to which the path should map
+ */
+ protected void cachePath(String path, UrlBinding binding) {
+ if (pathCache.containsKey(path)) {
+ UrlBinding conflict = pathCache.put(path, null);
+ List<String> list = pathConflicts.get(path);
+ if (list == null) {
+ list = new ArrayList<String>();
+ list.add(conflict.toString());
+ pathConflicts.put(path, list);
+ }
+ log.warn("The path ", path, " for ",
binding.getBeanType().getName(), " @ ", binding,
+ " conflicts with ", list);
+ list.add(binding.toString());
+ }
+ else {
+ log.debug("Wiring path ", path, " to ",
binding.getBeanType().getName(), " @ ", binding);
+ pathCache.put(path, binding);
+ }
+ }
+
+ /**
+ * Add a binding to the set of bindings associated with a prefix.
+ *
+ * @param prefix The prefix to cache
+ * @param binding The binding to map to the prefix
+ */
+ protected void cachePrefix(String prefix, UrlBinding binding) {
+ log.debug("Wiring prefix ", prefix, "* to ",
binding.getBeanType().getName(), " @ ", binding);
+
+ // Look up existing set of bindings to which the prefix maps
+ Set<UrlBinding> bindings = prefixCache.get(prefix);
+
+ // If necessary, create and store a new set of bindings
+ if (bindings == null) {
+ bindings = new TreeSet<UrlBinding>(new Comparator<UrlBinding>() {
+ public int compare(UrlBinding o1, UrlBinding o2) {
+ int cmp = o1.getComponents().size() -
o2.getComponents().size();
+ if (cmp == 0)
+ cmp = o1.toString().compareTo(o2.toString());
+ return cmp;
+ }
+ });
+ prefixCache.put(prefix, bindings);
+ }
+
+ // Add the binding to the set
+ bindings.add(binding);
+ }
+
+ /**
* Parse a binding pattern and create a {...@link UrlBinding} object.
*
* @param beanType the {...@link ActionBean} type whose binding is to be
parsed
Added:
branches/1.5.x/stripes/src/net/sourceforge/stripes/exception/UrlBindingConflictException.java
===================================================================
---
branches/1.5.x/stripes/src/net/sourceforge/stripes/exception/UrlBindingConflictException.java
(rev 0)
+++
branches/1.5.x/stripes/src/net/sourceforge/stripes/exception/UrlBindingConflictException.java
2008-12-23 16:24:56 UTC (rev 1019)
@@ -0,0 +1,130 @@
+/* Copyright 2008 Ben Gunter
+ *
+ * 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 net.sourceforge.stripes.exception;
+
+import java.util.Collection;
+
+import net.sourceforge.stripes.action.ActionBean;
+
+/**
+ * <p>
+ * This exception indicates that a URL does not contain enough information to
map it to a single
+ * {...@link ActionBean} class. In some cases, a URL may match more than one
URL binding.
+ * </p>
+ * <p>
+ * For example, suppose you have two ActionBeans with the URL bindings
<code>/foo/{param}/bar</code>
+ * and <code>/foo/{param}/blah</code>. The paths {...@code /foo} and {...@code
/foo/X} -- while legal,
+ * since any number of parameters or literals may be omitted from the end of a
clean URL -- match
+ * both of the URL bindings. Since Stripes cannot determine from the URL the
ActionBean to which to
+ * dispatch the request, it throws this exception to indicate the conflict.
+ * </p>
+ *
+ * @author Ben Gunter
+ * @since Stripes 1.5.1
+ */
+public class UrlBindingConflictException extends StripesRuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ /** Generate the message to pass to the superclass constructor */
+ protected static String getMessage(Class<? extends ActionBean>
targetClass, String path,
+ Collection<String> matches) {
+ return (targetClass == null ? "" : "Failure generating URL for " +
targetClass + ". ")
+ + "The path " + path + " cannot be mapped to a single
ActionBean because multiple "
+ + "URL bindings match it. The matching URL bindings are " +
matches + ". If you "
+ + "generated the URL using the Stripes tag library
(stripes:link, stripes:url, "
+ + "stripes:form, etc.) then you must embed enough
stripes:param tags within the "
+ + "parent tag to produce a URL that maps to exactly one of the
indicated matches. "
+ + "If you generated the URL by some other means, then you must
embed enough "
+ + "information in the URL to achieve the same end.";
+ }
+
+ private String path;
+ private Collection<String> matches;
+ private Class<? extends ActionBean> targetClass;
+
+ /**
+ * New exception indicating that the {...@code path} does not map to a
single ActionBean because it
+ * potentially matches all the URL bindings in the {...@code matches}
collection.
+ *
+ * @param message An informative message about what went wrong
+ * @param targetClass The class for which a URL could not be generated.
+ * @param path The offending path
+ * @param matches A collection of all the potentially matching URL bindings
+ */
+ public UrlBindingConflictException(String message, Class<? extends
ActionBean> targetClass,
+ String path, Collection<String> matches) {
+ super(message);
+ this.targetClass = targetClass;
+ this.path = path;
+ this.matches = matches;
+ }
+
+ /**
+ * New exception indicating that the {...@code path} does not map to a
single ActionBean because it
+ * potentially matches all the URL bindings in the {...@code matches}
collection.
+ *
+ * @param targetClass The class for which a URL could not be generated.
+ * @param path The offending path
+ * @param matches A collection of all the potentially matching URL bindings
+ */
+ public UrlBindingConflictException(Class<? extends ActionBean>
targetClass, String path,
+ Collection<String> matches) {
+ this(getMessage(targetClass, path, matches), targetClass, path,
matches);
+ }
+
+ /**
+ * New exception indicating that the {...@code path} does not map to a
single ActionBean because it
+ * potentially matches all the URL bindings in the {...@code matches}
collection.
+ *
+ * @param message An informative message about what went wrong
+ * @param path The offending path
+ * @param matches A collection of all the potentially matching URL bindings
+ */
+ public UrlBindingConflictException(String message, String path,
Collection<String> matches) {
+ this(message, null, path, matches);
+ }
+
+ /**
+ * New exception indicating that the {...@code path} does not map to a
single ActionBean because it
+ * potentially matches all the URL bindings in the {...@code matches}
collection.
+ *
+ * @param path The offending path
+ * @param matches A collection of all the potentially matching URL bindings
+ */
+ public UrlBindingConflictException(String path, Collection<String>
matches) {
+ this(getMessage(null, path, matches), path, matches);
+ }
+
+ /** Get the path that failed to map to a single ActionBean */
+ public String getPath() {
+ return path;
+ }
+
+ /** Get all the URL bindings on existing ActionBeans that match the path */
+ public Collection<String> getMatches() {
+ return matches;
+ }
+
+ /**
+ * Get the {...@link ActionBean} class for which a URL was being generated
when this exception was
+ * thrown. If the exception occurred while dispatching a request, then
this property will be
+ * null since the path cannot be associated with an ActionBean class.
However, if it is thrown
+ * while generating a URL that is intended to point to an ActionBean, then
this property will
+ * indicate the class that was being targeted.
+ */
+ public Class<? extends ActionBean> getTargetClass() {
+ return targetClass;
+ }
+}
Modified:
branches/1.5.x/stripes/src/net/sourceforge/stripes/util/UrlBuilder.java
===================================================================
--- branches/1.5.x/stripes/src/net/sourceforge/stripes/util/UrlBuilder.java
2008-12-23 16:01:51 UTC (rev 1018)
+++ branches/1.5.x/stripes/src/net/sourceforge/stripes/util/UrlBuilder.java
2008-12-23 16:24:56 UTC (rev 1019)
@@ -30,6 +30,7 @@
import net.sourceforge.stripes.controller.UrlBindingFactory;
import net.sourceforge.stripes.controller.UrlBindingParameter;
import net.sourceforge.stripes.exception.StripesRuntimeException;
+import net.sourceforge.stripes.exception.UrlBindingConflictException;
import net.sourceforge.stripes.format.Formatter;
import net.sourceforge.stripes.format.FormatterFactory;
import net.sourceforge.stripes.validation.ValidationMetadata;
@@ -366,8 +367,14 @@
Map<String, ValidationMetadata> validations = null;
Configuration configuration = StripesFilter.getConfiguration();
if (configuration != null) {
- Class<? extends ActionBean> beanType =
configuration.getActionResolver()
- .getActionBeanType(this.baseUrl);
+ Class<? extends ActionBean> beanType = null;
+ try {
+ beanType =
configuration.getActionResolver().getActionBeanType(this.baseUrl);
+ }
+ catch (UrlBindingConflictException e) {
+ // This can be safely ignored
+ }
+
if (beanType != null) {
validations =
configuration.getValidationMetadataProvider().getValidationMetadata(
beanType);
@@ -443,11 +450,23 @@
* @see #UrlBuilder(Locale, String, boolean)
*/
protected String getBaseURL(String baseUrl, Collection<Parameter>
parameters) {
- UrlBinding binding =
UrlBindingFactory.getInstance().getBindingPrototype(baseUrl);
+ UrlBinding binding = null;
+ try {
+ binding =
UrlBindingFactory.getInstance().getBindingPrototype(baseUrl);
+ }
+ catch (UrlBindingConflictException e) {
+ // This can be safely ignored
+ }
+
if (binding == null || binding.getParameters().size() == 0) {
return baseUrl;
}
+ // if we have a parameterized binding then we need to trim it down to
the path
+ if (baseUrl.equals(binding.toString())) {
+ baseUrl = binding.getPath();
+ }
+
// if any extra path info is present then do not add URI parameters
if (binding.getPath().length() < baseUrl.length()) {
return baseUrl;
@@ -520,6 +539,20 @@
buf.append(binding.getSuffix());
}
- return buf.toString();
+ // Test the URL to make sure it won't throw an exception when Stripes
tries to dispatch it
+ String url = buf.toString();
+ try {
+
StripesFilter.getConfiguration().getActionResolver().getActionBeanType(url);
+ }
+ catch (UrlBindingConflictException e) {
+ if (binding != null) {
+ UrlBindingConflictException tmp = new
UrlBindingConflictException(binding
+ .getBeanType(), e.getPath(), e.getMatches());
+ tmp.setStackTrace(e.getStackTrace());
+ e = tmp;
+ }
+ throw e;
+ }
+ return url;
}
}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development