0

I am trying to finish a prototype that using RMI to send workload to a few remote servers. After the work is done, the remote servers are supposed to write the result back to the database. I use JPA with Hibernate as the provider. But I am having a difficult time to ask the remote server to do so.

Here is code for the part is going to be sent to the remote server through RMI

public class UpdateDB implements ServerRun<Boolean>, Serializable {

private static final long serialVersionUID = 2683781993159094346L;

@Override
public Boolean execute() {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "abc" );
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.persist( new User( "First user!", new Date() ) );
    entityManager.persist( new User( "Second user", new Date() ) );
    entityManager.getTransaction().commit();
    entityManager.close();

    entityManager.close();
    entityManagerFactory.close();
    return true;
  }
}

Here is the persistence.xml in the resources/META-INF at the same level of the code above:

<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="abc" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>data.persist.User</class>

    <properties>
        <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://192.168.205.103:3306/event_grp" />
        <property name="javax.persistence.jdbc.user" value="username" />
        <property name="javax.persistence.jdbc.password" value="password" />

        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.hbm2ddl.auto" value="create" />
    </properties>

</persistence-unit>

If I run the JPA on the server it works, and anything else works in terms of RMI functions. But the EntityManagerFactory will not start, here is the error:

Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named abc
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:69)
    at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:47)
    at data.persist.UpdateDB.execute(UpdateDB.java:58)
    at data.persist.UpdateDB.execute(UpdateDB.java:1)
    at engine.ComputeEngine.executeTask(ComputeEngine.java:39)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:303)
    at sun.rmi.transport.Transport$1.run(Transport.java:159)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
    at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
    at sun.rmi.server.UnicastRef.invoke(Unknown Source)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
    at com.sun.proxy.$Proxy12.executeTask(Unknown Source)
    at client.JobSubmitter.main(JobSubmitter.java:94)

So, it seems that the RMI cant find or load the persistence.xml in the META-INF. And I had similar experience with log4j as well, but I got around by defining everything in the code instead of using the log4j.properties file.

Edit: The package for the code to be sent to the remote server looks like and this is the only place that I placed the persistence.xml:

-src/main/java/data/persist/UpdataDB.java
 |
 src/main/resources/META-INF/persistence.xml

Per user1888440's question, I put the security permission configuration here. And both client and remote servers use the following permissions:

grant {
permission java.security.AllPermission;
};

How can I make the remote server to initialize the EntityManagerFactory so it can write back to the database? I would appreciate a lot if you can provide some simple code as well.

Yellow Duck
  • 261
  • 1
  • 4
  • 14
  • I can't see how this has anything to do with RMI. It is about your Persistence configuration. – user207421 Jun 06 '13 at 10:16
  • It works fine with persistence on the local machine. It DOES NOT work when send it out through RMI to remote server. And please add the RMI tag back if this makes sense to you. – Yellow Duck Jun 06 '13 at 15:10

1 Answers1

0

The remote server will need the same access to resources as the client. Who do you want to be actually touching the database? Anyone? If so, each of those participants will need a copy of your persistence.xml so that they can create connections to the database.

robert_difalco
  • 4,821
  • 4
  • 36
  • 58
  • Thanks for the reply. There is a copy of the persistence.xml in the packaged jar with the 'UpdateDB' class. The problem is that when a job submitter send the 'UpdateDB' to the remote server, the remote server wont be able to get the persistence.xml from the classloader even it's in the classpath of 'UpdateDB'. This is most likely to be caused by the RMI remote class loader's behavior, which I do not fully understand. – Yellow Duck Jun 05 '13 at 17:43
  • Without knowing more about your configuration I can't help much. But you may want to check the permissions on the persistence.xml. Often with RMI you have to give specific grant permissions depending on the setup. Like grant codebase "file:/whatever/persistence.xml" { permission java.security.AllPermission; }; – robert_difalco Jun 05 '13 at 17:51
  • Please see the edited configuration for packaging and where the persistence.xml is placed. The permission are set to grant {permission java.security.AllPermission;} for both client and remote servers. – Yellow Duck Jun 05 '13 at 18:00
  • Looks like a permission issue but you may want to try the advice here. Specifically the part about where it thinks your META_INF/persistence.xml is. http://stackoverflow.com/questions/6148730/what-are-the-correct-security-policy-value-settings-to-allow-both-rmi-and-jpa-hi – robert_difalco Jun 05 '13 at 18:18
  • Thanks a lot for the reference. The interesting part is that I set all permission to all of them. It won't work. By the way, the whole set up works fine without using RMI on client's side, which rule out the possibilities of wrong persistence configuration here. So, it still looks like a RMI issue. I would vote you up for shearing the helpful reference. But I don't have enough reputation yet. – Yellow Duck Jun 05 '13 at 18:46
  • Have you tried this yet in DBUpdate? File f = new File("META-INF/persistence.xml"); System.out.println(f.getAbsolutePath()); – robert_difalco Jun 05 '13 at 21:32
  • And is it returning the path you would expect? – robert_difalco Jun 05 '13 at 21:32
  • Sorry for my late response, I just got a chance to go back to examine the issue. It prints out on the server side /home/USERNAME/META-INF/persistence.xml. It seems that I have to manually assign the classpath for it. – Yellow Duck Jul 01 '13 at 18:33
  • Ok. I found that the RMI is fetching the right persistence.xml file and it has access to it. But for some reasons, it just raises "Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named XX" exception. I ran the same set up locally from the RMI server and it works fine. Any suggestion? – Yellow Duck Jul 02 '13 at 15:27