Hot questions for Using Enterprise JavaBeans in rmi

Question:

I am getting the exception org.hibernate.PersistentObjectException: detached entity passed to persist. From the numerous posts on this forum and elsewhere, I understand that this happens in two cases(not considering One-One annotations etc),

  1. There is an issue with the transaction going out of scope
  2. An id is set where it should be automatically generated.

I see neither of these happening with my code. I am unable to reproduce the error, because I don't have the data which initially triggered it. On other data it runs perfectly fine. I have provided an SCCE below:

public class MyProcessor {
    private MyImportEJB myEJB = MyImportEJB.getInstance();
    private List<MyClass> saveQueue = new ArrayList<MyClass>();
    public void process() {
        List<X> rawData = getListOfX();
        for(X x:rawData) {
             processX();
         }
         saveFoos(saveQueue);   
     }

     public void saveOrUpdateFoos(List<Foo> foos) {

        for(MyClass foo:foos) {
              MyClass existingFoo = myEJB.getFoosForWidAndDates(foo.getWid(), foo.getEffBeginDt(),foo.getEffEndDt());
              if(existingFoo == null) saveQueue.add(foo);
              else {
                   existingFoo.updateIfDifferent(foo);
                   saveQueue.add(existingFoo);
              }
         }

         if(saveQueue.size() > 5000) {
             myEJB.saveObjects(saveQueue);
             saveQueue.clear();
         }
     }

     public void processX() {
          ArrayList<MyClass> foos = new ArrayList<MyClass>();

          if(x.reportPeriod != null && x.gravity != null){
              MyClass foo = new MyClass();
              foo.setId(null);
              foo.setWId(x.getWid());
              foo.setEffBeginDt(x.reportPeriod);
              foo.setEffEndDt(addOneMonth(x.reportPeriod));
              foo.setGravity(x.gravity);

              foos.add(foo);
          }
          saveOrUpdateFoos(foos);

     }
 }

MyImportEJB.java:

@Stateless
@EJB(name = "MyImportEJB", beanInterface = MyImportEJB.class)
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
@PermitAll
public class MyImportEJB{
    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void saveObjects(List<? extends P> mappedObjects) 
    {
        for (P mappedObject : mappedObjects)
        {
            this.saveObject(mappedObject);
        }
    }


    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void saveObject(P mappedObject) 
    {
        EntityManager entityManager = this.getEntityManager();

        Object identifier = this.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(mappedObject);
        if (identifier != null) {
            Object existingObject = entityManager.find(mappedObject.getClass(), identifier);

            if (existingObject != null) {
                entityManager.merge(mappedObject);
                return;
            }
         }

         entityManager.persist(mappedObject);
    }

    public MyClass getFoosForWidAndDates(Integer wid, Calendar effBeginDt, Calendar effEndDt) {
         try {
            return (MyClass)((this.entityManager
        .createQuery("select M from MyClass M where wid = :wid and effBeginDt = :effBeginDt and effEndDt = :effEndDt ", MyClass.class)
        .setParameter("wid",wid)
        .setParameter("effBeginDt", effBeginDt)
        .setParameter("effEndDt", effEndDt)).getSingleResult());
         } catch(NoResultException | NonUniqueResultException e) {
            return null;
        }
    }
 }

MyClass.java

public MyClass{

      @Id
      @GeneratedValue(strategy=GenerationType.IDENTITY)
      @Column(name = "Id")
      private Integer id;

      @Column(name = "wid")
      private Integer wId;

      @Column(name = "eff_begin_dt")
      private Calendar effBeginDt;

      @Column(name = "eff_end_dt")
      private Calendar effEndDt;

      @Column(name = "gravity")
      private Double gravity;

      private Integer dataDownloadId;

      public void updateIfDifferent(MyClass other) {
          if(other.gravity != null && other.gravity != this.gravity) this.gravity = other.gravity;
          //same for effBeginDt andeffEndDt

      }

 }

persistence.xml

  <?xml version="1.0" encoding="UTF-8" ?>

 <persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
    <persistence-unit name="ProdData">
        <description>ProdData Database Persistence Unit</description>
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>java:jboss/ProdDataJNDI</jta-data-source>
        <class>path.to.MyClass</class>
        <class>path.to.X</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>

        <properties>
            <property name="hibernate.show_sql" value="false" />
         </properties>
    </persistence-unit>
 </persistence>

The exception is thrown on calling entityManager.persist(mappedObject) <- MyImportEJB.saveObject <-MyImportEJB.saveObjects. I dont have the line number

I have tried writing a sample program where I get an existingFoo object from the database, update and save it, because that was the most likely source of the error. But I could not reproduce the error. Please help.

EDIT: Here are the details of getListofX() as requested

from MyProcessor.java:

public List<X> getListOfX() {
    return myImportEJB.getUnprocessedIds(X.class, 30495);
}

from the file MyImportEJB.java:

@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public List<Integer> getUnprocessedIds(Class<? extends ProductionRawData> clazz, Integer dataDownloadId) {
    String canonicalName = clazz.getCanonicalName();

    String queryStr = "select id from " + canonicalName + " where datadownloadId = :dataDownloadId and isProcessed != 1";

    TypedQuery<Integer> query = this.entityManager.createQuery(queryStr, Integer.class)
        .setParameter("dataDownloadId", dataDownloadId);
    try {
        return query.getResultList();
    } catch(NoResultException nre) {
         return new ArrayList<T>();
    }
}

EDIT: Also added the details of getFoosForWidAndDates(). It was suggested to me that I set the id on a new Foo to null before adding it to the save queue. I would like to know if it is possible that the id is being set "under the hood" by Hibernate to an unacceptable value


Answer:

I think this could be your issue

 if(saveQueue.size() > 5000) {
     myEJB.saveObjects(saveQueue);
     saveQueue.clear();
 }

You are filling the saveQueue up to 5000, and then you try to persist / merge them. I'm not sure about Hibernate, but EclipseLink's default shared cache size is 1000. That means, you could fill up saveQueue with, for example, 2000 existing Foos and, by the time you call persist() on them, they are no longer in entity manager's cache. This leads to calling persist() on detached instance which has id already set.

In your case, I think it would be perfectly OK to call entityManager.merge(mappedObject) on all objects, regardless of weather it is an existing object or not, because it will update existing ones, and persist new ones.

Question:

We have an EJB application deployed on WebSphere 8.5, We are getting the following exception on console,

java.rmi.Exception:CORBA NO_RESPONSE 0x4942fb01 Maybe: nested exception is:
RESPONSE: Request 221370 timed out vmcid: IBM minor code: B01 Completed maybe

I can also see the root cause of exception as below:

caused by: org.omg.CORBA.NO_RESPONSE: Request timed out vmcid: B01 Completed maybe
at com.ibm.rmi.iiop.Connection.getCallStream(Connection.java:2493)

The effect of it is end user is unable to connect to the application.

Upon doing some analysis: I found out that main reason could be the connection pool settings. So Can someone please help me on following:

  • possible root causes of above exception
  • possible way to fix this exception

Answer:

Request timed out means that the EJB request timed out (default 180 seconds): https://www.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/uorb_rsetg.html

This may have many causes, but in general, it's best to analyze the performance of the EJB backend service (e.g. garbage collection, long response times due to a database, etc.). Here is a place to start on investigating general WAS performance problems: https://publib.boulder.ibm.com/httpserv/cookbook/Recipes-WAS_Traditional_Recipes-General_WAS_Traditional_Performance_Problem.html

A key item is step 8 which gathers thread dumps and basic OS statistics during the problem. If you are stuck analyzing that data, you may open an IBM support request with that MustGather data.

Question:

I am developing an application in javafx that connects via RMI with an EAR. This EAR connects to a SQLServer DB and maps POJOS using hibernate.

These POJOS contain bidirectional OneToMany and ManyToOne relationships. As a consequence these relationships are mapped as List .

Company.java

@Entity
@Table(name = "Company")
public class Company implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = 1L;

@Id
@Column(name="id_company",nullable = false)
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;

@OneToMany(mappedBy = "company",cascade = CascadeType.ALL )
@ElementCollection
private List<Client> Clients;

//GETTERS&SETTERS   

}

Client.java

@Entity
@Table(name = "Client")
public class Client implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = 1L;

@Id
@Column(name="id_client",nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; 

@ManyToOne
private Company company;

//GETTERS&SETTERS   

}

When I execute this, T being Company:

public default T selectById(Serializable id, Class<T> entityClass,Session session)throws HibernateException {
    T obj = null;
    obj = session.get(entityClass, id);
    return obj;
}

The result is the POJO with all the corresponding information, but in debug view see this:

The object is successfully instantiated and my desktop application receives the object perfectly, but if the object sent it to the server again using a method that receives as a parameter the object Company then I have this Error.

javax.ejb.EJBException: java.io.StreamCorruptedException: serialVersionUID does not match!
at org.jboss.as.ejb3.remote.AssociationImpl.receiveInvocationRequest(AssociationImpl.java:128)
at org.jboss.ejb.protocol.remote.EJBServerChannel$ReceiverImpl.handleInvocationRequest(EJBServerChannel.java:450)
at org.jboss.ejb.protocol.remote.EJBServerChannel$ReceiverImpl.handleMessage(EJBServerChannel.java:188)
at org.jboss.remoting3.remote.RemoteConnectionChannel.lambda$handleMessageData$3(RemoteConnectionChannel.java:430)
at org.jboss.remoting3.EndpointImpl$TrackingExecutor.lambda$execute$0(EndpointImpl.java:926)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Caused by: java.io.StreamCorruptedException: serialVersionUID does not match!
    at org.jboss.marshalling.AbstractClassResolver.resolveClass(AbstractClassResolver.java:108)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadClassDescriptor(RiverUnmarshaller.java:1025)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1354)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:275)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:223)
at org.jboss.marshalling.river.RiverUnmarshaller.readFields(RiverUnmarshaller.java:1856)
at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1769)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1397)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:275)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:208)
at org.jboss.marshalling.AbstractObjectInput.readObject(AbstractObjectInput.java:41)
at org.jboss.ejb.protocol.remote.EJBServerChannel$RemotingInvocationRequest.getRequestContent(EJBServerChannel.java:805)
at org.jboss.as.ejb3.remote.AssociationImpl.receiveInvocationRequest(AssociationImpl.java:126)
... 7 more
Caused by: an exception which occurred:
    in field com.persistence.pojo.Company.Clients
in object com.persistence.pojo.Company@47368172
in object of type com.persistence.pojo.Company

I am using a Wildfly10.x server. The version of hibernatecore is 5.2.17.Final

I am sorry if it is very poorly explained but it is that the project is quite complex, in essence I would need hibernate to map to List object instead of to Persistentbag.


Answer:

The problem here, is that the object you get from hibernate is of some hibernate proxy class, and not your actual entity class. This is normal behaviour for hibernate. This proxy class is autogenerated, and so is it's serialVersionUID.

In general, it is not a good practice to serialize/send entity class objects directly, because of such problems, but also because of problems with lazy initialization and all those connected with having objects bound to entity manager context.

The most common solution is to create "data transport objects" or DTOs which may have the same fields (or very similar - like replace enums with Strings etc, depends on what you need), and nothing else. based on your example, you can have a class like that:

public class CompanyDTO implements Serializable {

private static final long serialVersionUID = 1L;

private int id;

private List<ClientDTO> Clients;

//GETTERS&SETTERS   

}

(by analogy you need to create ClientDTO class too).

Use this class instead, for outside (where outside is not necessarily remote, just wherever you need to detach from EM context) communication.

You can fill it by hand, or by any other means (like with reflection using BeanUtils, constructor with Company argument which copies properties [this I would not advise, as it interrupts application layer seperation, but for the purpose of this conversation it is a valid way to do that]). The only thing important is that you fill it from within entity manager context

Question:

In a distributed client server application, i am using java RMI to invoke server side method from client machine. At server side EJB is being used and application server is Glassfish. I have a SampleFacade Class at server end which is a java session bean and SampleFacadeRemote is a Remote interface exposed to client (@Remote has been used with it). SampleFacade implements SampleFacadeRemote Interface .

Please look at the following code snippet :

        private static SampleFacadeRemote lookupSampleFacade()
        {
            Context c = new InitialContext();
            return (SampleFacadeRemote)c.lookup("java:comp/env/SampleFacade");
        }
        catch (NamingException ne)
       {
          throw new RuntimeException(ne);
       }

Here, with the returned object, remote method can be successfully executed.

I am curious to know how it works. Does lookup method return SampleFacade object to client in order to execute its method? But SampleFacade's method is suppose to be run at server side/Remote JVM. then what type of object is being returned by lookup() method? Please explain the underlying mechanism.


Answer:

It returns a stub: a client-side object that implements the same remote interface and knows how to communicate with the actual remote object.

In fact you should note that it isn't the lookup() method that performs this magic: it is ultimately the bind() method concerned, or even the object itself, that translates the remote object to its stub, unless the stub is what was passed to bind(). In other words the stub is already in the Registry or LDAP or whatever you're looking up, and lookup() just gives you whatever was found.

Question:

I'm working through an EJB tutorial where my client program invokes a method via remote stateless EJB to add a book. Upon exit the client retrieves and prints all the books from the EJB (I know it's not a good idea to store data in a list within a stateless EJB). All of this works fine, except the initial RMI also returns the following exception (I've included the full output from the client test as well).

Client output:

Nov 29, 2016 11:34:29 PM org.jboss.ejb.client.EJBClient <clinit>
INFO: JBoss EJB Client version 2.1.4.Final
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit
Enter Choice: 1
Enter book name: Some book
Nov 29, 2016 11:34:44 PM org.xnio.Xnio <clinit>
INFO: XNIO version 3.4.0.Final
Nov 29, 2016 11:34:44 PM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.4.0.Final
Nov 29, 2016 11:34:44 PM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 4.0.21.Final
Nov 29, 2016 11:34:45 PM org.jboss.ejb.client.remoting.VersionReceiver handleMessage
INFO: EJBCLIENT000017: Received server version 2 and marshalling strategies [river]
Nov 29, 2016 11:34:45 PM org.jboss.ejb.client.remoting.RemotingConnectionEJBReceiver associate
INFO: EJBCLIENT000013: Successful version handshake completed for receiver context EJBReceiverContext{clientContext=org.jboss.ejb.client.EJBClientContext@4f7d0008, receiver=Remoting connection EJB receiver [connection=org.jboss.ejb.client.remoting.ConnectionPool$PooledConnection@271053e1,channel=jboss.ejb,nodename=slave01:server01]} on channel Channel ID 87a6ebda (outbound) of Remoting connection 64bfbc86 to /127.0.0.1:8133 of endpoint "client-endpoint" <64bf3bbf>
Nov 29, 2016 11:34:45 PM org.jboss.ejb.client.remoting.RemotingConnectionClusterNodeManager getEJBReceiver
INFO: Could not create a connection for cluster node ClusterNode{clusterName='ejb', nodeName='slave01:server01', clientMappings=[ClientMapping{sourceNetworkAddress=/0:0:0:0:0:0:0:0, sourceNetworkMaskBits=0, destinationAddress='0.0.0.0', destinationPort=8080}], resolvedDestination=[Destination address=0.0.0.0, destination port=8080]} in cluster ejb
java.net.ConnectException: Connection refused
    at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
    at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
    at org.xnio.nio.WorkerThread$ConnectHandle.handleReady(WorkerThread.java:321)
    at org.xnio.nio.WorkerThread.run(WorkerThread.java:567)
    at ...asynchronous invocation...(Unknown Source)
    at org.jboss.remoting3.EndpointImpl.doConnect(EndpointImpl.java:294)
    at org.jboss.remoting3.EndpointImpl.connect(EndpointImpl.java:430)
    at org.jboss.ejb.client.remoting.NetworkUtil.connect(NetworkUtil.java:153)
    at org.jboss.ejb.client.remoting.NetworkUtil.connect(NetworkUtil.java:133)
    at org.jboss.ejb.client.remoting.ConnectionPool.getConnection(ConnectionPool.java:78)
    at org.jboss.ejb.client.remoting.RemotingConnectionManager.getConnection(RemotingConnectionManager.java:51)
    at org.jboss.ejb.client.remoting.RemotingConnectionClusterNodeManager.getEJBReceiver(RemotingConnectionClusterNodeManager.java:79)
    at org.jboss.ejb.client.ClusterContext$EJBReceiverAssociationTask.call(ClusterContext.java:469)
    at org.jboss.ejb.client.ClusterContext$EJBReceiverAssociationTask.call(ClusterContext.java:443)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
**********************
Welcome to Book Store
**********************
Options 
1. Add Book
2. Exit 
Enter Choice: 2
Book(s) entered so far: 2
1. test1
2. Some book
***Using second lookup to get library stateless object***
Book(s) entered so far: 2
1. test1
2. Some book

So everything with the client, other than the exception, appears to work correctly. I suspect this issue has something to do with the zero'd out node addresses, but I'm not certain. The client properties file is below (in case that configuration is incorrect).

jboss-ejb-clients.properties:

endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
invocation.timeout=3000
reconnect.tasks.timeout=2000


# User Credentials
username=user
password=pass


# Remote Connections
remote.connections=h1,h2
remote.connection.h1.host=127.0.0.1
remote.connection.h1.port=8133
remote.connection.h1.username=user
remote.connection.h1.password=pass    
remote.connection.h2.host=127.0.0.1
remote.connection.h2.port=8134
remote.connection.h2.username=user
remote.connection.h2.password=pass


# Cluster
remote.clusters=ejb
remote.cluster.ejb.connect.timeout=2500
remote.cluster.ejb.max-allowed-connected-nodes=2
remote.cluster.ejb.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.cluster.ejb.connect.options.org.xnio.Options.SSL_ENABLED=false
remote.cluster.ejb.username=user
remote.cluster.ejb.password=pass

Answer:

After extensive research (and a good amount of trial and error with test code), I found a book on Safari (Java EE 7 Development with WildFly) that lead me in the right direction. I had to drop the jboss-ejb-clients.properties file and add the ejb-client configuration found in the answer here to my main client class.