Hot questions for Using Enterprise JavaBeans in weblogic12c

Question:

I am using Weblogic 12c (12.1.3 to be specific) to deploy my (EJB 3.1) application.

In my application, I have a @Stateful bean, which holds references to an EntityManager and other @Stateless beans, injected using @PersistenceContext and @EJB annotations respectively.

My issue is that when my stateful bean is being passivated and serialized to disk, Weblogic tries to serialize the references to the stateless beans as well, and throws a NotSerializableException referring to the bean's proxy that was injected by Weblogic. For comparison - the EntityManager reference is passivated and reactivated without issue at all. It is only the stateless beans who cause issues.

I know I can define @PrePassivate and @PostActivate methods to make my code work, but is there any way I can make the container handle the Stateless beans references on its own?

Attaching sample code which reproduces the problem for me.

Remote bean interface:

import javax.ejb.Remote;

@Remote
public interface Passivate {

    public void doSomething();

}

Stateful Bean implementation:

import javax.ejb.EJB;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Stateful;

@Stateful(mappedName = "PassivateBean")
public class PassivateBean implements Passivate {

    @EJB(mappedName = "NoStateBean")
    private NoState noStateBean;

    @Override
    public void doSomething() {
        System.out.println("Hello world");
    }

    @PrePassivate
    public void prePassivate() {
        // as a workaround - can set noStateBean to null here
    }

    @PostActivate
    public void postActivate() {
        // as a workaround - can lookup and set noStateBean here manually
    }
}

NoState Local interface:

import javax.ejb.Local;

@Local
public interface NoState {

    public void foo();

}

NoState bean implementation:

import javax.ejb.Stateless;

@Stateless(mappedName = "NoStateBean")
public class NoStateBean implements NoState {

    @Override
    public void foo() {
        System.out.println("foo");
    }

}

And finally, the exception I am getting when PassivateBean is being passivated to disk:

<Jul 14, 2015 2:36:20 PM IDT> <Error> <EJB> <BEA-010024> <Error occurred during passivation: java.io.NotSerializableException: passivateTest.NoStateBean_i02rk_Impl
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at weblogic.ejb.container.utils.Serializer.writeObject(Serializer.java:52)
    at passivateTest.PassivateBean_dmn8u8_Impl.writeObject(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
    at weblogic.ejb.container.swap.PassivationUtils.write(PassivationUtils.java:84)
    at weblogic.ejb.container.swap.DiskSwap.write(DiskSwap.java:173)
    at weblogic.ejb.container.manager.StatefulSessionManager.swapOut(StatefulSessionManager.java:1246)
    at weblogic.ejb.container.cache.LRUCache.passivateNode(LRUCache.java:199)
    at weblogic.ejb.container.cache.LRUCache.timerExpired(LRUCache.java:187)
    at weblogic.timers.internal.TimerImpl.run(TimerImpl.java:304)
    at weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:548)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)

Answer:

As of now, this seems like an actual bug/limitation in Weblogic 12.1.3 so I am posting my workaround as a possible solution.

To make the Stateful bean go through passivation successfully, one needs to implement methods annotated with javax.ejb.PrePassivate and javax.ejb.PostActivate. The @PrePassivate method will make the stateless bean reference point to null, and the @PostActivate method will perform a lookup for that bean when the bean is being activated again.

@PrePassivate
public void prePassivate() {
    noStateBean = null;
}

@PostActivate
public void postActivate() {
    // The lookup string is correct assuming the ejb module is deployed within an ear. If your setup is different the JNDI lookup name may be slightly different.
    noStateBean = InitialContext.doLookup("java:module/NoStateBean!NoState");
}

If there are no comments or other answers in the next couple of weeks or so, I will mark this answer as the solution.

Question:

Using WLS 12, I have the following EJB definition:

@Stateless
public class MyBean implements MyInterface {  ... }

@Remote
public interface MyInterface { ... }

I have also the following weblogic-ejb-jar.xml definition:

<weblogic-enterprise-bean>
    <ejb-name>MyBean</ejb-name>
    <enable-call-by-reference>true</enable-call-by-reference>
    <jndi-binding>
        <jndi-name>/ejb/myapp/server/MyBean</jndi-name>
    </jndi-binding>
</weblogic-enterprise-bean>

The ejb-jar.xml has no specific configuration to this bean.

My goal is to deploy the EJB under the following EJB-Name: /ejb/myapp/server/MyBean

I can achieve this using the annotation @weblogic.javaee.JNDIName("/ejb/myapp/server/MyBean") on MyBean but the annotation is specific to Weblogic. I try to find a way to define the JNDI-Name without any Weblogic specific annotation. Specific XML configuration is OK though.

The JNDI name must be the name I mentioned because it is referenced from another application where it is pratically impossible for technical reason to change the JNDI name reference.

Any idea how to configure the global JNDI name for this EJB?


Answer:

You need to add the class name of your interface in the jndi binding :

<weblogic-enterprise-bean>
    <ejb-name>MyBean</ejb-name>
    <enable-call-by-reference>true</enable-call-by-reference>
    <jndi-binding>
        <class-name>org.package.MyInterface</class-name>
        <jndi-name>/ejb/myapp/server/MyBean</jndi-name>
    </jndi-binding>
</weblogic-enterprise-bean>

Question:

I implemented SingletonService interface which is located inside weblogic API. This interface assure that the class which implements this interface is run only on one managed server. In my case I have two threads inside activate() method on SingletonService implementation class. The singletonService in migrated but threads are running as is on that server and it make duplicate entry inn my database.

When I do kill and restart on weblogic till some time the thread runs on both the server and some time run on one server.


Answer:

It is really simple trick to resolve this issue. I come to know How to stop thread. And I used same logic to stop the execution when SingletonService is deactivated. In deactivate() we added logic to stop the thread. We added simple flag it will helpful to break the execution of thread.

sample code

public void deactivate(){
 // take reference of thread and break the execution of thread 
 // call thread.interrupt();
} 

This is the simple trick I used to solve my problem.

Question:

I have deployed the code as war in WLS 12.1.3 where I am sending message from a Producer and the messages are consumed by the below code and the application is deployed as war in WLS server in Windows and it is listening but the same war is deployed with same version of 12.1.3 WLS in Linux but I can able to see the message count in the Queue Monitoring but the message is not listening by the application. How to track the application is reading the messages in Linux server and there is no update in logs.

@MessageDriven(mappedName = "jms/jjQueue", activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
 })
  public class JMSMessageConsumer implements MessageListener {

private final static Logger LOGGER = Logger.getLogger(JMSMessageConsumer.class);

public JMSMessageConsumer() {
}

@Override
public void onMessage(Message message) {
    if (message instanceof TextMessage) {
        try {

            String mess = ((TextMessage) message).getText();

            LOGGER.info("Message Received >> " + mess);

        } catch (JMSException e) {
            LOGGER.info("Error in exception" + e);
        }
    }

  }
 }

I found in my windows for the JMSMessageConsumer in WLS there is running cound but in Linux it is showing as "This EJB is not currently active on any running server." How to make it active in WLS as I have deployed this application as war.Please suggest how to make it active.


Answer:

I didn't start the service in WLS.After starting the service it is working fine.