Thursday, September 8, 2011

JSF 2 - Global Exception Handling

Build-in exception handling in JEE 6

As I described in a former article we replaced JEE 5 / Seam 2 with JEE 6. One of the features we really liked about Seam 2 was the global exception handling. You could declare exception handling rules in the global pages.xml such as logging, navigation, actions etc. Some might argue that the Servlet Container already allowed this in the web.xml:

<error-page>
 <error-code>404</error-code>
 <location>/404.xhtml</location>
</error-page>
...
<error-page>
 <exception-type>javax.faces.application.ViewExpiredException</exception-type>
 <location>/error.xhtml</location>
</error-page>

But this is really a poor replacement for the Seam features. First of all this JSF/Facelets-based exception page doesn't work because of a bug (with Weld on current JBoss AS 7):
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host]] (http--127.0.0.1-8082-1) Exception Processing ErrorPage[exceptionType=javax.faces.application.ViewExpiredException, location=/error.xhtml]: javax.servlet.ServletException: Context is already active
 at javax.faces.webapp.FacesServlet.service(FacesServlet.java:606) [jboss-jsf-api_2.1_spec-2.0.0.Beta1.jar:2.0.0.Beta1]
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.1.Final.jar:7.1.0.Alpha1-SNAPSHOT]
...
Caused by: java.lang.IllegalStateException: Context is already active
 at org.jboss.weld.context.AbstractConversationContext.activate(AbstractConversationContext.java:311) [weld-core-1.1.2.Final.jar:2011-07-26 15:02]
 at org.jboss.weld.jsf.WeldPhaseListener.activateConversations(WeldPhaseListener.java:114) [weld-core-1.1.2.Final.jar:2011-07-26 15:02]
So you need to use a static HTML, Servlet or JSP for this. I really don't have a problem with that because in this case you will not be tempted to include too much in your global exception handling page. Why this? Facelets make it really easy to reuse global templates. Think about a navigation tree that is configurable and stored in a database. Than you get database exceptions and redirect to an error page that uses a global layout template with navigation...nasty things could happen here. Best practice: Keep exception handling pages simple.

But there are further problems. The given <exception-type> doesn't catch super types, it needs to be an exact match (think about things like a myriad of O/R mapper exceptions with a super exception). And by far the worst problem: You can do nothing about the logging of this catched exceptions via this configuration. In Seam you could define if such exceptions should be logged at all and on which severity level. I don't know about your customers or operation team but for us such log entries are a no-go:
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/ifos].[Faces Servlet]] (http--127.0.0.1-8082-1) Servlet.service() for servlet Faces Servlet threw exception: ...controller.nutzer.AuthorizationException: Permission 'PERSON_LESEN_NUTZERDATEN' not granted!
 at ...controller.nutzer.Principal.check(Principal.java:46) [classes:]
...
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/ifos].[Faces Servlet]] (http--127.0.0.1-8082-1) Servlet.service() for servlet Faces Servlet threw exception: javax.faces.application.ViewExpiredException: viewId:/Veranstaltungstypen/filter.xhtml - Ansicht /Veranstaltungstypen/filter.xhtml konnte nicht wiederhergestellt werden.
 at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:205) [jsf-impl-2.1.3-b02-jbossorg-2.jar:2.1.3-SNAPSHOT]
...
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/ifos].[Faces Servlet]] (http--127.0.0.1-8082-2) Servlet.service() for servlet Faces Servlet threw exception: com.sun.faces.context.FacesFileNotFoundException: /Veranstaltungstypen/filtr.xhtml Not Found in ExternalContext as a Resource
 at com.sun.faces.facelets.impl.DefaultFaceletFactory.resolveURL(DefaultFaceletFactory.java:232) [jsf-impl-2.1.3-b02-jbossorg-2.jar:2.1.3-SNAPSHOT]
The log is triggered (JSF 2.1.3) via ExceptionHandlerImpl.handle() -> log(context) -> LOGGER.log(Level.SEVERE, ... with Logger name "context" which is used throughout JSF for all kind of things. Grossly said this <exception-type> feature is outright unusable in the current form.

Wait for JEE 10? Nope...

I really don't know why the standard hasn't added a simple extension like a log severity attribute in the last years. Sometimes I really wonder about some decisions in regards to production requirements, e.g. why is the new JSF resources folder in the web application root path and not under WEB-INF (where the Servlet Container doesn't allow access by default)? The hackers say thank you.

At least in JEE 6 there has been added a somewhat hidden feature - a custom exception handler class.

Remove the <exception-type> garbage from your web.xml. Add this to your faces-config.xml:
<faces-config>
 ...
 <factory>
  <exception-handler-factory>...controller.util.exception.ExceptionHandlerFactory</exception-handler-factory>
 </factory>
</faces-config>
This references the factory class for a custom exception handler:
public class ExceptionHandlerFactory extends javax.faces.context.ExceptionHandlerFactory {

 private final javax.faces.context.ExceptionHandlerFactory parent;

 public ExceptionHandlerFactory(final javax.faces.context.ExceptionHandlerFactory parent) {
  this.parent = parent;
 }

 @Override
 public ExceptionHandler getExceptionHandler() {
  return new ExceptionHandler(this.parent.getExceptionHandler());
 }

}
And finally our exception handler:
public class ExceptionHandler extends ExceptionHandlerWrapper {

 private static final Logger LOG = LoggerFactory.getLogger(ExceptionHandler.class);

 private final javax.faces.context.ExceptionHandler wrapped;

 public ExceptionHandler(final javax.faces.context.ExceptionHandler wrapped) {
  this.wrapped = wrapped;
 }

 @Override
 public javax.faces.context.ExceptionHandler getWrapped() {
  return this.wrapped;
 }

 @Override
 public void handle() throws FacesException {
  for (final Iterator<ExceptionQueuedEvent> it = getUnhandledExceptionQueuedEvents().iterator(); it.hasNext();) {
   Throwable t = it.next().getContext().getException();
   while ((t instanceof FacesException || t instanceof EJBException || t instanceof ELException)
     && t.getCause() != null) {
    t = t.getCause();
   }
   if (t instanceof FileNotFoundException || t instanceof HandledException
     || t instanceof ViewExpiredException) {
    final FacesContext facesContext = FacesContext.getCurrentInstance();
    final ExternalContext externalContext = facesContext.getExternalContext();
    final Map<String, Object> requestMap = externalContext.getRequestMap();
    try {
     LOG.info("{}: {}", t.getClass().getSimpleName(), t.getMessage());
     String message;
     if (t instanceof ViewExpiredException) {
      final String viewId = ((ViewExpiredException) t).getViewId();
      message = "View is expired. <a href='/ifos"   viewId   "'>Back</a>";
     } else {
      message = t.getMessage(); // beware, don't leak internal info!
     }
     requestMap.put("errorMsg", message);
     try {
      externalContext.dispatch("/error.jsp");
     } catch (final IOException e) {
      LOG.error("Error view '/error.jsp' unknown!", e);
     }
     facesContext.responseComplete();
    } finally {
     it.remove();
    }
   }
  }
  getWrapped().handle();
 }

}
And a (simple example) error.jsp:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Error</title>
</head>
<body>
 <h1>Error</h1>
 <p><%= request.getAttribute("errorMsg") %></p>
</body>
</html>

This is a heavily reduced example with only some example exceptions. HandledException is our abstract super exception for custom service exceptions. You can freely decide what you do for which exception type:
  • dispatch to different views in dependance from exception (what we do)
  • provide different messages
  • specialized logging
  • etc. - all is possible

Now we see such infos in the log file:
INFO  [...controller.util.exception.ExceptionHandler] (http--127.0.0.1-8082-2) AuthorizationException: Permission 'PERSON_LESEN_NUTZERDATEN' not granted!
...
INFO  [...controller.util.exception.ExceptionHandler] (http--127.0.0.1-8082-2) ViewExpiredException: viewId:/Veranstaltungstypen/filter.xhtml - Ansicht /Veranstaltungstypen/filter.xhtml konnte nicht wiederhergestellt werden.
...
INFO  [...controller.util.exception.ExceptionHandler] (http--127.0.0.1-8082-2) FacesFileNotFoundException: /Personen/ter.xhtml Not Found in ExternalContext as a Resource

You might say this all looks a little bit shirtsleeved - no annotations or abstractions etc. The Seam 3 Catch module does exactly that. But we like the freedom of the programmable custom exception handler even if the API is a little bit strange. Currently we are heavily into our "Back to the Roots" trip and don't like to add too many further libraries for such simple things. Another reason: Even the advanced Seam 2 exception features where sometimes not enough for us. If you provide an abstraction then you also give up flexibility. I think the ExceptionHandler code is simple enough and doesn't change often.

Thursday, September 1, 2011

JVM - Out of swap space! Really?

Houston, ...

One of our hosted Portal systems had suddenly stability problems and the production team found this exception in the server logs:
Exception java.lang.OutOfMemoryError: requested 20971520 bytes for GrET* in
/BUILD_AREA/jdk1.5.0_23/hotspot/src/share/vm/utilities/growableArray.cpp.
Out of swap space?
The Portal has been running for years without such problems and suddenly the JVM reboots once a day with this unexpected C++ (!?) related exception.

Pavlovian conditioning

The team started to look for the usual OutOfMemoryError stuff like open sessions, medium session sizes, Garbage Collection behaviour etc. But there was nothing unusual. The JVM had sufficient free heap and the GC behaved well. This research doesn't cause any harm but will not solve this issue - this is no typical OutOfMemory Error that follows a Java Object allocation.

The message Out of swap space? also triggered some reasonable researches. But the machine had enough swap space and didn't even use that. This should be the expected behaviour for Java server systems - swapping is the Garbage Collectors worst enemy.

What to do if nothing helps? Google is your friend...Bug reports, Forums and Blogs ;) But as often as not the found solutions don't match, contain stale information or even sometimes are simply wrong. The hits for this exceptions contain things like (forget about it):
  • Hotspot should be deactivated, JVM bug
  • Garbage Collector type CMS has a bug, switch to another one
  • Java Heap space too fragmented
  • you should run JProbe, Memory Analyzer and activate verbose GC
  • update Java Version (OK....nothing wrong about that)

    What's really up?

    The error simply means that the JVM process - a (complex) C++ program (forget Java for a moment) - cannot allocate a continuous 20 MB virtual memory element. The JVM process only takes a guess here and claims there may not be enough system swap space: But really, the JVM process cannot know from the memory allocation response. The malloc only delivers a ‘null’ as memory pointer and that’s it. The well-intentioned hint 'swap space' is more often wrong and misleading than true.

    growableArray is used at all kind of places in the JVM, not only for Heap and PermSpace but also for allocating additional working space for Code generation (Hotspot), Thread stacks, Garbage Collection etc. This error has nothing to do with insufficient Heap or Perm space.

    There are many possible reasons, e.g.:
    • Really not enough physical memory or swap space. The claimed continuous memory cannot be in swap space (!) but other memory pages could swap out and indirectly the guess “not enough swap space” could be true. This is very likely not the problem. You should deactivate swap on JVM server systems anyway because the Garbage Collector and swapping don't go well together.
    • You have a 32 Bit JVM and simply overflow the 32 Bit process size of the underlying operating system. Remember only Solaris allows nearly 4 GB 32 Bit processes, the maximum JVM 32 Bit process size on Windows or older Linux is more like 3 GB.
    • An additional problem in the 32 Bit case could be a fragmented process space. Use the best practice for server JVMs and set -Xms equal to -Xmx and this shouldn't be the reason for this problem.

    4 GB ought to be enough for anybody.

    The JVM process size is not only the sum of Heap and Perm space. There is also the thread stack space (-Xss), Garbage Collector working space, Hotspot compilation space, general process space (e.g. for I/O or array copy) and much more - many of them have no specific JVM maximum settings - and this are none-trivial sizes and can also sum up to multiple 100 MB in a well frequented system with lots of threads and GC (and maybe large memory page sizes).

    Indirectly Hotspot compilation or Garbage Collection can be a trigger for the Error because this functionality needs process memory too on top of the Java Heap space. E.g. the GC type CMS needs much more additional memory as other types (interesting statistics). But the real reason are too generous settings for Heap and Perm space in the restricted 32 Bit JVM process size. Many developers know the following image and the important Xmx and MaxPermSize settings. With them you can restrict the largest chunk of the used process memory and you will be tempted to optimize the maximum settings too much:


    The initially mentioned (suddenly instable) Portal server runs with -Xms2600m -Xmx2600m -Xss128k on Solaris and uses 350 MB Perm space. But the real process size is on the verge of the 4 GB hazard zone:

    PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
    25732 bea 3799M 3487M sleep 59 0 0:42:37 2.2% java/94

    Maybe we used more Perm space over the time because the Portal functionality is growing with each deployment. Or we used more worker threads because we have increasing peek traffic etc. It's really not important - lower the Heap settings by a small margin (the system runs nearly a full day before the error is triggered) and all is good ;)

    Switching to a 64 Bit VM is a possibility but keep the overhead in mind. For older JVMs this was an important decision. With modern JVMs CompressedOops may be an interesting option to alleviate the effects. In each case I cringe when I see a stateless high throughput system like an ESB with huge Heap sizes in 64 Bit mode.

    Monday, August 22, 2011

    Our Seam 2 to JEE 6 replacement list

    JBoss Seam 2 and JEE 5

    In the last years we had great success with JBoss Seam 2.x. This very innovative framework makes JEE 5 usable. The classic multi-tiered JEE-based Web application primarily consists of JavaServer Faces (JSF) in the presentation layer, Enterprise JavaBeans (EJB) in the business layer and Java Persistence API (JPA) as O/R mapper for the database access.
    The biggest problem was the missing link between JSF and EJB / JPA, some kind of binding framework. How can we access business methods in EJBs via Expression Language (EL)? How can we inject Entity data into the presentation layer and automatically validate input? Yes it's possible, but the classic JSF Managed Beans where really painful to use. JBoss Seam added this binding layer in form of an annotation based Dependency Injection (DI) framework. The addition of Web-relevant Contexts like Event (Request), Conversation, Session etc., the navigation and EL extensions, the Bean validation and much more resulted in a very powerful framework that just felt right.

    JEE 6!

    Many of this Seam-Core elements where standardized and integrated into JEE 6. The Context and Dependency Injection (CDI) is heavily influenced through Seam (and learned from past mistakes). Numerous JSF and JPA extensions have a counterpart in JBoss Seam 2.
    Recently we switched for an ongoing project from JEE 5 / Seam 2 to JEE 6. The main reasons where security issues with older Application servers, performance issues with Seam and also functional aspects like validation groups in JSF. Even though I did know about the common roots of Seam 2 ideas and many JEE 6 innovations I was amazed how smooth the transition was.
    Many things only needed minor adjustments. E.g. the JPA Enties should use the new Bean validation annotations (mostly only change the package name). We exchanged some Seam- against new JSF-components. Main work: The navigation rules must be reconfigured.

    A (not exhaustive) replacement list...


    Often there is really more to it than just a syntax replacement, e.g. @In and @Inject differ heavily. But on the surface you can start this way. Sry for the terrible Copy & Paste HTML:

    JEE 5 / Seam 2 JEE 6
    xmlns:c="http://java.sun.com/jstl/core" xmlns:c="http://java.sun.com/jsp/jstl/core"

    (avoid JSTL in JSF, but sometimes interesting out of performance reasons if you know what you are doing)
    xmlns:s="http://jboss.com/products/seam/taglib" (delete namespace 's', nearly for all of Seams JSF-Components now standard alternatives in JSF 2, see below)
    xmlns:a="http://richfaces.org/a4j"

    <a:support event="onchange" reRender="filter" />
    (delete namespace 'a')


     xmlns:f="http://java.sun.com/jsf/core"

    <f:ajax render=":filter"/>

    (event-attribute isn't necessary in this case, the components default change-event is used; use <h:head> to render the proper jsf.js link)
    <h:selectOneMenu value="#{...}">
      <s:selectItems label="#{_i.name}"
        value="#{userFilter.allOrgs}" var="_i"  noSelectionLabel="choose..." hideNoSelectionLabel="true"/>
    </h:selectOneMenu>
    <h:selectOneMenu value="#{...}" hideNoSelectionOption="true">
      <f:selectItem noSelectionOption="true" itemLabel="choose..." />
      <f:selectItems itemLabel="#{i_.name}"
        value="#{userFilter.allOrgs}" var="_i" />
    </h:selectOneMenu>
    <s:link includePageParams="false" 
        view="edit.xhtml" value="Edit"> 
        <f:param name="id" value="#{_user.id}" />
    </s:link>
    <h:link includeViewParams="false" 
        outcome="edit" value="Edit"> 
        <f:param name="id" value="#{_user.id}" />
    </h:link>
    <s:selectItems
        label
    ="#{messages[_action.name()]}" ... 
    <s:convertEnum />
    <f:selectItems
        itemLabel="#{messages[_action]}" ...

    (delete s:convertEnum, global default converter for single enum values)

    <template>.page.xml or pages.xml:

    <param name="id" value="#{userHome.id}" />
    <action execute="#{userHome.wire}" />

    insert into <template>.xhtml:

    <f:metadata>
        <f:viewParam name="id" value="#{userHome.id}" />
        <f:event type="preRenderView" listener="#{userHome.init()}" />
        <f:viewAction action="userHome.init()" /> (just since JSF 2.2)
    </f:metadata>



    import org.hibernate.annotations.Cache;
    import org.hibernate.annotations
        .CacheConcurrencyStrategy;
    @Entity
    @Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)

    public class User extends BaseEntity {

    import javax.persistence.Cacheable;
    @Entity
    @Cacheable
    public class User extends BaseEntity {

    (additionally add in persistence.xml: <shared-cache-mode>ENABLE_SELECTIVE </shared-cache-mode>)



    import org.hibernate.validator.Length;
    import org.hibernate.validator.NotEmpty;
    @Length(max = 50)
    @NotEmpty
    private String name;

    import javax.validation.constraints.NotNull;

    import javax.validation.constraints.Size;
    @NotNull
    @Size(max = 50, min = 1)
    private String name;

    import org.jboss.seam.framework.EntityQuery;
    @Name(userList")
    public class UserList extends EntityQuery<User> {
    (Seam 2 style list controller from seam-gen: don't use them, even with Seam 2)

    import org.jboss.seam.annotations.In;
    @In
    private UserHome userHome;

    @Out(required = false)
    private User user;

    @Factory(autoCreate = true, scope = ScopeType.APPLICATION)
    public Map<String, String> getProps() {
        return PROPERTY_MAP;
    }


    import javax.enterprise.context.ApplicationScoped;
    import javax.enterprise.inject.Produces; 
    import javax.inject.Inject;

    @Inject
    private UserHome userHome;

    @Produces
    @Named
    @ApplicationScoped
    public Map<String, String> getProps() {
        return PROPERTY_MAP;
    }

    @DataModel
    private List<Veranstaltungstyp> userList;
    ... 
    @DataModelSelection
    private User selectedUser;

    e.g. via @Produces, no "Outject" available:

    private ListDataModel<User> userList;
    ...
    User selectedUser = this.userList.getRowData();

    @Name("userService")
    @AutoCreate
    @Stateless
    @Local(UserService.class)
    public class UserServiceBean implements UserService {
    @Stateless
    public class UserService {

    (@Named only necessary if we use this in EL, all Stateful / Stateless / POJO Beans are automatically CDI Beans, default @Inject access via Type & optional Annotations, not via Named)
    final UserService userService = (UserService) Component.getInstance("userService");
    final UserService userService = CdiUtil.getSingleton(UserService.class);

    (was often necessary in Seam 2 out of performance reasons with @BypassInterceptors and in many none-Seam-Components, now only in Filter/Entity if really necessary, helper class for static BeanManager e.g.: https://issues.jboss.org/secure/attachmentzip/unzip/12429820/12341024%5B26%5D/swe2Web/src/de/swe2/util/CdiUtil.java)

    @Logger 
    private static Log log;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    private static final Logger LOG =
        LoggerFactory.getLogger(
            UserService.
    class);

    (in Seam 3 also possible "@Inject jboss.Logger log" but we really favor static access here, don't overdo injections)

    @In
    private FacesMessages facesMessages;

    facesMessages.add(
        Severity.INFO,
        "Info info #{el.info} info.");

    FacesContext.getCurrentInstance()
        .addMessage(

            "
    <componentId>" (or null),
        new FacesMessage(
            FacesMessage.
    SEVERITY_INFO,
            "
    Info info info."));

    (in Seam 3 also possible "@Inject Msg msg" but this cannot evaluate embedded EL yet and we favor own static wrapper here, like:)

    FacesMessages.addInfo(
        "<componentId>", 
        "Info info info.");

    #{identity.login}

    @In
    private Identity identity;

    @Name("authenticator")
    public class Authenticator {
        @In
        private Credentials credentials;
        @Override
        public boolean authenticate() {

    with Seam 3 Security:

    #{identity.login}

    @Inject
    private Identity identity;

    @Named
    @Stateless
    public class Authenticator {
        @Inject 
        private Credentials credentials;
        @Override
        public void authenticate() {
    <exception class="java.lang.IllegalStateException" log="false">
        <end-conversation />
        <redirect view-id="/error.xhtml" />
    </exception>
    see follow up post JSF 2 - Global Exception Handling


     

    Seam 3?

    I started with checking out the Seam 3 Booking example project (beware of PrettyFaces 3.2.0 in this example, it adds 500 ms CPU time to each request in development mode). I stripped the project down and build a new empty project template for us. During the conversion from Seam 2 to the new technology stack I noticed that we don't really need Seam anymore. There are some useful modules and ideas in Seam 3 but they are really optional and not a "must" like in JEE 5 days. Another interesting observation was that these extensions very often consists only of a few lines of code - CDI is _very_ powerful! The Seam Security Annotation tricks are amazing!

    If Seam is a selling point for JBoss then I would say from a business perspective the standardization of Seam core was like shooting themselves in the foot. If not - congratulations for the great work!

    Update 29.09.11

    I kind of expected something like that: http://planet.jboss.org/post/so_what_s_happening_with_seam

    Spring as CDI alternative?

    Some people might say I should use Spring as binding layer between JSF and JPA but I really don't like Spring in the JEE environment. It's like deploying Glassfish into JBoss AS because I like Grizzly. IMHO this are two heavy overlapping technology worlds. Decide for one or the other but only mix if it's really really necessary. It's OK to use Spring inside JEE for something like a great embedded Spring-based Process Engine but really not for something like 50 code lines less for a JNDI wrapper or some "I didn't want to learn CDI" developer.

    Friday, August 12, 2011

    Oracle / PostgreSQL Datasource in JBoss AS 7

    First follows a description for an Oracle RDBMS based datasource. The PostgreSQL variant works identical, the last section contains the necessary information.

    Install Oracle JDBC Driver

    We assume a ready-to-use Oracle connection URL and access data. You could e.g. install Oracle XE on your local machine. But beware: Then you have to switch the default port 8080 (or the interface) for your JBoss AS server because Oracle XE uses this port for a Web based administration console.

    Download the Oracle JDBC Driver from here: Oracle Database 11g Release 2 (11.2.0.2.0) JDBC Drivers
    (I use ojdbc6.jar for JDK 6.)

    You have two options for installing the driver:
    • as Deployment
    • as Module
    I prefer the second option but I  describe both here:

      Driver as Deployment

      Put ojdbc6.jar under .../jboss-as-7.2.0.Alpha1-SNAPSHOT/standalone/deployments.

      After some seconds the file "ojdbc6.jar.deployed" should appear in the same folder. JBoss AS 7 uses such files to trigger deployment events (e.g. create empty file "<artifact>.dodeploy") or to signal results (e.g. "<artifact>.deployed" or "<artifact>.failed"). You can also use the Web-based Admin console under http://localhost:8080/, but really...this thing is outright unusable and _years_ away from something like the Oracle WebLogic Server Admin console.

      Add  datasource in .../jboss-as-7.2.0.Alpha1-SNAPSHOT/standalone/configuration/standalone.xml
      (just like java:jboss/datasources/ExampleDS):
      <datasource jndi-name="java:/jdbc/testAppDS" pool-name="OracleDS" enabled="true" jta="true" use-java-context="true" use-ccm="true">
          <connection-url>
              jdbc:oracle:thin:@localhost:1521:XE
          </connection-url>
          <driver>
              ojdbc6.jar
          </driver>
          ...
      </datasource>
      Only if you need a 2PC / XA datasource you also must add a driver section in the datasource configuration (like H2):
      <driver name="ojdbc6.jar" module="">
          <xa-datasource-class>
              oracle.jdbc.xa.client.OracleXADataSource
          </xa-datasource-class>
      </driver>
      Restart the application server. You can and _should_ check the deployment state in the running application server. Use the command line:
      .../jboss-as-7.2.0.Alpha1-SNAPSHOT/bin/jboss-cli.bat
      You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.
      [disconnected /] connect
      Connected to standalone controller at localhost:9999
      [standalone@localhost:9999 /] /subsystem=datasources:installed-drivers-list
      {
          "outcome" => "success",
          "result" => [
              {
                  "driver-name" => "h2",
                  "deployment-name" => undefined,
                  "driver-module-name" => "com.h2database.h2",
                  "module-slot" => "main",
                  "driver-datasource-class-name" => "",
                  "driver-xa-datasource-class-name" => "org.h2.jdbcx.JdbcDataSource",
                  "driver-class-name" => "org.h2.Driver",
                  "driver-major-version" => 1,
                  "driver-minor-version" => 2,
                  "jdbc-compliant" => true
              },
              {
                  "driver-name" => "ojdbc6.jar",
                  "deployment-name" => "ojdbc6.jar",
                  "driver-module-name" => undefined,
                  "module-slot" => undefined,
                  "driver-datasource-class-name" => undefined,
                  "driver-xa-datasource-class-name" => undefined,
                  "driver-class-name" => "oracle.jdbc.OracleDriver",
                  "driver-major-version" => 11,
                  "driver-minor-version" => 2,
                  "jdbc-compliant" => true
              }
          ]
      }
      [standalone@localhost:9999 /] /subsystem=datasources/data-source=java\:\/jdbc\/testAppDS:test-connection-in-pool
      {
          "outcome" => "success",
          "result" => [true]
      }
      [standalone@localhost:9999 /] quit
      Closed connection to localhost:9999

      You have done something wrong if you see this instead:
      [standalone@localhost:9999 /] /subsystem=datasources/data-source=java\:\/jdbc\/testAppDS:test-connection-in-pool
      {
          "outcome" => "failed",
          "failure-description" => "Operation handler failed: java.util.NoSuchElementException: \"data-source\" => \"java:/jdbc/testAppDS\"",
          "rolled-back" => true
      }
      In this case your Web app deployments (that use this datasource) will fail with this unwilling message:
      12:04:06,628 INFO  [org.jboss.as.server.controller] (DeploymentScanner-threads - 2) Deployment of "test.war" was rolled back with failure message Operation handler failed to complete
      12:04:06,629 ERROR [org.jboss.as.deployment] (DeploymentScanner-threads - 1) {"Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => "Operation handler failed to complete"}}
      12:04:06,632 ERROR [org.jboss.as.deployment] (DeploymentScanner-threads - 1) Composite operation was rolled back
      According to the documentation the driver deployment is the recommended option but I had some problems with it. Sometimes the driver spontaneously undeploys and I have to trigger a redeployment - not impossible but annoying. My database views where also much faster after the switch but I don't know if this was another effect (also upgraded JBoss AS to a newer build). So I prefer the module version:

      Driver as Module

      Add folder oracle/db/main under .../jboss-as-7.2.0.Alpha1-SNAPSHOT/modules/com. Put ojdbc6.jar and the following file module.xml under this folder:

      <module xmlns="urn:jboss:module:1.0" name="com.oracle.db">
          <resources>
              <resource-root path="ojdbc6.jar"/>
          </resources>
          <dependencies>
              <module name="javax.api"/>
              <module name="javax.transaction.api"/>
          </dependencies>
      </module>

      Add this to the datasource drivers section (see above standalone.xml):
      <datasource jndi-name="java:/jdbc/testAppDS" pool-name="OracleDS" enabled="true" jta="true" use-java-context="true" use-ccm="true">
          <connection-url>
              jdbc:oracle:thin:@localhost:1521:XE
          </connection-url>
          <driver>
              oracle
          </driver>
          <security>
              <user-name>user</user-name>
              <password>pwd</password>
          </security>
      
          <new-connection-sql>select * from dual</new-connection-sql>
          <validation>
              <check-valid-connection-sql>select * from dual</check-valid-connection-sql>
              <background-validation>true</background-validation>
              <background-validation-millis>10000</background-validation-millis>
          </validation>
          <timeout>
              <allocation-retry>1</allocation-retry>
          </timeout>
      </datasource>
          ...
      <drivers>
          <driver name="oracle" module="com.oracle.db">
              <xa-datasource-class>
                  oracle.jdbc.xa.client.OracleXADataSource
              </xa-datasource-class>
          </driver>
      Now you should see this in the driver list (see above jboss-admin.bat):
              {
                  "driver-name" => "oracle",
                  "deployment-name" => undefined,
                  "driver-module-name" => "com.oracle.db",
                  "module-slot" => "main",
                  "driver-datasource-class-name" => "",
                  "driver-xa-datasource-class-name" => "oracle.jdbc.xa.client.OracleXADataSource",
                  "driver-class-name" => "oracle.jdbc.OracleDriver",
                  "driver-major-version" => 11,
                  "driver-minor-version" => 2,
                  "jdbc-compliant" => true
              }
      

      persistence.xml

      The persistence.xml of your Web application deployment is like usual:
      <?xml version="1.0" encoding="UTF-8"?>
      <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="database">
        <jta-data-source>java:/jdbc/testAppDS</jta-data-source>
        <properties>
         <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
         <property name="hibernate.hbm2ddl.auto" value="create-drop" />
         <property name="hibernate.show_sql" value="true" />
         <property name="hibernate.format_sql" value="false" />
         <property name="hibernate.use_sql_comments" value="true" />
        </properties>
       </persistence-unit>
      </persistence>
      

      Oracle11gDialect?

      Update: The following trick isn't necessary anymore with Hibernate Since 4.1 and JBoss 7.1.

      We use schema autocreation for development and Hibernate 4.0.0 trys to map boolean attributes to the datatype boolean. This type doesn't exist in Oracle DB.
      create table Organisation (id number(19,0) not null, aktiv boolean not null, ...
      There are different ways to fix this. We simply add this class to our Web app:
      package org.hibernate.dialect;
      
      import java.sql.Types;
      
      public class Oracle11gDialect extends Oracle10gDialect {
      
       public Oracle11gDialect() {
        registerColumnType(Types.BOOLEAN, "number(1,0)");
       }
      
      }
      And declare this as dialect in the persistence.xml:
         <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle11gDialect" />
      Add this as Maven dependency to your Web app (also good for debugging and some Hibernate annotations):
      <dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-core</artifactId>
          <version>4.0.0.Beta5</version>
          <scope>provided</scope>
      </dependency>
      Now everything works just fine.

      PostgreSQL datasource with XA

      Add folder postgresql/main under .../jboss-as-7.2.0.Alpha1-SNAPSHOT/modules/org. Put postgresql-9.1-901.jdbc4.jar and the following file module.xml under this folder:
      <?xml version="1.0" encoding="UTF-8"?>
      <module xmlns="urn:jboss:module:1.1" name="org.postgresql">
          <resources>
              <resource-root path="postgresql-9.1-901.jdbc4.jar"/>
          </resources>
          <dependencies>
              <module name="javax.api"/>
              <module name="javax.transaction.api"/>
          </dependencies>
      </module>
      

      Add this to the datasource drivers section (see above standalone.xml):
      <xa-datasource jndi-name="java:/testAppDS" pool-name="PostgresDS" enabled="true" use-java-context="true">
          <xa-datasource-property name="ServerName">
              abc.de
          </xa-datasource-property>
          <xa-datasource-property name="PortNumber">
              5432
          </xa-datasource-property>
          <xa-datasource-property name="DatabaseName">
              dbname
          </xa-datasource-property>
          <driver>postgresql</driver>
          <security>
              <user-name>user</user-name>
              <password>pwd</password>
          </security>
      </datasource>
          ...
      <drivers>
          <driver name="postgresql" module="org.postgresql">
              <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
          </driver>
      

      You might also be interested in