Spring Framework Abstraction [closed] - java

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I have a legacy application that uses a singleton pattern for all the services and accesses all the services via ServiceName.getInstance() inside services that use other services and in the web tier. I'm converting the project to use Spring and was thinking of creating a singleton utility class ServiceProvider with methods getServiceA, getServiceB..etc and have it get the bean from a Spring application context. I will use the ServiceProvider in the web tier only since I can't convert to it to use Spring just yet and autowire all the services that use other services. Is this a good solution?
I have a very simple web tier and maybe someone can recommend how to springify it with minimal changes. I have a map of url to controllers loaded on start up. The RequestDispatcher parses the request url, looks up the controller by class and executes a template method (there are various subclasses of the base controller but it doesn't complicate the problem).
RequestDispatcher:
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
int slashIndex = req.getRequestURL().lastIndexOf("/");
String path = req.getRequestURL().substring(slashIndex, req.getRequestURL().length());
ServiceURL url = urlMap.get(path);
ServiceProvider.getLog().info("Requested page: " + path);
if (url != null) {
try {
Utils.authenticate(req, resp);
grantAccess(req, url);
BaseServlet servlet = (BaseServlet)url.getClass().getClassLoader().loadClass(url.getClassName()).newInstance();
servlet.service(req, resp);
}
catch (AuthorizationException e) {
resp.getWriter().write(new ErrorModel("You are not authorized to perform the requested action.").getContent());
ServiceProvider.getAuthLog().info("auth", e);
}catch (SystemException e) {
I'm thinking of annotating my servlets as components, having the packages auto scanned. Can the ApplicationContext get the bean by full class name?

Looks like your services are stateless.
I would annotate them with #Service(make them spring beans) and just #Autowire them anywhere you need. Let Spring act as a service provider.

Your getInstance() solution sounds like the objects are not unnder Spring's control.
If you need to access the services as JNDI lookups you should configure them as such in Spring.
If it's under Spring's control it should not be instantiated in your code. If it's instantiated in your code, it's not under Spring's control.

Related

How do I configure a Spring web application to use a different authentication method per end point [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a web application - built using Java, Spring and Spring Security - that needs to support two different methods of authentication. The difficulty I have is that I want to use one authentication method on one set of controller end-points and the other method on the remaining end-points.
This is a difficulty because all the documentation I've read about multiple authentication providers seems to assume that you want all the providers to apply to all the end-points and you iterate through the providers until you find one that will authenticate the user.
I'm using Java annotation-base configuration (as opposed to XML configuration). Here are a few of the approaches I've explored without success:
configuring a provider with a pattern matcher to limit the end-points it applies
configuring a provider to only be triggered for certain authentication types, eg. if Digest credentials are present, trigger the Digest-based authentication provider
Can anyone suggest what is the best way to go about this? Is one of the above methods the correct way (and I've simply got it wrong)? Or is there another preferred way?
(I'm aware I've provided no specific code to review for an issue. This is because I'm only after guidance about the appropriate way of doing things in Spring.)
I'm using Spring Boot 2.0. I don't know about the best way but here's a way that worked for me. I had to break it out into to separate configuration classes and the second configuration needed to have the #Order annotation on it.
For my particular case I needed some administrative REST methods secured by HTTP basic authentication (username/password), and the remaining REST methods needed to be secured by custom logic.
#Configuration
#EnableWebSecurity
public class TestSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll();
// anything that is NOT /admin/**
RequestMatcher requestMatcher = new NegatedRequestMatcher(new AntPathRequestMatcher("/admin/**", "GET"));
// MyCustomFilter is my class that performs custom authentication logic
http.requestMatcher(requestMatcher)
.addFilterAfter(new MyCustomFilter(), BasicAuthenticationFilter.class);
}
#Order(1)
#Configuration
public static class AdminServiceConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
//this time anything that IS /admin/**
http.requestMatchers()
.antMatchers("/admin/**").and()
.httpBasic().and()
.authorizeRequests().antMatchers("/admin/**").fullyAuthenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder authBuilder) throws Exception {
authBuilder.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("username")
.password("password")
.roles("ADMIN");
}
}
}

more servlets vs more objects [duplicate]

This question already has answers here:
Design Patterns web based applications [closed]
(5 answers)
Closed 6 years ago.
I want to understand, If request has to be processed through multiple functions-
is it good to forward through multiple Servlets OR
implement as object methods
Example
req.getRequestDispatcher("LoadSession").forward(req, resp);
req.getRequestDispatcher("AuthoriseRoles").forward(req, resp);
req.getRequestDispatcher("Boot").forward(req, resp);
OR
sessionLoader.loadSession(req,res);
authoriseService.authoriseRoles(req,res);
bootService.boot(req, res);
I assume you are at the phase of designing an API. According to REST design principles, the url should reflect the resource that is handled or requested and the HTTP method should reflect what action is required to be taken on the resource.
So, instead of /LoadSession and having the session id as query param in the Http request, it should be GET /session/{id} for example GET /session/e841092fa2194340bc40 (I am assuming LoadSession is a request to return an existing session)
You might ask yourself what is the advantage of following this design. It is that there are several libraries and frameworks that are able to parse incoming HTTP requests and take care of the routing for you (for example, Jersey is the reference JAX-RS implementation, JAX-RS being JavaEE's REST standard) . So instead of writing a servlet as you mentioned, you write the class that represents the resource and methods that are fired according to the HTTP method. you tie it all together with annotations:
#Path("/session")
import javax.ws.rs.*;
import javax.ws.rs.core.*;
#Produces({MediaType.APPLICATION_JSON})
public class SessionHandler
{
#Context
private HttpServletRequest httpRequest;
#Context
private HttpServletResponse httpResponse;
#GET
#Path("{id}")
public Session load(#PathParam("id") String id) {
...

Spring MVC Controller as Liferay Portlet and Servlet

We are trying to have a spring MVC Controller that works as a portlet and a servlet, in order to be deployed in a Liferay context or as a standalone version. But it seems that the we have a conflict if we decide to have multiple RequestMappings on the method level (as opposed to having just 1 mapping on the level of the controller). we get the error shown below.
Note that if we decide to just have a requestMapping on the level of the controller that hosts a servlet mapping and a portlet mapping, it works.
#RequestMapping({"view", "/"})
The controller that does not work:
#Controller("controller")
#RequestMapping("VIEW")
public class MyController {
#RenderMapping
public ModelAndView doView(RenderRequest request, RenderResponse response) throws Exception {
HttpServletRequest portletHttpReq = PortalUtil.getHttpServletRequest(request);
HttpServletResponse portletHttpResp = PortalUtil.getHttpServletResponse(response);
return doView(portletHttpReq, portletHttpResp);
}
#RequestMapping(value="/home")
protected ModelAndView doView(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
// do something
return new ModelAndView("view");
}
}
The resulting error:
[...]
Caused by: java.lang.IllegalStateException: Mode mappings conflict between method and type level: [/home] versus [view]
Do you have any suggestions on how we could implement such thing? What we would really like to avoid is having to maintain 2 controllers for every portlet/servlet.
Thank you.
I don't really think this is a good idea... the #RequestMapping annotation on the class level is going to cause problems for sure, simply because Spring portlet MVC expects the portlet mode, while Spring Web MVC expects a root URL.
Also, your code doesn't seem to be correct either, since ModelAndView exists in both the portlet MVC as the web MVC part of the Spring framework, and since you cannot import both, you'll have to specify the full package for one of them, and since you're not doing that either, your code is just wrong.
Except the technical issues, both portlets and servlet have different terminology and point of views. These are some key questions that pop up with me if I hear this:
What are you going to do about the different phases (ACTION and RENDER)
What about the the different portlet modes (VIEW, EDIT, HELP, ...)
What are you going to do about the specific portlet features (PortletSession, PortletPreferences, ...)
How are you going to handle the different kind of requests (ResourceRequest, ActionRequest, RenderRequest, PortletRequst, EventRequest vs HttpServletRequest)
How are you going to handle security? The portal container provides authentication for you, a standalone web application does not.
And these are just questions from a portlet mindset, I'm pretty sure there are also technical issues if you look at it from the web application point of view.
It makes much more sense to divide your code into a view layer and business logic. Put the business logic in a separate package or separate services, and build a separate portlet- and standalone application, using the same/shared business logic.

How to override getSession() in spring mvc

I'm working on an web application and have a problem of session storage.
The application is deployed to a cluster, and we place an apache http server to handle load-balancing. So each request may be handled by different node in the cluster. We set out to use Redis(master/slave) as a shared session storage.
My question is how to plug it to Spring mvc, so we can use redis and don't need change our application code.
I find a solution on the internet which uses Filter and HttpServletRequestWrapper:
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
//get sessionId from cookie or generate one if not found
filterChain.doFilter(new CustomHttpServletRequestWrapper(sid, request),
servletResponse);
}
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
String sid = "";
public HttpServletRequestWrapper(String sid, HttpServletRequest arg0) {
super(arg0);
this.sid = sid;
}
public HttpSession getSession(boolean create) {
return new HttpSessionSidWrapper(this.sid, super.getSession(create));
}
public HttpSession getSession() {
return new HttpSessionSidWrapper(this.sid, super.getSession());
}
}
I wonder whether I can find an equivalent in spring mvc?
The first one came to my mind is HandlerInterceptor. But not like filter's api, HanlderIntercepor does not handle the chain, so there is no way to pass a custom request to the next interceptor.
Any idea is appreciate, thanks in advance.
UPDATE:
I found two strategy on this topic:
The first one is extending your web container(such as Tomcat) and There is some mature open source project focused on it already.
The second one is use filter + wrapper. This stratey is web container agnositic.
Personally I prefer the first one because it's transparent to the developers. Let's say we use Weblogic in test/production evironment and we use embedded jetty for development because it's faster and requires less resources. In this situation, developer doesn't have to setup a session storage for development. On the other hand, however, every developer need to setup a session storage of his/her own if we adopt the second strategy. The alternative solution is provide a shared session storage for development environment or some configurations to swtich the sesson storage strategy(built-in for development, shared for test/production). I think it's easier to perform dependency(configuration) injection via spring than that via raw servlet filter and hence raise this question.
Does anyone know is there an out-of-box implementation of the first strategy for Weblogic by the way?
I don't know about WebLogic session storage configuration options, but I can comment on the filter based strategy.
You can implement the filter to be aware of its environment. You can add configuration for the development, which will say "don't wrap request" and enable wrapping only in production (or test) environment.
You can implement your filter to be Spring application context aware (check WebApplicationContextUtils) or even being managed by Spring's application context (via DelegatingFilterProxy). Then you will be able to pull out configuration values or use Spring profiles to set up the filter manually.

A Spring MVC controller that delegates to a Servlet

One of my projects uses Spring MVC to handle URL mappings and dispatch logic. I have now to use a third party library which uses its own HttpServlet as the main entry point for its functionalities, but as it's an optional drop-in replacement for another library I can't just put the <servlet> declaration in the web.xml: I'd rather use a Controller and Spring profiles to switch between such implementations without having to edit the web.xml.
Is there anything offered OOTB by Spring to handle such cases? I don't seem to find it right away.
Thanks in advance!
Since registering the third party servlet in your web.xml is a no-go, I think your best bet would be to create a singleton instance of the servlet in your ApplicationContext, and then create a custom view that delegates to said servlet's service method.
You can see an example of custom views in action in this tutorial.
Answering my own question here just in case my approach can be useful to others.
There are two key factors I needed to consider:
the proper initialization of the servlet
give the servlet full control over the HTTP layer (e.g. setting HTTP headers, etc)
In my specific case there's no need for properly handling the servlet destruction, as it's a no-op.
I ended up writing a dedicated Controller, to be instantiated only if a specific Spring profile is activated, which takes care of instantiating and initializing the Servlet. Then, all the requests will be directly handled in a void handler method, as follows:
public class ServletDelegatingController implements ServletConfig {
private final DelegateServlet delegate = new DelegateServlet();
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
delegate.service(request, response);
}
// properly initializes the servlet
public void setServletConfig(ServletConfig servletConfig) {
try {
delegate.init(servletConfig);
} catch (ServletException e) {
throw new IllegalStateException("Failure while initializing the servlet", e);
}
}
}
The delegating-servlet.xml for the DispatcherServlet looks like the following:
<beans profile="custom">
<bean id="cmisServiceFactory"
class="com.foo.ServletDelegatingController"/>
</beans>

Categories