Services – REST, Hibernate, JSF mit JBoss 7

Sonntag, 27. Oktober 2013 von  
unter Fachartikel Architektur

 Die Motivation

Neulich erinnerte ich mich an einen sehr interessanten und unterhaltsamen JUG-Vortrag von Lars Röwenkamp bei der JUG Münster über JavaEE (CDI-)Projekte mit JBoss Seam, wobei es darum ging, dass die eigentliche Schichtentrennung einer JavaEE-Applikation nicht aufgehoben wird, sondern im wesentlich „unter der Haube“ vorhanden bleibt, man aber klar erkennen kann, dass mit der Einführung von CDI (seit Java EE 6) und dem neuen JavaEE 7 deutlich weniger Overhead bei der leichtgewichtigen Erstellung von Unternehmens-Anwendungen vorhanden ist. Die Entwicklung geht damit hin zu einer vereinfachten, lose gekoppelten Architektur, in der sich die Transaktionen auf die fachliche Ebene verschieben und die Services (z.B. RESTful WebServices) über Business-Objekte zur Verfügung stehen, deren Funktionalitäten (z. B. per REST-ServiceClient) angefragt  werden können.

In diesem Blog-Eintrag soll es auch um das Deployment von robusten, professionellen JSF-/Hibernate JavaEE Web-Applikationen bzw. REST-WebService Apps mit JBoss Seam auf dem JBoss 6 und 7 gehen.

Es ist hierbei sowohl möglich, gut funktionierende JavaEE Apps mit EJB3-Backend, als auch ohne EJBs, stattdessen dafür mit den Seam Entities unter Verwendung von JPA oder Hibernate zu implementieren.

Die Beispiel App

Eine kleine Beispiel-App hierzu ist mit dem JBoss Developer Studio schnell erstellt. Der Klick-Pfad hierfür ist File/New/Project/Other/Seam Web Project.

Zuvor sollte man jedoch Seam 2.2 oder höher und den JBoss AS 6 oder höher installiert und am Start haben. Diese gibt man dann auf der nächsten Registerkarte des Wizards als Target Runtime (JBoss 6.1.0.Final Runtime), Target Server (…) und Configuration (Dynamic Web Project with Seam 2.2) an.

Auf einer der nächsten Registerkarten noch den Context Root (testProject) und das Content Dirctory (WebContent), [x] Generate web.xml, und danach die folgende Java Server Faces Konfiguration auf der Registerkarte „JSF Capabilities“:
Type: Library Provided by Target Runtime
[x] Configure JSF servlet in deployment descriptor
JSF Configuration File: /WEB-INF/faces-config.xml
JSF Servlet Name: Faces Servlet
JSF Servlet Class Name: javax.faces.webapp.FacesServlet
URL Mapping Patterns: *.seam

Auf der Seam Facet Registerkarte wählt man z.B.:
Seam Runtime: jboss-seam-2.2.1.Final
Deploy as WAR
Copy Libraries from Seam Runtime
Database Type: MySQL 5 (InnoDB)
Ansonsten können die folgenden vorgegebenen Defaults belassen werden, da diese nachher auch eher direkt in den Konfigurationsdateien und im erstellten Projekt editiert werden können:

Connection profile: DefaultDS
Session Bean Package Name: org.domain.testproject.session
Entity Bean Package Name: org.domain.testproject.entity

Sehr positiv hinsichtlich des Themas Test Driven Development (TDD) mit Java und speziell zum TDD mit TestNG und JBoss Seam fällt noch auf, dass hier gleich entsprechende Test-Projekte mitangelegt werden können. Dafür wählt man aus:
[x] Create Test Project
Test project name: testProject-test
Test Package name: org.domain.testproject.test

Es gibt übrigens bereits zwei sehr gute Blog-Einträge zum Thema Seam-Gen und JBoss Seam in diesem Blog:
Praxisbezogener Einstieg in JBoss Seam und
Einstieg in JBOSS SEAM Konversation & Pageflow

Auf Finish wird das Beispiel-Projekt mit der bekannten Struktur erstellt:

testProject
+ src/hot
+ src/main
+ JRE System Library [jdk1.7.0]
+ Web App Libraries
+ JBoss 6.x Runtime
+ build
+ resources
+ src
+ WebContent
hibernate-console.properties
testProject.launch

Hierbei sind vorteilhafterweise keine extra hibernate*.jars und keine JSF-Pakete hinzuzufügen, da die JARs allesamt bereits in der JBoss Runtime und die JBoss Seam-Pakete alle in den installierten JBoss Seam-Libraries enthalten sind.

Lediglich für den REST-Service werden noch zwei benötigte JAR-Dateien ins /WebContent/WEB-INF/lib-Verzeichnis hinzugefügt: org.restlet.ext.servlet.jar und org.restlet.jar

Neben die hibernate-console.properties legt man nun die folgende Datei testProject-ds.xml:

<?xml version=“1.0″ encoding=“UTF-8″?>
<datasources>
  <local-tx-datasource>
   <jndi-name>testProjectDatasource</jndi-name>
   <use-java-context>true</use-java-context>
   <connection-url>jdbc:mysql://localhost:3306/binaris_db?useUnicode=true&amp;characterEncoding=UTF-8</connection-url>
   <driver-class>com.mysql.jdbc.Driver</driver-class>
   <user-name>root</user-name>
   <password>tester</password>
   <connection-property name=“autoReconnect“>true</connection-property>
  </local-tx-datasource>
</datasources>

Diese testProject-ds.xml findet sich auch im Verzeichnis resources.

Die hibernate-console.properties ändert man folgendermaßen:

#File used by hibernate tools to override <datasource> and other container specific settings in persistence.xml
hibernate.connection.password=tester
hibernate.connection.username=root
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.url=jdbc:mysql://localhost:3306/binaris_db?useUnicode=true&amp;characterEncoding=UTF-8

hibernate.connection.provider_class=
  org.hibernate.connection.DriverManagerConnectionProvider
hibernate.datasource=java:/testProjectDatasource
hibernate.transaction.manager_lookup_class=
  org.hibernate.transaction.JBossTransactionManagerLookup

Unter src/main legt man nun im Package de.binaris.service.model.entity mit File/New/Seam Entity/… die JPA Entities an (für Bspl. siehe auch den Blog-Eintrag über Datenbankviewer mit Swing).

Dabei sieht die src/main/persistence.xml folgendermaßen aus:

<?xml version=“1.0″ encoding=“UTF-8″?>
<!– Persistence deployment descriptor for dev profile –>
<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_1_0.xsd“
version=“1.0″>

<persistence-unit name=“testProject“ transaction-type=“JTA“>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/testProjectDatasource</jta-data-source>
<properties>
<property name=“hibernate.dialect“ value=“org.hibernate.dialect.MySQLDialect“/>
<property name=“hibernate.hbm2ddl.auto“ value=“create-update“/>
<property name=“hibernate.show_sql“ value=“true“/>
<property name=“hibernate.format_sql“ value=“true“/>
<property name=“jboss.entity.manager.factory.jndi.name“ value=“java:/testProjectEntityManagerFactory“/>
</properties>
</persistence-unit>
</persistence>

Diese findet sich ebenfalls im Verzeichnis WebContent/WEB-INF/classes/META-INF/persistence.xml

Unter src/hot legt man im Package de.binaris.service.model.session mit File/New/Other/Seam Form/UserForm die erste @SessionScoped Seam FormBean an. Wenn man diese noch von EntityHome<User> ableitet verbindet man hiermit Database-Controller und Form-Controller (mit den implementierenden Actions und deren ActionHandlern), kann also durch die Verwendung einer Basisklasse des Seam-Pakets erneut etwas Overhead einsparen. Hier die Bean:

package de.binaris.service.model.session;

import java.util.List;

import javax.enterprise.context.SessionScoped;
import javax.persistence.EntityManager;

import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.web.RequestParameter;
import org.jboss.seam.framework.EntityHome;
import org.jboss.seam.international.StatusMessages;
import org.jboss.seam.log.Log;

import de.binaris.service.model.entity.User;

/**
* The default transactional C-R-U-D DAO extending the generic EntityHome<T> base DAO of the org.jboss.seam.framework
*     Calls to its form bound default actions (persist, find, update, remove) are restricted
*     to logged in support gui users and are handled by the generic base class methods.
*     The UserForm class provides some actions.
*
* @author krull
*/
@Name(„userForm“)
@SessionScoped
public class UserForm  extends EntityHome<User>
{
private static final long serialVersionUID = 542777310277739441L;

@RequestParameter
Integer userId;

@Logger
private Log log;

@In
@Out
StatusMessages statusMessages;

/**
* The action handler method
*
* @return true, if succeeded, otherwise: false
*/
public boolean actionHandlingMethod() {
try {
// […]
return true;
} catch (Throwable th) {
log.info(„Error occured: „, th.getCause());
return false;
}
}

@Override
public Object getId()
{
if (userId == null)
{
return super.getId();
}
else
{
return userId;
}
}

@Override
@Begin(join=true)
public void create() {
super.create();
}
}

Vorausschauenderweise fügen wir dem Package noch die folgende UserHome-Bean hinzu:

package de.binaris.service.model.session;

import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.web.RequestParameter;
import org.jboss.seam.framework.EntityHome;

import de.binaris.service.model.entity.User;

/**
* The default transactional C-R-U-D DAO extending the generic EntityHome<T> base DAO of the org.jboss.seam.framework
*     Calls to its form bound default actions (persist, find, update, remove) are restricted
*     to logged in support gui users and are handled by the generic base class methods.
*
* @author krull
*/
@Name(„userHome“)
public class UserHome extends EntityHome<User>
{
private static final long serialVersionUID = 7768995678699767323L;

@RequestParameter
Integer userId;

@Override
public Object getId()
{
if (userId == null)
{
return super.getId();
}
else
{
return userId;
}
}

@Override
@Begin(join=true)
public void create() {
super.create();
}

}

Im Verzeichnis WebContent hat uns Seam-Gen bzw. der zugehörige ant-Task erfreulicherweise direkt die folgende RichFaces user.xhtml angelegt, die man nun gemäß den Anforderungen ausbauen kann:

<!DOCTYPE composition PUBLIC „-//W3C//DTD XHTML 1.0 Transitional//EN“
„http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd“>
<ui:composition xmlns=“http://www.w3.org/1999/xhtml“
xmlns:s=“http://jboss.com/products/seam/taglib“
xmlns:ui=“http://java.sun.com/jsf/facelets“
xmlns:f=“http://java.sun.com/jsf/core“
xmlns:h=“http://java.sun.com/jsf/html“
xmlns:rich=“http://richfaces.org/rich“
xmlns:a=“http://richfaces.org/a4j“
template=“layout/template.xhtml“>

<ui:define name=“body“>
<h:form id=“UserForm“>
<rich:panel>
<f:facet name=“header“>user</f:facet>

<s:decorate id=“valueField“ template=“layout/edit.xhtml“>
<ui:define name=“label“>Value</ui:define>
<h:inputText id=“value“ required=“true“
value=“#{User.value}“/>
</s:decorate>

<div style=“clear:both“/>

</rich:panel>

<div>
<h:commandButton id=“user“ value=“user“
action=“#{User.user}“/>
</div>
</h:form>
</ui:define>
</ui:composition>

Die UserList.java legen wir auch noch an und machen uns hierbei die EJB QueryLanguage (EJB-QL)-Implementierung des Seam Frameworks zunutze:

package de.binaris.service.model.session;

import org.jboss.seam.annotations.Name;
import org.jboss.seam.framework.EntityQuery;
import de.binaris.service.model.entity.User;

/**
* The default transactional (CMT) find and SELECT query DAO extending the generic EntityQuery<T> base DAO of the  org.jboss.seam.framework
*     Calls to its form bound default actions (getResultList, getSingleResult) are restricted
*     to logged in support gui users and are handled by the generic base class methods.
*     This finder DAO uses EJB-QL for CMP.
*
* @author krull
*/
@Name(„userList“)
public class UserList extends EntityQuery<User>
{
private static final long serialVersionUID = 3779765732187645679L;

public UserList()
{
setEjbql(„select user from User user“);
}
}

Die userList.xhtml, die nun ausgebaut werden kann, legt Seam-Gen dabei ebenfalls an:

<!DOCTYPE composition PUBLIC „-//W3C//DTD XHTML 1.0 Transitional//EN“
„http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd“>
<ui:composition xmlns=“http://www.w3.org/1999/xhtml“
xmlns:s=“http://jboss.com/products/seam/taglib“
xmlns:ui=“http://java.sun.com/jsf/facelets“
xmlns:f=“http://java.sun.com/jsf/core“
xmlns:h=“http://java.sun.com/jsf/html“
xmlns:rich=“http://richfaces.org/rich“
template=“layout/template.xhtml“>

<ui:define name=“body“>

<rich:panel>
<f:facet name=“header“>Alle User</f:facet>
<div>
<h:outputText value=“Es existieren keine User.“
rendered=“#{empty userList.resultList}“/>

<h:dataTable id=“userList“ var=“users“
value=“#{userList.resultList}“
rendered=“#{not empty userList.resultList}“>
<h:column>
<f:facet name=“header“>Id</f:facet>
<s:link id=“users“
value=“#{users.iduser}“
propagation=“none“
view=“/user.xhtml“>
<f:param name=“userId“
value=“#{users.iduser}“/>
</s:link>
</h:column>

<h:column>
<f:facet name=“header“>Vorname</f:facet>
#{users.vorname}
</h:column>

<h:column>
<f:facet name=“header“>Nachname</f:facet>
#{users.nachname}
</h:column>

<h:column>
<f:facet name=“header“>Angelegt</f:facet>
<h:outputText value=“#{users.angelegtDatum}“>
<f:convertDateTime pattern=“yyyy-MM-dd HH:mm:ss“/>
</h:outputText>
</h:column>
</h:dataTable>

</div>
</rich:panel>

<div>
<s:button id=“done“
value=“Create user“
view=“/user.xhtml“/>
<s:button id=“Show users“
value=“Action of user“
view=“/userList.xhtml“
action=“#{userForm.actionHandlingMethod()}“/>
</div>

</ui:define>
</ui:composition>

Somit gibt es nun alle Möglichkeiten, die Projekt-Erfordernisse zu implementieren.

Im Verzeichnis src/conf/binaris_db/legt man die folgende  hibernate.cfg.xml an:

<?xml version=’1.0′ encoding=’UTF-8′?>
<!DOCTYPE hibernate-configuration PUBLIC
„-//Hibernate/Hibernate Configuration DTD 3.0//EN“
„http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd“>

<hibernate-configuration>
<session-factory>
<property name=“connection.url“>jdbc:mysql://localhost:3306/binaris_db?useUnicode=true&amp;characterEncoding=UTF-8</property>
<property name=“connection.username“>root</property>
<property name=“connection.password“>tester</property>
<property name=“connection.driver_class“>com.mysql.jdbc.Driver</property>
<property name=“dialect“>org.hibernate.dialect.MySQLDialect
</property>
<property name=“current_session_context_class“>thread</property>
<property name=“hibernate.transaction.factory_class“>
   org.hibernate.transaction.JDBCTransactionFactory
</property>
<property name=“hbm2ddl.auto“>update
</property>
<mapping />
</session-factory>
</hibernate-configuration>

Diese findet sich auch unter resources/conf/binaris_db/hibernate.cfg.xml

Die aufmerksame Leserin/der aufmerksame Leser wird sich evtl. schon gefragt haben, ob hier wirklich eine RichFaces-GUI in derselben .war-Datei wie der RESTful-WebService enthalten sein soll, was sich mit jboss-resteasy gelegentlich etwas schwierig gestaltet. Dies funktioniert hier im Rahmen der Einsparung von Layern/Packages/Deployment-Paketen durch Auswahl eines Vorfahren von jboss-resteasy zur Implementierung eines RESTful Services: RESTlet. Hierzu darf eine Literaturempfehlung für das e-Book „RESTlet in Action“ ausgesprochen werden.

Hier noch die web.xml:

<?xml version=“1.0″ encoding=“UTF-8″?>
<web-app xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance“ xmlns=“http://java.sun.com/xml/ns/javaee“ xmlns:web=“http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd“ xsi:schemaLocation=“http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd“ id=“WebApp_ID“ version=“2.5″>
<display-name>testProject</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!– Restlet adapter –>
<servlet>
<servlet-name>RestletServlet</servlet-name>
<servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
<init-param>
<!– Application class name –>
<param-name>org.restlet.application</param-name>
<param-value>de.binaris.service.testProjectApplication</param-value>
</init-param>
</servlet>
<!– match all requests –>
<servlet-mapping>
<servlet-name>RestletServlet</servlet-name>
<url-pattern>/restservice/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.seam</url-pattern>
</servlet-mapping>
<context-param>
<param-name>org.jboss.jbossfaces.JSF_CONFIG_NAME</param-name>
<param-value>Mojarra-1.2</param-value>
</context-param>
<context-param>
<param-name>org.richfaces.SKIN</param-name>
<param-value>blueSky</param-value>
</context-param>
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
<filter>
<filter-name>Seam Filter</filter-name>
<filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Seam Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Seam Resource Servlet</servlet-name>
<url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
</web-app>

Ein zu deployendes EAR-File ist entweder aus einem Zip-Archiv oder mit Hilfe von File/New/… schnell erstellt und hat für JBoss 5 und JBoss 6 die folgende Struktur:

testProject.ear:
+ META-INF
– application.xml
– testProject-ds.xml
+ testProject.war

Hierbei sieht die application.xml so aus:

<?xml version=“1.0″ encoding=“UTF-8″?>
<application xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance“ xmlns=“http://java.sun.com/xml/ns/javaee“ xmlns:application=“http://java.sun.com/xml/ns/javaee/application_5.xsd“ xsi:schemaLocation=“http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd“ id=“Application_ID“ version=“6″>
<display-name>testProject</display-name>
<module>
<web>
<web-uri>testProject.war</web-uri>
<context-root>testProject</context-root>
</web>
</module>
</application>

Man hat also nun prinzipiell zwei Möglichkeiten:

a) entweder nur das testProject.war testweise auf dem JBoss 5 oder 6 zu deployen: Rechte Maustaste auf dem testProject/Run As/Run On Server/jboss-6.1.1.Final Server/Next/Finish, oder

b) man deployt das EAR-Archiv einfach ins Deployment-Verzeichnis des Servers (lokal z.B. unter …\workspace\.metadata\.plugins\org.jboss.ide.eclipse.as.core\jboss-6.1.0.Final\deploy\ und startet in der Server-View des JBoss Developer Studios einfach den JBoss AS 6 oder 7 Server mit Rechte Maustaste/Start.

Das Deployment einer bereits für JBoss 5 und JBoss 6 generierten JavaEE WebApp bzw. WebService-Komponente ist ebenfalls simpel. Für den JBoss 7 sieht die Struktur des testProject.ear dann so aus:

testProject.ear:
+ META-INF
– application.xml
+ testProject.war

Hier eine typische produktive standalone.xml für den JBoss 7:

<?xml version=’1.0′ encoding=’UTF-8′?>

<server xmlns=“urn:jboss:domain:1.2″>

<extensions>
<extension module=“org.jboss.as.clustering.infinispan“/>
<extension module=“org.jboss.as.configadmin“/>
<extension module=“org.jboss.as.connector“/>
<extension module=“org.jboss.as.deployment-scanner“/>
<extension module=“org.jboss.as.ee“/>
<extension module=“org.jboss.as.ejb3″/>
<extension module=“org.jboss.as.jaxrs“/>
<extension module=“org.jboss.as.jdr“/>
<extension module=“org.jboss.as.jmx“/>
<extension module=“org.jboss.as.jpa“/>
<extension module=“org.jboss.as.logging“/>
<extension module=“org.jboss.as.mail“/>
<extension module=“org.jboss.as.naming“/>
<extension module=“org.jboss.as.osgi“/>
<extension module=“org.jboss.as.pojo“/>
<extension module=“org.jboss.as.remoting“/>
<extension module=“org.jboss.as.sar“/>
<extension module=“org.jboss.as.security“/>
<extension module=“org.jboss.as.threads“/>
<extension module=“org.jboss.as.transactions“/>
<extension module=“org.jboss.as.web“/>
<extension module=“org.jboss.as.webservices“/>
<extension module=“org.jboss.as.weld“/>
</extensions>

<management>
<security-realms>
<security-realm name=“ManagementRealm“>
<authentication>
<properties path=“mgmt-users.properties“ relative-to=“jboss.server.config.dir“/>
</authentication>
</security-realm>
<security-realm name=“ApplicationRealm“>
<authentication>
<properties path=“application-users.properties“ relative-to=“jboss.server.config.dir“/>
</authentication>
</security-realm>
</security-realms>
<management-interfaces>
<native-interface security-realm=“ManagementRealm“>
<socket-binding native=“management-native“/>
</native-interface>
<http-interface security-realm=“ManagementRealm“>
<socket-binding http=“management-http“/>
</http-interface>
</management-interfaces>
</management>

<profile>
<subsystem xmlns=“urn:jboss:domain:logging:1.1″>
<console-handler name=“CONSOLE“>
<level name=“INFO“/>
<formatter>
<pattern-formatter pattern=“%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n“/>
</formatter>
</console-handler>
<periodic-rotating-file-handler name=“FILE“>
<formatter>
<pattern-formatter pattern=“%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n“/>
</formatter>
<file relative-to=“jboss.server.log.dir“ path=“server.log“/>
<suffix value=“.yyyy-MM-dd“/>
<append value=“true“/>
</periodic-rotating-file-handler>
<logger category=“com.arjuna“>
<level name=“WARN“/>
</logger>
<logger category=“org.apache.tomcat.util.modeler“>
<level name=“WARN“/>
</logger>
<logger category=“sun.rmi“>
<level name=“WARN“/>
</logger>
<logger category=“jacorb“>
<level name=“WARN“/>
</logger>
<logger category=“jacorb.config“>
<level name=“ERROR“/>
</logger>
<root-logger>
<level name=“INFO“/>
<handlers>
<handler name=“CONSOLE“/>
<handler name=“FILE“/>
</handlers>
</root-logger>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:configadmin:1.0″/>
<subsystem xmlns=“urn:jboss:domain:datasources:1.0″>
<datasources>
<datasource jndi-name=“java:/jdbc/servicetracker“ pool-name=“servicetrackerDS“ enabled=“true“ use-java-context=“true“>
<connection-url>jdbc:mysql://localhost:3306/servicetracker?useUnicode=true&amp;characterEncoding=UTF-8</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<connection-property name=“autoReconnect“>
true
</connection-property>
<driver>mysql-connector-java-5.1.12.jar</driver>
<security>
<user-name>test</user-name>
<password>db2</password>
</security>
</datasource>
<datasource jndi-name=“java:/binarisds“ pool-name=“binarisDS“ enabled=“true“ use-java-context=“true“>
<connection-url>jdbc:mysql://localhost:3306/binaris_db?useUnicode=true&amp;characterEncoding=UTF-8</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<connection-property name=“autoReconnect“>
true
</connection-property>
<driver>mysql-connector-java-5.1.12.jar</driver>
<security>
<user-name>test1</user-name>
<password>db</password>
</security>
</datasource>
<datasource jndi-name=“java:jboss/datasources/ExampleDS“ pool-name=“ExampleDS“ enabled=“true“ use-java-context=“true“>
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<drivers>
<driver name=“h2″ module=“com.h2database.h2″>
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:deployment-scanner:1.1″>
<deployment-scanner path=“deployments“ relative-to=“jboss.server.base.dir“ scan-interval=“5000″/>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:ee:1.0″/>
<subsystem xmlns=“urn:jboss:domain:ejb3:1.2″>
<session-bean>
<stateless>
<bean-instance-pool-ref pool-name=“slsb-strict-max-pool“/>
</stateless>
<stateful default-access-timeout=“5000″ cache-ref=“simple“/>
<singleton default-access-timeout=“5000″/>
</session-bean>
<pools>
<bean-instance-pools>
<strict-max-pool name=“slsb-strict-max-pool“ max-pool-size=“20″ instance-acquisition-timeout=“5″ instance-acquisition-timeout-unit=“MINUTES“/>
<strict-max-pool name=“mdb-strict-max-pool“ max-pool-size=“20″ instance-acquisition-timeout=“5″ instance-acquisition-timeout-unit=“MINUTES“/>
</bean-instance-pools>
</pools>
<caches>
<cache name=“simple“ aliases=“NoPassivationCache“/>
<cache name=“passivating“ passivation-store-ref=“file“ aliases=“SimpleStatefulCache“/>
</caches>
<passivation-stores>
<file-passivation-store name=“file“/>
</passivation-stores>
<async thread-pool-name=“default“/>
<timer-service thread-pool-name=“default“>
<data-store path=“timer-service-data“ relative-to=“jboss.server.data.dir“/>
</timer-service>
<remote connector-ref=“remoting-connector“ thread-pool-name=“default“/>
<thread-pools>
<thread-pool name=“default“>
<max-threads count=“10″/>
<keepalive-time time=“100″ unit=“milliseconds“/>
</thread-pool>
</thread-pools>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:infinispan:1.2″ default-cache-container=“hibernate“>
<cache-container name=“hibernate“ default-cache=“local-query“>
<local-cache name=“entity“>
<transaction mode=“NON_XA“/>
<eviction strategy=“LRU“ max-entries=“10000″/>
<expiration max-idle=“100000″/>
</local-cache>
<local-cache name=“local-query“>
<transaction mode=“NONE“/>
<eviction strategy=“LRU“ max-entries=“10000″/>
<expiration max-idle=“100000″/>
</local-cache>
<local-cache name=“timestamps“>
<transaction mode=“NONE“/>
<eviction strategy=“NONE“/>
</local-cache>
</cache-container>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:jaxrs:1.0″/>
<subsystem xmlns=“urn:jboss:domain:jca:1.1″>
<archive-validation enabled=“true“ fail-on-error=“true“ fail-on-warn=“false“/>
<bean-validation enabled=“true“/>
<default-workmanager>
<short-running-threads>
<core-threads count=“50″/>
<queue-length count=“50″/>
<max-threads count=“50″/>
<keepalive-time time=“10″ unit=“seconds“/>
</short-running-threads>
<long-running-threads>
<core-threads count=“50″/>
<queue-length count=“50″/>
<max-threads count=“50″/>
<keepalive-time time=“10″ unit=“seconds“/>
</long-running-threads>
</default-workmanager>
<cached-connection-manager/>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:jdr:1.0″/>
<subsystem xmlns=“urn:jboss:domain:jmx:1.1″>
<show-model value=“true“/>
<remoting-connector/>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:jpa:1.0″>
<jpa default-datasource=““/>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:mail:1.0″>
<mail-session jndi-name=“java:jboss/mail/Default“>
<smtp-server outbound-socket-binding-ref=“mail-smtp“/>
</mail-session>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:naming:1.1″/>
<subsystem xmlns=“urn:jboss:domain:osgi:1.2″ activation=“lazy“>
<properties>
<property name=“org.osgi.framework.startlevel.beginning“>
1
</property>
</properties>
<capabilities>
<capability name=“javax.servlet.api:v25″/>
<capability name=“javax.transaction.api“/>
<capability name=“org.apache.felix.log“ startlevel=“1″/>
<capability name=“org.jboss.osgi.logging“ startlevel=“1″/>
<capability name=“org.apache.felix.configadmin“ startlevel=“1″/>
<capability name=“org.jboss.as.osgi.configadmin“ startlevel=“1″/>
</capabilities>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:pojo:1.0″/>
<subsystem xmlns=“urn:jboss:domain:remoting:1.1″>
<connector name=“remoting-connector“ socket-binding=“remoting“ security-realm=“ApplicationRealm“/>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:resource-adapters:1.0″/>
<subsystem xmlns=“urn:jboss:domain:sar:1.0″/>
<subsystem xmlns=“urn:jboss:domain:security:1.1″>
<security-domains>
<security-domain name=“binaris“>
<authentication>
<login-module code=“org.jboss.security.auth.spi.DatabaseServerLoginModule“ flag=“required“>
<module-option name=“unauthenticatedIdentity“ value=“guest“/>
<module-option name=“dsJndiName“ value=“java:/binarisds“/>
<module-option name=“hashAlgorithm“ value=“MD5″/>
<module-option name=“hashEncoding“ value=“base64″/>
<module-option name=“principalsQuery“ value=“SELECT password FROM binaris_user WHERE name=?“/>
<module-option name=“rolesQuery“ value=“SELECT role,’Roles‘ FROM binaris_role WHERE name=?“/>
</login-module>
</authentication>
</security-domain>
<security-domain name=“other“ cache-type=“default“>
<authentication>
<login-module code=“Remoting“ flag=“optional“>
<module-option name=“password-stacking“ value=“useFirstPass“/>
</login-module>
<login-module code=“RealmUsersRoles“ flag=“required“>
<module-option name=“usersProperties“ value=“${jboss.server.config.dir}/application-users.properties“/>
<module-option name=“rolesProperties“ value=“${jboss.server.config.dir}/application-roles.properties“/>
<module-option name=“realm“ value=“ApplicationRealm“/>
<module-option name=“password-stacking“ value=“useFirstPass“/>
</login-module>
</authentication>
</security-domain>
<security-domain name=“jboss-web-policy“ cache-type=“default“>
<authorization>
<policy-module code=“Delegating“ flag=“required“/>
</authorization>
</security-domain>
<security-domain name=“jboss-ejb-policy“ cache-type=“default“>
<authorization>
<policy-module code=“Delegating“ flag=“required“/>
</authorization>
</security-domain>
</security-domains>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:threads:1.1″/>
<subsystem xmlns=“urn:jboss:domain:transactions:1.1″>
<core-environment>
<process-id>
<uuid/>
</process-id>
</core-environment>
<recovery-environment socket-binding=“txn-recovery-environment“ status-socket-binding=“txn-status-manager“/>
<coordinator-environment default-timeout=“300″/>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:web:1.1″ default-virtual-server=“default-host“ native=“false“>
<connector name=“http“ protocol=“HTTP/1.1″ scheme=“http“ socket-binding=“http“/>
<virtual-server name=“default-host“ enable-welcome-root=“true“>
<alias name=“localhost“/>
<alias name=“example.com“/>
</virtual-server>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:webservices:1.1″>
<modify-wsdl-address>true</modify-wsdl-address>
<wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
<endpoint-config name=“Standard-Endpoint-Config“/>
<endpoint-config name=“Recording-Endpoint-Config“>
<pre-handler-chain name=“recording-handlers“ protocol-bindings=“##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM“>
<handler name=“RecordingHandler“/>
</pre-handler-chain>
</endpoint-config>
</subsystem>
<subsystem xmlns=“urn:jboss:domain:weld:1.0″/>
</profile>

<interfaces>
<interface name=“management“>
<inet-address value=“${jboss.bind.address.management:127.0.0.1}“/>
</interface>
<interface name=“public“>
<inet-address value=“${jboss.bind.address:127.0.0.1}“/>
</interface>
<interface name=“unsecure“>
<inet-address value=“${jboss.bind.address.unsecure:127.0.0.1}“/>
</interface>
</interfaces>

<socket-binding-group name=“standard-sockets“ default-interface=“public“ port-offset=“${jboss.socket.binding.port-offset:0}“>
<socket-binding name=“management-native“ interface=“management“ port=“${jboss.management.native.port:9999}“/>
<socket-binding name=“management-http“ interface=“management“ port=“${jboss.management.http.port:9990}“/>
<socket-binding name=“management-https“ interface=“management“ port=“${jboss.management.https.port:9443}“/>
<socket-binding name=“ajp“ port=“8009″/>
<socket-binding name=“http“ port=“8080″/>
<socket-binding name=“https“ port=“8443″/>
<socket-binding name=“osgi-http“ interface=“management“ port=“8090″/>
<socket-binding name=“remoting“ port=“4447″/>
<socket-binding name=“txn-recovery-environment“ port=“4712″/>
<socket-binding name=“txn-status-manager“ port=“4713″/>
<outbound-socket-binding name=“mail-smtp“>
<remote-destination host=“localhost“ port=“25″/>
</outbound-socket-binding>
</socket-binding-group>

</server>

Es muß also prinzipiell nur die DataSource-Konfiguration angepasst werden, der passende Datenbank-Treiber ins Verzeichnis AS7_HOME/standalone/deployments/mysql-connector-java-5.1.15.jar hinzugefügt werden und erforderlichenfalls bekannt gemacht werden. Im Standalone Deployment Verzeichnis AS7_HOME/standalone/deployments/ befindet sich auch das testProject.ear, wenn der Default-Deployment-Pfad verwendet wird. Danach kann der JBoss AS 7 zwecks Deployment gestartet, oder bei Verwendung von Hot Deployment das deployte EAR-Archiv nach einigen Sekunden entweder per Url (WebApp) oder per REST-ServiceClient (RESTful Service) aufgerufen werden.

Detaillierte Erklärungen und Antworten auf Fragen zur Migration von JBoss 5+6 JavaEE Apps auf JBoss 7 finden sich hier.

Zum Thema Deployment von Spring-basierten Services auf JBoss 7 gibt es hier weitere Informationen.

Weitere Beispiele für den JBoss AS 7 gibt es ebenfalls hier.

Auch zum Thema CDI gibt es bereits einen Eintrag in diesem Blog:
JBoss Seam – Von Seam2 nach Seam3 mit CDI und Weld

Allen interessierten Leserinnen und Lesern noch ein angenehmes Erntedankfest und schönes Thanksgiving 2013.

Kommentare

3 Kommentare zu “Services – REST, Hibernate, JSF mit JBoss 7”

  1. Von Services – mit Spring MVC und Spring Remoting : binaris informatik GmbH am Sonntag, 22. Dezember 2013 18:06

    […] zum Thema „Sencha trifft REST“, welches serverseitig bereits in einem früheren Blog-Eintrag hier erwähnt wurde, spricht auch das wichtige Thema Security bei RESTful WebServices an: ‚Es bietet […]

  2. Von Services – mit Hibernate 4, Vaadin 6, JBoss 7 : binaris informatik GmbH am Samstag, 1. März 2014 11:19

    […] „mapperApp“ wurde anhand eines vorigen Blog-Eintrags über ein Seam-JavaEE-Beispiel-Projekt hier bereits berichtet, weshalb die Hibernate-Konfiguration im Projekt mittels hibernate.cfg.xml und […]

  3. Von Architekturen – mit Spring CDI, JPA, JBoss, JavaEE : binaris informatik GmbH am Dienstag, 1. Juli 2014 22:29

    […] Über das Erstellen von JBoss Seam Applikationen mit Hibernate, JPA-Entities mittels JBoss Developer Studio gibt es bereits einen Blog Eintrag hier. […]

Einen Kommentar hinzufügen...

Sie müssen registriert und angemeldet sein um einen Kommentar zu schreiben.