RMI und Hibernate

xell66

Grünschnabel
Hallo,

ich bin mir nicht sicher in welches Unterforum dieses Thema soll deswegen habe ich es einfach im Oberforum gepostet. Zu meiner Fragestellung:

Im Rahmen meines Studiums muss ich ein Programm schreiben in dem sich ein Client mit einem Server verbindet (mit RMI) sich entsprechende Objekte holt (Remote zugriff, also ändere ich den zustand des Objektes auf dem Client ist er auch auf dem Server geändert). Die Objekte sollen vom Server in und aus einer Datenbank geladen werden (mittels Hibernate).

Ich habe in dem Bereich keine Vorerfahrung und einfach mal drauf los probiert.
Jetzt komm ich aber garnicht weiter und ich bin mir nicht sicher ob ich mit diesem Ansatz in die ganz falsche Richtung laufe.
Das Problem ist, Instanziere ich ein Objekt auf dem Server ohne Hibernate(new Object) funktioniert der Remote zugriff, mit Hibernate nicht. Hierzu ist zusagen das nur der Zugriff auf eine Collection innerhalb des Objektes Probleme macht.


hier der Code:

Auf diese Klasse soll Remote zugegriffen werden (liegt auf Server, auf Client entsprechendes Interface names Department)
Java:
@Entity  (name="DEPARTMENT")
public class DepartmentImpl extends UnicastRemoteObject implements Department
{
    
    
    public DepartmentImpl() throws RemoteException
    {
        super();
    }
 
    
    
    @Id 
    private int abteilungsNr;
    private String name;
    private String beschreibung;
    private String anschrift;
    private int plz;
    private String standort;
    
    
    
 
 
@ElementCollection (fetch=FetchType.EAGER)  //extra auf EAER gestellt damit Hibernate nicht nachladen muss
@JoinTable (name="Employee",                // tabellen name auf Employee geändert
    joinColumns=@JoinColumn (name="Deptno")) 
@GenericGenerator (name="hilo-gen", strategy="seqhilo")
 @CollectionId(columns = { @Column(name="Emp_ID") }, generator = "hilo-gen", type = @Type(type="long"))
        
private Collection<Employee> empl= new ArrayList<Employee>();
                
    // Getter und Setter...
        
}



Hier das Objekt das im Department als Collection gepeichert wird.(liegt auf Server und Client,Annotation nur auf Server Sersion)

Java:
@Embeddable
public class Employee implements Serializable
{
    
    private static final long serialVersionUID = 2L;
    
            
    public Employee()
{   }
 
    private int personalnummer;
    private String vorname;
    private String nachname;
    private String geburtstag;
    private String geburtsort; 
    private String tätigkeit;
    private String gehalt;
 
}



Server Klasse (vereinfacht)

Java:
public class Server
{
 
 
 
//erstelle Department Objekt  und binde es an registry. Mit dieser Variante habe ich zugriff auf das Objekt UND seine Collection!
 registry.bind("DepartmentOhneHibernate", department );
 
 
 
//Hibernate Variante 
//Session öfnen...
//Department mit PK 1 aus Datenbank laden
department = (DepartmentImpl)session.get(DepartmentImpl.class, 1);
//Objekt an Registry binden, hier funktioniert der zugriff auf die Collection NICHT
registerObject(DepartmentmitHibernate, department );


Client (vereinfacht)
Java:
public class Client
{
    public static void main(String[] args) throws ExceptionDepartment {
 
 
 
//zugriff auf Objekt das nicht aus der Datenbank geladen wurde
 Department dep= (Department) registry.lookup("DepartmentOhneHibernate")
//zugriff auf Collection , funktioniert
System.out.println(+dep.getEmpl().size());
 
 
//zugriff auf Objekt das  aus der Datenbank geladen wurde(Hibernate)
 Department dep= (Department) registry.lookup("DepartmentmitHibernate")
//zugriff auf Collection , funktioniert nicht
System.out.println(+dep.getEmpl().size());
;

hier die Fehlermeldung
Java:
Exception in thread "main" java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
    java.lang.ClassNotFoundException: org.hibernate.collection.internal.PersistentIdentifierBag
    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.$Proxy1.getEmpl(Unknown Source)
    at Client.main(Client.java:89)
Caused by: java.lang.ClassNotFoundException: org.hibernate.collection.internal.PersistentIdentifierBag
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.rmi.server.LoaderHandler$Loader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadClassForName(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
    at sun.rmi.server.LoaderHandler.loadClass(Unknown Source)
    at java.rmi.server.RMIClassLoader$2.loadClass(Unknown Source)
    at java.rmi.server.RMIClassLoader.loadClass(Unknown Source)
    at sun.rmi.server.MarshalInputStream.resolveClass(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at sun.rmi.server.UnicastRef.unmarshalValue(Unknown Source)

Einen Security Manager habe ich auf Client und Server im einsatz.
Ohne den Security Manager bekomme ich eine andere Fehlermeldung beim zugriff auf das Datenbank Objekt im Client.
Auf dem Server habe ich auch zugriff auf die Collection des Objektes das aus Hibernate geladen wurde.

Für jeden Tipp bin ich sehr dankbar.
 
Zuletzt bearbeitet:

saftmeister

Nutze den Saft!
Hi,

na die Exception sagt dir ja schon, was nicht passt. Auf dem Client ist die Klasse org.hibernate.collection.internal.PersistentIdentifierBag nicht zu finden. Das bedeutet, da ist das Jar hibernate-core nicht im Classpath.

Allerdings wäre es evtl. ratsam, keine Hibernate-Entitäten direkt über RMI zu verwenden. Dadurch wird das Projekt nur ziemlich abhängig von einer Library und du müsstest bei Änderungen immer Client und Server anpassen. Versuch doch mal, Transport-Objekte einzubauen und Mapper, die zwischen Hibernate-Entity und TO konvertieren. Normalerweise macht man das in einem DAO. Dadurch entkoppelst du direkte Abhängigkeiten. Durch den Einsatz von Interfaces statt konkreten Objekten kannst du das sogar noch flexibler gestalten. Ich denke da an so ein Bild:


Client Server
[TO-Interface] < = = = > RMI < = = = > [TO] < = > [DAO] < = = > Hibernate-Entity

Das Interface wird durch das TO implementiert. Das TO wird vom DAO zurück gegeben. Das DAO mappt die Hibernate-Entity zu TO.

Dadurch bist du in der Lage, ohne eine Änderung am Client das Server-Backend komplett auszutauschen. Achja: Das DAO implementiert ein Interface, das auf dem Client bekannt ist.