Loading webservlet after spring context is initialized - spring-mvc

We use Spring MVC annotations.
I have a StartUpServlet as well. My requirement is to load this servlet after the FilterDispatcher servlet is initialized.
Basically, we would like to initialize the Google Guava cache and load the cache with the data from the table.
I can have a static block and load the data. But the problem is the class where we do the cache initialization and cache loading might be garbage collected if we never access it for long time.
So, though of having the cache loading class instance refernece inside a servlet so that it will never be garbage collected. But the servlet gets loaded before the FrameworkServlet dispatcher initialized and Dependency injections are working.
Looking for help on this ......
Thanks in Advance,
Baskar.S

The cache does not actually need to be in a servlet, the simplest would be to put it inside a singleton bean that populates the cache at server startup time. The bean would look like this:
#Component("cacheBean")
public class MyCachedDataService implements InitializingBean {
private MyCache cache;
public void afterPropertiesSet() {
... populate the cache ...
}
public void cacheLookup(String key) {
... lookup the cache ...
}
}
The most important here would be to avoid making further changes to the cache after server startup, in order to avoid race conditions. The bean can then be injected in other beans using #Autowired as usual.

Related

How to invoke a listener or interceptor in #CacheEvict

I have a requirement to invoke some functionality when #CacheEvict is being called. Is there a way to call a listener or interceptor to be invoked in Spring #CacheEvict?
Typically, this is very "cache provider" specific since no 2 cache providers have the same capabilities.
For instance, I primarily work with In-Memory Data Grid (IMDG) technology like Pivotal GemFire and the OSS version Apache Geode. Both, of which, can be used as a "caching provider" in Spring's Cache Abstraction. With GemFire/Geode, you can register a o.a.g.cache.CacheListener callback on the GemFire/Geode Region (essentially a java.util.Map) that is backing the Spring Cache interface, and used in Spring's Caching infrastructure as the "Adapter" to the backing store. As you can see with SD GemFire/Geode provider implementation, the "eviction" triggers a GemFire/Geode Region.remove(key). This eviction can subsequently be captures and handled in the Region's registered CacheListener.afterDestroy(:EntryEvent) callback method.
However, this is just 1 way to handle notifications on evictions in your application.
Of course, as #Borino pointed out, you can leverage Spring's AOP support to "intercept" the cache eviction operation. The advantage of this approach is that it is more generic and reusable across different caching providers.
Although, I would say that you should not be developing a AOP Pointcut expression based on the underlying "caching provider", as #Borino instructed, i.e. ...
execution(* org.springframework.cache.concurrent.ConcurrentMapCache.evic‌​t(..))
This expression ties your AOP Aspect to the ConcurrentMapCache "provider", the default in Spring's Cache Abstraction (and in Spring Boot).
What happens when you use Ehcache, Hazelcast, Redis, GemFire/Geode or multiple combinations of these "providers" in your application?
Rather, you can slightly adjust the AOP Pointcut expression to this...
execution(* org.springframework.cache.Cache.evic‌​t(..))
See here. This is safe because all "caching providers" must supply 2 things: a CacheManager implementation and a Cache implementation for each cache specified in the application. Again, the Cache interface is a "Adapter" to the backing store. Again, see the docs for more details.
There are tradeoffs with either approach. Provider specific solutions generally give your more control capabilities, but using the AOP approach is more reusable. Do what is right for your UC.
Hope this helps.
Cheers!
-John
John's answer is on the right track, but it's important to know that the Cache class is not a Spring managed bean, the CacheManager is.
For this reason, you'd have to pull in additional AspectJ dependencies and do some sort of compile or post-compile weaving to target the Cache.evict method.
i tried injecting cache manager to an aspect and set up my point cuts on methods that cache eviction was necessary like here:
package com.example.aspectdemo.aop;
import com.example.aspectdemo.domain.Customer;
import com.example.aspectdemo.service.CustomerService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;
#Component
#Aspect
public class CacheEvictHandler {
public static Logger logger = LoggerFactory.getLogger(CacheEvictHandler.class);
private final CacheManager cacheManager;
private final CustomerService customerService;
public CacheEvictHandler(CacheManager cacheManager, CustomerService customerService) {
this.cacheManager = cacheManager;
this.customerService = customerService;
}
#Pointcut(value = "execution(* com.example.aspectdemo.service.impl.CustomerServiceImpl.save(..))")
public void loggingPointCut() {
}
#AfterReturning(value = "loggingPointCut()", returning = "customer")
public void LoggAfterEviction(JoinPoint joinPoint, Customer customer) throws Throwable {
cacheManager.getCache("customer-cache").clear();// remove cache
logger.info("*** saved customer id : {}", customer.getId());// do what you like here, i added some logs
logger.info("*** after eviction : {}", customerService.findAll());
logger.info("*** cache evicted ***");
}
}
here is where i save:
#Transactional
#Override
public Customer save(Customer customer) {
log.debug("Request to save Customer : {}", customer);
return customerRepository.save(customer);
}

How does ejb session work? [duplicate]

I'm building my first Java EE application using JSF, PrimeFaces, Glassfish and Netbeans. Because I'm new, it's possible I'm approaching the core problem wrong.
Core problem: I want to maintain user's information securely. There seems to be conflicting ideas on whether it should be maintained in a JSF session bean or a stateful session EJB. I'm trying to use a stateful session EJB because it is more secure that way.
The problem is that my application seems to be creating multiple instances of that bean when I expect it to create one and re-use it. If I refresh the page it runs the #PostConstruct and #PostActivate 3 times, all of them with a different instances. Then they all get destroyed when I re-deploy the application.
Did I misunderstand how it should work or is something wrongly configured?
I'll try to show a trimmed down code sample:
basic.xhtml:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
Hello from Facelets
<c:if test="#{loginController.authenticated}">
Authenticated
</c:if>
<c:if test="#{loginController.authenticated}">
Authenticated
</c:if>
<c:if test="#{loginController.authenticated}">
Authenticated
</c:if>
</h:body>
</html>
LoginController:
#Named(value = "loginController")
#RequestScoped
public class LoginController implements Serializable {
#EJB
private UserBeanLocal userBean;
public boolean isAuthenticated() {
return userBean.isAuthenticated();
}
}
UserBean (excluding UserBeanLocal interface)
#Stateful
public class UserBean implements UserBeanLocal, Serializable {
boolean authenticated = false;
#PostConstruct
#PostActivate
public void setup(){
System.out.println("##### Create user Bean: "+this.toString());
}
#Override
public boolean isAuthenticated() {
System.out.println("########## Authentication test is automatically passing.");
authenticated = true;//hard coded for simplicity.
return authenticated;
}
#PrePassivate
#PreDestroy
public void cleanup(){
System.out.println("##### Destroy user Bean");
}
}
Finally, here is the Glassfish output after refreshing three times:
INFO: ##### Create user Bean: boundary._UserBean_Serializable#2e644784
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable#691ae9e7
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable#391115ac
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
Stateful session beans (SFSB) are not exactly what you think they are. You seem to think that they behave somehow like session scoped JSF managed beans. This is untrue. The term "session" in EJBs has an entirely different meaning than the HTTP session which you've had in mind.
The "session" in EJBs must be interpreted in transactional context. The transaction (basically, the DB session) lives in case of SFSB as long as the client lives. The SFSB's client is in your particular example not the webbrowser, but the JSF managed bean instance itself, exactly the one where the SFSB is been injected. Since you have put the JSF managed bean in the request scope, the SFSB will be recreated on every HTTP request together with the JSF managed bean.
As an example, try to put the JSF managed bean in the view scope. The view scope is useful for a multi-step form on the same page, for example. Everytime when the view postbacks to itself, then the same JSF managed bean instance will be reused and this instance gives you access to the same instance of the SFSB as it is when the bean was created, which is not shared elsewhere. The SFSB transaction lives as long as the client (the view scoped JSF managed bean) lives.
A stateless session bean (SLSB) can be shared elsewhere, but that shouldn't matter as it's intented to be treated as stateless anyway. This "feature" saves the container time and memory to create and store them. The container can just have a pool of them. Even more, the SLSB instance which is been injected in a view, session or application scoped JSF managed bean does not necessarily need to refer exactly the same instance on every HTTP request as it was during JSF managed bean's creation. It can even be a completely different instance, depending on the available instances in the container's pool. The transaction lives (by default) as long as a single method call on the SLSB.
That said, a SFSB is unsuitable for your particular case of "remembering a logged-in user". That it's "more secure" makes really no sense. Just put the JSF managed bean in the session scope and let it remember the logged-in user by itself and make use of a SLSB to do any business actions (such as interacting with the DB) and use SFSB only when you want a real stateful session bean (I assume that you now understand what exactly they are :) ).
See also:
When is it necessary or convenient to use Spring or EJB3 or all of them together?
Why Stateless session beans?
JSF Service Layer
As far as I understand from my investigation and usage, EJB SFSB is not usefull for web applications since JSF, Spring provides helfull annotation to keep the session per user. But in case where webservice and RPC method invocation call required application is running, EJB SFSB is neccs to keep the session(trancation) per user.

How to access "session" scoped beans in a Spring WebSocket handler (not "websocket" scope)

In a raw Spring WebSocket application (not using sockjs/STOMP or any other middleware), how can I have Spring inject beans that have been registered in the HTTP session scope so that they can be used by code in my WebSocketHandler bean?
Note that what I am not asking is any of these questions:
How do I create beans in a scope that is accessible to all handler invocations for the same WebSocket session (e.g. as described in the answer to Request or Session scope in Spring Websocket). The beans I need to access already exist in the scope for the HTTP session
How do I (programatically) access objects in the servlet container's HTTP session storage (I haven't tried to do this, but I'm pretty sure the answer involves using an HttpSessionHandshakeInterceptor), but that doesn't get me injection of Spring scoped dependencies.
How to use a ScopedProxy to pass beans between code in different scopes (e.g. as described here); I'm already familiar with how to do this, but attempting to do so for a WebSocketHandler causes an error because the session scope hasn't been bound to the thread at the point the object is accessed.
How to access the current security principal -- again, very useful, but not what I'm currently trying to achieve.
What I'm hoping to do is provide a simple framework that allows for the traditional HTTP-request initiated parts of an MVC application to communicate directly with a WebSocket protocol (for sending simple push updates to the client). What I want to be able to do is push data into a session scoped object from the MVC controller and pull it out in the websocket handler. I would like the simplest possible API for this from the MVC controller's perspective, which if it is possible to just use a session-scoped bean for this would be ideal. If you have any other ideas about very simple ways of sharing this data, I'd also like to hear those in case this approach isn't possible.
You can also use Java API for websocket. This link https://spring.io/blog/2013/05/23/spring-framework-4-0-m1-websocket-support
explains how to do this with Spring.
Ufortunately, something like this
#ServerEndpoint(value = "/sample", configurator = SpringConfigurator.class)
public class SampleEndpoint {
private SessionScopedBean sessionScopedBean;
#Autowired
public SampleEndpoint(SessionScopedBean sessionScopedBean) {
this.sessionScopedBean = sessionScopedBean;
}
}
causes exception (because we're trying to access bean outside its scope), but for singleton and prototype beans it works well.
To work with session attributes you can modify the hanshake and pass required attributes:
public class CustomWebSocketConfigurator extends SpringConfigurator {
#Override
public void modifyHandshake(ServerEndpointConfig config,
HandshakeRequest request,
HandshakeResponse response) {
//put attributes from http session to websocket session
HttpSession httpSession = (HttpSession) request.getHttpSession();
config.getUserProperties().put("some_attribute",
httpSession.getAttribute("some_attribute_in_http_session"));
}
}
P. S. More a comment than an answer. I just wanted to add another way of handling session attributes in websocket to your question-answer. I have been searching the web for exactly the same issue and the way showed above seems to me the most systematic approach to handling the session data in websocket.

Write Junit tests for Spring MVC application which internally relies upon ContextLoader.getCurrentWebApplicationContext()

I'm trying to write integration tests for a controller in our spring mvc application. The controller invokes a service class which in turn invokes a dao to read/write data from the repository. The DAO needs to lookup some configuration. The configuration bean is defined in WEB-INF/applicationContext.xml.
I'm using something like this:
Configuration config =(Configuration)ContextLoader.getCurrentWebApplicationContext().getBean("config");
private String namespace = config.getProperty("someproperty");
The properties are stored in zookeeper so I'm not using spring's property management artifacts.
The problem is that while running the JUnit test ContextLoader.getCurrentWebApplicationContext() always returns null.
I have so far looked at the following approaches:
1. Ted Young's approach ( just google search for spring mvc integration tests ted young)
2. https://github.com/SpringSource/spring-test-mvc
3. this site.. questions/8464919/unit-testing-a-servlet-that-depends-on-springs-webapplicationcontextutils-getre
4. Use Selenium/JWebunit
5. http://confluence.highsource.org/display/Hifaces20/Hifaces20+Testing+package+-+testing%2C+tracing+and+debugging+web+applications+with+Jetty
1 doesn't resolve this issue. WebApplicationContext stays null
2 states that support for WebApplicationContext will be available in spring 3.2
3. I don't understand this. Where do I get the testApplicationContext and the getServletContext() from?
4. I do not want to go this way as this is completely blackbox testing.
5. I'm currently looking at 5. But this requires starting up a servlet container. Is there no other alternative?
I will appreciate any help you can provide.
Thanks
PixalSoft
#Ted Young SO didn't allow me to finish what I was saying.With loader=MockWebApplicationContextLoader,isn't it supposed to be available as the default contextloader exactly as the Spring ContextLoader behaves when the webapp is initialized by a servletcontainer?Is there something special I need to do get a handle on the MockWebApplicationContextLoader?Injecting the config object works for singleton objects. But all can't be singleton. Passing a config object in every constructor sounds too tedious. For now, I have created a class which has a static config object, autowired via a setter method. I will take a look at ApplicationContextAware.Many thx
You have to manually add the WebApplication context to ContextLoderListner.
This will work.
#ContextConfiguration(locations = "classpath:module-test-beans.xml")
#WebAppConfiguration
public class SampleTest extends AbstractTestNGSpringContextTests {
#Autowired
private WebApplicationContext wac;
#BeforeClass
public void setUp() throws ServletException {
MockServletContext sc = new MockServletContext("");
ServletContextListener listener = new ContextLoaderListener(wac);
ServletContextEvent event = new ServletContextEvent(sc);
listener.contextInitialized(event);
}
#Test
public void testMe() {
Assert.assertFalse(ContextLoader.getCurrentWebApplicationContext() == null);
}
}
Add the following code at the beginning of your junit test:
MockServletContext sc = new MockServletContext("");
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/applicationContext-test.xml"); // <== Customize with your paths
ServletContextListener listener = new ContextLoaderListener();
ServletContextEvent event = new ServletContextEvent(sc);
listener.contextInitialized(event);
If you need to add more than one xml for the context path just put them in the same string separated with spaces, like this:
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/applicationContext-test.xml /applicationContext-other.xml");
The reason why ContextLoader.getCurrentWebApplicationContext is returning null is because, when you use my MockWebApplicationContextLoader, you are neither using a web application context nor that particular ContextLoader implementation.
Since your repository is managed by Spring, why do not you simply inject the config object into the repository? Injecting the config object is the most appropriate way to get access to it. You can then initialize your namespace property in a method annotated with #PostConstruct.
Alternatively, your DOA could implement ApplicationContextAware to receive a copy of the application context during construction.
store your property file in your classpath.
now access that property in your controller class like this:
/*to access your filename.properties file */
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("filename.properties"));
String sServerLocation = properties.getProperty("key");
now you can access your property file.
I am sure it will work.

When, exactly, #Inject annotation initiates injection of SessionScoped bean in Servlet?

I need to modify a user session object (SessionScoped bean - CDI) in a Servlet, so I have to obtain that bean somehow. I used injection in the following way:
#Inject
private UserSession user;
where UserSession is the SessionScoped CDI bean. user methods are called from either doPost or doGet servlet methods.
This works perfectly; every time the #Inject annotation injects the appropriate UserSession bean, but I don't understand how this behavior is achieved.
I assumed that the beans, annotated with #Inject, are injected only once (when the object - Servlet instance in this case - is created), but it is obviously a wrong presumption.
So, when are these beans injected into the servlet? Per request? And how does this approach avoids conflicts (one servlet instance - multiple threads to deal with it) when there are multiple UserSession objects?
The CDI uses the proxy pattern. The injected instance is actually not the real instance, but a proxy which locates the real instance depending on the current context and delegates all methods to it (like as how EJBs work). The autogenerated class of your UserSession bean looks roughly like this:
public UserSessionCDIProxy extends UserSession implements Serializable {
public String getSomeProperty() {
UserSession instance = CDI.resolveItSomehow();
return instance.getSomeProperty();
}
public void setSomeProperty(String someProperty) {
UserSession instance = CDI.resolveItSomehow();
instance.setSomeProperty(someProperty);
}
}
This mechanism allows you to inject instances of a narrower scope in instances of a broader scope and allows you to still get the expected instance in the current context. The standard JSF #ManagedProperty annotation doesn't support it, simply because it does not use a proxy, but injects the desired instance directly. That's why it's not possible to inject something of a narrower scope by #ManagedProperty.
See also:
Backing beans (#ManagedBean) or CDI Beans (#Named)?
Get JSF managed bean by name in any Servlet related class
When using #EJB, does each managed bean get its own #EJB instance?
How to choose the right bean scope?
Your answer lies in the C of CDI, which stands for Contexts.
What happens is that not the actual bean is injected, but a proxy. This proxy is contextual and resolves to the actual session scoped bean depending on the context of the caller on who's behalf the proxy is executed.

Resources