if I understand it right a #Stateful bean saves the state. If the client does a request again it comes back to the same instance. So it's possible to save class-attributes, what's not possible in #Stateless. In an other thread here someone wrote "it's like a classical java instance, every injection gets it's own instance of this bean".
But I don't understand how the mapping of the request to the #Stateful bean works - what is to do that it works? This question goes out for two cases:
I call #Stateful by a webservice by the client software. Is it an ID I have to send with it? But what is the ID and how do the container knows that this is the identify-attribut and routes it to the right #Stateful bean?
I call #Stateful out of an #Stateless bean. As example if the client first calls a #Stateless bean and is redirect to his #Stateful bean.
This question is not for the technical process of the container / server-software, it's for the specific doing at the development. Thank you for your support.
Greetings
That's unfortunately not the way web services work. The stateful bean is only stateful for the stateless bean. And not for a client. And that's very dangerous for several reasons:
-The stateless bean saves state of a call in its stateful reference. But the next call of the stateless bean can be happen in another context/by another client.
-The stateful bean can be destroyed by the container while the stateless is still alive/in the pool.
You can use stateful beans with remote-calls or in web applications but not in the context of webservices.
A webservice is per definition without any application state. The Java EE-Servlet listens for the requests and call one stateless bean implementation from a pool of instances.
If you really want to implement stateful web services, you must do it on your own. The following example will work in a Java EE 6-container:
/// Client depended values(your statefull bean)
public class SessionValues {
private final List<String> values = new ArrayList<String>();
public void addValue(String s){
values.add(s);
}
public List<String> loadValues(){
return Collections.unmodifiableList(values);
}
}
You can store the sessions in a singleton(your own pool)
#Singleton
#Startup
public class StatefullSingleton {
private final Map<String, SessionValues> sessions = new Hashtable<String, SessionValues>();
#Lock(LockType.READ)
public void addValue(String sessionId, String value) {
if (!sessions.containsKey(sessionId))
sessions.put(sessionId, new SessionValues());
SessionValues p = sessions.get(sessionId);
p.addValue(value);
}
#Lock(LockType.READ)
public List<String> loadValues(String sessionId) {
if (sessions.containsKey(sessionId))
return sessions.get(sessionId).loadValues();
else
return new ArrayList<String>();
}
}
and inject the singleton in the stateless webservice beans(the pool, the singleton and the calls of the singleton are managed by the Java EE-Container):
#Stateless
#WebService
public class WebserviceBean {
#Inject
private StatefullSingleton ejb;
public void addvalue(String sessionId, String value) {
ejb.addValue(sessionId, value);
}
public List<String> loadValues(String sessionId) {
return ejb.loadValues(sessionId);
}
}
The example above is only a pattern. You must be very carefully with the session-id and the multithreading if you want to implement it in production.
Edit: remove the unnecessary #localBean
Related
I have a class as below:
public class UserAuthenticator {
private static UserAuthenticator authenticator =
#Inject
private UserRepository userRepository;
#PostConstruct
public void init() {
List<User> allUsers = userRepository.findAll();
for (User user : allUsers) {
users.put(user.getEmail(), user.getPassword());
serviceKeys.put(user.getServiceKey(), user.getEmail());
}
}
public static UserAuthenticator getInstance() {
if (authenticator == null) {
authenticator = new UserAuthenticator();
}
return authenticator;
}
}
When I call
UserAuthenticator authenticator = UserAuthenticator.getInstance();
init() method isn't called and userRepository is null
My web application run in JBOSS EAP 6.3.
How is this caused and how can I solve it?
In a Java EE application, don't think in singletons. That's only recipe for trouble and confusion. Instead, think in "just create one". Tell the Java EE container to just create only one instance of the specified class, application wide, and obtain the instance via the facility offered by the Java EE container. Your concrete problem is caused because you're manually creating an instance of the class using new operator without manually performing the injection and post construct call like as the technical correct but conceptually wrong example below:
authenticator = new UserAuthenticator();
authenticator.userRepository = new UserRepository();
authenticator.init();
In other words, you incorrectly expected that the new operator magically recognizes the bean management and dependency injection related annotations.
The right approach depends on the one you'd like to point out as the responsible for creating and managing the instance of the specified class. If it's CDI, then just tell it to create only one managed bean instance of the backing bean class, application wide, using #Named #ApplicationScoped.
import javax.inject.Named;
import javax.enterprise.context.ApplicationScoped;
#Named
#ApplicationScoped
public class UserAuthenticator {}
It will be created just once and be available via #Inject as below in any other Java EE managed artifact (read: in any other class annotated with #Named, #Stateless, #ManagedBean, #WebServlet, #WebListener, #WebFilter, #Path, etc..):
#Inject
private UserAuthenticator userAuthenticator;
If you're absolutely positive that you need a static method to grab the current CDI managed bean instance of a given backing class, then you should be obtaining it via BeanManager as below instead of manually constructing the instance (assuming Java EE 7 / CDI 1.1 available):
#SuppressWarnings("unchecked")
public static <T> T getCurrentInstance(Class<T> beanClass) {
BeanManager beanManager = CDI.current().getBeanManager();
Bean<T> bean = (Bean<T>) beanManager.resolve(beanManager.getBeans(beanClass));
return (T) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
}
Usage:
UserAuthenticator userAuthenticator = YourCDIUtil.getCurrentInstance(UserAuthenticator.class);
// ...
See also:
Java singleton class vs JSF application scoped managed bean - differences?
Java EE 6 and Singletons
Well i think you shouldn't explictly call UserAuthenticator.getInstance() but to define the UserAuthenticator for example as #ApplicationScoped and get the instance via DI provided by your app server (#Inject).
UserAuthenticator should be then initialized properly.
The #PostConstruct method will not be invoked until you do some action on that class (ex: call some methods
I am new to the Struts2 framework and to EJB as well. I have a class LoginDAO which implements checkUser method of an interface LoginDAOLocal. I don't understand why I see different behavior for the following scenarios:
If I use an EJB (LoginDAO is stateless session bean) as follows, method call works perfectly without any error.
#EJB
private LoginDAOLocal loginDao;
loginDao.checkUser(userName,password);
If I use Struts2 as follows, it gives a Null pointer exception for the method call.
public class LoginAction extends ActionSupport {
// Getters setters for userName and password)
private LoginDAOLocal loginDao;
loginDao.checkUser(this.userName,this.password);
}
If I use a simple Java application (no EJB or Struts2), the method call creates a compile time error saying loginDao is not initialized
public static void main(String[] args) {
LoginDAOLocal loginDao;
loginDao.checkUser(userName,password);
}
Can someone explain why this different behavior ?
Without getting too much into the Java EE spec: EJBs are managed by an EJB container that exists in J2EE servers (JBoss \ Websphere etc..). The container takes control of bean lifecycle and is responsible for creating \ destroying beans according to the application needs.
When running out of container (simple java application) your beans won't get initialized and you don't have a JNDI context to get beans from, even if you add #EJB annotation to the field member.
We can say that there are two ways to manage the beans, using the container (managed by the container), or by another component (managed by a servlet, listener or filter).
Using components managed by the container, the container injects the references. e.g.:
#WebServlet("/test")
public class MyServlet extends HttpServlet {
#Resource(lookup = "jdbc/TestDS")
private DataSource testDS;
}
By contrast, a component managed by a bean, e.g.:
#Namespace("/User")
#ResultPath(value = "/")
#Result(name = "success", location = "pages/login.jsp")
public class LoginAction extends ActionSupport {
}
is managed by the filter org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter. The latter should be responsible for performing dependency injection. Spring, for example, takes care of injecting all necessary dependencies.
Does CDI allows pooling in some way?Because I thought this is a feature of EJB beans but Adam Bien says in this screencast that container chooses whether to create new instance of class through reflection or use the existing one. So if I have for example these two beans
#RequestScoped
public class RequestBean {
public void doIt() {
}
}
#SessionScoped
public class SessionBean {
#Inject
private RequestBean bean;
public void doSomething() {
bean.doIt();
}
}
the question is - is there always new instance of RequestBean created upon calling doSomething or does CDI container somehow manage instances in pool?
The first one is scoped to the request, so a new instance is created for each request. The second one is scoped to the session, so a new one is created for each session.
CDI doesn't pool and recycle the objects, because it has no idea if the objects are stateful or not, and you don't want, in a request, to get back the state that a bean had in a previous request. That would ruin the whole point of the request/session scope.
Unless beans are really costly to create (because they start a new connection or something like that), pooling them doesn't bring any advantage. Short-lived objects are very fast to create and garbage collect nowadays. And if the bean is really expensive to create, then it should probably be a singleton.
We're developing a Web Frontend using JSF 2 and Weld Cdi on Tomcat.
Now I've a problem executing multiple webservices in parallel to optimize the request time.
The user may select mutliple items form a list.
For each selected item, the process gathers it's information from one webservice using the list key as parameter.
My current approach is using a Producer, that returns the webservice port interface, which is injected into the bean. The bean calls this webservie in a loop for each selected key.
#Inject
private WSAnzeigeAssetsummen serviceAccess;
:
for ( Integer pfNr : sessionKeys.getPfnrList() ) {
summaryTable = serviceAccess.execute(snr, pfnr, requestType, "", desiredRows, userName);
processResult(summaryTable):
}
To get faster, I tried to use a ExecutorService and as many workers as needed, which are returning Futures.
The problem of this construct is, that I can't inject the service port into the worker, cause the worker is not managed. Creating the service port by hand, works but is not appreciated, cause it ignores the producer class.
Also when testing, it's not possible to inject a dummy service port, which delivers predefined result sets.
Since I did not find anything, about parallel execution in a tomcat-weld enviroment, there must be something wrong with my approach.
What is the correct approach to solve such a situation ?
Edit: To be more clear what I tried...
public class DataCollector implements ISumRequest<Integer, Integer, String, FutureResult> {
ExecutorService pool = Executors.newCachedThreadPool();
#Inject
SessionBean sessionBean;
public Future<FutureResult> collectInformation(Integer snr, Integer pfnr, String requestType) {
CollectWorker worker = new CollectWorker (snr,pfnr,requestType,sessionBean.getUserName());
return pool.submit(worker);
}
}
When doing like this, the worker is not managed.
You can wrap your created worker in a CDI creational context, something like this:
#Inject
private BeanManager beanManager;
public <T extends Object> T performInjection(final T obj) {
if (this.beanManager != null) { // only do injection if the bean manager is present.
// Create a creational context from the BeanManager
final CreationalContext creationalContext = this.beanManager.createCreationalContext(null);
// Create an injection target with the Type of the instance we need to inject into
final InjectionTarget injectionTarget = this.beanManager.createInjectionTarget(this.beanManager.createAnnotatedType(obj.getClass()));
// Perform injection into the instance
injectionTarget.inject(obj, creationalContext);
// Call PostConstruct on instance
injectionTarget.postConstruct(obj);
}
return obj;
}
Is it possible to make the container inject the same stateful session bean instance into multiple other stateful session beans?
Given the following classes:
#Stateful
public class StatefulTwoBean implements StatefulTwo {
#EJB
private StatefulOne statefulOne;
}
#Stateful
public class StatefulThreeBean implements StatefulThree {
#EJB
private StatefulOne statefulOne;
}
In the above example, StatefulTwoBean and StatefulThreeBean each get injected their own instance of StatefulOneBean.
Is it possible to make the container inject the same instance of StatefulOneBean into both StatefulTwoBean and StatefulThreeBean?
The problem is this - Stateful beans' isntances are allocated by differentiating the clients that call them. Glassfish (and perhaps others) don't propagate this difference on injected beans. The EJB specification, as far as I remember, isn't clear about this.
So your solution is to implement the differentiation yourself. How to achieve this. I'm not pretending this is the most beautiful solution, but it worked. - we did it by putting a Facade (an EJB itself) (I'm calling it a facade, although it does not entirely cover the facade pattern) in front of all our EJBs, with the following code:
public Object call(Object bean,
String methodName,
Object[] args,
Class[] parameterTypes,
UUID sessionId) throws Throwable {
//find the session
SessionContext sessionContext = SessionRegistry.getSession(sessionId);
//set it as current
SessionRegistry.setLocalSession(sessionContext);
.....
}
The important parameter is sessionId - this is something both the client and the server know about, and identifies the current seesion between them.
On the client we used a dynamic proxy to call this facade. So the calls look like this:
getBean(MyConcreteEJB.class).someMethod(), an the getBean method created the proxy, so that callers didn't have to know about the facade bean.
The SessionRegistry had
private static ThreadLocal<SessionContext> localSessionContext = new
ThreadLocal<SessionContext>();
And the SessionContext was simply a Map providing set(key, value) and get(key)
So now, instead of using #Stateful beans to store your state, you could use the SessionContext.
In EJB3.1 you can create your StatefulOne bean as singleton (using the #Singleton annotation) giving you the desired semantics. JBoss should already support this annotation (they've wrote the standard).