Hi have create a interface as
#Remote
public interface MathInter{
public int add(int x, int y);
public int showResult();
}
and the class as
#Stateful(mappedName="test")
public class MathImp implements MathInter{
public int result;
public int showResult()
{
return result;
}
#Override
public int add(int x, int y) {
result = x + y;
return x+y;
}
}
and used it on a client.jsp
<%!
#EJB(mappedName="abc")
MathInter m;
%>
<%
out.write("previous result was "+m.showResult());
out.write("result is "+m.add((int)(Math.random()*100), (int)(Math.random()*100)));
%>
The problem is that on Lan, I have 2 computers with IP address as 192.168.1.4 and 192.168.1.2. The server begin 192.168.1.4, when I visit the client.jsp page from the server, a new object of MathImp is created, and then when I access via the other comp, the same object seems to be used
Isn't it required that a new request for a new client has a new object created?
Shortly: one JSP -> one instance of corresponding Servlet -> EJB injected once -> same instance is shared between all requests, no matter which client.
Longer explanation:
No, it is not required that container creates new instance for each new client. But it is required that for each dependency injection (as in your case) and for each JNDI lookup container creates new instance of stateful session bean.
In your case injection happens only once. That is because container compiles JSP to Servlet and there is only one instance of that Servlet (and consequently injection of ejbs to the fields of that servlet only once) that serves all requests. That's why same instance of MathInter is shared between all requests.
If you need per client instances (as is the case with stateful session beans) you should not inject those to servlet, but just for example lookup them and store reference to the HttpSession.
Related
I have got a serious problem where the DAO-layer stops returning records after a few calls. I'm using Spring Framework 5.3.10. The main components involved are:
Spring MVC Connection pooling over HikariCP 5.0.0
JDBC connector Jaybird 4.0.3 (Firebird 3.0.7 database server)
ThreadPoolExecutor (using default values)
Spring Transactions
Mybatis
I have got one Spring controller (A), that repeatedly (every 2 - 3 seconds) calls a method of a Spring Service (B) asynchronously (method marked with #Async) and a different parameter for each call. There is a DAO-layer (C) declared as a Spring service. The worker method in the Spring service (B) calls a DAO-method in the beginning of each run to retrieve a data set from a database table corresponding to the passed parameter. At the end of the execution of the worker method in the Spring service (B), rows corresponding to the input parameter are updated (not the field corresponding to the input parameter). The method in the Spring service (B) takes a long time to process the data, about 10 - 15 seconds.
After about the third or fourth call from the Spring controller (A), the call to the DAO-method returns an empty result set. When calling the method in the Spring service (B) slowly, waiting for the previous call to complete, everything is working correctly.
Setting transaction isolation has got no effect whatsoever.
I have tried to solve this problem for a couple of days now, and getting nowhere. I would be very grateful if somebody can point me in the right direction how to solve this. Using some kind of mutexes or semaphores is just a way to circumvent the problem without really solving it.
Schematically
Controller A <---------
| |
| | repeats every 2-3 secs.
Service B |
worker method |
takes 15 - 20 secs. ----
calls DAO-method getData(token)
|
do work
|
calls DAO-method updateData(token)
Controller (A)
#Controller
#RequestMapping("/test")
public class TestController {
#Autowired
private TestService testService;
...
...
#GetMapping(value="/RunWorker")
public String runWorker(ModelMap map, HttpServletRequest hsr) {
...
testService.workerMethod(token);
...
}
}
Service (B)
public interface TestService {
public void workerMethod(long token);
}
#Service
public class TestServiceImpl implements TestService {
#Autowired
private TestDAO testDao;
#Override
public void workerMethod(long token) {
List<MyData> myDataSet = testDao.getData(token);
...
// very long process
...
testDao.updateData(token);
}
}
DAO (C)
public interface TestDAO {
public List<MyData> getData(long token);
public void updateData(long token);
}
#Service
public class TestDAOImpl implements TestDAO {
#Autowired
private TestMapper testMapper; // using Mybatis mappers
public List<MyData> getData(long token) {
return testMapper.getData(token);
}
public void updateData(long token) {
testMapper.updateData(token);
}
}
Mapper class (D)
public interface TestMapper {
#Select("SELECT * FROM TESTTABLE WHERE TOKEN=#{token}")
public List<MyData> getData(#Param("token") long token);
#Update("UPDATE TESTTABLE SET STATUS=9 WHERE TOKEN=#{token}
public void updateData(#Param("token") long token);
}
Thanks #M. Deinum for the suggestion about #Repository. This did not help, however.
I remade the Spring service (B) to a Spring bean with prototype scope, and injecting it with #Lookup. The behavior is still the same. After the second call, the DAO-method getData returns an empty result set. Very puzzling and frustrating.
I solved the problem. It was probably resource exhaustion due to repeated multiple calls to the Spring service (B) with the same call parameters. I guess the statement pool got depleted, active statements not returning fast enough, and then returning empty data sets for each call.
Best regards,
Peter
I created Stateful, Stateless and singleton bean classes and trying to access them two different servlet. And running project on JBoss server.
When I access Stateful bean from each servlet two different bean object will be created and different states(data) are preserved for them. But stateless bean object is shared between both servlet. Singleton bean also behaves same way as stateless bean.
My question is why stateful and stateless bean behaves in opposite way? Is lifecycle of session bean is same as lifecycle of servlet?
FirstServlet.java
#WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
StatelessBean statelessBean;
#EJB
StateFullBean statefulBean;
#EJB
SingletonBean singletonBean;
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String message = "Beans not injected.";
String beanType = request.getParameter("beanType");
if ("Stateless".equals(beanType)) {
if (statelessBean != null) {
message = statelessBean.getHits();
} else {
message = "Stateless bean not injected.";
}
}
if ("Stateful".equals(beanType)) {
if (statefulBean != null) {
message = statefulBean.getHits();
} else {
message = "Stateful bean not injected.";
}
}
if ("Singleton".equals(beanType)) {
if (singletonBean != null) {
message = singletonBean.getHits();
} else {
message = "Singleton bean not injected.";
}
}
response.setContentType("text/html");
response.getWriter().print("<h1>" + message + "</h1>");
}
}
Similarly, I created one more servlet DemoServlet.java.
StateFullBean.java
#Stateful
public class StateFullBean{
int hits=0;
public String getHits() {
hits++;
return "StateFullBean number of hits " + hits;
}
public StateFullBean() {
System.out.println("StateFullBean created.");
}
}
StatelessBean.java
#Stateless
public class StatelessBean{
int hits=0;
public String getHits() {
hits++;
return "StatelessBean number of hits " + hits;
}
public StatelessBean() {
System.out.println("StatelessBean created.");
}
}
SingletonBean.java
#Startup
#Singleton(name="SingletonBean")
public class SingletonBean {
int hits=0;
public SingletonBean() {
System.out.println("SingletonBean created.");
}
public String getHits() {
hits++;
return "Singleton bean number of hits " + hits;
}
}
Am I missed something in code?
Everything is behaving as specified.
A stateless EJB delegates the call further to currently available instance in the pool. Apparently there's only one which is not used concurrently (yet) and therefore all clients have the same chance to access the same instance in the pool. If you fire more HTTP requests concurrently on the servlet(s), then chances increase that there's no available instance anymore and the container will create a new instance in the pool.
A stateful EJB is tied to its client (in your case, the web servlet instance). In other words, each servlet has its own stateful EJB instance which is not shared elsewhere.
A singleton bean is application wide and shared across all clients. In other words, each servlet will share the same singleton EJB instance.
Do note that the terms "client" and "session" in EJB context are absolutely not the same as those in WAR context and this is where many starters fall over. The EJB client is not the webbrowser, but the instance of the class where the EJB is injected (in your case, the web servlet instance). The EJB session is not the HTTP session, but the EJB-client session.
See also:
#Inject stateless EJB contains data from previous request
Why Stateless session beans?
When using #EJB, does each managed bean get its own #EJB instance?
I am new to EJB concept. I have seen the following in different website :
Sample 1:
#Stateless
#EJB(name="audit", beanInterface=AnotherEJBLocal.class)
public class EmployeeBean implements EmployeeServiceLocal, EmployeeServiceRemote {
#PersistenceContext(unitName = "EmployeeService")
private EntityManager manager;
public void doAction(){
try {
Context ctx = new InitialContext();
AnotherEJBLocal audit = (AnotherEJBLocal) ctx.lookup("java:comp/env/audit");
audit.doAnother();
} catch (NamingException e) {
throw new EJBException(e);
}
}
}
Sample 2:
public static void main(String[] a) throws Exception {
EmployeeServiceRemote service = null;
service = (EmployeeServiceRemote) new InitialContext().lookup("EmployeeBean/remote");
service.doAction();
}
Sample 3:
obj = ctx.lookup(ejb/CBDWebAppEAR/CBDWebApp.jar/<EJB name>/<Remote Interface Class Name>);
CBDWebApp is the project name in which the bean resides.
My question is:
What is the need & MEANING of java:comp/env/audit
Why same type of string is not used in case of Sample 2. I guess as
it is a remote EJB not local.
Why is the meaning of the EJB look up string in the Sample 3.
The java:comp/env/audit string is looking up the EJB reference that was declared earlier by the #EJB(name="audit", beanInterface=AnotherEJBLocal.class). Names declared by #EJB (and #Resource and all other EE references) are implicitly declared in the java:comp/env context. With this reference, the deployer can retarget the "audit" reference to any EJB in the application that implements the AnotherEJBLocal interface, or if the deployer doesn't specify anything, the javadoc for the #EJB annotation requires it to target a single EJB within the same application that implements the interface.
This main method is (probably) declared by a standalone Java program. In that case, it (probably) is configured via system properties to connect the JNDI server of an application server, which will return the remote reference to the client. The name that is looked up is vendor-specific, and it was probably configured for the EJB during deployment.
This is very similar to #2, the only difference being the specific string being used. In this case, it is probably relying on an application server's "default" binding name if none was configured for the EJB during deployment using the pattern ejb/<app>/<module>/<bean>/<interface>.
How to pass global variable to a referenced assembly?
I am modifying an asp.net app. It is required to log all Employee (the current user of the website) actions like saving a new customer or update invoice data. The UI layer is calling a referenced assembly BLL.dll.
I want to pass current Emplyee to the referenced assembly. The passed Employee should be shared accross all static methods in that dll. It should be thread safe because the Employee can be changed accross requests.
I can't expose static field in the BLL because the Employee is stored in session state.
I need something not static, Global, accessible by both assemblies (UI layer and BLL.dll), and thread safe.
I am thinking about using some variable stored in current thread object. but I don't know what exactly I should do??
Any workarrounds ??
Thanks
Basically you need something in your BLL that can get the reference. You can use a strategy pattern with an interface.
// IN BLL.dll
public interface IEmployeeContextImplementation
{
Employee Current { get; }
}
public static EmployeeContext
{
private static readonly object ImplementationLock = new object();
private static IEmployeeContextImplementation Implementation;
public static void SetImplementation(IEmployeeContextImplementation impl)
{
lock(ImplementationLock)
{
Implementation = impl;
}
}
public static Employee Current { get { return Implementation.Current; }
}
Then in your web app, implement IEmployeeContextImplementation with the session state and call SetImplementation only once in application start.
However, Session state is only good enough for within the context of a request. If you need it to go on a different thread, you will have to explicitly pass it to a different thread.
i have this in the server:
class Person{...}
and
#Stateless
public class HelloServiceBean implements HelloServiceLocal, HelloServiceRemote {
public Person getPerson(String name) {
return new Person(name);
}
}
And i have this in my client (in some different JVM):
public static void main(String[] a) throws Exception{
String name = "java2s";
HelloServiceRemote service = null;
service = (HelloServiceRemote)new InitialContext().lookup("HelloServiceBean/remote");
Person p = service.getPerson(name));
}
When i need to call, for example, getPerson() method from my EJB, which return an object of type of Person, how my client is going to understand that Person is a class ?
Do i have to re-write the Person class another time in my client (and also the HelloServiceRemote class), so it can understand what is a Person ? Or do i have to include the Ejb project into my client project ?
You have to include jar of EJB project at client side containing Interfaces, Entities & other utility classes used.
But exposing Entity Beans at client side is not preferable, you can get more information regarding this at http://www.ibm.com/developerworks/websphere/library/bestpractices/ejbs_access_entity_bean.html