2

I want to share model(form data) among multiple requests so have implemented ScopedModelDriven Interceptor in the action class.

Below is my code

Model - EventSearchBean.java

public class EventSearchBean {

   private Integer eventId;

   private String location;

   //getters and setters

}

Action - EventSearchAction

public class EventSearchAction implements ScopedModelDriven<EventSearchBean>
{
   private EventSearchBean eventSearchBean;

   public static final String EVENT_MODEL_SESSION_KEY = "eventSearchBean"; 

   public EventSearchBean getModel() {
        return eventSearchBean;
   }

   public String getScopeKey() {
        return EVENT_MODEL_SESSION_KEY;
   }

   public void setModel(EventSearchBean eventSearchBean) {
        this.eventSearchBean = eventSearchBean;  
   }

   public void setScopeKey(String arg0) {
        // TODO Auto-generated method stub
   }

   public String execute();
   {
     String locale = eventSearchBean.getLocation();

     //Calling business service to fetch events based on location
     List<> eventList = eventManager.getEvents(locale);

     return "success";

   }
}

struts.xml

     <!-- old stack used for other action classes -->

    <interceptor-stack name="oldStack">
      <interceptor-ref name="servletConfig"/>
      <interceptor-ref name="modelDriven"/>
      <interceptor-ref name="exception"/>  
      <interceptor-ref name="fileUpload"/>
      <interceptor-ref name="params"/>
    </interceptor-stack>

   <!-- new stack used for EventSearchAction class -->
    <interceptor-stack name="newStack">
      <interceptor-ref name="servletConfig"/>
      <interceptor-ref name="scopedModelDriven"/>
      <interceptor-ref name="exception"/>  
      <interceptor-ref name="fileUpload"/>
      <interceptor-ref name="params"/>
    </interceptor-stack> 

    <action name="eventSearch" class="com.karthik.EventSearchAction">
       <interceptor-ref name="newStack">
         <param  name="scope">session</param>
         <param  name="name">eventSearchBean</param>
         <param  name="className">com.karthik.beans.EventSearchBean</param> 
       </interceptor-ref>
       <result name="success">/jsp/eventlist.jsp</result>
       <result name="error">/jsp/generalExceptionPage.jsp</result>
    </action>

1) New model is getting created on every request(Model data is not getting copied from session for subsequent request). What needs to be changed in code to put model in session scope?
How to make model behave like ActionForm of session scope in Struts1?

2) If I remove new operator in action class while declaring model, that is
private EventSearchBean eventSearchBean;
I get Null Pointer exception when I access model in action class.
How to declare/initialize model?

3) How to override/update model in session only when form is submitted in UI?

Karthik
  • 1,302
  • 5
  • 25
  • 56
  • Scoped model driven should be first, then you can pass some value, or better stop using model driven and inject the scope into the action and use it in the ui. One approach that to expose a session to the user I found in [this](http://stackoverflow.com/q/18237036/573032) question, another is [here](http://stackoverflow.com/q/17244036/573032). – Roman C Jan 19 '16 at 18:32

2 Answers2

2

Exploding the defaultStack, this is what you're defining:

<interceptor-stack name="defaultStack">
    <interceptor-ref name="exception"/>
    <interceptor-ref name="alias"/>
    <interceptor-ref name="servletConfig"/>
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="prepare"/>
    <interceptor-ref name="chain"/>
    <interceptor-ref name="scopedModelDriven"/> <!-- here -->
    <interceptor-ref name="modelDriven"/>
    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="datetime"/>
    <interceptor-ref name="multiselect"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="actionMappingParams"/>
    <interceptor-ref name="params"/>
    <interceptor-ref name="conversionError"/>
    <interceptor-ref name="validation">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="workflow">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="debugging"/>
    <interceptor-ref name="deprecation"/>
</interceptor-stack>

<interceptor-ref name="scopedModelDriven">
    <param  name="scope">session</param>
    <param  name="name">eventSearchBean</param>
    <param  name="className">com.karthik.beans.EventSearchBean</param> 
</interceptor-ref>

As you can see, it already includes the ScopedModelDriven Interceptor. Hence you are defining it twice, the first time in the defaultStack, the second one manually, but only the second has the parameters set, the first has everything empty :)

Then, instead of

<interceptor-ref name="defaultStack"/>
<interceptor-ref name="scopedModelDriven">
    <param  name="scope">session</param>
    <param  name="name">eventSearchBean</param>
    <param  name="className">com.karthik.beans.EventSearchBean</param> 
</interceptor-ref>

just use

<interceptor-ref name="defaultStack">
    <param  name="scopedModelDriven.scope">session</param>
    <param  name="scopedModelDriven.name">eventSearchBean</param>
    <param  name="scopedModelDriven.className">com.karthik.beans.EventSearchBean</param> 
</interceptor-ref>
Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
  • Thanks. Made the correction. But still new model is getting created for every request(Session data is not getting copied). I suspect the new operator in action class is creating model for every request. – Karthik Jan 19 '16 at 17:12
  • Also, I would like to know to how to override session values. If some value(location) is passed from form, the location property of the model(EventSearchBean) in the session should be updated . – Karthik Jan 19 '16 at 17:33
  • Are you defining the above interceptor stack (and have you updated it correctly, as specified in the answer) in EVERY action you're running ? Or do you have it (updated) only in some of them ? You need it everywhere, set it as default interceptor stack – Andrea Ligios Jan 19 '16 at 17:50
  • I have updated my post. I am not using default stack for EventSearchAction. I am using custom stack for EventSearchAction. I have used another custom stack which contains model driven interceptor for other action classes. I have also removed new operator for initializing model in the action class. – Karthik Jan 20 '16 at 05:01
  • @Karthik: If you are using another stack that contains Model Driven interceptor (and not Scoped Model Driven interceptor), how on earth are you expecting it to work ? You can get the auto-population of the model only when communicating between actions running stacks with ScopedModelDriven (and with the same parameters). Also note that you're missing important interceptors like `workflow` ([read here why](http://stackoverflow.com/a/23450365/1654265)), and that `exception` should be put as first, so he can catch every exception when coming back from the action, after the method execution – Andrea Ligios Jan 20 '16 at 08:56
  • I am talking about the stack('newStack') that contains Scoped Model Driven interceptor without model driven interceptor. I know it wont work without Scoped Model driven interceptor but I thought it will work without ModelDriven interceptor as scoped model driven interceptor extends it. Model Driven interceptor must be in stack besides Scoped model driven interceptor for it to work. – Karthik Jan 20 '16 at 09:05
0
    <interceptor-stack name="newStack">
       <interceptor-ref name="servletConfig"/>
       <interceptor-ref name="scopedModelDriven"/>
       <interceptor-ref name="modelDriven"/>
       <interceptor-ref name="exception"/>  
       <interceptor-ref name="fileUpload"/>
       <interceptor-ref name="params"/>
    </interceptor-stack> 

    <action name="eventSearch" class="com.karthik.EventSearchAction">
       <interceptor-ref name="newStack">
         <param name="scopedModelDriven.scope">session</param>
         <param name="scopedModelDriven.name">eventSearchBean</param>
         <param name="scopedModelDriven.className">com.karthik.beans.EventSearchBean</param> 
       </interceptor-ref>
       <result name="success">/jsp/eventlist.jsp</result>
       <result name="error">/jsp/generalExceptionPage.jsp</result>
    </action>

The following changes were made in the code:

  • If custom stack is used, the custom stack should contain modelDriven interceptor besides scopedModelDriven interceptor.

  • If the params are specified inside the action class as shown above, the params must be prefixed with scopedModelDriven. That is, scopedModelDriven.paramName whereas if scopedModelDriven params are specified within the interceptor stack outside action class, prefix is not required.

  • The model in the action class must not be initialized with new operator. The model has to be just declared. That is, private EventSearchBean eventSearchBean;

Karthik
  • 1,302
  • 5
  • 25
  • 56