# JBoss und die Einbindung eines externen JAR



## OlliL (5. Dez 2012)

Hallo,

ich entwickel gerade EJB auf meinem JBoss in Eclipse für die spätere Verwendung in meinem Swing Client.

Aktuell habe ich folgende Packages in meinem EJB-Projekt

business       (enthällt die Interfaces der Beans)
entity          (enthällt die Business Objekte - z.B. User)
businesslogic (enthällt die Implementierung der Interfaces aus business)

Der EJB Aufruf klappt wunderbar von meinem Swing Client aus.

Nun möchte ich die Packages business und entity in ein extra Eclipse Project "Lib" auslagern und diese dann als JAR sowohl in meinem JBoss EJB wie auch meinem Swing-Client nutzen.

Und - hier fangen die Probleme an. Erstmal meine Schritte zur Einbindung der JAR in meinem JBoss Deployment:

- Generieren des Projekts "Lib" als Lib.jar in Eclipse via "Export -> JAR"
- Kopieren von Lib.jar nach C:\....\jboss-as-7.1.1.Final\modules\my\structure\main
- Erzeugen von module.xml im oben genannten Pfad:


```
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="my.structure">
  <resources>
    <resource-root path="Lib.jar"/>
  </resources>
</module>
```

- Einbinden von Lib.jar as an "External JAR" in Eclipse für mein EJB Projekt zum Auflösen der Abhängigkeiten.
- Erzeugen der META-INF\jboss-deployment-structure.xml file in meinem EJB Projekt:


```
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
  <deployment>
    <dependencies>
      <module name="my.structure" export="true" />
    </dependencies>
  </deployment>
</jboss-deployment-structure>
```

- Rebuild des EJB Projekts
- Republish des EJB Project nach JBoss.​
Und nun fangen die Probleme an...

1.)
Als erstes mal steht mein Bean nicht mehr via JBoss Remoting zur Verfügung. Das "java:jboss/exported...." JNDI binding wird nicht mehr von JBoss generiert. Die anderen Bindings der Bean (global, app, module) werden erzeugt. Annotiere ich neben dem in der Lib befindlichen Interface auch nochmal zusaetzlich die Implementierung mit "@Remote" klappt das wieder. Das sollte eigentlich nicht nötig sein, da bereits das Interface welches nun im Lib.jar ist mit @Remote annotiert wurde.

2.)
Mein Hibernate Zugriff auf meine Datenbank Tabelle funktioniert nicht mehr. Folgende Funktion in meiner Bean Implementierung:


```
@Override
public User findUserByUsernamePassword(User user) {
    String q = "SELECT p from " + User.class.getName() + " p WHERE p.name = :name AND p.password = SHA1(:pass)";
    Query query = entityManager.createQuery(q);
    query.setParameter("name", user.getName());
    query.setParameter("pass", user.getPassword());
    User u = (User) query.getSingleResult();
    return u;
}
```

User ist das Objekt aus dem "entity" Package was sich nun ja ebenfalls in dem externen JAR befindet.

Es sieht vom header her so aus:

```
@Entity(name = "users")

public class User  implements Serializable {
    private static final long    serialVersionUID    = 7898904802394084838L;
    @Id
    private long    userid;
    private String    name;
    private String    password;
    @Column(name = "att_new", columnDefinition = "TINYINT(1)")
    private boolean    attNew;
    @Column(name = "perm_login", columnDefinition = "TINYINT(1)")
    private boolean    permLogin;
    @Column(name = "perm_admin", columnDefinition = "TINYINT(1)")
    private boolean    permAdmin;
```

Die Fehlermeldung bei verwenden dieser Methode als EJB lautet:

Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryParameterException: could not locate named parameter [name]


Warum kommt es zu diesen Problemen? Wie gesagt, kopiere ich die 2 Packages entity und business wieder in mein EJB Projekt und binde die JAR nicht ein, funktioniert alles wunderbar.

Irgendwo vermute ich den Fehler darin wie die JAR eingebunden wird, oder vielleicht auch die JAR-Datei selbst (vielleicht muss man sie auf eine "besondere" Art und Weise generieren?).


----------



## FArt (5. Dez 2012)

JBoss arbeitet sehr modular. Du musst wohl Abhängigkeiten definieren.

https://docs.jboss.org/author/display/AS71/Class+Loading+in+AS7


----------



## OlliL (5. Dez 2012)

Hallo FArt,

aber ich dachte das ist genau der Grund wozu ich META-INF\jboss-deployment-structure.xml erstellt habe? Muss ich Abhängigkeiten noch feiner granuliert angeben? Also auf Objekt-Ebene? Wenn aber mein "UserBean" die Entität "User" aktuell gar nicht kennen würde, dann würde ich doch ganz andere Fehlermeldungen bekommen, oder? Lösche ich z.B. die META-INF\jboss-deployment-structure.xml, kann ich das Projekt gar nicht mehr deployen wegen den fehlenden Dependencies.

Also mir wird nicht ganz klar, was genau zu tun ist, Sorry.


----------



## FArt (5. Dez 2012)

OlliL hat gesagt.:


> aber ich dachte das ist genau der Grund wozu ich META-INF\jboss-deployment-structure.xml erstellt habe?(


Ja, das ist prinzipiell richtig, aber wo ist dein "Deployment"? Wo ist deine Enterpriseapplikation?

Du versuchst deine Library zu den mitgelieferten JBoss Libraries zu kopieren und einzubinden. Warum?

Warum baust du nicht einfach ein EAR mit deiner Library, deinen Beans usw. und deployst das?


----------



## OlliL (5. Dez 2012)

Hallo FArt,

OK, mit EAR Deployment unter JBoss habe ich mich bisher noch nicht auseinander gesetzt. Das kannte ich bisher nur aus der OC4J Schiene. Aktuell in der "Entwicklungsphase" starte ich das ganze halt einfach aus Eclipse heraus als "Run As -> Run on Server" und der deployt nur das JAR mit den Elementen aus dem aktuellen Projekt.

Und was ich im Netz bisher so gefunden hatte, schien das "JBoss Vorgehen" zu sein, die JARs in modules/ abzulegen und dann via der XML Datei darauf zu verweisen.

Ist aber nicht das richtige Vorgehen? Muss ich mich nun also um EAR-Erzeugung kümmern?

Nun... dann werde ich mir heute Abend mal ein EAR Projekt in Eclipse anlegen, die entsprechenden Projekte dort verlinken und dann deployen.


----------



## OlliL (5. Dez 2012)

Hallo,

leider nicht das gewünschte Ergebniss.

Ich habe jetzt ein EAR Projekt (Java EE -> Enterprise Application Projekt), und die erzeugte EAR Datei hat folgenden Inhalt:

/
/lib/Lib.jar
/META-INF/application.xml
/META-INF/MANIFEST.MF
/Server.jar

Ich kann die EAR Datei problemlos auf meinen JBoss Server deployen, und die meine Beans werden auch als "java:jboss/exported/..." in den JNDI Bindings eingetragen.

1. Eine weitere Annotation @Remote bei der Implementierung des Interfaces aus der Lib im Server-Projekt ist nicht mehr notwendig.

2. Der Fehler beim Hibernate-Zugriff bleibt nach wie vor:

17:41:14,942 ERROR [org.jboss.ejb3.invocation] (EJB default - 1) JBAS014134: EJB Invocation failed on component UserBean for method public abstract my.project.entity.User my.project.business.UserIf.findUserByUsernamePassword(my.project.entity.User): javax.ejb.EJBException: java.lang.IllegalArgumentException: org.hibernate.QueryParameterException: could not locate named parameter [name]

OK, machen wir mal einen einfacheren Query:

Eine weitere Routine in meinem Bean:


```
@Override
	public User findUserById(User user) {
		User u = entityManager.find(User.class, user.getUserid());
		return u;
	}
```

Erzeugt beim Aufruf vom Client aus z.B. folgenden Fehler:

17:42:26,508 ERROR [org.jboss.ejb3.invocation] (EJB default - 2) JBAS014134: EJB Invocation failed on component UserBean for method public abstract my.project.entity.User my.project.UserIf.findUserById(my.project.entity.User): javax.ejb.EJBException: java.lang.IllegalArgumentException: Unknown entity: my.project.entity.User


my.project.entity.User kommt aus der Lib


----------



## fastjack (5. Dez 2012)

Ich denke der "my.project.entity.User" muss entsprechend in einer hibernate config (da wo auch die persistence-unit definiert wird) gemappt werden.


----------



## JimPanse (5. Dez 2012)

Man könnte sich ja auch eines der Beispeile runterladen quickstarts

Die Frage ist wie rufst du die Methode auf: Über das Interface ( @Locale oder @Remote) oder die Bean? Seit EJB3.1 brauch man für den Lokalen Zugriff kein Interface mehr definieren. (@LocalBean) d.h.


```
@EJB // @Inject
UserBean userBean;
```

sollte reichen. Weitere Frage: Wo rufst du die Bean auf?

Nachtrag:
Ganz wichtig: hast du die Zugriffsdaten zur DB in die standalone.xml (bzw. domain.xml) eingetragen???


----------



## JimPanse (5. Dez 2012)

fastjack hat gesagt.:


> Ich denke der "my.project.entity.User" muss entsprechend in einer hibernate config (da wo auch die persistence-unit definiert wird) gemappt werden.



 Bei EJB nicht notwendig. Es reicht die persistence.xml mit der Konfiguration des jeweiligen Persistence Providers.


----------



## OlliL (5. Dez 2012)

In einem Swing Client via JBoss Remoting

in etwa so (vereinfacht):


```
Context context = ClientUtility.getInitialContext();
final UserIf bean = (UserIf) context.lookup("/ServerEAR/Server/UserBean!my.project.business.UserIf");
String msg = "Message From EJB --> " + bean.findUserByUsernamePassword(user).getName();
```

Trage ich in meine persistence.xml die Entity explizit ein:


```
<class>my.project.entity.User</class>
```

verschwindet der Fehler. Ist dies nun die einzige und auch richtige Lösung? Warum brauche ich das ohne eine extra Lib.jar nicht? Sucht JBoss evtl. nicht in meiner Lib.jar nach Entities? Kann ich Ihn irgendwie dazu bewegen? <jar-file>Lib.jar</jar-file> hat leider auch nicht den gewuenschten Erfolg gebracht.


----------



## OlliL (5. Dez 2012)

OK, ich habs - Es reicht tatsaechlich <jar-file> in der persistence.xml. Aber - es muss der tatsaechliche relative Pfad angegeben werden. Also nicht

```
<jar-file>Lib.jar</jar-file>
```
sondern

```
<jar-file>lib/Lib.jar</jar-file>
```

Jetzt klappts auch ohne <class> wunderpraechtig! 



```
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
             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">

	<persistence-unit name="JPADB">
		<jta-data-source>java:/MySQLDS</jta-data-source>

		<jar-file>lib/Lib.jar</jar-file>

		<properties>
			<property name="showSql" value="true"/>
			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
		</properties>
	</persistence-unit>

</persistence>
```


----------

