I am putting together an SSO system for all of our internal apps and will be using CAS. I have been asked to make a simple web app whose sole purpose in life is to monitor CAS and display a page containing the usernames of all the currently logged-in users.
I am trying to figure out the best way to query CAS for this kind of information.
I know that CAS has a concept of a TicketRegistry that keeps a list of all active/valid tickets; where each ticket has user information (I believe in the form of an IPersonAttributeDao). Perhaps there is a why to query CAS for the contents of its ticket registry, and obtain each person attribute's username info somehow?
If not the ticket registry, what would be a good way to access this info?
There's nothing in CAS protocol that allows to query a server for the list of the currently active tickets.
I assume you are using Jasig CAS as your server. I think you could add a view, controller and domain object injected with current ticket registry and simply call TicketRegistry.getTickets() to have all Tickets (including expired ones). You will still have to call getAuthentication for the implementation of Ticket (it exists in both ServiceTicket and ServiceGrantingTicket but I could not find it in any superclass or interface), and then Authentication.getPrincipal().
I do not know if the list of PrincipalS that you will get will contains duplicates, but if I were you I would test for such duplicates.
CAS is a Spring application so the first place to look for adding this stuff should be cas-server-webapp/src/main/webapp/WEB-INF/cas-servlet.xml.
I'm afraid I can't do more without knowing the exact implementation of CAS you will use.
cas-server-webapp is a spring-mvc app, so you should find a lot of information in Spring documentation - please note that as CAS 3.1 uses version 2 of Spring you should look at http://docs.spring.io/spring-framework/docs/2.5.3/reference/ .
The following is only a skeleton of what could be done and is untested stuff that may contains typo or other mistakes. Also, there are no interfaces, and view name is hardcoded what are not recommended practices in real world. It must be taken for what it is : a simplified skeletal example of a possible implementation.
Domain object (optional)
private TicketRegistry ticketRegistry;
public class LoggedUsersService {
public List<what_you_want> getLoggedInUsers() {
List<Principal> userList; // or List<Authentication> or ...
// extract pricipal list from ticketRegistry
...
return userList;
}
public void setTicketRegistry(TicketRegistry ticketRegistry) {
this.ticketRegistry = ticketRegistry);
}
}
It should be declared in deployerConfigContext.xml
<bean id="loggedUserService" class="path_to/LoggerUserService">
<property name="ticketRegistry" ref="ticketRegistry"/>
</bean>
It is optional because you could do that stuff directly in controller ... but separation makes tests easier.
Controller
private LoggedUsersService loggedUsersService;
public class LoggedUserController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
// set view name and optionaly whant you need to do
mav.setViewName("loggedusers")
mav.addObject("userList", loggedUserService.getLoggedInUsers());
return mav;
}
public void setLoggedUsersService(LoggedUserService loggedUsersService) {
this.loggedUsersService = loggedUsersService;
}
}
It should be declared in cas-servlet.xml and included in a handler mapping
<bean id="loggedUserController" class="path_to/LoggerUserService">
<property name="ticketRegistry" ref="ticketRegistry"/>
</bean>
<bean id="handlerMappingC"
...
<props>
...
<prop key="/loggedUsers">loggedUsersController</prop>
</props>
...
</bean>
View
Then in your loggedusers.jsp, you can access to the list of users under bean name "userList" in request scope
<jsp:useBean id="userList" scope="request"/>
Related
Working with Spring / Spring security on a small project at the moment and having difficulty implementing this feature. Ideally I only want user1 to view the details of user1 and not those of 2,3 or 4 for example.
I've implemented Spring Security with Roles and understand that I can retrieve a UserDetails object or a principle, I'm not sure exactly but I know I can retrieve the details of the current logged in user using one of, what appears to be many methods.
This is what I'm currently using as a proof of concept when we go to the Admin/home page:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Gamer gamer = gamerService.findGamerByEmail(auth.getName());
System.out.println("Auth: " + auth.getName());
System.out.println("Gamer: " + gamer.getName() + gamer.getId() + gamer.getEmail());
The security config takes care of whether or not the current user can access because of the roles assigned to it.
I believe I should be able to go to the url of /mysite/viewUserDetails and have that page display information of the current user but I cannot find any examples of this, I've found plenty of example that prove a logged in user can view a page but none that specify checks in place to ensure user1 can only view user1's details.
On an older page I do this to display information for a particular user but I understand this to be bad practice-
<a th:href="#{/gamer/{gamerid}/games/excited (gamerid=${gamer.id}) }">
*Worth noting that this isn't using any form of login/registration to pull out this info, I'm simple using the id I pass in as part of the DB query.
It maps onto :
#RequestMapping("/gamer/{gamerid}/games/excited")
public String getExcited(#PathVariable final Long gamerid, Model model){
addGamerListAttributes(model, gamerid, "EXC");
return "games";
}
So my question becomes, and I hope you can point in the right direction, How can I implement a solution where a user can only view his/her details and how should this be represented via the form and connecting controllers as passing ids in the url is kinda ugly (I could use a guid but...)
Thanks so much in advance.
It's actually quite an easy choice. Either you have an entry point like:
#RequestMapping("/gamer/{gamerid}/games/excited")
and you manually check that the user in session can access the requested resource, or you have something like
#RequestMapping("/my-games")
that automatically reads the user id from the security context.
More than a security choice, I'd pick one depending on code reuse and future use-cases (for example the same page/set of pages can be seen by more than one user).
Have a look at #PreAuthorize annotation. It is possbile to annotate given endpoint with it and create custom logic in a bean. Then you can use custom method to allow or disallow the endpoint to proceed :
#Controller
public class HomeController {
#Autowired
private AuthenticationService authenticationService;
#RequestMapping("/gamer/{gamerid}/games/excited")
#PreAuthorize("#authenticationService.hasAccess(#gamerid)")
public String getExcited(#PathVariable final Long gamerid, Model model){
addGamerListAttributes(model, gamerid, "EXC");
return "games";
}
}
Service class :
#Service
public class AuthenticationService {
public boolean hasAccess(String tgamerid) {
//implement logic here
return true;
}
}
Method hasAccess in the AuthenticationService should return boolean. #PreAuthorize will be launched before controller handler method is invoked. The controller above is just an example. You can pass Authentication object in SPeL expression in #PreAuthorize annotation to service method or get it from security context inside service class, to implement logic which fits your needs. More information can be found here and in Spring Docs.
I am not sure if I'm getting it right what Spring Security is capable of.
What my problem is, is that I want to prevent a logged in user to send arbitrary IDs to my server and therefore access data that does not belong to him. But every tutorial I can find is about a simple login procedure. But how can I use that to get rid of
if(item .getStore().getId() == store.getId()) { /* .. */ }
in this example:
// StoreService.java
#Transactional
public ItemDTO deleteItem(String sessionId, Long storeId, ItemDTO itemDto) {
// sessionId is the cookie I have placed in my database
// This way I want to ensure that I am only accessing a store
// that is associated with the logged in store owner (the user basically)
Store store = this.storeOwnerRepository.getStore(sessionId, storeId);
Item item = ConvertDTO.convertItem(store, itemDto);
// THIS CHECK IS WHAT I WANT TO GET RID OF:
// Check if the store ID that I got using the cookie is the
// same ID as the store ID from the item that should be deleted
if(item.getStore().getId() == store.getId()) {
item = this.storeOwnerRepository.deleteItem(item);
} else {
// If this didn't work we have a potentially hostile user:
throw new RuntimeException("Is somebody trying to delete items from a store he doesn't own?");
}
itemDto = ConvertEntity.convertItem(item);
return itemDto;
}
using Spring Annotations? Is that even possible with Spring Security?
Another thing that might work would be Hibernate Filters but I am not sure if I want my database to know about security aspects of my data.
So I am quite confused about how to do that correctly. Any ideas?
We've implemented this kind of security on domain objects with Spring's ACL API. This involves:
creating an implementation of Spring's org.springframework.security.acls.model.AclService interface that knows how to return the permissions a given principal has on a given domain object. E.g. if the principal has relationship foo to this domain object, then grant READ and WRITE permissions; if relationship bar, then grant READ, WRITE, and DELETE permissions.
adding to the service methods that operate on the domain objects annotations like org.springframework.security.access.prepost.PreAuthorize and org.springframework.security.access.prepost.PreAuthorize that define the access-control assertions to be enforced. E.g. this method requires the current authenticated user to have the "WRITE" permission on the argument of type X, or that method requires the current authenticated user to have the "READ" permission on the return object. If either assertion fails, an AccessDeniedException will be thrown.
adjusting your Spring Social config to turn on method-level security. I used the global-method-security element in Spring Security's XML namespace.
There are a lot of details to consider, but we use this approach in several web applications to good effect. It allows you to separate the who-gets-what-permissions-on-which-objects logic from the what-permissions-are-needed-to-perform-this-action logic, and it keeps both away from your database queries.
Of course, in some cases you'll want to enforce access control in the queries instead of querying first, and then filtering the results. I've seen the term "early binding" used to describe enforcement of access control in database queries, and "late binding" used to describe access control on the results of the queries. The Spring Security ACL API is a very good, robust solution for late binding.
You would end up with business service methods like:
#PostAuthorize("hasPermission(returnObject, 'READ')")
public MyItem getMyItem(Long id) {
return dao.getMyItem(id);
}
#PreAuthorize("hasPermission(#toDelete, 'DELETE')")
public void deleteMyItem(MyItem toDelete) {
dao.delete(toDelete);
}
And an AclService with a method like:
public Acl readAclById(ObjectIdentity objectIdentity, List<Sid> sids) throws NotFoundException {
/*
examines objectIdentity which identifies domain object in question, and sids which identifies the principal who wants permissions on the domain object, then returns an ACL instance with permission grants on that domain object for that/those principals
*/
return new AclImpl(...);
}
And the following in your applicationContext-security.xml:
<beans:bean id="permissionEvaluator"
class="org.springframework.security.acls.AclPermissionEvaluator">
<beans:constructor-arg ref="aclServiceImpl" />
</beans:bean>
<beans:bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<beans:property name="permissionEvaluator" ref="permissionEvaluator" />
</beans:bean>
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler" />
</global-method-security>
Probably you should implement Spring security and work roles and permissions, in this way you will be able to ensure you wont get requests by users that are not admin (by delimiting the method with #Secured("ROLE_SOMEROLE")) , this can help you in case in the future you will have other roles.
Then you should work more with role permissions
Spring Security with roles and permissions
And then add permissions over stores, to read or write them. You can associate many permissions to a user, so, can read/write/whatever only to the stores you want.
Check this tutorial, it could help you.
http://slackspace.de/articles/roles-permissions-with-spring-security-3/
http://springinpractice.com/2010/10/27/quick-tip-spring-security-role-based-authorization-and-permissions
I think what you are talking about has more to do with validation than security.
As long as you store data for multiple clients/customers in the same database, you must take care to prevent users from inadvertently (or maliciously) accessing each other's data.
I suggest that you perform this validation at the web service layer and keep the business logic focused on the details of what needs to be done.
I'm using Shiro to secure my Spring MVC webapp. I'm using Hibernate for persistence and so I have a HibernateRealm to get and populate an AuthenticationInfo object.
#Override
#Transactional
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
Account account = accountDao.findByUsername((String)token.getPrincipal());
SimplePrincipalCollection principals = new SimplePrincipalCollection(account, getName());
SimpleAccount info = new SimpleAccount(principals, account.getPassword());
return info;
}
Account is my custom user class. I use the DAO to retrieve an Account by username. I was wondering if there is any point in making this method #Transactional. This is a read only operation after all.
I'm also having the following problem: the DAO does sessionFactory.getCurrentSession() to get a session, but I'm getting a
HibernateException: No Session found for current thread
when the method gets called. I have these in my application context:
<tx:annotation-driven transaction-manager = "transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I can't understand why Spring isn't opening a session for me.
Edit: To login, we do this in a Spring #Controller method using Shiro's Subject
#RequestMapping(value = "/account/login", method = RequestMethod.POST)
public String login(#RequestParam("username") String username, #RequestParam("password") String password) {
Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated) {
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
currentUser.login(token);
return "profile";
}
return "home";
}
Internally, Shiro uses the realm method I have above to get the stored username/password information. It uses an #Autowired DAO to check my database for the right account. It then matches the passwords with a CredentialsMatcher implementation.
So you have two problems. It is usually better to split such questions into two, since these problems are not really connected to each other.
No Session found for current thread
It seems that #Transactional annotations does not work. To be sure you may run you code or tests in Debug mode and look for the JdkDynamicAopProxy or something similar in the stack - if it is present, than your Realm is invoked through transactions-intercepting proxy, but I suppose that there is no proxy curently. For it to work you need to take from the SpringContext not the HibernateRealm directly but the interface that this realm is implementing. This is due to the fact that built-in standard java library proxies can deal only with interfaces.
As for making the read-only service methods transactional.
There are several valid reasons to do so:
Since you are using Hibernate it is really possible that you actually use more than one query to get your Account object. And if this account is modified concurrently it may lead to inconsistent state:
first query for Account retrieval
Account is modified or deleted
second query for Account retrieval - this query will see the results of modification that together with the results of the first query may lead to inconsistent behavior, but if first and second query were in the same transaction with the proper level of transaction isolation second query would not see the modifications.
Uniform access to the database - it is really helpful when all your database connectivity layer access the DB in one and the same way - I greatly simplifies maintaining and extending of the application.
Using some transactional hints like #Transactional(readOnly=true) may improve your performance with proper configuration (e.g. for the really high-loaded application readOnly queries may use secondary replica of the DB Server). It is really easier to setup the java.sql.Connection.setReadOnly() method as part of the Spring transactions, than in the other way.
It appears that Spring isn't creating a transactional proxy for your Realm bean. This is the only reason that I can see why a Hibernate Session isn't available - because the backing infrastructure isn't there (on the thread) ready for use.
As to your question, if you do want to mark it #Transactional, you might consider specifying #Transactional(readOnly=true)
Shiro creates it's own instance of my Realm and therefore Spring has no power over it to wrap it in a proxy. That's why it can't add the transactional behavior.
I'm working on a Java EE web application where I use Spring MVC and Spring security.
Until now, I succeeded in implementing the common security features using a custom userService (which retrieves the information from my database) but I'm now facing a new security issue and I don't really know what's the best way to tackle it...
Here is what I need to do:
Users who are authenticated in my app are allowed to navigate through their projects but should only be able to open the projects they have authorizations to (and open what is inside) but no other project.
My current implementation deals with it with the navigation (user interface) offering only the list of the authorized projects to the user. However if a clever user directly edits the URL to open a project with another id then no authorization test on the project id and the user is done so that it opens the project without trouble.
So, what I would like to add is a control on every requests for opening a project or something inside it. This control will test if the project id requested can be opened by the current user or not. If not, it will return to the user an access denied page. This control is easy to implement in itself but as it is a bit of code which could be in many methods of my app I would like to find the cleanest way to do it !
What do you think is the best way to implement that ? I considered several possibilities but I need advice:
1) Use servlet filters ?
2) Add a special access on Spring security with a custom authenticationManager ? something like :
<security:intercept-url pattern="/open*" access="canOpen()" />
(but I'm not sure how to define this and if I would be able to get the parameters coming from the original request...)
3) Use Aspect Oriented Programming ? (but I read somewhere that it does not work on controller calls)
4) Use Spring interceptors ?
5) other ideas ?
Thanks in advance for you help!
I would advise you to use a custom PermissionEvaluator so you could basically use the same implementation in both webpages and controllers:
in the webpage you could use: <security:authorize access="hasPermission(#project,'read')"></security:authorize>
in your controller and in any of your service methods you could use:#PreAuthorize("hasPermission(#project,'read')")
or also #PostAuthorize and #PostFilter("hasPermission(filterObject,'read')") (for lists)
all of these function will either restrict access or filter result list according to you own permission evaluator. they will all point to the same implementation, which would look something like this:
#Component
public class MyPermissionEvaluator implements PermissionEvaluator {
private final Log logger = LogFactory.getLog(getClass());
#Override
public boolean hasPermission(Authentication auth, Object arg1, Object arg2) {
logger.info("hasPermission "+auth+" - "+arg1+" - "+arg2+" ");
if(arg2 instanceof String && arg1 instanceof MyProject){
MyProject project = (MyProject)arg1;
if(((String) arg2).equals("read")){
boolean result = hasPermissionReadProject(auth, project);
return result;
}
}
return false;
}
#Override
public boolean hasPermission(Authentication arg0, Serializable arg1,
String arg2, Object arg3) {
logger.info("hasPermission "+arg0+" - "+arg1+" - "+arg2+" - "+arg3+" ");
return false;
}
}
Also, when these methods return false it automatically throws an AccessDeniedException and you can easily configure that to redirect to your own accessDenied page in the http element:
<http auto-config="true">
<intercept-url pattern="/admin*" access="ROLE_ADMIN" />
<access-denied-handler error-page="accessDeniedPage"/>
</http>
I am not using Spring Security, but I had to face a similar case.
I chose to implement database access validation. Each of my requests has a built in user/data confirmation. Maybe this isn't the simplest way to do it, but this way, users can only request data that they can read/write. I never had any troubles with that.
My requests are adapted for the logged in user role. For example, in my case, if a user is a student, he can only access his own folder, but if it's a teacher, he can access the folders of the students he teaches to.
Request (simplified a lot!) [with IBatis]:
SELECT *
FROM FOLDER F
<dynamic prepend="WHERE">
<isNotEmpty property="user">
<isEqual property="user.role" compareValue="student">
F.ID_STUDENT = #user.idStudent:NUMERIC#
</isEqual>
<isEqual property="user.role" compareValue="teacher">
F.ID_STUDENT IN
(SELECT ID_STUDENT
FROM CLASSES
WHERE ID_TEACHER = #user.id:NUMERIC#)
</isNotEmpty>
</isNotEmpty>
<isEmpty property="user">
F.ID IS NULL
</isEmpty>
</dynamic>
We are migrating a struts application over to Spring MVC and utilizing the #Controller annotation to direct pages to various method calls.
I'm having trouble determining a good strategy for reuse though.
We basically do the same things in many of our pages:
prepareView(..., ...); //Various params -- could likely be standardized
if (!allowedToView()) {
mav.setViewName(injectedErrorPage);
}
performBusinessLogic(..., ...); //Various params -- not seeing how to standardize
persistEntities();
finalizeView(..., ...); // Various params -- could likely be standardized
What strategies are used for creating a final method which will allow the developers to "forget" about these processes? I'd thought about making an abstract class, but there really isn't a way I'm seeing to "standardize" this due to differences in what each method will take.
For instance we have the following:
#RequestMapping("params="assign", method=RequestMethod.Post)
public ModelAndView assign(#SessionAttribute(value="sessionAttr") Pojo pojo,
#ModelAttribute("command") CommandPojo commandPojo,
BindingResult result) {
//Follows pattern above
}
#RequestMapping()
public ModelAndView filterResults(#SessionAttribute(value="sessionAttr") Pojo pojo,
#RequestAttribute("requestAttr") String requestAttr,
#ModelAttribute("command") CommandPojo2 commandPojo2,
BindingResult result) {
//Follows pattern above
}
Having a final method would require this to be broken into two POJOs (which would then call the descriptive functions). My immediate concern there is how do we deal with different parameters coming into this final method? I don't see any way to handle this situation.
It'd be nice if we could still have this "final" method with protected functions which we could override where needed.
I have the same problem as you. I don't have a clean solution yet, but I believe that I made some progress so I thought I'd share with you what I have found so far.
I explored the use of interceptors as suggested by three_cups_of_java, but I run into various problems (described below). Currently I am trying to use a custom AnnotationMethodHandlerAdapter, but I am not done yet with this effort.
Interceptors
Since the interceptors don't have access to the controller object that they intercept (correction: they do have access to it, but with limited control over the execution flow), the controller and the interceptor have to communicate through objects in the session.
Here is a somewhat simplified example of what I mean:
In our old architecture, we have our own base controller that everyone extends. It itself extends MultiActionController, and adds some custom behavior - like in your example, updating a server-side view after post request before invoking the handler method. This works because all the controllers provide an implementation of a template method (e.g. getViewKeyInSession()).
Thus, the custom code in the base controller looks roughly like this:
// inside handleRequestInternal method
if (request.getMethod().equals("POST") {
updateViewAfterPost (session.get(getViewKeyInSession());
}
return super.handleRequestInternal();
Now, when we moved this code to the interceptor, we run into several problems:
The interceptor can't invoke getViewKeyInSession(), forcing us to use the same session key for all controllers (not good), or adhere to some convention that the session key for the view is based on the url or a param of the request (so far this is not good either).
Individual controllers can no longer override the behavior of updateModelAfterPost. This is usually not necessary, but unfortunately it was necessary for some controllers.
If the controller provides an implementation of updateModelAfterPost and wants to signal to the interceptor that it is not interested in the interceptor's help, it needs to do so by putting a marker object in the session for the interceptor to look at, and it needs to do it during the previous GET request (also not good and not flexible).
Using a Custom AnnotationMethodHandlerAdapter
Currently I am looking at specifying the DefaultAnnotationHandlerMapping directly in my xml (instead of mvc:annotation-driven) and then supplying it with a custom AnnotationMethodHandlerAdapter.
As I said earlier, I haven't made enough progress to present full results, however the direction that I am aiming at is this:
I think of AnnotationMethodHandlerAdapter as a Spring-supplied MultiActionController, but for pojo controllers. For example, I already know how to plug to it my own method resolver (see this question) and other Spring goodies.
This adapter has several methods that you can override, such as
invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler),
and maybe
handle(HttpServletRequest request, HttpServletResponse response, Object handler)
as well.
In your custom code, you can inspect the handler class, and then act accordingly. To continue my previous example, if the handler class has a method updateViewAfterPost or if it implements a certain interface, then you can invoke that method, and then call super to let spring proceed with the regular invocation. Thus, the code looks roughly like this:
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// inspect handler object, look for marker interface, methods and/or annotations
// perform pre-processing on the handler object
// e.g. handler.updateViewAfterPost(request, response)
ModelAndView mav = super.handle (request, response, handler);
// post-processing on the handler object
return mav;
}
(Of course, this is just a toy example. In real code you'll need better exception handling)
UPDATE:
I tried the above strategy with a custom AnnotationMethodHandlerAdapter, and it indeed works. I used a marker interface on my pojo controller, and introduced only one new method named updateModelAfterPost to the life-cycle, and it works as expected.
There are several small caveats that I ran into, mainly because I was combining the old ways with the new ways in the same mvc context. Below you can see the changes I made to the xml context, followed by a list of the issues that I think are worth highlighting.
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="order" value="2" />
</bean>
<bean class="com.sample.MyAnnotationMethodHandlerAdapter">
<property name="order" value="2" />
</bean>
<bean class="com.sample.MySimpleControllerHandlerAdapter" >
<property name="order" value="1" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="order" value="1" />
<property name="mappings">
<props>
...
</props>
</property>
</bean>
As mentioned in the comment, I unrolled the <mvc:annotation-driven> short-hand. I had to explicitly define two handler mapping, and also define two handler adapters.
Unfortunately in my legacy code some controllers are transcational and are proxied by cglib. The AnnotationMethodHandlerAdapter doesn't cope well with that, therefore I set the order of elements such that the legacy handler mapping and handler adapter act first, and the annotation-based handler mapping and handler adapter act second.
I had to define explicitly Spring's SimpleControllerHandlerAdapter, but I also had to extend it with my own class, because it doesn't implement the Ordered interface.
I had a problem defining the validator, because I didn't have the jar for jsr-303. Therefore I dropped the declaration of validators and conversion service. The above xml snippet is exactly what I use, it is not a trimmed-down version simplified for the sake of the answer.
and finally, here is the code for the relevant classes:
package com.sample;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
public class MyAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter {
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof MyMarkerInterface) {
MyMarkerInterface handler2 = (MyMarkerInterface) handler;
handler2.updateModelAfterPost(request);
}
return super.invokeHandlerMethod(request, response, handler);
}
}
package com.sample;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
public class MySimpleControllerHandlerAdapter extends SimpleControllerHandlerAdapter implements Ordered {
private int order = 0;
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}
Could you implement a base class as you are suggesting and force a Template Method design pattern and also to borrow from what Nix said in his earlier comment to your question about leveraging a parameter collection in this base class?
Does that help?
If the parameters are varying from function to function I think #Nix suggestion of parameter collection is a good one. Alternatively you could use var arg of objects. But you might need to have a check to see if all parameters are present before a function is called like a Pre condition check.
Or maybe a combination of both like, you would know that some of the parameters are always needed and others optional. So use varargs for the optional likethe following for filterResults
public ModelAndView filterResults(#SessionAttribute(value="sessionAttr") Pojo pojo,
#RequestAttribute("requestAttr") String requestAttr,
#ModelAttribute("command") CommandPojo2 commandPojo2,
Object...restOfParameters){}
This could be combined with the template pattern that is disscussed earlier.
If you want reusability you really should look into spring webflow, if you haven’t already. In short, webflow is an advanced spring mvc contoller that allows better separation between you view layer and your business logic. The controller accepts request, maps and validates your model, delegates requests to the correct business services, and finally decides which view to render based on the outcome of services called, of state of the model.
Everything is configured through xml, which gives you a single point where all your webflow logic and navigation is located (there is an eclipse plugin to visualize the navigation if you don’t like xml). Spring webflow also plays nice with other mvc controllers if you need to handle some requests the old fashioned way. And last but not least, spring webflow adds some scopes for your variables that are very handy. Besides request , session and application, you also get flow and conversation scope, which is kind of like session scope, but only for the current application window. That means you can have multiple windows/tabs in your browser without any of these interfering with each other.
But you should check it out for yourself, there is a small reference guide available on the spring website, as well as multiple demo’s in their svn repo. Also, the book “spring in action” touches the subject of webflow. Hope this is useful.
http://www.springsource.org/webflow