How does ejb session work? [duplicate] - ejb

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.

Related

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.

Loading webservlet after spring context is initialized

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.

Does Role Provider cache per request?

My MVC application makes use of a User's Role in multiple places during individual page requests. My question is whether the default SqlRoleProvider caches the current User's Roles for the lifetime of a page-request?
For example, I make use of Roles in attributes on Controller methods:
[Authorize(Roles = "Admin")]
and custom code
if (user.IsInRole(MembershipRole.Admin))
{
// Do something
}
else if (user.IsInRole(MembershipRole.Printer))
{
// Do something else
}
If the Role Provider does not cache roles, is the best solution to write a custom Role Provider that inherits from the default one, and override the methods to get the Roles once and cache them for the Request duration? Can this be done in a way that both the Authorize attribute and my own code will make use of the cached roles?
(In case you were wondering, I don't want to use the cacheRolesInCookie web.config option to cache the roles in cookies).
Thanks in advance for any suggestions.
[Edit to include details triggered from Joe's answer]
I decompiled System.Web.Mvc.AuthorizeAttribute and the AuthorizeCore method calls the following method for each role to be checked:
httpContext.User.IsInRole
Then peering into System.Web.Security.RolePrincipal (which is what "User" is above) both the methods below do indeed use a cached copy of the User's roles (or populates the cache if empty):
public string[] GetRoles()
public bool IsInRole(string role)
The cache is stored as a field on User, so its lifetime is for the duration of the request.
The methods find the roles using:
Roles.Providers[this._ProviderName].GetRolesForUser(this.Identity.Name)
so will use whatever role provider you have chosen for the application (default or custom).
If you use a RoleProvider in an ASP.NET or ASP.NET MVC application, then HttpContext.User will reference a RolePrincipal which does cache roles for the lifetime of the request.
However, in a WCF service that uses ASP.NET roles:
<behavior ...>
<serviceAuthorization principalPermissionMode ="UseAspNetRoles"
roleProviderName ="MyRoleProvider" />
</behavior>
this is not true: instead HttpContext.User will reference the internal class System.ServiceModel.Security.RoleProviderPrincipal, which does not cache roles: instead it always calls RoleProvider.IsUserInRole.
The out-of-the-box RoleProviders don't do any caching, so this can result in repeated connections to the underlying data store. It seems like a deficiency to me: it would have been easy to cache the roles on first access.
is the best solution to write a custom Role Provider that inherits from the default one, and override the methods to get the Roles once and cache them for the Request duration?
Not necessary for ASP.NET or ASP.NET MVC, but could be envisaged for WCF. Caching for the Request duration will presumably use HttpContext.Items, so will introduce a dependency on the existence of HttpContext, but that's not necessarily a problem except for making unit testing harder.
Can this be done in a way that both the Authorize attribute and my own code will make use of the cached roles?
If you configure your custom RoleProvider in web.config there's nothing more you need to do so that the Authorize attribute will use it.

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.

How to obtain OSGi service references from a Servlet that is registered in OSGi HttpService?

It seems natural that a HttpServlet running in OSGi environment (i.e. registered in OSGi HttpService) would want to call some OSGi services to accomplish it's tasks. The question is how to obtain references to these OSGi service inside the servlet.
One way would be to inject dependencies into the HttpServlet instance that is being registered to the OSGi HttpService like this:
MyServlet servlet = new MyServlet();
servlet.setFooService(fooService);
httpService.registerServlet("/myservlet", servlet, initparams, context);
I'm not sure if this is a valid approach since in non-OSGi environment the servlet life-cycle is managed by the Web Container and hence the service reference would not be injected for the servlet instances created later on.
There is another way to solve this when using PAX Web as an implementation of the OSGi HttpService. PAX Web exports the OSGi BundleContext into the ServletContext as a special attribute "osgi-bundlecontext". The BundleContext can then be used to obtain necessary service references:
public void init(ServletConfig servletConfig) throws ServletException {
ServletContext context = servletConfig.getServletContext()
BundleContext bundleContext =
(BundleContext) context.getAttribute("osgi-bundlecontext");
ServiceReference serviceRef =
bundleContext.getServiceReference("com.foo.FooService")
}
However this approach is rather ugly and ties you to a concrete implementation of the OSGi HttpService. Do you know any other (and possibly better) solution to this problem?
If you use a setter for the dependency on the service, as you have shown, it can work outside of OSGi as well. You just need to use some other dependency injection mechanism. If there is none, you could provide a subclass that initializes the servlet using JNDI lookups or from the servlet context.
public class MyServlet_AdapterForMissingDI extends MyServlet{
public void init(ServletConfig config){
setFooService(getItFromSomewhere());
}
}
The point being that if you have DI capabilities that can inject setFooService, you can just use the same servlet in OSGi and elsewhere, if you do not (and still want to support this case), you provide an adapter.
On a related note, check out Felix SCR to configure your object's dependencies, and Pax Web Extender Whiteboard, which takes care of hooking your servlet up with the HttpService.
Specifically, without SCR and Whiteboard, you need to think about the case when the fooService becomes unavailable later, or the HttpService gets started after your servlet.
In these cases your servlet would have a reference to a dead service that prevents the bundle from being garbage-collected, or your servlet would not be registered with the HttpService.
Update: Here is the SCR descriptor I use for one of my servlets. SCR handles servlet instantiation, life-cycle, registration (via Whiteboard), and dependencies. There is no OSGi-specific code in the servlet. There is not even the need for a BundleActivator anymore (SCR registers all services):
<component name="oracle.statusServlet" >
<implementation class="mypackage.DataSourceStatusServlet"/>
<property name="service.description" value="Oracle DataSource status servlet" />
<property name="alias" value="/OracleDataSourceStatus" />
<property name="servlet-name" value="Oracle DataSource status servlet" />
<service>
<provide interface="javax.servlet.Servlet" />
</service>
<reference name="DATASOURCES"
interface="javax.sql.DataSource"
cardinality="0..n" policy="dynamic"
bind="bindDataSource" unbind="unbindDataSource"/>
</component>
The dependencies for the servlet are specified in the reference tag. SCR will do the service lookup and binding.
May be an old post and you already might have got the answer..
Are you launching felix or whatever OSGi container yourself. If that is the case you can set the bundle context as an attribute to the servlet context.
Whats wrong in using an http service by PAX. ultimately the thread management and other aspects are taken care of by the servlet container in which you run this http service.
You could inject the services into some object, which is then queried by the servlets.

Resources