2

i would like to have some global results in my application. In good old XML configuration it would look like:

<global-results>
  <result name="error" type="redirectAction">
    <param name="actionName">index</param>
    <param name="namespace">/</param>
  </result>
</global-results>

But as I'm using the convention plugin the global results in the XML seem to be ignored so how could I implement this using the convention plugin? I don't want to have all my action classes extend a custom class that has those global results defined. I think the package-info.java should be my friend but all i can define there having something to do with results is @org.apache.struts2.convention.annotation.ResultPath.

Just to make clear: I don't want to avoid struts.xml configuration - I just want to have some working global forwards so in case of an error in any action i want to forward the user to a central error page. This is currently not working with my configuration. If you see the problem in my struts.xml or my action and can help me to fix it it would be perfectly fine.

Maybe the order in the struts.xml matters? Here's the structure of my struts.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
  <constant name="struts.devMode" value="false" />
  <constant name="struts.convention.result.path" value="/content/"/>
  <constant name="struts.convention.default.parent.package" value="my-package"/>
  <constant name="struts.convention.package.locators.disable" value="true"/>
  <constant name="struts.convention.action.packages" value="..."/>
  <constant name="struts.custom.i18n.resources" value="global" />
  <constant name="struts.multipart.maxSize" value="10485760" />
  <package name="my-package" extends="struts-default,json-default" namespace="/">
    <result-types>
      <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult"/>
    </result-types>

    <interceptors>
      <interceptor name="login" class="loginInterceptor" />
      <interceptor name="pagetitle" class="pagetitleInterceptor"></interceptor>

      <interceptor-stack name="secureStack">
        ...
      </interceptor-stack>

      <interceptor-stack name="insecureStack">
        ...
      </interceptor-stack>
    </interceptors>

    <default-interceptor-ref name="secureStack" />

    <global-results>
      <result name="error" type="redirectAction">
        <param name="actionName">index</param>
        <param name="namespace">/</param>
      </result>
    </global-results>
  </package>
</struts>

in my action I have:

public class MyActionClass extends ActionSupport {
  @Actions({ @Action(value = "my-action", results = { @Result(name = "success", type = "tiles", location = "my.location") }) })
  public final String myAction() throws Exception {
    return ERROR;
  }
}

of course myAction has more functionality - this is just for illustration. When the action is executed it forwards to the my-action.jsp without using tiles but I expected it to forward to /index.action.

Roman C
  • 49,761
  • 33
  • 66
  • 176
LordHelmchen
  • 149
  • 3
  • 12
  • http://stackoverflow.com/a/16934584/1654265 – Andrea Ligios Sep 27 '13 at 08:15
  • sorry, i don't see the connection to my question, the only thing i found was the statement: _using Convention plugin does not mean you don't have a struts.xml; it means that ... when some struts configuration **not** action-related ... you absolutely can use struts.xml_ – LordHelmchen Sep 27 '13 at 09:27
  • Yes. The other question starts from the opposite point of view: you are saying ***(how) Can I avoid using struts.xml for global results with Convention Plugin ?*** while the question linked said ***(how) Can I use struts.xml for global results with Convention Plugin?***. But the answer is the same: ***Convention Plugin or not, global results (can and) must be put in the `struts.xml`***. That is straight, if you think about it: in which action should you put a *global* result ? – Andrea Ligios Sep 27 '13 at 09:34
  • Well regarding to: [Convention Plugin Documentation](http://struts.apache.org/release/2.3.x/docs/convention-plugin.html#ConventionPlugin-Resultannotation): _From 2.1.7 on, global results (defined on the class level) defined using annotations will be inherited._ So it sounds to me as i can for example have a base action which all of my actions extend and then i have a global result. The other idea was the package-info.java. – LordHelmchen Sep 27 '13 at 09:46
  • i think it is already in my question: _I don't want to have all my action classes extend a custom class that has those global results defined_ ;) – LordHelmchen Sep 27 '13 at 09:54
  • DTD 2.1 ? Which version of Struts2 are you using ? Which error is giving to you now while redirecting to ERROR ? Does it work if, instead of a redirectAction, you return an "error.jsp" from the "error" result ? Are you sure that you are not referencing circularly the index action in the wrong Interceptor Stack ? (Interceptor Stack detects you are not logged -> returns error -> redirects to index -> Interceptor Stack detects you are not logged -> returns error -> redirects to index ... ) – Andrea Ligios Sep 27 '13 at 12:07
  • ...updated Struts (to 2.3) but forgot about the DTD - fixed it. Unfortunately there is no error _"When the action is executed it forwards to the my-action.jsp"_ it ignores the global forward from struts.xml - even when i use a non existent actionName there is no error it is just ignored. – LordHelmchen Sep 27 '13 at 13:31

3 Answers3

1

Unfortunately you can't define the Result or Results annotation on the package using convention plugin. You have to define global results in xml configuration and they aren't ignored because the runtime configuration is defined regardless which configuration provider you use. The workaround is to define Result or Results on the base class.

Roman C
  • 49,761
  • 33
  • 66
  • 176
1

You are defining a global-result in a package. These kind of results(global) are global only to the package they are defined in. So only those actions which are also declared in the same package can access these global-results. You have two options in front of you:


XML Configuration:

It's very obvious how to do it in XML configuration(you just define them in the same package):

<package name="my-package" extends="struts-default,json-default" namespace="/">

    <!-- This result is local to this action -->
    <action name="someAction"class="com.example.SomeAction" method="execute">
        <result name="someLocalResult">/localResult.jsp</result>
    </action>
    .
    .
    .
    <global-results>
        <!--This result is global **to the actions in my-package** -->
        <result name="error" type="redirectAction">
            <param name="actionName">index</param>
            <param name="namespace">/</param>
        </result>
    </global-results>

</package>

Convention Plugin:

So if you're using convention plugin to only mark your java classes as actions, you are not defining a package for them to rest in(They will belong to the default package). To do so, you can use the annotation @ParentPackage to tell the framework that this action belongs to this package and can use it's global-results. In order to achieve this, your java class should look like this:

@ParentPackage(value="my-pacakge")
public class MyActionClass extends ActionSupport {
    @Actions({ @Action(value = "my-action", results = { @Result(name = "success", type = "tiles", location = "my.location") }) })
    public final String myAction() throws Exception {
        return ERROR;
    }
}

Your struts.xml will remain the same:

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <package name="my-package" extends="struts-default,json-default" namespace="/"> 
        .
        .
        . 
        <global-results> 
             <result name="error" type="redirectAction"> 
                 <param name="actionName">index</param> 
                 <param name="namespace">/</param> 
             </result> 
         </global-results> 
     </package> 
 </struts>

A similar alternative solution to get rid of setting every action's @ParentPackage is to set the actions default pacakge to your favorite package(Here, the package containing the global-result). Just add this constant element to your struts.xml (inside of <struts>) and you'll be fine:

<constant name="struts.convention.default.parent.package" value="my-package"/>

Here is a useful link about @ParentPackage:

  1. @ParentPackage annotation from apache
Community
  • 1
  • 1
Amir Qasemi
  • 70
  • 2
  • 10
0

Well regarding to: Convention Plugin Documentation:

From 2.1.7 on, global results (defined on the class level) defined using annotations will be inherited.

So it sounds to me as i can for example have a base action which all of my actions extend and then i have a global result. The other idea was the package-info.java.

The same documentation says:

The Convention plugin allows action classes to define different results for an action. Results fall into two categories, global and local. Global results are shared across all actions defined within the action class. These results are defined as annotations on the action class. Local results apply only to the action method they are defined on. Here is an example of the different types of result annotations`

So I think they are a different concept from the standard Local Result and Global Result.

Standard Struts:

  1. Global Result is visible to each Action / Interceptor defined in the package;
  2. Local Result is visible to that Action only (but to all methods if invoked with Dynamic Method Invocation);
  3. Local Result is visible to that Action and Method only, if the method is included in the Action tag in struts.xml (then you would have multiple action tags for the same Action class and different methods).

I think that With Convention, Global is (2.) and Local is (3.) They're both local to the Action, but global is returnable from each method, while local only from the specific method who defined it.

Community
  • 1
  • 1
Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
  • i'm perfectly with you - but unfortunately i don't see how this could help me with my problem to have one global forward that i can use in different action classes. – LordHelmchen Sep 27 '13 at 10:34
  • Not always the answer can be "you can do like that". This is a "you CAN'T do it" answer, that (unless it is proven wrong) perfectly answer the question. Note that even the Base Action extended by all action with a global result will not make that result *really* a Struts2 Global Result, it will be a "locally global" result to all actions that extends the base one. Not one interceptor or actions not extending the base one will be able to access it. Then, use struts.xml. BTW, for experience, global results are maximum 3-4 for project, otherwise there is something wrong (or special)... – Andrea Ligios Sep 27 '13 at 11:42
  • At least now we know why in Convention plugin documentation they are talking about "global *annotated* results", and what they are. – Andrea Ligios Sep 27 '13 at 11:46
  • you wrote "Then, use struts.xml." this is exactly what i tried but it didn't work for me (see my updated question). And your correct about the number of global results - i have exactly 3 in my project ;) – LordHelmchen Sep 27 '13 at 11:57