I am new to Java EE so my question may be very basic. I have built following REST web service with Stateless session bean (simplyfied):
#Path("/list/")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Stateless
public class ListResource {
#PersistenceContext(unitName = "unitName")
private EntityManager em;
#GET
#Path("/")
public List<Compound> getCompounds() {
List<Compound> list = tq.getResultList();
if (list.isEmpty()) {
throw new WebApplicationException(Response.status(404).entity("There are no compounds in database.").build());
}
return list;
}
}
It works like charm. Its accessible via URL and return JSON. Problem is that I have another part of the program written in plain Java that needs to use this Session bean as some kind of model to get all Compounds.
Problem is that when I initialize this Session bean somewhere it is outside of persistence context and therefore doesnt know EntityManager to access database. I believe.
I dont know what to do. Can I initialize class ListResource in distant part of code and have Dependency injection of EntityManager working? Or somehow to get persistence context and then initialize this session bean?
I hope it makes sense. Its complicated problem for me to describe.
If you have a web service and a standalone app calling the same bean, I would recommend you to move the functionality in a separate stateless bean and create remote and local interfaces to it. This way you can inject local bean into you web service bean, and call the remote one with jndi.
More about accessing Java EE beans here.
Alternatively, your client java code can call the web service to get all the data. Refer to this question about ways to connect to a RESTful service.
Related
I have an enterprise application with (at least) a web tier (UI only) and a service tier. In the service layer is all the business logic and the current conversation state implemented as #Stateful #LocalBean EJBs (no CDI).
This is somewhat similar to a #SessionScoped bean in terms of CDI, right?
So, here's the issue:
I have a long running conversation in the web tier (#Named #ConversationScoped) and want to access the Stateful EJB. The EJB should be accessed in different controllers (beans) of this conversation. I can't do it like this: #EJB because it would be a different instance of the particular EJB type. I have to save the reference to the EJB somehow. This is my current solution:
#EJB
private MyEJB _myEJB; // a stateful EJB
#Produces
#Builder // custom quallifier
#ConversationScoped
public MyEJB produceMyEJB() {
return _myEJB;
}
Now I can access the same instance of the stateful EJB in each of the conversation scoped controllers like this #Inject #Builder MyEJB _myEJB.
It works, most of the time. But in some long running tests this reference is null and I don't know why.
I get this stack trace in the server.log of Glassfish:
javax.ejb.NoSuchObjectLocalException: The EJB does not exist. session-key:
907f0200001f-ffffffffc3388fbb-761
and/or
Cannot load from BACKUPSTORE FOR Key: <907f0200001f-ffffffffc3388fbb-761>
Do You have any ideas why this happens? Thanks for help and sorry for my bad English.
Your stateful EJB is probably timing out. Check out javax.ejb.StatefulTimeout: http://docs.oracle.com/javaee/6/api/javax/ejb/StatefulTimeout.html
#Stateful
#StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)
public class MyEJB {
I have created stateless session bean in Java. Now I want to invoke a method of another stateless session bean. Some things are missing in my code. Usual way of invoking method does not fit here. Being invoked method at another stateless session bean retrieves data from the Internet.
Likewise, how to invoke a method from #Stateless bean of a simple Java class. I build a REST web service with Java and somehow I can't invoke methods being at simple Java class from #Stateless beans.
Cheers
Just inject it with #EJB
#Stateless
public class StatelessBean1 {
#EJB
private StatelessBean2 bean;
}
There's nothing special about invoking methods on a stateless session bean. You use the exact same syntax as with every other kind of bean.
As Bozho indicated, the only thing special about EJBs is that you can't construct an instance using the new operator. You need to inject an instance or alternatively do a JNDI lookup. After that, the normal Java rules apply.
It really shouldn't need to be explained but to be sure, calling a method on a stateless session bean called 'bean':
bean.someMethod(someArgument);
a standard case - you have a controller (#Controller) with #Scope("session").
classes put in the session usually are expected to implement Serializable so that they can be stored physically in case the server is restarted, for example
If the controller implements Serializable, this means all services (other spring beans) it is referring will also be serialized. They are often proxies, with references to transaction mangers, entity manager factories, etc.
It is not unlikely that some service, or even controller, hold a reference to the ApplicationContext, by implementing ApplicationContextAware, so this can effectively mean that the whole context is serialized. And given that it holds many connections - i.e. things that are not serializable by idea, it will be restored in corrupt state.
So far I've mostly ignored these issues. Recently I thought of declaring all my spring dependencies transient and getting them back in readResolve() by the static utility classes WebApplicationContextUtils and such that hold the request/ServletContext in a ThreadLocal. This is tedious, but it guarantees that, when the object is deserialized, its dependencies will be "up to date" with the current application context.
Is there any accepted practice for this, or any guidelines for serializing parts of the spring context.
Note that in JSF, managed beans (~controllers) are stateful (unlike action-based web frameworks). So perhaps my question stands more for JSF, than for spring-mvc.
In this presentation (around 1:14) the speaker says that this issue is resolved in spring 3.0 by providing a proxy of non-serializable beans, which obtains an instance from the current application context (on deserialization)
It appears that bounty didn't attract a single answer, so I'll document my limited understanding:
#Configuration
public class SpringConfig {
#Bean
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
MyService myService() {
return new MyService();
}
#Bean
#Scope("request")
public IndexBean indexBean() {
return new IndexBean();
}
#Bean
#Scope("request")
public DetailBean detailBean() {
return new DetailBean();
}
}
public class IndexBean implements Serializable {
#Inject MyService myService;
public void doSomething() {
myService.sayHello();
}
}
public class MyService {
public void sayHello() {
System.out.println("Hello World!");
}
}
Spring will then not inject the naked MyService into IndexBean, but a serializable proxy to it. (I tested that, and it worked).
However, the spring documentation writes:
You do not need to use the <aop:scoped-proxy/> in conjunction with beans that are scoped as singletons or prototypes. If you try to create a scoped proxy for a singleton bean, the BeanCreationException is raised.
At least when using java based configuration, the bean and its proxy can be instantiated just fine, i.e. no Exception is thrown. However, it looks like using scoped proxies to achieve serializability is not the intended use of such proxies. As such I fear Spring might fix that "bug" and prevent the creation of scoped proxies through Java based configuration, too.
Also, there is a limitation: The class name of the proxy is different after restart of the web application (because the class name of the proxy is based on the hashcode of the advice used to construct it, which in turn depends on the hashCode of an interceptor's class object. Class.hashCode does not override Object.hashCode, which is not stable across restarts). Therefore the serialized sessions can not be used by other VMs or across restarts.
I would expect to scope controllers as 'singleton', i.e. once per application, rather than in the session.
Session-scoping is typically used more for storing per-user information or per-user features.
Normally I just store the 'user' object in the session, and maybe some beans used for authentication or such. That's it.
Take a look at the spring docs for configuring some user data in session scope, using an aop proxy:
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection
Hope that helps
I recently combined JSF with Spring. I use RichFaces and the #KeepAlive feature, which serializes the JSF bean backing the page. There are two ways I have gotten this to work.
1) Use #Component("session") on the JSF backing bean
2) Get the bean from ELContext when ever you need it, something like this:
#SuppressWarnings("unchecked")
public static <T> T getBean(String beanName) {
return (T) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(FacesContext.getCurrentInstance().getELContext(), null, beanName);
}
After trying all the different alternatives suggested all I had to do was add aop:scoped-proxy to my bean definition and it started working.
<bean id="securityService"
class="xxx.customer.engagement.service.impl.SecurityContextServiceImpl">
<aop:scoped-proxy/>
<property name="identityService" ref="identityService" />
</bean>
securityService is injected into my managedbean which is view scoped. This seems to work fine. According to spring documentation this is supposed to throw a BeanCreationException since securityService is a singleton. However this does not seems to happen and it works fine. Not sure whether this is a bug or what the side effects would be.
Serialization of Dynamic-Proxies works well, even between different JVMs, eg. as used for Session-Replication.
#Configuration public class SpringConfig {
#Bean
#Scope(proxyMode = ScopedProxyMode.INTERFACES)
MyService myService() {
return new MyService();
}
.....
You just have to set the id of the ApplicationContext before the context is refreshed (see: org.springframework.beans.factory.support.DefaultListableBeanFactory.setSerializationId(String))
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
// all other initialisation part ...
// before! refresh
ctx.setId("portal-lasg-appCtx-id");
// now refresh ..
ctx.refresh();
ctx.start();
Works fine on Spring-Version: 4.1.2.RELEASE
It is continues of question ( struts 2 bean is not created )
I'm using struts2 + toplink in my very simple web application under Tomcat.
On the page I would like use iteration tag. That is why I've declared some factory (SomeFactory) that resolves collection of entities (Entity).
Per article: http://download-uk.oracle.com/docs/cd/B32110_01/web.1013/b28221/usclient005.htm#CIHCEHHG
the only thing I need is declaration:
#PersistenceContext(unitName="name_in_persistence_xml")
public class SomeFactory
{
#PersistenceUnit(unitName="name_in_persistence_xml")
EntityManagerFactory emf;
public EntityManager getEntityManager() {
assert(emf != null); //HERE every time it is null
return emf.createEntityManager();
}
public Collection<Entity> getAll()
{
return getEntityManager().createNamedQuery("Entity.findAll").getResultList();
}
}
What is wrong? May be i miss something in web.xml? How to pre-init toplink for web application to allow injection happen?
You won't get anything injected by Tomcat which is not a Java EE container (and even with a Java EE 5 container, injection only works for managed components like servlets, filters, listeners, EJB, web service endpoints...). So you will have to create the EntityManagerFactory manually (typically in a servlet or a helper class) and get the EntityManager from it:
EntityManagerFactory emf = Persistence.createEntityManagerFactory(PU_NAME);
EntityManager entityManager = emf.createEntityManager();
Note that creating an EntityManagerFactory is a costly operation and should not be done for each request. However, creating an EntityManager is not and you should get one for each thread. But in your case, I'd suggest to use the struts2-persistenceplugin to handle this.
Thanks, but it seems [...] that Java EE is not mandatory to use injection [...] the Spring brings necessary engine for it.
Indeed. But you wrote "NO spring at all" in your other question and you didn't list any piece that could provide injection out of the box. Anyway, check out the struts2-persistenceplugin, it might be enough for your needs.
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).