Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
None
-
None
-
None
-
Struts-2.1.6
TC 6.0.14
JDK 1.6.0_10> Subject: Re: ExecuteAndWaitInterceptor not working (2.1.6)
> > execAndWait in 2.1.6 gives the following exception when it kicks in: (code pasted below)
> >
> >
> > java.lang.UnsupportedOperationException
> > ??? java.util.Collections$UnmodifiableMap.put(Collections.java:1285)
> > ??? org.apache.struts2.interceptor.ExecuteAndWaitInterceptor.doIntercept(ExecuteAndWaitInterceptor.java:256)
>Struts-2.1.6 TC 6.0.14 JDK 1.6.0_10 > Subject: Re: ExecuteAndWaitInterceptor not working (2.1.6) > > execAndWait in 2.1.6 gives the following exception when it kicks in: (code pasted below) > > > > > > java.lang.UnsupportedOperationException > > ??? java.util.Collections$UnmodifiableMap.put(Collections.java:1285) > > ??? org.apache.struts2.interceptor.ExecuteAndWaitInterceptor.doIntercept(ExecuteAndWaitInterceptor.java:256) >
Description
public static final String WAIT = "wait";
org.apache.struts2.interceptor.ExecuteAndWaitInterceptor.java
.............
protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
..............
//sync on the real HttpSession as the session from the context is a wrap that is created
//on every request
synchronized (httpSession)
{
BackgroundProcess bp = (BackgroundProcess) session.get(KEY + name);
if ((!executeAfterValidationPass || secondTime) && bp == null)
if ((!executeAfterValidationPass || !secondTime) && bp != null && !bp.isDone()) {
actionInvocation.getStack().push(bp.getAction());
Map results = proxy.getConfig().getResults();
if (!results.containsKey(WAIT))
if (TokenHelper.getToken() != null)
{ session.put(TokenHelper.getTokenName(), TokenHelper.getToken()); } return WAIT;
} else if ((!executeAfterValidationPass || !secondTime) && bp != null && bp.isDone()) {
session.remove(KEY + name);
actionInvocation.getStack().push(bp.getAction());
// if an exception occured during action execution, throw it here
if (bp.getException() != null)
return bp.getResult();
} else
}
}
where
Collections.singletonMap("location", "/org/apache/struts2/interceptor/wait.ftl"))
public static <K,V> Map<K,V> singletonMap(K key, V value)
{ 3343 return new SingletonMap<K,V>(key, value); 3344 }//Here is applicable SingletonMap
3349 private static class SingletonMap<K,V>
3350 extends AbstractMap<K,V>
3351 implements Serializable {
3352 private static final long serialVersionUID = -6979724477215052911L;
3353
3354 private final K k;
3355 private final V v;
3356
3357 SingletonMap(K key, V value) { 3358 k = key; 3359 v = value; 3360 }
//UnsupportedOperation details
The "destructive" methods contained in this interface, that is, the methods that modify the map on which they operate, are specified to throw UnsupportedOperationException if this map does not support the operation. If this is the case, these methods may, but are not required to, throw an UnsupportedOperationException if the invocation would have no effect on the map. For example, invoking the #putAll(Map) method on an unmodifiable map may, but is not required to, throw the exception if the map whose mappings are to be "superimposed" is empty.
//which calls Builder
http://struts.apache.org/2.1.6/struts2-core/apidocs/com/opensymphony/xwork2/config/entities/ResultConfig.Builder.html
//which calls addparams method which takes 2 String placeholders for Map
ResultConfig.Builder addParams(Map<String,String> params)
//the code calls singletonMap which is an immutable Map
3332 /**
3333 * Returns an immutable map, mapping only the specified key to the
3334 * specified value. The returned map is serializable.
3335 *
3336 * @param key the sole key to be stored in the returned map.
3337 * @param value the value to which the returned map maps <tt>key</tt>.
3338 * @return an immutable map containing only the specified key-value
3339 * mapping.
3340 * @since 1.3
3341 */
3342 public static <K,V> Map<K,V> singletonMap(K key, V value) { 3343 return new SingletonMap<K,V>(key, value); 3344 }
so the fix would be to replace
Collections.SingletonMap
.addParams(Collections.singletonMap("location", "/org/apache/struts2/interceptor/wait.ftl"))
with 2 plain strings for addParams e.g.
.addParams("location", "/org/apache/struts2/interceptor/wait.ftl"))
?
Martin