# Client-Jar und JPA-Entities für Remotzugriff



## foobar (9. Dez 2008)

Hi,

ich beschäftige mich gerade mit JEE und habe da ein Verständnisproblem:

Eclipse legt mir für das Ejb-Projekt auch ein Ejb-Client-jar an in dem alle APis liegen d.h. die RemoteInterfaces der SessionBeans. Soweit alles klar. Der Client benötigt ja nur die Interfaces, um per Jndi (RMI) auf den Service zu zugreifen. 
Wenn ich jetzt aber in einem RemoteInterface eine Persistent Entity (JPA) zurück geben will gibt das Probleme, denn die Perstitent Entites liegen im Ejb-Jar und das Ejb-Jar hat schon eine Dependency auf das Client-Jar d.h. ich kriege hier nen Classpath-Cycle.
Aber wie soll das sonst funktionieren? Ich will dem Client ja auch nicht das EJb-Jar mitgeben nur damit er die Persistent Entities nutzen kann.
Wie löst man das am sinnvollsten?

Mein zweites Problem bezieht sich auf das DAO-Pattern innerhalb einer JEE-Application. Im Moment nutze ich ein GenericDAO als Basis für alle DAOs in das der EntityManager injiziert wird:


```
@Stateless
public class GenericDAOImpl<T extends Serializable, PK extends Serializable> implements GenericDAO<T, PK>
{
    @PersistenceContext
    protected EntityManager em;
    private Class<T> domainClass;
    
    @SuppressWarnings("unchecked")
    protected Class<T> getDomainClass()
    {
        if (null == domainClass)
        {
           ParameterizedType thisType = (ParameterizedType) getClass().getGenericSuperclass();
           domainClass                = (Class<T>) thisType.getActualTypeArguments()[0];
        }
        return domainClass; 
    }
    
    public T load(PK id)
    {
        return em.find(getDomainClass(), id);
    }

    public void refresh(T t)
    {
        em.refresh(t);
    }
    
    public void persist(T t)
    {
        em.persist(t);
    }

    public void remove(T t)
    {
        em.remove(t);
    }

    @SuppressWarnings("unchecked")
    public List<T> getAll()
    {
        return em.createQuery("from " + getDomainClass().getName()+ " x").getResultList(); //$NON-NLS-1$ //$NON-NLS-2$
    }

    public void deleteById(PK id)
    {
        Object obj = load(id);
        em.remove(obj);
    }

    public void deleteAll()
    {
        em.createQuery("delete " + getDomainClass().getName()).executeUpdate(); //$NON-NLS-1$
    }

    public int count()
    {
        Integer count  = (Integer) em.createQuery("select count(*) from "+ getDomainClass().getName() + " x").getSingleResult(); //$NON-NLS-1$ //$NON-NLS-2$
        return count.intValue();
    }
}
```


Alle DaoLocalInterfaces erben dann von GenericDaoImpl und implementieren GenericDAO:


```
public interface GenericDAO<T, P>
{
    public T load(P id);
    public void refresh(T t);
    public void persist(T t);
    public void remove(T t);
    public List<T> getAll();
    public void deleteById(P id);
    public void deleteAll();
    public int count();
}
```

Die einzelnen DAOs können dann in die Services (Stateless SessionBeans) injiziert werden. Funktioniert auch alles wunderbar. Ich habe eine saubere Trennung von Persistenz und Logik und kann sehr einfach Unittests für meine Services schreiben. Die DAOs lassen sich einfach mocken, da sie nur injiziert werden und keien Logik enthalten.

Wie wird das denn normalerweise in JEE-Applications gehandhabt? Ich habe vorher Spring verwendet und da wird das so gemacht wie eben beschrieben. Wir hatten hier ja schon mehrmals die Diskussion zu DAO vs. Repistories nur kann ich bei den Repositories keinen wirklichen Unterschied erkennen zu DAOs.
Aber auf eine Persitenzkappselung will ich auch nicht verzichten. Denn wenn ich überall in alle Serviceklassen einen EntityManager injizieren lasse habe ich keine Trennung der schichten mehr.


----------



## maki (9. Dez 2008)

Mit Maven2 kannst du dein Projekt imho besser aufteilen als mit dem Eclipse Wizard für JEE Projekte.



> Wir hatten hier ja schon mehrmals die Diskussion zu DAO vs. Repistories nur kann ich bei den Repositories keinen wirklichen Unterschied erkennen zu DAOs.


Kurz gesagt:
Repositories gehören zur Domain-, DAOs zur Persistenzschicht.
Repositories sind high level, während DAOs low level sind.

Falls du ein Domänenmodell hast:
zB., ohne deine DAOs (und damit die Abhängigkeit zur Persistenzschicht) kannst du deine Domainklassen nicht vollständig testen.

Deine DAOs sind SessionBeans, spricht eigentlich gegen ein Domänenmodell.


----------



## foobar (9. Dez 2008)

maki hat gesagt.:
			
		

> Mit Maven2 kannst du dein Projekt imho besser aufteilen als mit dem Eclipse Wizard für JEE Projekte.



Wie würde denn das Endresultat mit Maven2 aussehen? Lässt du dir dann ein Clientjar erstellen in dem auch die Jpa-Entities enthalten sind?




			
				maki hat gesagt.:
			
		

> > Wir hatten hier ja schon mehrmals die Diskussion zu DAO vs. Repistories nur kann ich bei den Repositories keinen wirklichen Unterschied erkennen zu DAOs.
> 
> 
> Kurz gesagt:
> ...



Mir bleibt nichts anderes übrig als DAOs als SessionBeans zu implementieren. Ansonsten kann ich die ja nicht mehr injizieren.
Wie sieht denn die Schnittstelle eines Repositories bei dir aus? Wie greifst du auf die Repos zu werden die injiziert oder gibts ne Factory?


----------



## maki (9. Dez 2008)

>> Mir bleibt nichts anderes übrig als DAOs als SessionBeans zu implementieren. Ansonsten kann ich die ja nicht mehr injizieren. 

Ja, EJB DI hat eben ihre Nachteile.

>> Wie sieht denn die Schnittstelle eines Repositories bei dir aus?

Wie sieht denn ein Domainmodell aus? 
Problematisch an der Antwort zu dieser Frage ist eben das konkrete Domainmodell.
Im Prinzip high level Methoden zum hinzufügen/ändern/suchen/löschen von Domainklassen, speziell alle möglichen suchen sind drinnen, denn oft enthält eine Query schon Domain- bzw. Businesslogik (suche alle Artikel mit einem Preis der höher ist als..., etc. pp.)

>> Wie greifst du auf die Repos zu werden die injiziert oder gibts ne Factory?

Beides ist möglich, je nach Gusto.
Jede Domainklasse bekommt ihr Repository, persönlich bevorzuge ich DI (Konstruktorinjection bze. Setterinjection).

So kümmern sich die Domainklassen selbst um die anderen Domainklassen welche sie brauchen und können viel mehr Logik enthalten.


----------



## foobar (9. Dez 2008)

maki hat gesagt.:
			
		

> >> Mir bleibt nichts anderes übrig als DAOs als SessionBeans zu implementieren. Ansonsten kann ich die ja nicht mehr injizieren.
> Ja, EJB DI hat eben ihre Nachteile.


Da gefällt mir persönlich Spring besser aber Ejb3 ist schon ne ganz andere Welt als Ejb 2. Wer weiß wie sich das nocht entwickeln wird.



			
				maki hat gesagt.:
			
		

> >> Wie sieht denn die Schnittstelle eines Repositories bei dir aus?
> Wie sieht denn ein Domainmodell aus?
> Problematisch an der Antwort zu dieser Frage ist eben das konkrete Domainmodell.
> Im Prinzip high level Methoden zum hinzufügen/ändern/suchen/löschen von Domainklassen, speziell alle möglichen suchen sind drinnen, denn oft enthält eine Query schon Domain- bzw. Businesslogik (suche alle Artikel mit einem Preis der höher ist als..., etc. pp.)


Ja, das lässt sich nicht vermeiden ist beim Einsatz von JPA respektive Hibernate aber zu vernachlässigen.



			
				maki hat gesagt.:
			
		

> >> Wie greifst du auf die Repos zu werden die injiziert oder gibts ne Factory?
> 
> Beides ist möglich, je nach Gusto.
> Jede Domainklasse bekommt ihr Repository, persönlich bevorzuge ich DI (Konstruktorinjection bze. Setterinjection).
> ...



Gibts auch sowas wie ein GenericRepository mit den Basic CRUD Operationen oder ist dir das auch zu Lowlevel? ;-)


----------



## foobar (9. Dez 2008)

Hab gerade noch das hier gefunden: http://relation.to/Bloggers/ChristiansBlog/Page/1
Da wird ganz gut der Unterschied zwischen DAOs und Repository beschrieben.
Für mich ist das JPA-DAO ja auch nur eine Kapselung der Queries und nicht eine Abstraktion der DB, denn das macht JPA ja schon,


----------



## maki (9. Dez 2008)

> Ja, das lässt sich nicht vermeiden ist beim Einsatz von JPA respektive Hibernate aber zu vernachlässigen.


Sehe ich nicht so.

Selbst wenn du deine DAO Interfaces mockst, bist du immer noch von der Persistenzschicht abhängig, denn eben diese DAO Interfaces sind teil davon, ausserdem landet so ganz schnell Domänenlogik in der Persistenzschicht... 



> Gibts auch sowas wie ein GenericRepository mit den Basic CRUD Operationen oder ist dir das auch zu Lowlevel? icon_wink.gif


Klar gibt es das: der EntityManager

Der nimmt einem doch alle primitiven CRUD Operationen ab, es gibt also keinen echten Grund diese primitiven CRUD Operationen nochmals in DAOs zu kapseln... stattdessen schreibe lieber Repositories anstatt DAOs, dann hast du nicht mehr Aufwand als vorher, ausser das es sauberer wird, weil deine Domäne eben nicht mehr von den DAOs abhängig ist und die Logik in der richtigen Schicht bleibt.



			
				foobar hat gesagt.:
			
		

> Hab gerade noch das hier gefunden: http://relation.to/Bloggers/ChristiansBlog/Page/1
> Da wird ganz gut der Unterschied zwischen DAOs und Repository beschrieben.,


Finde den Blog nicht so dolle, er hat anscheinend nicht den Unterschied verstanden und zeiht eigentlich nur über das Repository her, auch fehlt ihm der Bezug zu JPA und dem EntityManager, da er immer noch DAOs schreibt 



			
				foobar hat gesagt.:
			
		

> Für mich ist das JPA-DAO ja auch nur eine Kapselung der Queries und nicht eine Abstraktion der DB, denn das macht JPA ja schon


Richtig, der EM kapselt die CRUD Operationen, Repositories die fachlichen Apsekte, Repositories sind eben teil der Domäne.

Persönlich glaube ich, dass viele Leute an DAOs festhängen, "weil man das immer so gemacht hat", aus dem selben Grund hat man den EM unterbewertet, schliesslich musste man ja unbedingt seine DAOs schreiben, denn ohne geht es ja nicht, oder? *g*

Im Prinzip sind die meisten DAOs schon durchsetzt mit Domänenlogik und damit eigentlich Repositories, nur dass sie in der falschen Schicht sind 

Ps: Spring macht keinen Unterschied zwischen DAOs und Repositories, ausserdem wird empfohlen beim Einsatz von JPA mit Spring keine Templates mehr zu verweden, sondern direkt den EM.


> NOTE: JpaTemplate mainly exists as a sibling of JdoTemplate and HibernateTemplate, offering the same style for people used to it. For newly started projects, consider adopting the standard JPA style of coding data access objects instead, based on a "shared EntityManager" reference injected via a Spring bean definition or the JPA PersistenceContext annotation.  (Using Spring's SharedEntityManagerBean / PersistenceAnnotationBeanPostProcessor, or using a direct JNDI lookup for an EntityManager on a Java EE 5 server.)


----------



## maki (9. Dez 2008)

Nachtrag:



> > Gibts auch sowas wie ein GenericRepository mit den Basic CRUD Operationen oder ist dir das auch zu Lowlevel? icon_wink.gif
> 
> 
> Klar gibt es das: der EntityManager
> ...


Ist natürlich quatsch was ich da geschrieben habe.

Neuer Versuch:
Die primitiven CRUD Operationen der Generischen DAOs werden schon durch den EM abgedeckt.

Im Prinzip müsstest du dein (generisches) DAO nur in Repository umbennen und es als Teil der Domäne modelieren, dann noch eine konkrete Implementierung + die speziellen Queries, fertig 

Hattest recht hiermit:


> Wir hatten hier ja schon mehrmals die Diskussion zu DAO vs. Repistories nur kann ich bei den Repositories keinen wirklichen Unterschied erkennen zu DAOs.



Der Unterschied ist eher wo sie in der Archtektur auftauchen, also in welcher Schicht, Persistenz/Integrationschicht, oder eben in der Domäne.


----------



## foobar (9. Dez 2008)

> Der Unterschied ist eher wo sie in der Archtektur auftauchen, also in welcher Schicht, Persistenz/Integrationschicht, oder eben in der Domäne.


Ja, das ist mir jetzt auch klar geworden. Im Buch von Martin Fowler wurde nicht so direkt darauf hingewiesen. Habe mir jetzt gerade Domain Driven Desgin von Eric Evans bestellt vielleicht hilfts ja.



> Ps: Spring macht keinen Unterschied zwischen DAOs und Repositories, ausserdem wird empfohlen beim Einsatz von JPA mit Spring keine Templates mehr zu verweden, sondern direkt den EM.


In Spring verwende ich direkt Hibernate mit dem HibernateTemplate.

JPA verwende ich im Moment nur weil es Teil der JEE Spezifikation ist. Generell bin ich der Meinung, daß Hibernate schon genug kappselt und auf einen anderen Appserver mirgrieren der nicht Hibernate verwendet will ich sowieso net. Mir gehts im Moment erstmal nur darum die Unterschiede zwischen JPA und Hibernate zu lernen und heraus zu finden wie man am schönsten mit JEE Anwendungen entwickelt.
Ist ja ganz nett, daß es endlich ne API wie JPA gibt aber wer will schon seine ORM-Tool austauschen?


----------



## maki (9. Dez 2008)

> Ist ja ganz nett, daß es endlich ne API wie JPA gibt aber wer will schon seine ORM-Tool austauschen?


Klar, das Wissen/die Erfahrung wurde alles hart erarbeitet.. trotzdem finde ich TopLink immer besser, zumindest theoretisch, viel probiert habe ich noch nicht damit, aber es gibt ein paar Dinge die wirklich interessant aussehen, zB. keine Proxies usw.
Denke dass mit JPA2.0 der umstieg einfacher wird bzw. es zumindest möglich sein wird 90% der Arbeiten ohne spezielle Frameworkfeatures zu lösen.



> Wie würde denn das Endresultat mit Maven2 aussehen? Lässt du dir dann ein Clientjar erstellen in dem auch die Jpa-Entities enthalten sind?


Mit Maven2 könnte man das Projekt in belibieg viele Subprojekte aufteilen (nennt sich "multi module project"), eines für die Domain, eines fürs Frontend,  eines für die Services/EJBs, etc. pp.

Man kann Abhängigkeiten zwischen diesen Projekten definieren, zB. dass das EJBProjekt vom DomainProjekt abhängig ist, genauso wie das Frontend vom EJBProjekt abhängig ist usw., so kann man sehr genau steuern, welches Modul wohin kommt bzw. welches Modul von welchem abhängig ist.

Es gibt bestimmt auch eine Möglichkeit mit Eclipse, diese kenne ich aber nicht, veilleciht kommt noch jemand der das weiss


----------



## foobar (10. Dez 2008)

maki hat gesagt.:
			
		

> Klar, das Wissen/die Erfahrung wurde alles hart erarbeitet.. trotzdem finde ich TopLink immer besser, zumindest theoretisch, viel probiert habe ich noch nicht damit, aber es gibt ein paar Dinge die wirklich interessant aussehen, zB. keine Proxies usw.
> Denke dass mit JPA2.0 der umstieg einfacher wird bzw. es zumindest möglich sein wird 90% der Arbeiten ohne spezielle Frameworkfeatures zu lösen.


Klingt interessant. Hab mir TopLink bisher noch nie angeguckt. Ich hätte gerne eine Lösung mit der man Remote LazylLoading realisieren kann, denn wenn man sowieso nur mit nem Javaclient drauf zugreift ist SOAP unnötig. Mit Spring kann man ja auch ganz einfach seine Services parallel als Webservice und RMI o.ä. exportieren.




			
				maki hat gesagt.:
			
		

> Es gibt bestimmt auch eine Möglichkeit mit Eclipse, diese kenne ich aber nicht, veilleciht kommt noch jemand der das weiss


Ja, die gibt es http://www.quendor.org/archiv/389#more-389


----------



## maki (10. Dez 2008)

> Ich hätte gerne eine Lösung mit der man Remote LazylLoading realisieren kann


Denke das byto hier mal so eine Lösung gepostet hatte, welche Spring AOP nutzt.

Hab ich mir auch schon überlegt, theoretisch:
Member die Collections sind werden nur aus den Repos. geholt, kein Lazy Load, höchstens Lazy Init, letzteres macht die Sache komplizierter.
Die Domainklassen bekommen auf dem Client ein anderes Repository Injected als auf dem Server, welches den Remote zugriff kapselt.


----------



## foobar (10. Dez 2008)

Ja, die Lösung von byto kenne ich. Es gibt mehrere solcher Lösungen z.b. hier http://h3t.sourceforge.net/  oder hier http://www.hibernate.org/377.html

Durch Repos wird das ganze aber nochmal komplizierter wenn man auf dem Client andere Repos injizieren muß. Ich hätte gerne eine Lösung, die das alles von Haus aus kann vielleicht geht das ja mit Remote OSGI-Services und von Eclipse gibt es auch noch ein Projekt auf Basis von EMF, daß sich mit sowas auseinander setzt.
Aber da die meisten EE Applications Webanwendungen sind, ist die Nachfrage nicht besonders hoch. Schade eigentlich.


----------

