You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@struts.apache.org by "Martin Gainty (JIRA)" <ji...@apache.org> on 2009/03/31 01:11:03 UTC

[jira] Created: (WW-3068) ExecuteAndWaitInterceptor org.apache.struts2.interceptor.ExecuteAndWaitInterceptor.doIntercept(ExecuteAndWaitInterceptor.java:256)

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.


[jira] Commented: (WW-3068) ExecuteAndWaitInterceptor org.apache.struts2.interceptor.ExecuteAndWaitInterceptor.doIntercept(ExecuteAndWaitInterceptor.java:256)

Posted by "Musachy Barroso (JIRA)" <ji...@apache.org>.
    [ 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.


[jira] Resolved: (WW-3068) ExecuteAndWaitInterceptor org.apache.struts2.interceptor.ExecuteAndWaitInterceptor.doIntercept(ExecuteAndWaitInterceptor.java:256)

Posted by "Musachy Barroso (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/struts/browse/WW-3068?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Musachy Barroso resolved WW-3068.
---------------------------------

       Resolution: Fixed
    Fix Version/s: 2.1.7

The solution is to create a FreeMarker result and delegate the rendering to it, instead of creating a FreeMarkerResult and adding it to the config (which causes the exception)

> 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
>             Fix For: 2.1.7
>
>
> 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.