How to lookup configured Struts action - java

I want to do the following:
final Action myAction = getActionDefinedInStrutsConfig(param);
myAction.execute(params);
Is there a way to lookup the actions that the ActionServlet has initialized ?
I can create a new one like so:
final Action myAction = new ActionImpl();
myAction.execute(params);
but this way the new action is not properly initialized, the attached servlet is not set and getServlet() returns null.
A little clarification on why I need this:
The problem is that I currently have 2 login pages. One for normal users and one for admins. They should be separate systems completely, but the fact is they're currently not. I need to make a 'proxy' login page which decides which login page to redirect to according to the request. If I redirect to the URL however the UI would be drawn. I need to call the either the user or admin login actions to process my proxy page request. Also moving the logic inside a service, while being the correct approach, is not currently an option.

Ok, since I see what you mean here's what I would suggest:
Use your action for validatory purposes, i.e., retrieval of data from ActionForm and checking for validity. Once all information is done, send the info to a service.
The service (need not to be a web service, but a simple POJO) will have the business logic of the application, with relevant exceptions and return types. Once you call the relevant service with its method, retrieve the result and, finally,
Populate your necessary ActionForm or do a mapping.findForward().
This way, if you need another business logic that is used by another Struts Action, rather call the service that the 2nd action uses. This is an effective way for code-reuse and good OOP practise.
Hope this helps.
The hackable way would be to do this:
final Action myAction = new ActionImpl();
myAction.setServlet(getServlet());
/* ONLY if your form enctype is "multipart/request-data". */
myAction.setMultipartRequestHandler(getMultipartRequestHandler());
//Finally
myAction.execute(params);

You can define actions in your forwards:
<action parameter="command" path="/firstAction"
input="firstAction.tiles" name="someForm" scope="session" validate="true" type="com.mycompany.FirstAction">
<forward name="toSecond" path="/secondAction.do?command=someMethod" redirect="true"/>
</action>
<action parameter="command" path="/secondAction" input="secondAction.tiles" name="someForm"
scope="session" validate="true" type="com.mycompany.SecondAction">
<forward name="backToFirst" path="/firstAction.do?command=myMethod" redirect="true" />
</action>
Now you can use mapping.findForward("toSecond"), in your first action and mapping.findForward("backToFirst") on the other.

Related

Struts2 - Validate error not refreshing on action tag call

I'm currently having a problem with my setup.
I have this action tag in my JSP
<s:action name="doLogin" executeResult="true"></s:action>
and below is the corresponding struts.xml entry
<action name="doLogin" class="siteLoginAction">
<result name="input">login</result>
<result name="success">home</result>
</action>
The jsp is just a login div (form, textfield, label).
Now the problem is that when I'm testing the validate function
#Override
public void validate() {
String username = siteUser.getSiteUserUsername();
String password = siteUser.getSiteUserPassword();
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
addFieldError("siteUser.siteUserUsername", "Invalid login");
} else if (!siteUserService.checkLoginExists(username, password, getBlogSiteUrl())) {
addFieldError("siteUser.siteUserPassword", "Invalid login");
}
}
As you can see it works,
but it will not go away. The error message will stay there everytime I visit that page.
Is this because of the singleton default model of the Struts2 action?
I have tried #Scope("prototype") but if I use it it doesn't display the error at all
I have this <s:action> tag in my JSP
You should not use that tag, it's an old and useless technology, drop it ASAYC.
Is this because of the singleton default model of the Struts2 action? I have tried #Scope("prototype") but if I use it it doesn't display the error at all
Actions are ThreadLocal. What you're referring to with "default model" is the default scope (Singleton) of a Spring bean, and hence of a Struts2 Action if managed by Spring. And it would be wrong, you should use scope="prototype" in that case, to make the Spring managed actions working correctly as ThreadLocal objects.
This question is not answerable more than this right now; just drop the <s:action/> tag, use scope="prototype" (or drop Spring, at least on actions handling) and see what happens, then if it still doesn't work, come back here and ask again: it will be easy to help you then.

Do I need to create a new Struts Action class for each and every request?

I am new to struts and I have a basic doubt in Struts.
I have created a new webpage which contains 10 links (link1, link2,......link10). When clicking on each link it should link to corresponding pages. My question is do I need to create 10 new Struts Action classes to perform redirection or do I have any other way that deals with single Struts Action class that can handle all the 10 links.
It dependents upon what all those 10 links will be doing.There are couple of options here.
If all you links are doing same type of work (e.g user related work), its better to create one action with multiple methods.
S2 provides way to define method for each action mapping and based on the method name S2 will call respected method of your action like
<action name="action1" class="myActionClass" method="method1"/>
<action name="action2" class="myActionClass" method="method2"/>
Note that create an Action class with method only if you have some sort of logic needs to be implemented before doing any redirect etc.
for simple one page to other page redirection S2 provides a very elegant way where it will create an empty Action with execute method on run time and will always return SUCCESSthis is what you need to do
<action name="Hello">
// ...
</action>
in above case If the class attribute in an action mapping is left blank, the com.opensymphony.xwork2.ActionSupport class is used as a default.
For detail refer to this page action-configuration
You are not required to make a separate action for each URL in Struts 2. You can work with a single class, Just make separate functions for each link.
Example action definition in struts.xml:
<action name="Link1" class="com.project.YourActionClass" method="handleLink1">
........
</action>
<action name="Link2" class="com.project.YourActionClass" method="handleLink2">
.........
</action>
It is not required to create separate action class for each link, we just need to configure the method name you would like to call on click on each link using the method attribute, one action class is sufficient and action mappings should be configured in struts.xml.
This is an advantage in struts2.xml, where as in struts1 I guess we need to use dispatch action in order to call a particular method.

Struts2 portlet is executing a default action on refresh of Liferay (instead of its current action)

EDIT: Edited title to reflect new findings. It doesn't matter what type of portlet the second portlet is. See general behavior below:
I have a Struts2 portlet A on the page, its default "index" action is pageA1.
I click a link on A1 and go to pageA2.
I refresh the page and the portlet A still shows pageA2.
There are other portlets on the page. I choose any one portlet B and click a link on B1.
Portlet B navigates to B2. Meanwhile, Liferay refreshes the other portlets on the page, including Struts2 portlet A.
Expected result after portlet A refresh is pageA2, however the page shown is pageA1!
Symptoms:
I added some logging to the struts action to display the parameters passed. During normal navigation (i.e. I'm just using the struts2 portlet A by itself), the parameters struts.portlet.action and struts.portlet.mode are displayed. However, if an auto-refresh occurs on struts2 portlet A due to another portlet B's render/action phase, those parameters don't seem to be passed to struts2, and thus the portlet A defaults back to its index pageA1, instead of the page shown before the refresh (pageA2).
Does this mean that since there is no struts.portlet.action param detected by struts2, it will call the default action (in this case, i set it to "index"->pageA1)?
Old Details
I have a project set up that has two portlets, both using the Struts2 framework. Both portlets are actually quite similar to each other, but their code exists in different packages, and in struts.xml, their Actions are defined in separate modules with their own namespaces. They are still part of one project, though, and are packaged together in a single WAR file.
I deploy the WAR to Liferay, and add both portlets to a single page. The following behavior occurs when I use the two portlets:
Click a link on Portlet A.
Portlet A loads into screen A2.
Click a link on Portlet B.
Portlet B loads into screen B2.
However, as a side effect, Portlet A refreshes and the screen shown is its "index" page (instead of screen A2).
Is this the expected behavior, or is there anything else I should do to make this particular setup work in a single portal page?
EDIT:
The links I am clicking are renderURLs (generated using the s:url tag). The second page of both portlets contain forms, which I am not sure is of any significance.
I've added some simple logging, and based on it, I've discovered that on every page refresh, both portlets are being rendered twice. I don't think that's a natural behavior.
Here is my struts.xml if it's of any use:
<package name="portletA" extends="struts-portlet-default" namespace="/portletA">
<action name="index" class="my.a.DisplayFirstPageAction">
<result name="success">/pageA1.jsp</result>
</action>
<action name="displayForm" class="my.a.DisplaySecondPageAction">
<result name="input">/pageA2.jsp</result>
</action>
</package>
<package name="portletB" extends="struts-portlet-default" namespace="/portletB">
<action name="index" class="my.b.DisplayFirstPageAction">
<result name="success">/pageB1.jsp</result>
</action>
<action name="displayForm" class="my.b.DisplaySecondPageAction">
<result name="input">/pageB2.jsp</result>
</action>
</package>
On both portlets, pageA1.jsp has a link that calls the struts action "displayForm". The FirstPageAction's execute method returns SUCCESS, while the SecondPageAction's execute method returns INPUT.
I thought it might be because I don't have a "success" result in my second action (my execute() method returns "input" since I have a form in the page). Adding a result=success tag doesn't help, though.
Thinking out loud, if I click on A1's link while B2 is rendered, B2's render/execute action should be called, but it seems like B1's render/execute action is called instead.
Check http://www.liferay.com/documentation/liferay-portal/6.0/development/-/ai/understanding-the-two-phases-of-portlet-execution, specifically the paragraphs bellow:
The portlet specification defines two phases for every request of a portlet, to allow the portal to differentiate when an action is being performed (and should not be repeated) and when the content is being produced (rendered):
Action phase: The action phase can only be invoked for one portlet at
a time and is usually the result of an user interaction with the
portlet. In this phase the portlet can change its status, for
instance changing the user preferences of the portlet. It is also
recommended that any inserts and modifications in the database or
operations that should not be repeated are performed in this phase.
Render phase: The render phase is always invoked for all portlets in
the page after the action phase (which may or not exist). This
includes the portlet that also had executed its action phase. It's
important to note that the order in which the render phase of the
portlets in a page gets executedis not guaranteed by the portlet
specification. Liferay has an extension to the specification through
the element render-weight in liferay-portlet.xml. Portlets with a
higher render weight will be rendered before those with a lower
value.
[...]
There are three types of URLs that can be generated by a portlet:
renderURL: this is the type of URL that we have used so far. It invokes a portlet using only its render phase.
actionURL: this type of URL tells the portlet that it should execute its action phase before rendering all the portlets in the page.
resourceURL: this type of URL can be used to retrieve images, XML, JSON or any other type of resource. It is often used to generate images or other media types dynamically. It is very useful also to make AJAX requests to the server. The key difference of this URL type in comparison to the other two is that the portlet has full control of the data that will be sent in response.
So I guess you are using an actionURL to go to page A2 instead of a renderURL.

hiding contents of the URL in struts

I want to hide the parameters which are attached in my url .
My action is being hit from another website (URL redirection)
https://myserver/web/myaction.do?username=jhon&password=1234
on this action I simply redirect to a jsp
<action name="myaction" class="ncom.company.project.Head">
<result>/pages/HelloWorld.jsp</result>
</action>
on my jsp username and password are visible , i want to hide them
I guess you mean the parameters should not be visible in the URL, right? If so, you should do a real redirect, what you're doing is a actually forward.
In Struts 2 you'd use the "redirect" result type to send the redirect to the browser. The parameters should still be in your session/action context.
May I suggest that you use a POST request. As far as I can see from your question you're sending a GET request. That's why you can see the parameters in the URL. I don't think this is a struts-specific problem. It's part of HTTP. Just make the other website to use a POST request.
You might wanna take a look here too to find out the usage of both methods.
You can do 2 things here either the one like redirect but in that case it means creating a new request object and a new action instance in value-stack.
I believe that once application hits the myaction and once you have done the work you can use redirectAction by passing any any parameters you need (if any).
But just be clear that even redirectAction will create a new Request Cycle you can use redirectAction like
<action name="myaction" class="ncom.company.project.Head">
<result type="redirectAction">
<param name="actionName">redirectAction</param>
// any parameter you want
</result>
</action>
<action name="redirectAction">
<result>/pages/HelloWorld.jsp</result>
</action>
here are more details for the redirectAction
Redirect Action
hope it will help you

Struts JSP previous link

Does anyone know how I can retrieve the previous JSP URL that a page has come from within a JSP?
Can I retrieve this from the session/ request/ response object?
Hope this makes sense, Thank you
Many thanks - apologies for not being able to mark my correct answer as the site seems to have changed and i cant see how to do this but i used
Even simpler:
<%= request.getHeader("Referer") %>
(assuming Struts 1)
Well in the struts-config.xml there is a input parameter in the action element (in the action-mappings section)
So in your action (java class) you can access this value like this :
public ActionForward action(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
//do some stuff
return mapping.getInputForward(); //return to the caller
}
so if you want an action to return to its originating page, you can define
multiple action entry pointing to the same action but with a different name and input value.
Hope that helps.
Assuming that you are talking about navigating within your own application and assuming struts 2 you can pass a parameter to the action, lets call it next, with the name of the next action. Lets say you have an action defined in struts.xml:
<action name="myaction" class="com.me.MyActionClass">
<result name="success">${next}</result>
</action>
In MyActionClass you will have to declare the property next with its getters and setters. On invoking this action you must provide the value for next which could be the same name as the page from which you are invoking the action.
for example in referer i got the uri as http://www.sun.com/questions?pnr=18&value=gg
while i pront referer at that time i got this string ok. now i need to get the parameter value how to get it. from that string

Categories