Spring 2.5 managed servlets: howto? - java

Correct me if anything is wrong.
As I understand, all Spring functionality, namely DI works when beans are got thru
Spring Context, ie getBean() method.
Otherwise, none can work, even if my method is marked #Transactional and I will
create the owning class with a new operator, no transaction management will be provided.
I use Tomcat 6 as a servlet container.
So, my question is: how to make Servlet methods managed by Spring framework.
The issue here is that I use a framework, and its servlets extend the functionality of
basic java Servlets, so they have more methods. Still, web.xml is present in an app as usual.
The thing is that I do not control the servlets creation flow, I can only override a few methods
of each servlet, the flow is basically written down in some xml file, but I control this process
using a graphical gui.
So, basically, I only add some code to a few methods of each Servlet.
How to make those methods managed by Spring framework? The basic thing I need to do is
making these methods transactional (#Transactional).
comment to Bozho:
#Bozho Let's see. In these servlets' methods I work with framework capabilities, let's say special variables that are got and saved in the current session. And what is needed, is looping through those framework-based collections while saving some values in a database. What you suggest is introducing a new very complex object, so that it could be passed to a service layer. (Service layer will not know anything about framework, its classes and objects kept in current Session! First, we "wrap" framework based collections to such a object, so copy everything into it. Then, again, the Service layer method should either save changes in a database or, worse case, return a new complex object so that Servlet framework method could update framework variables depending on the result of Service layer method execution. It is a workaround but do you think it is a good idea?

You can also define your servlets directly in the Spring application context. You'll need a "proxy" servlet registered in web.xml and delegating to the servlet instance which is configured as bean in the applicationContext.xml. Proxy servlet is configured with the name of the target servlet bean, it discovers this bean via WebApplicationContextUtils.getRequiredWebApplicationContext().getBean(...) and delegates all the processing to the target servlet. In this case an instance of your servlet is completely managed by Spring.

I'd suggest restructuring your code - making servlet methods transactional is not a good thing to do. Put the transactional logic in a separate, service class, and either
obtain these spring-managed classes by WebApplicationContextUtils.getRequiredWebApplicationContext().getBean(..) or
in your servlet init() method obtain the ApplicationContext with the above method and call appCtx.getAutowireCapableBeanFactory().autowireBean(this). This way you can inject the transactional classes in your servlet as if it was spring-managed.
Now, you can do all this, but it is definitely not a beautiful way to go. I'd suggest using Spring MVC or any other MVC framework (which support spring integration of its components)
If this is all not possible, as a last resort I think you can use #Configurable (on your servlets) with a <context:load-time-weaver/>.

You should take a look how Spring proxy filters:
http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.web/3.0.2/org/springframework/web/filter/DelegatingFilterProxy.java
In theory you could easily make the same sort of proxy for servlets and DispatcherServlet is sort of a proxy.

Related

How to make legacy HttpServlet Spring web aware

We have a legacy HttpServlet class that is the backbone of our application. At this point, the app doesn't have any Spring libraries in it. We are looking to introduce Spring, in particular so we can use Spring-Data in conjunction with Hibernate.
I was wondering if there is a way to make this legacy Servlet web-aware so we can have Request and Session scopes injected. In particular, we would like to be able to inject the HttpServletRequest object into some beans.
One of the main reasons we need to do this, is for a weird multi-tenancy solution we have in place. Hibernate can handle Multi-Tenancy using a combination of a AbstractMultiTenantConnectionProvider and a CurrentTenantIdentifierResolver When using Spring-JPA's Repositories, you lose control of the session creation. One way to take care of this is to implement the CurrentTenantIdentifierResolver Since our tenant identifier is partially determined by something that comes in on the request, it is necessary to inject the request into our CurrentTenantIdentifierResolver implementation.
Also, it would be great to get Spring involved for all the other benefits it can provide in a legacy app.
Do you know how we can accomplish this?
You can define org.springframework.web.context.ContextLoaderListener within your web.xml, which will load your spring application context.
Then, within your servlet code, you access the context using WebApplicationContextUtils.getWebApplicationContext(servletContext) helper method.
Take a look at the Spring docs here:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#web-integration-common

Transaction like logic while using web services

There are several update staments that can be done by web service calls. Those staments should be transactional; they must be done if and only if all can be done.
I cannot change the web services. what I can do is try to change all of them, if one of them fails I change back the previous ones. This plain sloution is pretty ugly.
Is there a more elegant approach to this problem ?
note: I am using JavaEE, SOAP, Spring MVC.
we have a #TransactionAttribute for different targets(method and class).
If you apply this annotation to a class with appropriate TransactionAttributeType(Constants) then that transaction strategy will apply to all the methods inside that class i.e You can keep all calls to your update statements in this class and inject this class where you are having your web services, so if even one update call fails it will rollback
You can write a Transactional class which uses Apache HTTP utils to call these web services one by one. ( This class should have a #Transactional annotation)

WebApp. Java EE. Where I should initialize my business logic?

I recently started learning java EE (jsp, servlets and some patterns for working with database like a DAO) and I dont understand where I should initialize my bussines logic? I think that create instances of it in body of do*** servlet methods is a bad practice. P.S. my app use DataSource and ConnectionPool for connection with db.
You need to specify your requirement somehow, what initialization you are looking for. Is it a EJB solution? Pure Servlet/JSP solution? etc.
Normally when deploying your application, after an invocation the application will load the required logic.
Of course you can do initialize to speed up the load, to make required code run before users enter the application etc.
In EJB we are talking about #Singleton and #Startup annotations.
For servlet you can use the annotation #WebServlet(name="startup", loadOnStartup="0"). Or put it in your web.xml. Depends how you code.
A more recommended way is to create you own listener, and override the contextInitialized and contextDestoryed methods. E.g. create db connection etc in initialized method and deregister the driver in contextdestory method. Use annotation #WebServletContextListener or add the listener to your web.xml
Also Java web server specific solutions exists, you need to check your vendor.

CDI choosing correct scope for bean

Coming from plain old DI of Spring I can't figure out how to choose scopes properly while writing with CDI.
In Spring all my services have singleton scope by default, which I suppose maps to application scope in CDI (or even #Singleton). I know for e.g. logged in user information I need to use Session scope and for e.g. form params I need request scope.
Say I have a bean that hides external service API calls. It is completely stateless. Should I put it as #Singleton or simply application scoped? Or let it be created on every request (possibly bad option).
Is this correct to inject everything everywhere? In Spring I create my data objects by new. Should I do the same in CDI or simply #Inject them?
Are you only using CDI? or a Java EE 6 container? If you have a stateless class that is used for service calls, then I would recommend using #Stateless, which is from the EJB spec (so you would need a Java EE 6 container) It isn't a singleton, but it doesn't get created on each request either. I believe it is more closely bound to the session, but since it is stateless, instances can be pooled and shared. If you are only dealing with CDI, I believe Singleton matches more directly to Spring's singleton, but I would recommend using ApplicationScoped because it provides a proxy which makes serialization of beans that use it easier.
#Service
#Scope("prototype")
public class CustomerService
{
......
}
Just add #Scope("prototype") annotation to your component.
Is there a reason you would need the bean to remember it's state? If you are using something like a web client, that is a better place to store state in say, session scoped managed beans (assuming jsf), or whatever equivalent for your case. On the back end server side your EJB's would be better kept as #stateless to keep overhead to a minimum and help with the 'keep it simple s..." paradigm. And in case this works, just declare #Stateless on your bean. Unless there is a reason to use a singleton, again it is better to use a stateless bean if you want to go with a Java EE container for your services.
Stateless beans are not really being recreated with every request. That is the purpose of the pool. The app server keeps a ready supply of stateless beans on hand, and if it gets busy, it will make more, and if it quiets down, it will empty some out.

How to integrate JSF with custom servlets?

I'm just getting started on JavaServer Faces and it looks very attractive. However I'd like to use my own servlets in the same web application as JSF.
This might be really obvious, but what are the best practices for integrating JSF with a "normal" servlets-based application? This would include accessing JSF data from the servlets (read and write).
If your servlets are well-written, they should already not have any business logic inside, but just pure request/response controlling/preprocessing/postprocessing logic. The business logic should already be placed in standalone javabean-like domain/model classes. The database logic should already be placed in standalone DAO classes. And so on. You can just reuse them all in JSF.
That said, it may be good to know that JSF (when running on top of Servlet API --the common case) manages request scoped beans as attributes of HttpServletRequest, the session scoped beans as attributes of the HttpSession, the application scoped beans as attributes of ServletContext. It may also be good to know that all of those request, session and application attributes are accessible by ExternalContext#getRequestMap(), #getSessionMap() and #getApplicationMap(). You should now realize that you can just access them the usual way from inside a servlet.
In any case, when there is technical need to access the FacesContext inside a Servlet or a Filter, then immediately stop coding it and rethink your approach based on the above facts. Shouldn't it better be done in a new managed bean? Or maybe a PhaseListener?
You don't have to integrate servlets with JSF. This is contrary to the nature of JSF, which is "component based" rather than "action based".
JSF has managed beans whose methods get called when you press a button. You have both the request and response available (using FacesContext.getCurrentContext().getExternalContext()), but they shouldn't really be needed - all the data is automatically populated by JSF in the fields of the managed bean.
If you want servlets that do not integrated with JSF but work in the same application, then you just have to map them to a url that doesn't conflict with the url of the JSF servlet.

Categories

Resources