[ 
https://issues.apache.org/struts/browse/WW-3068?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=45813#action_45813
 ] 

Musachy Barroso commented on WW-3068:
-------------------------------------

The problem is that configuration is now unmodifiable, so adding a "fake" 
result to the result config map will cause an exception to be thrown. 

> ExecuteAndWaitInterceptor  
> org.apache.struts2.interceptor.ExecuteAndWaitInterceptor.doIntercept(ExecuteAndWaitInterceptor.java:256)
> -----------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: WW-3068
>                 URL: https://issues.apache.org/struts/browse/WW-3068
>             Project: Struts 2
>          Issue Type: Bug
>         Environment: 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)
> > 
>            Reporter: Martin Gainty
>
> 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)
>             {
>                 bp = getNewBackgroundProcess(name, actionInvocation, 
> threadPriority);
>                 session.put(KEY + name, bp);
>                 performInitialDelay(bp); // first time let some time pass 
> before showing wait page
>                 secondTime = false;
>             }
>             if ((!executeAfterValidationPass || !secondTime) && bp != null && 
> !bp.isDone()) {
>                 actionInvocation.getStack().push(bp.getAction());
>                 Map results = proxy.getConfig().getResults();
>                 if (!results.containsKey(WAIT)) {
>                     LOG.warn("ExecuteAndWait interceptor has detected that no 
> result named 'wait' is available. " +
>                             "Defaulting to a plain built-in wait page. It is 
> highly recommend you " +
>                             "provide an action-specific or global result 
> named '" + WAIT +
>                             "'! This requires FreeMarker support and won't 
> work if you don't have it installed");
>                     // no wait result? hmm -- let's try to do dynamically put 
> it in for you!
>                     ResultConfig rc = new ResultConfig.Builder(WAIT, 
> "org.apache.struts2.views.freemarker.FreemarkerResult")
>                             .addParams(Collections.singletonMap("location", 
> "/org/apache/struts2/interceptor/wait.ftl"))
>                             .build();
> /************ABOVE CODE causes abend************/
>                     results.put(WAIT, rc);
> //http://java.sun.com/j2se/1.4.2/docs/api/java/util/Map.html#put(java.lang.Object,%20java.lang.Object)
>                 }
>                 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) {
>                     throw bp.getException();
>                 }
>                 return bp.getResult();
>             } else {
>                 // this is the first instance of the interceptor and there is 
> no existing action
>                 // already run in the background, so let's just let this pass 
> through. We assume
>                 // the action invocation will be run in the background on the 
> subsequent pass through
>                 // this interceptor
>                 return actionInvocation.invoke();
>             }
>         }
>     }
> 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

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to