I'm new to Struts2.
How does one invoke methods from a class without using an ActionSupport-implemented-class? So a simple Java class.
It's because I want to add something to a include jsp file. Therefore this value is always valid - independent of the page one is requesting.
Probably simple.
You can write your Action without extending ActionSupport class.
ActionSupport is just for convenience
ActionSupport has default implementations of common methods (e.g., execute(), input()), gives access to Action.SUCCESS, Action.ERROR and other result names, etc.
Action Class:
public class TestAction
{
public String testMethod()
{
return "success";
}
}
Struts.xml:
<action name="TestAction" class="com.TestAction" method="testMethod">
<result name="success">Mypage.jsp</result>
</action>
Struts2 architecture does not require you to extend ActionSupport class. It is that flexible. ActionSupport is just a convenience and provides basic functionality like validation etc. You can write a simple pojo action class. All you need is to return a String that will be used to forward to a resource like jsp.
For Example
public class MyAction
{
public String testAction()
{
//Perform your logic here. Note it is not mandatory to return SUCCESS here, you can actually return any String here, but make sure you map that String to a resource in your `struts.xml`
return SUCCESS;
}
}
Related
I have two Struts2 actions and both actions are chained so that flow sequence with be
action1 ---> action2 ---> display.jsp
class Action1 extends ActionSupport
{
public String display()
{
Student stud = new Student();
stud.setName("I am from Action1");
//what should be done here so that I can get stud in another action via chain
return "success";
}
}
class Action2 extends ActionSupport
{
private Student stud;
//getter/setter
public String display()
{
Sting name = stud.getName();//getting NULL here
return "success";
}
}
I want to pass stud object from one action to another via chain.
My strut2.xml setting is as below
<action name="action1" class="com.internet.Action1" method="display">
<result name="success" type="chain">action2</result>
</action>
action name="action2" class="com.internet.Action2" method="display">
<result name="success" type="tiles">MyDiplayPage</result>
</action>
I have worked in spring 3.0 and I am uncomfortable with struts2 and trying to acquire comfort in that.. please help me to sort out the issue.
Maybe Chaining Interceptor is what you are looking for:
If you need to copy the properties from your previous Actions in the
chain to the current action, you should apply the Chaining
Interceptor. The Interceptor will copy the original parameters from
the request, and the ValueStack is passed in to the target Action. The
source Action is remembered by the ValueStack, allowing the target
Action to access the properties of the preceding Action(s) using the
ValueStack, and also makes these properties available to the final
result of the chain, such as the JSP or Velocity page.
You can access whatever you want from the Value Stack. Just push the Bean you want from one Action to it's Value Stack:
Map<String, Object> myValues = new HashMap<String, Object>();
myValues.put("key", myBean);
ActionContext.getContext().getValueStack().push(myValues);
Passing some values it's ok, but take care that excesive needing of passing information from one Action to another one, maybe could be a symptom that you need to re-think your Action's scope:
All the core logic should be pushed back to a support class or a
business facade, so that Actions only call methods. Actions are best
used as adapters, rather than as a class where coding logic is
defined.
Struts 2, 2.3.20 mentioned that
Support for accessing static methods from expression will be disabled
soon, please consider re-factoring your application to avoid further
problems!
We have used OGNL static calls in validators:
#ExpressionValidator(
expression = "#foo.bar#isValidAmount(amount)",
key = "validate.amount.is.not.valid"),
Also we used it in tags
<s:set var="test"
value="#foo.bar#sampleMethod(#attr.sampleObject.property1)" />
Well, what is the best way to refactor above two usages ?!
In your code you are using a static method call. The best way is to create a method in the action class that wraps a static methods and use it in OGNL.
public class Wrapper {
public boolean isValidAmount(amount){
return foo.barr.isValidAmount(amount);
}
public Object sampleMethod(Object property1){
return foo.barr.sampleMethod(Object property1);
}
}
As soon as action bean is in the value stack you can use
#ExpressionValidator(
expression = "isValidAmount(amount)",
key = "validate.amount.is.not.valid"),
or in JSP
<s:set var="test"
value="sampleMethod(#attr.sampleObject.property1)" />
I have two Struts2 actions. I want to use a public method of a action in another action. Is it Ok that I can call an action through new operator and call its public method? (For the sake of reusing some common functionality)
public class OneAction extends ActionSupport{
public void doSomeThing(){
// some code
}
public String execute(){
// some code
}
}
public class AnotherAction extends ActionSupport{
public String execute(){
/* is it ok?*/
new OneAction().doSomeThing();
}
}
(shudder) I would not. I'd refactor the common functionality into a separate class that both can call. But that class would be a POJO, not an Action.
I'd be careful about embedding functionality in Actions. I think they're firmly in the web tier camp. You should do little more than validate and bind parameters into objects, hand them off to POJOs for processing, and package results for return.
I plus-oned #duffymo's answer, but here's some more food for thought.
If the functionality is common across actions, it belongs in either a base action (if web-related), or a utility class (either web-related or not). Which makes the most sense depends a lot on context.
Along those contextual lines, depending on the actual functionality you're talking about, it might make more sense yet somewhere else--in an interceptor, an aspect, a mixin (how to do that depends on the implementation language), etc. Without knowing details, it's difficult to be more specific.
I have a search form that can search in different provider.
I started out by having a base controller
public SearchController : Controller
{
protected readonly ISearchService _searchService
public SearchController(ISearchService searchService)
{
_searchService= searchService;
}
public ActionResult Search(...)
{
// Use searchService to query and return a view.
}
}
And child controllers
TwitterController : SearchController
{
...
}
NewsController : SearchController
{
...
}
I use StructureMap to insert all my dependencies in the controller. With this setup, I was able to change the SearchService depending on the type of the controller being instanciated.
x.For<ISearchService>().ConditionallyUse(o =>
{
o.TheDefault.Is.OfConcreteType<NewsSearchService>();
o.If(c => c.ParentType == typeof(TwitterController))
.ThenIt.Is.OfConcreteType<TwitterSearchService>();
...
});
That even allowed me to set different Views for each controller, (just putting the corresponding folder (Twitter, News...) and the Parent controller is still handling all the Search, with a simple
return View(results)
which is displaying the correct view specific to twitter, news, or other
Now that was cool and looked great, I a single form and the different views are displayed in tabs on the same page. That's where it starts to get complicated with this approach. The form has to post to /Twitter to search in twitter, to /News to search in news... which means I should change the action parameter of the form depending on which tab I am and display the correct tab on when the form returns depending on.. the url? craziness follows.
If you have built something like this already or know what's the best approach to this, please advices are welcome.
Now I think I would have less pain using a parameter in the form and posting to a single controller. I am thinking of injecting the correct SearchService depending on this parameter. What would be the best approach? I thought of using a model binder,
So I would have my ActionMethod that look like this:
public ActionResult Search(ISearchService service, Query query)
{
var results = service.Find(query);
}
But I think would need to make a call like this in the ModelBinder
ObjectFactory.GetInstance(...);
Based on the querystring parameter that describe which provider to use, and that doesn't seem more elegant to me. I feel stuck, help :(.
Whenever you need to vary a dependency based on a run-time value, Abstract Factory is the general solution.
Instead of injecting ISearchService into your Controllers, inject an ISearchServiceFactory:
public SearchController : Controller
{
private readonly ISearchServiceFactory searchServiceFactory;
public SearchController(ISearchServiceFactory searchServiceFactory)
{
if (searchServiceFactory == null)
{
throw new ArgumentNullException("searchServiceFactory");
}
this.searchServiceFactory = searchServiceFactory;
}
public ActionResult Search(...)
{
// Use searchServiceFactory to create an ISearchService based on
// run-time values, and use it to query and return a view.
}
}
It is not entirely clear to me which run-time value you need to vary on, but assuming that it's the Query, ISearchServiceFactory might be defined like this:
public interface ISearchServiceFactory
{
ISearchService Create(Query query);
}
I was trying to figure out how to use the abstract factory pattern and still let structuremap resolve all the dependencies of my components.
I believe that is the way I am going to implement it, but I submit this here to get some feedback if someone would read this.
As explain in the previous answer, I do not want to build the whole object graph depending on which provider I need in the Abstract factory.
ie :
class StatServiceFactory : IStatServiceFactory
{
public IStatService Create(string provider)
{
switch(provider)
{
case "blog":
return new StatService(IFacetRepository,ISearchManager,IConfigManager,BooleanQueryBuilder);
//How to resolve the Config, the SearchManager, and BooleanQueryBuilder?
//Add more abstract factories? It starts to get messy in my opinion...
}
}
}
What I can do is have the abstract factory use my container to create an instance of my search managers depending on a parameter (coming from the querystring in my case)
Structuremap allows to create named instances this way :
x.For<ISearchManager>().Use<AbcSearchManager>().Named("Abc");
x.For<ISearchManager>().Use<DefSearchManager>().Named("Def");
I need a way to inject the container in my Abstract factory.
I would probably wrap the container in a wrapper defined like this. That would keep me from leaking Structuremap into my project. I dont need more that those 2 features within the abstract factory anyway, but it is not necessary:
public interface IContainerWrapper
{
object GetInstance<T>();
object GetNamedInstance<T>(string key);
}
and the implementation :
public class ContainerImpl : IContainerWrapper
{
private readonly Container _container
public ContainerImpl(Container container)
{
_container = container;
}
...
}
And setup StructureMap to resolve dependencies to my abstract factory like that :
x.For<IContainer>.Use(new ContainerImpl(this));
x.For<IFactory>.Use<Factory>()
My factory would be then much simpler and would create my instance like that :
public class SearchmanagerFactory
{
private readonly IContainerWrapper _container;
public SearchmanagerFactory(IContainerProvider containerProvider)
{
_container = containerProvider;
}
public ISearchManager Create(string provider)
{
//eed to handle the bad input for provider.
return (ISearchManager)
_container.Resolve<ISearchManager>(provider);
}
}
That seems pretty clean this way :).
Thoughts?
This is more an extensive comment than an answer to explain why an AbstractFactory seems complicated. Here is something that looks closer from the reality:
class StatServiceFactory : IStatServiceFactory
{
public IStatService Create(string provider)
{
switch(provider)
{
case "blog":
return new StatService(IFacetRepository,ISearchManager,IConfigManager,BooleanQueryBuilder);
//How to resolve the Config, the SearchManager, and BooleanQueryBuilder?
//Add more abstract factories? It starts to get messy in my opinion...
}
}
}
The FacetRepository is the same for any provider, but the SearchManager changes, the ConfigManager changes, and the BooleanQueryBuilder is an abstract class with different implementation for different provider (because every API doesnt use the same keyword for their queries) All those dependencies are currently resolved by structuremap, based on the type of the controller.
I would really like to keep the benefit of StructureMap here, rather than using factories all the way, for each different pieces.'
Please see my edit at the end of my question for another suggestion to my problem.
With my understading, the nature of a Action is that properties can be pushed w/ request parameter values. And, one wonderful feature is that Struts2 allows you to directly populate parameter values against Class type property ;)
Assuming there exists a Action and property class as below,
class Action extends ActionSupport {
User user;
#Action(value="hello" {#result=(.......)})
public void execute() {
........
}
.....
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return this.user;
}
}
class User {
String name;
.....
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
you could populate User class property by doing like this.
http://...../hello.action?user.name=John or via jsp page
Then, I realize that there are actually people make an Action property as a Interface type. My question is what is the reason behind this. If there is a sample code demonstrating it will be great.
Thanks in advance!
Sorry, but your question does not make much sense.
To clarify:
"Properties": in Java a "property" of a class is something that is accesible via getter/setters method (setXXX() / getXXX() => property XXX), tipically (but not necessarily) corresponds to a private field.
In Struts2 you have an Action object and typically (not necessarily, not always) the properties are populated (set) from the request (via the "Parameters" interceptor), and later in the view stage read from the JSP (or whatever) page.
So, in your example, for the request http://...../hello.action?user.name=John , Struts2 would try to find in your action (...actually in your value stack) a property "user" which has a property "name", and try to set it (if the types are convertible). That is, he would try to call something like yourAction.getUser().setName("John") . Struts2 does not know -does not care- what type are the properties "User" or "Name", even if they are real fields or not. (They are expected to behaviour as "beans", though: i.e. they should have a default constructor).
Why and when you should code interfaces instead of concrete classes is something that is explained in any Java book, it's just a standard good practice and there are tons of pages about it. It has nothing to do with Struts2. In this context, for an Action, one is tipically only interested in doing so for some "service" fields, objects that are typically long-lived (perhaps singletons), are not instantiated by the action itself (nor by the request!). So, those interfaces are NOT the properties we are considering here, they ( usually ) are not exposed publically and usually are not populated nor read from the client.