WildFly EJB UnknownSessionID - java

I just started learning ejb and now have problems.
My ejb code is
#Stateful
#StatefulTimeout(value=80, unit=TimeUnit.SECONDS)
public class HelloWorldBean
{
int i = 0;
public int SayHello()
{
return i++;
}
}
It's only for testing. Ok, so, after 80 sec I get problem from WildFly
javax.ejb.NoSuchEJBException: WFLYEJB0168: Could not find EJB with id UnknownSessionID [5156495653657051576570495270526865695251507057526654654868486852]
1) I thought that after 80 sec ejb should be deleted and after refresh page I'll get new instance. Or after 80 sec instance going to passivation (saving on hard drive) ?
2) What is this problem with UnknownSessionID? Why WildFly doesn't want assign ID to session ?
3) With this code example - Why if I use two different browsers at the same time I have the same instance? I thought stateful bean works as one_bean-to-one_user ? So in Google Chrome and Firefox, for example, I should start from i=0 and shouldn't have any similar data between browser sessions
I'll be appreciated for your help!

1) The specification says exactly that removal will happen after a stateful timeout. Wildfly follows the EJB specification.
2) An Unknown session ID is a way of saying that the bean does not exist.
3) You must have been using the same servlet to access the bean code above. This means that you must have been using just a single client to access the bean.

Related

How spring rest recognizes a new session?

I have a problem to understand how spring rest recognizes a new session. Let's assume we have simple session bean defined like that:
#SessionScope
public class Counter {
private int counter;
public int inc() {
return counter++;
}
}
We have also a simple rest controller that provides get method that calls inc() method of the Counter and returns its current value.
I was expecting that every single request (made in postman) will result in getting value 1 since there is no way to recognize the session. For instance there is no JSESSION_ID cookie like it was in traditional servlet-based app. What I actually get is increased value of the counter and it does not matter if I make request in postman, web-browser or curl. Even using browser in private mode still refers to the same instance of the bean.
The question is how spring recognizes new sessions and how I can simulate different sessions in my "test" envinronment.
Answer found - bean was missing #Component annotation. With that JSESSION_ID cookie is created and obviously this is the way spring recognizes session.

Spring boot 2 Embedded tomcat 8 - slow request handling [duplicate]

I have built a web application that uses
SpringBoot v1.3.6.RELEASE
Tomcat 8.0.36
Java 1.8u101
on CentOS 7.2
The web application is also a SOAP client that calls out to another web application.(JAX-WS RI 2.2.9) If the applications remains idle for 15 seconds the first webservice call stalls for nearly 2 seconds. It appears that the stall happens in o.a.c.loader.WebappClassLoaderBase.
After idle 15 seconds
16:02:36.165 : Delegating to parent classloader org.springframework.boot.loader.LaunchedURLClassLoader#45283ce2
16:02:36.170 : Searching local repositories
16:02:36.170 : findResource(META-INF/services/javax.xml.soap.MetaFactory)
16:02:38.533 : --> Resource not found, returning null
16:02:38.533 : --> Resource not found, returning null
Next request no idle time
16:07:09.981 : Delegating to parent classloader org.springframework.boot.loader.LaunchedURLClassLoader#45283ce2
16:07:09.984 : Searching local repositories
16:07:09.985 : findResource(META-INF/services/javax.xml.soap.MetaFactory)
16:07:09.986 : --> Resource not found, returning null
16:07:09.986 : --> Resource not found, returning null
16:07:09.988 : findResources(META-INF/services
All above messages produced by o.a.c.loader.WebappClassLoaderBase and they are apparently being caused by ClientSOAPHandlerTube.processRequest which is from JAX-WS RI.
You'll notice the first call takes over 2 seconds but subsequent calls take only milliseconds.
I'm wondering if anyone has experienced this behavior?
Possible solutions:
Is it possible to change out the classloader used by tomcat in springboot to use ParallelWebappClassLoader
Or maybe this is a product of the reloadable flag on the classloader but I don't see how to change that flag in springboot.
When run using Jetty as the container this does not occur.
Final Solution: (thanks to Gergely Bacso)
#Bean
public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
customizeTomcat((TomcatEmbeddedServletContainerFactory) container);
}
}
private void customizeTomcat(TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory) {
tomcatEmbeddedServletContainerFactory.addContextCustomizers(new TomcatContextCustomizer() {
#Override
public void customize(Context cntxt) {
cntxt.setReloadable(false);
}
});
}
};
}
Actually your findings are quite good and you have 90% answered your question already. These two facts:
"it appears that the stall happens in o.a.c.loader.WebappClassLoaderBase"
"when run using Jetty as the container this does not occur."
show that it is going be a Tomcat-related problem because:
o.a.c. stands for org.apache.catalina
Your code works well on another container. (Jetty)
You also observed, that the issue is happening after 15 seconds of idle time. This perfectly corresponds to Tomcat's default checkInterval setting, which is:
The number of seconds between checks for modified classes and
resources, if reloadable has been set to true. The default is 15
seconds.
So in short: currently your reloadable flag is ON, and Tomcat tries to reload your classes which is handy during development, but unacceptable in any other case. The way to switch it off is not via Spring-boot though.
SOLUTION:
You need to locate your context.xml / server.xml where you will find your Context defined like this:
<Context ... reloadable="true">
Remove the reloadable flag, and you have solved the problem. The file itself can be either in $CATALINA_BASE/conf of $CATALINE_HOME/conf, but in reality these locations can be a bit tricky to find if you are using some IDE to manage Tomcat for you.
In case of embedded Tomcat with Spring-boot:
The class you can use to manipulate Tomcat settings is: EmbeddedServletContainerCustomizer.
Through this you can add a TomcatContextCustomizer (addContextCustomizers) so that you can call setReloadable on the context itself.
I do not see any reason for Spring-boot needing this flag on true.

Spring Event for all Contexts being initialized

A similar question has been answered...
Here: Listener for server starup and all spring bean loaded completely
Here: How to add a hook to the application context initialization event?
and several other places.
In my primary application, when the Root Spring context initializes it will trigger three child contexts to initialize. When listening for an event to fire (based on the ContextRefreshedEvent), this results in four total events. This does not give the consumer of these events accurate information regarding the overall state of the application's Spring context.
Unfortunately I don't have the ability to change the primary application. The code that I'm wrestling with now is packaged as a jar and loaded into the primary application using a plugin architecture. I am able to hook into the application's Spring context without issue, and I can successfully receive ContextRefreshEvent triggers.
What I'm looking for is a way to understand if all Spring application contexts in the primary application have completed. One thing I tried was to manually keep track of the starting and completing of the application context (using a map) so that I could tell when all known application contexts were finished initializing. This didn't work for me, as I found that the ContextStartedEvent didn't trigger during Spring's refresh operation.
Additional things that could work for me would be knowing how many application contexts exist or how many beans there are that need to be loaded. That way I could keep track of them as they finished and ultimately know that all application contexts are complete.
Any ideas would be appreciated.
EDIT
In an attempt to ask as pointed a question as possible, I made this question too prescriptive in terms of the implementation. Here is the actual problem that I was trying to solve (in the form of a question):
How might a plugin, packaged as a jar inside of a webapp, tell when the context of the webapp has been deployed successfully in Tomcat?
Through testing, I thought it was fairly safe to assert that the initialization of the Spring context was synonymous with the deploy phase of the application through Tomcat. This may be false, but it lined up well enough.
Broadening the scope of the fix from exclusively using Spring, I was able to come up with a solution to the problem. I will post that as a separate answer.
As of Spring 2.5.X < 4.X
One thing you could do is listen for ContextStartedEvent-s, add them to a map and then once ContextRefreshedEvent-s are triggered, wait while all contexts are refreshed.
This still might be not safe if the context is refreshed multiple times though...but at least a place to start.
As of Spring 4+
Reading ContextRefreshedEvent javadocs:
Event raised when an {#code ApplicationContext} gets initialized or refreshed.
What this means is that you can have your own logic to track whether that context was initialized or refreshed.
#EventListener( { ContextRefreshedEvent.class } )
void contextRefreshedEvent( ContextRefreshedEvent e ) {
ApplicationContext context = ( ApplicationContext ) e.getSource();
System.out.println( "a context refreshed event happened for context: " + context.getDisplayName() );
}
Meaning - the first time you'll get an event with that context - you will know that it was initialized. The following times - you will know that it was refreshed.
Being brutally simple ( no optimizations ) you can do the following:
private final Map<String, String> contextStatuses = new HashMap<>();
#EventListener( { ContextRefreshedEvent.class } )
public void contextRefreshedEvent( ContextRefreshedEvent e ) {
ApplicationContext context = ( ApplicationContext ) e.getSource();
if ( !contextStatuses.containsKey( context.getDisplayName() ) ) { // initialized
contextStatuses.put( context.getDisplayName(), "initialized" );
} else { // refreshed
contextStatuses.put( context.getDisplayName(), "refreshed" );
}
checkAllContextsRefreshed();
}
private void checkAllContextsRefreshed() {
for ( String status : contextStatuses.values() ) {
if ( !"refreshed".equals( status ) ) {
return;
}
}
doWhenAllContextsRefreshed();
}
Per the edit on my question, here is the solution that I went with:
In the plugin that is packaged inside the primary application, I added a check using JMX against the stateName attribute of the WebModule type under Catalina. This isn't the exact code I used, but for simplicity the logic looks like this:
ObjectName name = new ObjectName("Catalina:j2eeType=WebModule,name=//localhost/" + contextPath + ",J2EEApplication=none,J2EEServer=none");
MBeanServer mx = ManagementFactory.getPlatformMBeanServer();
String state = String.valueOf(mx.getAttribute(name, "stateName"));
if (state.equals("STARTED")) {
LOGGER.warn("SUCCESS!");
}
As I mentioned in the edit, equating Tomcat deploy to Spring context initialization was close, but ultimately it wasn't a fair comparison. Using this JMX endpoint gives me a very accurate representation of the state of the Tomcat deploy.

How spring session beans saved ? replicating spring session beans via Hazelcast

I'm trying to integrate Hazelcast (lasted version - 3.3) session replication.
Our infrastructure consists of :
Apache 2.0 server for the load balancing
Tomcat 7 servers serving our web application
Our main reasons are:
Duplicate user session for high availability
Atmosphere web-socket PubSub servlet need share the same data in order to make full
broadcasting
integrating Hazelcast to our Environment:
each of the tomcat servers will serve as Hazelcast member
basically Hazelcast WebFilter is the first one that executes and its
wrap with : WebFilter->HazelcastSession->setAttribute() implements
HttpSession interface
each time setAttribute is called Hazelcast sync the session attribute
with the rest of the cluster members.
now - its seems like every spring bean we injecting scoped as session bean don't get replicated .
as a workaround :
Save only basic session information via #Context annotation
Dont use Spring session scope , only Singletons and inject the HazelcastInstance
I can Wrap the relevant data as Hazelcast structures
Also, when i looked on other stackoverflow i saw the following : Spring "session" scope of a bean?
The Spring session does not exactly match the HttpSession, and even
the Spring documentation on the #SessionAttributes annotation says
that it might be stored in the session or "some conversational
storage". I got that from [The Spring docs for 2.5][1] I've basically
quit trying to make sense of it, and just got on with my life, if I
want something stored in the HttpSession, I just have Spring inject
the HttpSession to me, assuming you're using Spring MVC its pretty
easy, instructions on the same page.
[1]:
http://static.springsource.org/spring/docs/2.5.x/reference/mvc.html
Its seems strange , Does Spring session beans not exactly match the HttpSession.setAttribute ?
How spring know how to #Inject the proper bean ?
Maybe Spring save the Beans in an internal data storage and only in
the Injection phase Spring getting the proper element using the same
session id attribute and bind the proper bean.
is there any way to control this behavior ?
Update :
debugging spring-web -> ServletRequestAttributes-> is using the
Server impl HTTPSession (For example - in Dev Jetty - org.eclipse.jetty.server.session.HashedSession)
this way the Bean is update in the HTTPSession but skipping the
HazelcastSession :-(
/**
* Update all accessed session attributes through {#code session.setAttribute}
* calls, explicitly indicating to the container that they might have been modified.
*/
#Override
protected void updateAccessedSessionAttributes() {
// Store session reference for access after request completion.
this.session = this.request.getSession(false);
// Update all affected session attributes.
if (this.session != null) {
try {
for (Map.Entry<String, Object> entry : this.sessionAttributesToUpdate.entrySet()) {
String name = entry.getKey();
Object newValue = entry.getValue();
Object oldValue = this.session.getAttribute(name);
if (oldValue == newValue) {
this.session.setAttribute(name, newValue);
}
}
} catch (IllegalStateException ex) {
// Session invalidated - shouldn't usually happen.
}
}
this.sessionAttributesToUpdate.clear();
}
thanks in advance ,
elad.

Can Servlets have multi-step interactions?

Is there any way to start executing java Servlet code (specifically, in Websphere Application Server) (one session, one thread on the Servlet) and then pause to get more information from the calling client at various points? I require that the current session, and ongoing Servlet thread, not die until specified, and instead keep waiting (open) for information from the client.
Is this kind of ongoing conversation possible? Or can the Servlet call to "doPost" only be started - and then the Servlet ignores the client until it finishes?
As suggested, I would use an object stored in session to maintain the state needed. You can also modify the session on a servlet by servlet basis if you need certain actions to extend the session timeout beyond the webapp defaults using the following method in the HttpSession API:
public void setMaxInactiveInterval(int interval) Specifies the time, in seconds, between client requests before the servlet container will invalidate this session. A negative time indicates the session should never timeout.
You just need to establish your logic for your object setting/retrieval from session. Typically something like this:
HttpSession session = req.getSession();
MyBeanClass bean;
Object temp = null;
temp = session.getAttribute("myBean");
if(temp !=null) {
bean = (MyBeanClass) temp;
} else {
bean = new MyBeanClass();
}
// Logic
session.setAttribute("myBean", bean);
You can save/update your session state between requests and when the next request comes, you can restore and continue whatever you were doing.
I have not done this with directly, but the underlying support is somewhat related to Jetty's continuation model and Servlet 3.0 Suspend/Resume support.
Web frameworks that work like the post description (actually, they are resumed across different connections) are sometimes called Continuation-Based frameworks. I am unsure of any such frameworks in Java (as the Java language is not conducive to such models) but there are two rather well known examples of the general principle:
Seaside (for Smalltalk) and;
Lift (for Scala).
Hope this was somewhat useful.

Categories

Resources