Multiple Instances of Session Bean created & #PostConstruct method called - eclipselink

Project comprise of EJB 2.0 and EJB 3.0 Beans. I converted a session bean from EJB 2.0 to EJB 3.0 and as I start the project, it initialize the session bean multiple times. The session bean call other session beans which in turn calls different methods of this session bean. As long as it was EJB 2.0 session bean, only one instance was initialized but now multiple instances are initialized.
UtilitiesController Session Bean initiates a thread which calls Miscellaneous Class (Helper Class POJO) which in return calls ProductScheme Session Bean which calls ServerGlobalValues (Helper Class POJO) and it calls UtilitiesController Session Bean
Following are the logs:
setSessionContext Called!
setSessionContext Called!
#PostConstruct method Called!
Starting Initialization
<2013-06-07 15:03:53.535--ServerSession(316201757)--EclipseLink, version: Eclipse Persistence Services - 2.1.3.v20110304-r9073>
<2013-06-07 15:03:53.535--ServerSession(316201757)--Server: 10.3.5.0>
setSessionContext Called!
setSessionContext Called!
#PostConstruct method Called!
Starting Initialization
<2013-06-07 15:03:53.691--ServerSession(316201757)--The DatabaseSession has an external transaction controller defined by something other than the ServerPlatform. EclipseLink will permit the override of the external transaction controller, but we recommend you consider the alternative of subclassing org.eclipse.persistence.platform.server.ServerPlatformBase and override getExternalTransactionControllerClass().>
<2013-06-07 15:03:53.691--ServerSession(316201757)--EclipseLink, version: Eclipse Persistence Services - 2.1.3.v20110304-r9073>
<2013-06-07 15:03:53.691--ServerSession(316201757)--Server: 10.3.5.0>
setSessionContext Called!
setSessionContext Called!
#PostConstruct method Called!
Starting Initialization
<2013-06-07 15:03:53.722--ServerSession(316201757)--The DatabaseSession has an external transaction controller defined by something other than the ServerPlatform. EclipseLink will permit the override of the external transaction controller, but we recommend you consider the alternative of subclassing org.eclipse.persistence.platform.server.ServerPlatformBase and override getExternalTransactionControllerClass().>
<2013-06-07 15:03:53.722--ServerSession(316201757)--EclipseLink, version: Eclipse Persistence Services - 2.1.3.v20110304-r9073>
<2013-06-07 15:03:53.722--ServerSession(316201757)--Server: 10.3.5.0>
setSessionContext Called!
setSessionContext Called!
#PostConstruct method Called!
Starting Initialization
<2013-06-07 15:03:53.847--ServerSession(316201757)--The DatabaseSession has an external transaction controller defined by something other than the ServerPlatform. EclipseLink will permit the override of the external transaction controller, but we recommend you consider the alternative of subclassing org.eclipse.persistence.platform.server.ServerPlatformBase and override getExternalTransactionControllerClass().>
<2013-06-07 15:03:53.847--ServerSession(316201757)--EclipseLink, version: Eclipse Persistence Services - 2.1.3.v20110304-r9073>
<2013-06-07 15:03:53.847--ServerSession(316201757)--Server: 10.3.5.0>
setSessionContext Called!
setSessionContext Called!
#PostConstruct method Called!
Starting Initialization
<2013-06-07 15:03:53.879--ServerSession(316201757)--The DatabaseSession has an external transaction controller defined by something other than the ServerPlatform. EclipseLink will permit the override of the external transaction controller, but we recommend you consider the alternative of subclassing org.eclipse.persistence.platform.server.ServerPlatformBase and override getExternalTransactionControllerClass().>
<2013-06-07 15:03:53.879--ServerSession(316201757)--EclipseLink, version: Eclipse Persistence Services - 2.1.3.v20110304-r9073>
<2013-06-07 15:03:53.879--ServerSession(316201757)--Server: 10.3.5.0>
javax.ejb.EJBTransactionRolledbackException: EJB Exception: ; nested exception is: Exception [EclipseLink-8030] (Eclipse Persistence Services - 2.1.3.v20110304-r9073): org.eclipse.persistence.exceptions.JPQLException
As it can be seen from logs that setSessionContext is called twice for each instance creation and #PostConstruct method is also called before initialization.
Can anyone please point out what can be the reason behind such behaviour. Is there any configuration missing?

I forgot to mention that the helper classes (i.e Miscellaneous Class & ServerGlobalValues) are singleton and the behaviour of singleton class is unexpected. I found that the reason for multiple instances has relation with calling getInstance() of helper classes. If I call getInstance() inside PostConstruct, I see multiple instances of both helper classes and controller but moving it to class level resolves multiple instance issue.

Related

Hangfire cannot find registered service

I have an issue with Hangfire, most likely because of my ignorance about some topics.
I have a host/plugins infrastructure, where each plugin is loaded at runtime and it register its interfaces.
public void ConfigureServices(IServiceCollection services, IConfigurationRoot Configuration)
{
services.AddTransient<IManager, Manager>();
services.AddTransient<IAnotherManager, AnotherManager>();
this.AddControllers(services);
}
Some plugin may add jobs using Hangfire, which are also set during runtime
public void ScheduleJobs()
{
RecurringJob.AddOrUpdate<IManager>(n => n.SayHello(), Cron.Monthly);
}
The issue I have is, while any service registered directly in the host is correctly resolved in hangfire,
all the interfaces (ex IManager) that are defined in external assemblies aren't found.
I added a customer JobActivator where I'm passing the IServiceCollection and I can actually see that those external services are registered (and I can use them anywhere else but from Hangfire), but still
in the JobActivator, when Hangfire tries to resolve the external service, it fails.
public override object ActivateJob(Type type)
{
// _serviceCollection contains the IManager service
var _provider = _serviceCollection.BuildServiceProvider();
// this will throw an Exception => No service for type '[...].IManager' has been registered.
var implementation = _provider.GetRequiredService(type);
return implementation;
}
In the same example, if I use the Default JobActivator, then the exception I get is System.MissingMethodException: Cannot create an instance of an interface.
I could enqueue the job using the Class instead of the Interface, but that's not the point and anyway if the Class has services injected, those will not be resolved as well.
What am I missing?
The problem has been solved. The solution is to add a specific IoC Container for hangfire. I used Unity. In that way dependencies are resolved correctly.
Thanks Matteo for making it clear that HF requires its own IoC container. This link makes the point too:
Hangfire needs to have it's own container with dependencies registered independently of the global UnityContainer. The reason for this is twofold; Hangfire's dependencies need to be registered with the PerResolveLifetimeManager lifetime manager. This is so that you don't get concurrency issues between workers that have resolved a dependency to the same instance. For example; with the normal HierarchicalLifetimeManager, two workers needing the same repository dependency may resolve to the same instance and share a common db context. The workers are meant to each have their own db contexts. Secondly, when the OWIN bootstrapper is run, the global UnityContainer may or may not be initialised yet and Hangfire is unable to take in a reference to the container. So giving Hangfire it's own managed container is a clear separation of purpose and behaviour in how our dependencies are resolved.

Glassfish 3: Calling method on ejb in ServletContextListener.contextDestroyed method leads to exception

I have an #Singleton ejb which will be called in a ServletContextListener contextInitialized and contextDestroyed method. The call in the contextDestroyed method leads to an Exception:
javax.ejb.EJBException: Attempt to invoke when container is in STOPPED
It looks as if the contextDestroyed method is called after the container went down leaving
me with no chance to access any resources like my ejb.
Does anyone know if there is any way to know about application shutdown before the container
is down?
Thanx in advance.
Cheers, Sven
You could use the #PreDestroy annotation on a method directly in your #Singleton bean. Thus marked, the method will be called before the bean destruction, during the application shutdown.

Differences in calling JMX MBean remotely or from servlet deployed in the same JVM

I have several applications deployed on WebLogic server. Those applications expose some JMX MBeans. When I call operations on those MBeans remotely through JConsole or JRMC, they work fine.
But since JMX is not really firewall-friendly I have created another simple Servlet application that is deployed on the same server and that invokes operations on a set local MBeans. From within servlet I use ManagementFactory.getPlatformMBeanServer() to find and call MBeans of other applications deployed in the same JVM, but for some operations I get either ClassCastException or ClassNotFoundException depending on the operation that is called, but some operations work fine.
Any ideas?
I suspect what is happening here is that your servlet thread has a context classloader that is different from that of the MBeans that you are invoking against. Consequently, if the MBean attributes, operation parameters or return values contain types that are not core JVM classes (or classes not shared from the same root classloader), you will get ClassCast, ClassNotFound and ClassDefNotFound Exceptions.
This procedure may work for you. What you need to do is temporarily change the context classloader of the servlet thread to the same classloader as the MBean was loaded from. Once the invocation is complete, you set it back again. Since you know the ObjectName of the target MBean, the MBeanServer will supply you the correct classloader.
Here's a basic example:
public void callMBean() throws MalformedObjectNameException, NullPointerException, InstanceNotFoundException {
final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
try {
ObjectName targetObjectName = new ObjectName(".....");
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ClassLoader tmpClassLoader = server.getClassLoaderFor(targetObjectName);
Thread.currentThread().setContextClassLoader(tmpClassLoader);
// ==========================================
// Invoke operations here
// ==========================================
} finally {
Thread.currentThread().setContextClassLoader(currentClassLoader);
}
}

Windsor IOC in a non-Http WCF application - error initialising IOC kernel

I have a problem trying to initialise my IOC container in a WCF application. The application is non HTTP based using WAS.
When I start the application I get this error message...
Kernel was null, did you forgot to call DefaultServiceHostFactory.RegisterContainer
I have seen other answers to this solution which say to do the following...
Add a Factory definition to the ServiceHost definition e.g.
Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration"
Create a class in th App_Code folder with a static method called AppInitialize(). This method should then automatically be called and you can use it to register your container.
I have done this but my AppInitialize method is not called and I am still getting the error above.
Thanks.

Are CDI event observer methods compatible with EJBs?

I have a Singleton EJB (javax.ejb.Singleton version. sigh.) which has a CDI observer method on it. When I try to deploy this to glassfish 3.1 the server fails to deploy the EAR file without any real explanation - simply saying there was an exception during deployment without any more details.
SEVERE: Exception while loading the app
SEVERE: Exception while shutting down application container
....
SEVERE: Exception while shutting down application container : java.lang.NullPointerException
This is the CDI event listener :
public void updateFromGranule(#Observes #CloudMask GranuleAvailableEvent granuleEvent) {
LOG.info("updating cloud map");
update(granuleEvent.getGranule(), CloudMask.class);
fireUpdate();
}
If I change the Singleton bean to just be an #ApplicationScoped bean the app deploys fine. Similarly, if I remove the CDI event observer method the application deploys fine.
I actually need the class to be an EJB singleton because I want the transaction, thread safety etc. of EJBs, so just leaving this as a #ApplicationScoped POJO isn't much use to me. The problem doesn't seem to be limited to Singleton beans though - I've experimented by changing the annotation to #Stateless and #Stateful and I get the same issue.
It seems to me that this might be a bug in Weld, perhaps Weld and EJB are fighting about how they proxy that method - presumably EJB needs to add an interceptor class and wrap that method to ensure thread safety, and Weld is trying to do something else to make the event listener work?
Am I misunderstanding something here, and should CDI event handlers simply not be used on EJBs (in which case there should be better error messages from glassfish) - or is this actually just a bug in the CDI or EJB implementation?
I think this is the answer :
CDI observer methods must apparently either be static or declared in the local interface of an EJB if the EJB declares a local interface. Normally if you try to declare an observer method that isn't in the local interface you get an exception from Weld like this :
org.jboss.weld.exceptions.DefinitionException: WELD-000088 Observer method must be static or local business method: [method] public org.stain.ObserverBean.testMethod(EventClass) on public#Singleton class org.stain.ObserverBean
For some reason glassfish does not report this exception properly when loading my EAR file and simply says Exception while loading the app.
Adding the method to the local interface (or removing the interface declaration on the class) fixes the problem and allows the application to load normally.
I noticed the same problem with the latest version of weld. But if you add the #LocalBean annotation it will work with #Singleton and #Singleton #Startup.