I have a LoginAction class in which I have three methods execute(), read() and write(). Inside the execute method I'm calling read and writ methods using:
LoginAction l1 = new LoginAction();l1.read();l1.write(null);
execute file-----upload file from directory.
read and write------------read uploaded file and convert it into excel.
In my struts.xml I wrote these steps for calling these methods.
action name="login" class="net.myapp.struts.LoginAction"
method="execute"
but at run time only one method (execute method) is working. How can I call all the methods?
My methods are:
public String execute() throws Exception
boolean write(List<String> l1) throws Exception
public String Read() throws Exception
form tag. s:form action="login1" method="post" enctype="multipart/form-data"
namespace="/".
for this we can use chaining in Struts 2. One action leads to another one and so on.
Request>Action1>Action2>Action3>Response.
http://viralpatel.net/blogs/struts-2-action-chaining-example/
Related
I am trying to find the replacement for org.apache.struts.actions.DispatchAction.types in Struts2.
Below code snippet:
if(types != null)
{
if(types.length == forward.length)
{
select.add(type[0]);
}
}
The forward is a string type object and select is a list type array.
The documentation for DispatchAction.types:
types
protected java.lang.Class[] types
The set of argument type classes for the reflected method call. These are the same for all calls, so calculate them only once.
There's not the same thing in Struts2. You should refresh your mind to understand that struts2 works differently than struts-1.
For example you can map your actions directly to the method. You can use SMI for method call like in this answer
You should place the annotation directly on the method. Because if you put it on the class the default method execute() is used for the mapping.
#ParentPackage("basePackage")
#Namespace("/")
#AllowedMethods("test")
public class UserAction {
#Action(value = "userAction")
public String test() {
// your code
rerurn Action.SUCCESS;
}
}
or use wildcard mapping like this answer.
The action name is overridden if used in the same package. The action name maps to a specific method or execute.
You can use wildcard mapping to put a method name in the action.
<action name="*product" class="com.DispatchAction" method="{1}">
public class UserAction{
private UserData user;
//getter, setter
public String Load() {
user = UserDao.getInstance().getItem(getUserContext().getId());
request.getSession().setAttribute("item", user);
return super.Load();
}
}
public class PropertyAction {
private List <PropertyData> propertyList;
//getter, setter
#Override
public String execute() throws Exception {
propertyList=PropertyDao.getInstance().getItems();
return "list";
}
}
jsp:
<s:iterator value="propertyList" var="item">
${item.name}
${item.thema}
${item.desc}
</s:iterator>
I want to show very strange behaviour of Struts2.
I click property link -> then run PropertyAction.execute() and it display above jsp.
I click user link -> then run UserAction.Load()
I click property link -> then run PropertyAction.execute() and error has been shown "UserData has no property thema".
I spy what happened and I notice that I set setAttribute with name "item". So if I use var="item" in my iterator in jsp, it doesn not use value from propertyList but from session !
My question is it is correct behaviour ?
This is defined behavior; whether or not it's "correct" is debatable.
Because you're using JSP EL, the Struts request wrapper is responsible for resolving JSP EL expressions. The normal application scopes are searched first (e.g., application, session, request). If nothing is found, only then will the value stack be queried for matching expressions.
If you accessed item via non-JSP EL means, e.g., the <s:property> tag, only the value stack would be queried, and you'd get the expected behavior.
When you mix ELs results are not always what you'd expect, so you must be aware how the frameworks in question relate to each other.
I'm trying to write a test method for one of my controller methods.
Here is the controller method
public ActionResult LicenseDetails(Guid id)
{
var licenseDetails = _businessUnitRepository.GetLicenseDetails(id);
return View(licenseDetails);
}
and here is the test i've written to check if it calls the method in repository.
[TestMethod]
public void ModuleDetails_Action_Calls_GetLicenseDetails()
{
_mockBusinessUnitRepository.GetLicenseDetails(Arg<Guid>.Is.Anything);
_controller.LicenseDetails(Arg<Guid>.Is.Anything);
_mockBusinessUnitRepository.AssertWasCalled(x=>x.GetLicenseDetails(Arg<Guid>.Is.Anything));
}
I'm getting error right now that says:
Test method AdminPortal.Tests.Controller_Test.Customer.BusinessUnitControllerTests.ModuleDetails_Action_Calls_GetLicenseDetails threw exception:
System.InvalidOperationException: Use Arg ONLY within a mock method call while recording. 1 arguments expected, 3 have been defined.
Ps: I'm using Rhino mock and i'm new to this testing thing
I think it is complaining about this line:
_controller.LicenseDetails(Arg<Guid>.Is.Anything);
Instead of doing that, try passing in an actual value:
_controller.LicenseDetails(Guid.NewGuid());
in jsf2 if we have some function like
public String greeting(String gtr) {
return "Hello " + gtr;
}
then from jsf page we can call this function as
<h:outputLabel value="#{greetingBean.greeting['some-name']}"
now my question is i want to pass the dynamic parameter from the same bean class instead of 'some-name' something like value="#{greetingBean.greeting[greetingBean.name]} is it possible ?
i required this because i have value in Map<String, ArrayList> and want to edit particular ArrayList value ?
any suggestions ?
Brackets are used to replace the dot notation. That is,
#{greetingBean.greeting['some-name']}
is the same as
#{greetingBean.greeting.some-name}
So, the greeting method will not be called. Instead, JSF will try to access a greeting property, and then try to access a some-name property of the object returned by greeting property. That is, your code above is already generating an error.
If you are using EL 2.2 and want to call an action, simply put:
#{greetingBean.greeting('some-name')}
or
#{greetingBean.greetingThatReceivesAMap(greetingBean.name)}
I was wondering if I can capture the result of an action after the result returns and the JSP is rendered. I want to be able to take the entire result (generated HTML) and push it into memcached so I can bring it via Nginx with-out hitting the application server. Any ideas?
PS: I know I can run the interceptor after the action executes but before the result returns and the JSP is rendered, but not after the JSP is rendered.
I haven't found a way to do this inside of struts2, your best bet it to create a servlet Filter and have it modify the OutputStream.
http://onjava.com/pub/a/onjava/2003/11/19/filters.html
Hey I know its quite late now to answer you might have already found out the answer, however for others to benefit I am posting the answer.
One thing that is very similar to what you are doing is done by sitemesh filter.
Yes, filter comes before and after the Struts2 filter itself, so you can mess with the inputs and outputs easily.
But struts does evaluate JSP/freemarker/velocity and generate the final html which is passed to the user. JSP is a bit trickey because internally a servlet is called but check out org.apache.struts2.views.freemarker.FreemarkerResult class, you can see the actual html getting generated in template.process(model, writer);. This writer is actually ServletActionContext.getResponse().getWriter();
Now to get the html all you need to do is
ServletActionContext.getResponse().getWriter().toString() //This does not work out of box. To get the toString() to work you need to use a ResponseWrapper - which is the same method to get result html in Filters. See- Programming Customized Requests and Responses.
Listing to modify resulting html in struts 2. This is not tested, but it is extracted from my code I have written earlier for custom template engine. I will probably post full description in Custom template engine for struts2
public class DecoratorInterceptor implements Interceptor {
public String intercept(ActionInvocation invocation) throws Exception {
final ActionContext context = invocation.getInvocationContext ();
HttpServletResponse responseParent = (HttpServletResponse)
context.get(ServletActionContext.HTTP_RESPONSE);
CharResponseWrapper wrapper = new CharResponseWrapper(responseParent);
ServletActionContext.setResponse(wrapper);
//Actual Action called
String result = invocation.invoke();
String htmlReturned = wrapper.toString();
//play with htmlReturned ...
String modifiedhtml = pushintoMemCache(htmlReturned );
CharArrayWriter car = new CharArrayWriter();
car.write(modifiedhtml );
PrintWriter out = responseParent.getWriter();
out.write(car.toString());
out.flush();
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void init() {
// TODO Auto-generated method stub
}
}
Read this article - http://struts.apache.org/2.0.6/docs/interceptors.html
SUMMARY:When you request a resource
that maps to an "action", the
framework invokes the Action object.
But, before the Action is executed,
the invocation can be intercepted by
another object. After the Action
executes, the invocation could be
intercepted again. Unsurprisingly, we
call these objects "Interceptors."
Question: How do you determine if the view has been generated? Do you set a request header or an some sort of a flag to determine if the view has been generated?
You could try throwing a MemCachedException to indicate that it is time to load into a mem cache. Your interceptor code could read
try {
return invocation.invoke();
} catch (MemCachedException mce) {
// Your code to upload to MemCache.
} finally {
// blah blah clean up.
}
Within your interceptor's intercept() method, the ActionInvocation parameter has a getResult() method which returns null before Action execution (i. e. before you call invocation.invoke() in your intercept() method) and contains an implementation of Result afterwards. That object should give you some way to access the data you need, but how this is done probably depends on the class that is actually used.
See also my somewhat related question and the answer I posted after figuring it out.