© 2017 The original authors.

Target Audience

Java Developers

1. Class Loading in WildFly

Since JBoss AS 7, Class loading is considerably different to previous versions of JBoss AS. Class loading is based on the MODULES project. Instead of the more familiar hierarchical class loading environment, WildFly’s class loading is based on modules that have to define explicit dependencies on other modules. Deployments in WildFly are also modules, and do not have access to classes that are defined in jars in the application server unless an explicit dependency on those classes is defined.

1.1. Deployment Module Names

Module names for top level deployments follow the format deployment.myarchive.war while sub deployments are named like deployment.myear.ear.mywar.war.

This means that it is possible for a deployment to import classes from another deployment using the other deployments module name, the details of how to add an explicit module dependency are explained below.

1.2. Automatic Dependencies

Even though in WildFly modules are isolated by default, as part of the deployment process some dependencies on modules defined by the application server are set up for you automatically. For instance, if you are deploying a Jakarta EE application a dependency on the Java EE API’s will be added to your module automatically. Similarly if your module contains a beans.xml file a dependency on Weldwill be added automatically, along with any supporting modules that weld needs to operate.

For a complete list of the automatic dependencies that are added, please see Implicit module dependencies for deployments.

Automatic dependencies can be excluded through the use of jboss-deployment-structure.xml.

1.3. Class Loading Precedence

A common source of errors in Java applications is including API classes in a deployment that are also provided by the container. This can result in multiple versions of the class being created and the deployment failing to deploy properly. To prevent this in WildFly, module dependencies are added in a specific order that should prevent this situation from occurring.

In order of highest priority to lowest priority

  1. System Dependencies - These are dependencies that are added to the module automatically by the container, including the Jakarta EE api’s.

  2. User Dependencies - These are dependencies that are added through jboss-deployment-structure.xml or through the Dependencies: manifest entry.

  3. Local Resource - Class files packaged up inside the deployment itself, e.g. class files from WEB-INF/classes or WEB-INF/lib of a war.

  4. Inter deployment dependencies - These are dependencies on other deployments in an ear deployment. This can include classes in an ear’s lib directory, or classes defined in other ejb jars.

1.4. WAR Class Loading

The war is considered to be a single module, so classes defined in WEB-INF/lib are treated the same as classes in WEB-INF/classes. All classes packaged in the war will be loaded with the same class loader.

1.5. EAR Class Loading

Ear deployments are multi-module deployments. This means that not all classes inside an ear will necessarily have access to all other classes in the ear, unless explicit dependencies have been defined. By default the EAR/lib directory is a single module, and every WAR or EJB jar deployment is also a separate module. Sub deployments (wars and ejb-jars) always have a dependency on the parent module, which gives them access to classes in EAR/lib, however they do not always have an automatic dependency on each other. This behaviour is controlled via the ear-subdeployments-isolated setting in the ee subsystem configuration:

<subsystem xmlns="urn:jboss:domain:ee:1.0" >            
  <ear-subdeployments-isolated>false</ear-subdeployments-isolated>
</subsystem>

By default this is set to false, which allows the sub-deployments to see classes belonging to other sub-deployments within the .ear.

For example, consider the following .ear deployment:

myapp.ear
 |
 |--- web.war
 |
 |--- ejb1.jar
 |
 |--- ejb2.jar

If the ear-subdeployments-isolated is set to false, then the classes in web.war can access classes belonging to ejb1.jar and ejb2.jar. Similarly, classes from ejb1.jar can access classes from ejb2.jar (and vice-versa).

The ear-subdeployments-isolated element value has no effect on the isolated classloader of the .war file(s). i.e. irrespective of whether this flag is set to true or false, the .war within a .ear will have a isolated classloader and other sub-deployments within that .ear will not be able to access classes from that .war. This is as per spec.

If the ear-subdeployments-isolated is set to true then no automatic module dependencies between the sub-deployments are set up. User must manually setup the dependency with Class-Path entries, or by setting up explicit module dependencies.

Portability

The Jakarta EE specification says that portable applications should not rely on sub deployments having access to other sub deployments unless an explicit Class-Path entry is set in the MANIFEST.MF. So portable applications should always use Class-Path entry to explicitly state their dependencies.
It is also possible to override the ear-subdeployments-isolated element value at a per deployment level. See the section on jboss-deployment-structure.xml below.

1.5.1. Dependencies: Manifest Entries

Deployments (or more correctly modules within a deployment) may set up dependencies on other modules by adding a Dependencies: manifest entry. This entry consists of a comma separated list of module names that the deployment requires. The available modules can be seen under the modules directory in the application server distribution. For example to add a dependency on javassist and apache velocity you can add a manifest entry as follows:

Dependencies: org.javassist export,org.apache.velocity export services,org.antlr

Each dependency entry may also specify some of the following parameters by adding them after the module name:

  • export This means that the dependencies will be exported, so any module that depends on this module will also get access to the dependency.

  • services By default items in META-INF of a dependency are not accessible, this makes items from META-INF/services accessible so servicesin the modules can be loaded.

  • optional If this is specified the deployment will not fail if the module is not available.

  • meta-inf This will make the contents of the META-INF directory available (unlike services, which just makes META-INF/services available). In general this will not cause any deployment descriptors in META-INF to be processed, with the exception of beans.xml. If a beans.xml file is present this module will be scanned by Weld and any resulting beans will be available to the application.

  • annotations If a jandex index has be created for the module these annotations will be merged into the deployments annotation index. The Jandex index can be generated using the Jandex ant task, and must be named META-INF/jandex.idx. Note that it is not necessary to break open the jar being indexed to add this to the modules class path, a better approach is to create a jar containing just this index, and adding it as an additional resource root in the module.xml file.

Adding a dependency to all modules in an EAR

Using the export parameter it is possible to add a dependency to all sub deployments in an ear. If a module is exported from a Dependencies: entry in the top level of the ear (or by a jar in the ear/lib directory) it will be available to all sub deployments as well.
To generate a MANIFEST.MF entry when using maven put the following in your pom.xml:
pom.xml
<build>
   ...
   <plugins>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-war-plugin</artifactId>
       <configuration>
          <archive>
             <manifestEntries>
                <Dependencies>org.slf4j</Dependencies>
             </manifestEntries>
          </archive>
       </configuration>
     </plugin>
   </plugins>
</build>

If your deployment is a jar you must use the maven-jar-plugin rather than the maven-war-plugin.

1.5.2. Class Path Entries

It is also possible to add module dependencies on other modules inside the deployment using the Class-Path manifest entry. This can be used within an ear to set up dependencies between sub deployments, and also to allow modules access to additional jars deployed in an ear that are not sub deployments and are not in the EAR/lib directory. If a jar in the EAR/lib directory references a jar via Class-Path: then this additional jar is merged into the parent ear’s module, and is accessible to all sub deployments in the ear.

1.6. Global Modules

It is also possible to set up global modules, that are accessible to all deployments. This is done by modifying the configuration file (standalone/domain.xml).

For example, to add javassist to all deployments you can use the following XML:

standalone.xml/domain.xml
<subsystem xmlns="urn:jboss:domain:ee:1.0" >            
  <global-modules>
    <module name="org.javassist" slot="main" />            
  </global-modules> 
</subsystem>

Note that the slot field is optional and defaults to main.

1.7. Global Directory

The EE subsystem allows the configuration of a global directory, which represents a directory tree scanned automatically to include .jar files and resources as a single additional dependency. This dependency is added as a system dependency to all deployed application. See Subsystem EE Global Directory to get more information about how to set up a global directory.

1.8. JBoss Deployment Structure File

jboss-deployment-structure.xml is a JBoss specific deployment descriptor that can be used to control class loading in a fine grained manner. It should be placed in the top level deployment, in META-INF (or WEB-INF for web deployments). It can do the following:

  • Prevent automatic dependencies from being added

  • Add additional dependencies

  • Define additional modules

  • Change an EAR deployments isolated class loading behaviour

  • Add additional resource roots to a module

An example of a complete jboss-deployment-structure.xml file for an ear deployment is as follows:

jboss-deployment-structure.xml
<jboss-deployment-structure>
  <!-- Make sub deployments isolated by default, so they cannot see each others classes without a Class-Path entry -->
  <ear-subdeployments-isolated>true</ear-subdeployments-isolated>
  <!-- This corresponds to the top level deployment. For a war this is the war's module, for an ear -->
  <!-- This is the top level ear module, which contains all the classes in the EAR's lib folder     -->
  <deployment>
     <!-- exclude-subsystem prevents a subsystems deployment unit processors running on a deployment -->
     <!-- which gives basically the same effect as removing the subsystem, but it only affects single deployment -->
     <exclude-subsystems>
        <subsystem name="resteasy" />
    </exclude-subsystems>
    <!-- Exclusions allow you to prevent the server from automatically adding some dependencies     -->
    <exclusions>
        <module name="org.javassist" />
    </exclusions>
    <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
    <dependencies>
      <module name="deployment.javassist.proxy" />
      <module name="deployment.myjavassist" />
      <!-- Import META-INF/services for ServiceLoader impls as well -->
      <module name="myservicemodule" services="import"/>
    </dependencies>
    <!-- These add additional classes to the module. In this case it is the same as including the jar in the EAR's lib directory -->
    <resources>
      <resource-root path="my-library.jar" />
    </resources>
  </deployment>
  <sub-deployment name="myapp.war">
    <!-- This corresponds to the module for a web deployment -->
    <!-- it can use all the same tags as the <deployment> entry above -->
    <dependencies>
      <!-- Adds a dependency on a ejb jar. This could also be done with a Class-Path entry -->
      <module name="deployment.myear.ear.myejbjar.jar" />
    </dependencies>
    <!-- Set's local resources to have the lowest priority -->
    <!-- If the same class is both in the sub deployment and in another sub deployment that -->
    <!-- is visible to the war, then the Class from the other deployment will be loaded,  -->
    <!-- rather than the class actually packaged in the war. -->
    <!-- This can be used to resolve ClassCastExceptions  if the same class is in multiple sub deployments-->
    <local-last value="true" />
  </sub-deployment>
  <!-- Now we are going to define two additional modules -->
  <!-- This one is a different version of javassist that we have packaged -->
  <module name="deployment.myjavassist" >
    <resources>
     <resource-root path="javassist.jar" >
       <!-- We want to use the servers version of javassist.util.proxy.* so we filter it out-->
       <filter>
         <exclude path="javassist/util/proxy" />
       </filter>
     </resource-root>
    </resources>
  </module>
  <!-- This is a module that re-exports the containers version of javassist.util.proxy -->
  <!-- This means that there is only one version of the Proxy classes defined          -->
  <module name="deployment.javassist.proxy" >
    <dependencies>
      <module name="org.javassist" >
        <imports>
          <include path="javassist/util/proxy" />
          <exclude path="/**" />
        </imports>
      </module>
    </dependencies>
  </module>
</jboss-deployment-structure>

1.9. Accessing JDK classes

Not all JDK classes are exposed to a deployment by default. If your deployment uses JDK classes that are not exposed you can get access to them using jboss-deployment-structure.xml with system dependencies:

Using jboss-deployment-structure.xml to access JDK classes
<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
    <deployment>
        <dependencies>
            <system export="true">
                <paths>
                    <path name="com/sun/corba/se/spi/legacy/connection"/>
                </paths>
            </system>
        </dependencies>
    </deployment>
</jboss-deployment-structure>

1.10. The "jboss.api" property and application use of modules shipped with WildFly

The WildFly distribution includes a large number of modules, a great many of which are included for use by WildFly internals, with no testing of the appropriateness of their direct use by applications or any commitment to continue to ship those modules in future releases if they are no longer needed by the internals. So how can a user know whether it is advisable for their application to specify an explicit dependency on a module WildFly ships? The "jboss.api" property specified in the module’s module.xml file can tell you:

Example declaration of the jboss.api property
<module xmlns="urn:jboss:module:1.5" name="com.google.guava">
    <properties>
        <property name="jboss.api" value="private"/>
    </properties>

If a module does not have a property element like the above, then it’s equivalent to one with a value of "public".

Following are the meanings of the various values you may see for the jboss.api property:

Value Meaning

public

May be explicitly depended upon by end user applications. Will continue to be available in future releases within the same major series and should not have incompatible API changes in future releases within the same minor series, and ideally not within the same major series.

private

Intended for internal use only. Only tested according to internal usage. May not be safe for end user applications to use directly.Could change significantly or be removed in a future release without notice.

unsupported

If you see this value in a module.xml in a WildFly release, please file a bug report, as it is not applicable in WildFly. In EAP it has a meaning equivalent to "private" but that does not mean the module is "private" in WildFly; it could very easily be "public".

preview

May be explicitly depended upon by end user applications, but there are no guarantees of continued availability in future releases or that there will not be incompatible API changes. This is not a common classification in WildFly. It is not used in WildFly 10.

deprecated

May be explicitly depended upon by end user applications. Stable and reliable but an alternative should be sought. Will be removed in a future major release.

Note that these definitions are only applicable to WildFly. In EAP and other Red Hat products based on WildFly the same classifiers are used, with generally similar meaning, but the precise meaning is per the definitions on the Red Hat customer support portal.

If an application declares a direct dependency on a module marked "private", "unsupported" or "deprecated", during deployment a WARN message will be logged. The logging will be in log categories "org.jboss.as.dependency.private", "org.jboss.as.dependency.unsupported" and "org.jboss.as.dependency.deprecated" respectively. These categories are not used for other purposes, so once you feel sufficiently warned the logging can be safely suppressed by turning the log level for the relevant category to ERROR or higher.

Other than the WARN messages noted above, declaring a direct dependency on a non-public module has no impact on how WildFly processes the deployment.

1.11. How to list the module dependencies of a deployed application

In WildFly it is possible to list the module dependencies added by the container to your deployed application. This task can be achieved via the command line interface, where specific operations are available to list the module dependencies for deployments and ear-subdeployments.

You can list the module dependencies of a deployment using the list-modules operation as below:

[standalone@localhost:9990 /] /deployment=test-application.war:list-modules

In case of ear-subdeployments, the list-modules operation is also available under the subdeployment resource:

[standalone@localhost:9990 /] /deployment=test-application.ear/subdeployment=test-application.war:list-modules

If you are running WildFly in domain mode, this operation is available via the server resource at the host level:

[domain@localhost:9990 /] /host=master/server=server-one/deployment=test-application.war:list-modules
[domain@localhost:9990 /] /host=master/server=server-one/deployment=test-application.ear/subdeployment=test-application.war:list-modules

By default, the list-modules operation shows the list of dependencies in a compact view, including only the module name. You can control this output using the attribute verbose=[false*|true] to enable/disable a detailed response.

The following output shows an example of a detailed view:

[standalone@localhost:9990 /] /deployment=test-application.ear:list-modules(verbose=true)
  {
      "outcome" => "success",
      "result" => {
          "system-dependencies" => [
              {
                  "name" => "com.fasterxml.jackson.datatype.jackson-datatype-jdk8",
                  "optional" => true,
                  "export" => false,
                  "import-services" => true
              },
              {
                  "name" => "com.fasterxml.jackson.datatype.jackson-datatype-jsr310",
                  "optional" => true,
                  "export" => false,
                  "import-services" => true
              },
              ...
          ],
          "local-dependencies" => [
              {
                "name" => "deployment.test-application.ear.test-application-ejb.jar",
                "optional" => false,
                "export" => false,
                "import-services" => true
              },
              ...
          ],
          "user-dependencies" => [
              {
                  "name" => "com.fasterxml.jackson.datatype.jackson-datatype-jdk8",
                  "optional" => false,
                  "export" => false,
                  "import-services" => false
              },
              {
                  "name" => "org.hibernate:4.1",
                  "optional" => false,
                  "export" => false,
                  "import-services" => false
              },
              ...
          ]
      }
  }

The list_modules operation shows information in three different categories:

  • system-dependencies: These are the dependencies added implicitly by the server container.

  • local-dependencies: These are dependencies on other parts of the deployment.

  • user-dependencies: These are the dependencies defined by the user via a manifest file or deployment-structure.xml.

For each module, the following information is shown:

  • name: The module name and, if the slot name is not the default "main" slot, the slot name is concatenated after a ":" character separator.

  • optional: If the dependency was added as an optional dependency.

  • export: If the dependency is being exported to other modules.

  • import-services: If the module for the deployment or subdeployment is allowed to import services from the dependency.

2. Implicit module dependencies for deployments

As explained in the Class Loading in WildFly article, WildFly 21 is based on module classloading. A class within a module B isn’t visible to a class within a module A, unless module B adds a dependency on module A. Module dependencies can be explicitly (as explained in that classloading article) or can be "implicit". This article will explain what implicit module dependencies mean and how, when and which modules are added as implicit dependencies.

2.1. What’s an implicit module dependency?

Consider an application deployment which contains EJBs. EJBs typically need access to classes from the javax.ejb.* package and other Java EE API packages. The jars containing these packages are already shipped in WildFly and are available as "modules". The module which contains the javax.ejb.* classes has a specific name and so does the module which contains all the Jakarta EE API classes. For an application to be able to use these classes, it has to add a dependency on the relevant modules. Forcing the application developers to add module dependencies like these (i.e. dependencies which can be "inferred") isn’t a productive approach. Hence, whenever an application is being deployed, the deployers within the server, which are processing this deployment "implicitly" add these module dependencies to the deployment so that these classes are visible to the deployment at runtime. This way the application developer doesn’t have to worry about adding them explicitly. How and when these implicit dependencies are added is explained in the next section.

2.2. How and when is an implicit module dependency added?

When a deployment is being processed by the server, it goes through a chain of "deployment processors". Each of these processors will have a way to check if the deployment meets a certain criteria and if it does, the deployment processor adds a implicit module dependency to that deployment. Let’s take an example - Consider (again) an EJB3 deployment which has the following class:

MySuperDuperBean.java
@Stateless
public class MySuperDuperBean {
 
...
 
}

As can be seen, we have a simple @Stateless EJB. When the deployment containing this class is being processed, the EJB deployment processor will see that the deployment contains a class with the @Stateless annotation and thus identifies this as a EJB deployment. This is just one of the several ways, various deployment processors can identify a deployment of some specific type. The EJB deployment processor will then add an implicit dependency on the Jakarta EE API module, so that all the Jakarta EE API classes are visible to the deployment.

Some subsystems will always add a API classes, even if the trigger condition is not met. These are listed separately below.

In the next section, we’ll list down the implicit module dependencies that are added to a deployment, by various deployers within WildFly.

2.3. Which are the implicit module dependencies?

Subsystem responsible for adding the implicit dependency Dependencies that are always added Dependencies that are added if a trigger condition is met Trigger which leads to the implicit module dependency being added

Core Server

javax.api sun.jdk org.jboss.vfs

 

 

Batch Subsystem

javax.batch.api

 

 

EE Subsystem

javaee.api

 

 

EJB3 subsystem

 

javaee.api

The presence of ejb-jar.xml (in valid locations in the deployment, as specified by spec) or the presence of annotation based EJBs (ex: @Stateless, @Stateful, @MessageDriven etc)

JAX-RS (Resteasy) subsystem

javax.xml.bind.api

org.jboss.resteasy.resteasy-atom-provider org.jboss.resteasy.resteasy-cdi org.jboss.resteasy.resteasy-jaxrs org.jboss.resteasy.resteasy-jaxb-provider org.jboss.resteasy.resteasy-jackson-provider org.jboss.resteasy.resteasy-jsapi org.jboss.resteasy.resteasy-multipart-provider org.jboss.resteasy.async-http-servlet-30

The presence of JAX-RS annotations in the deployment

JCA subsystem

javax.resource.api

javax.jms.api javax.validation.api org.jboss.logging org.jboss.ironjacamar.api org.jboss.ironjacamar.impl org.hibernate.validator

If the deployment is a resource adaptor (RAR) deployment.

JPA (Hibernate) subsystem

javax.persistence.api

javaee.api org.jboss.as.jpa org.hibernate

The presence of an @PersistenceUnit or @PersistenceContext annotation, or a <persistence-unit-ref> or <persistence-context-ref> in a deployment descriptor..

Logging Subsystem

org.jboss.logging org.apache.commons.logging org.apache.log4j org.slf4j org.jboss.logging.jul-to-slf4j-stub

 

 

SAR Subsystem

 

org.jboss.logging org.jboss.modules

The deployment is a SAR archive

Security Subsystem

org.picketbox

 

 

Web Subsystem

 

javaee.api com.sun.jsf-impl org.hibernate.validator org.jboss.as.web org.jboss.logging

The deployment is a WAR archive. JSF is only added if used. Multiple version options exist for mojarra.

Web Services Subsystem

org.jboss.ws.api org.jboss.ws.spi

 

 

Weld (CDI) Subsystem

 

javax.persistence.api javaee.api org.javassist org.jboss.interceptor org.jboss.as.weld org.jboss.logging org.jboss.weld.core org.jboss.weld.api org.jboss.weld.spi

If a beans.xml file is detected in the deployment

3. Deployment Descriptors used In WildFly

This page gives a list and a description of all the valid deployment descriptors that a WildFly deployment can use. This document is a work in progress.

Descriptor Location Specification Description Info

jboss-deployment-structure.xml

META-INF or WEB-INF of the top level deployment

 

This file can be used to control class loading for the deployment

Class Loading in WildFly

beans.xml

WEB-INF or META-INF

CDI

The presence of this descriptor (even if empty) activates CDI

Weld Reference Guide

web.xml

WEB-INF

Servlet

Web deployment descriptor

 

jboss-web.xml

WEB-INF

 

JBoss Web deployment descriptor. This can be use to override settings from web.xml, and to set WildFly specific options

 

ejb-jar.xml

WEB-INF of a war, or META-INF of an EJB jar

EJB

The EJB spec deployment descriptor

ejb-jar.xml schema

jboss-ejb3.xml

WEB-INF of a war, or META-INF of an EJB jar

 

The JBoss EJB deployment descriptor, this can be used to override settings from ejb-jar.xml, and to set WildFly specific settings

 

application.xml

META-INF of an EAR

Jakarta EE Platform Specification

 

application.xml schema

jboss-app.xml

META-INF of an EAR

 

JBoss application deployment descriptor, can be used to override settings application.xml, and to set WildFly specific settings

 

persistence.xml

META-INF

JPA

JPA descriptor used for defining persistence units

Hibernate Reference Guide

jboss-ejb-client.xml

WEB-INF of a war, or META-INF of an EJB jar

 

Remote EJB settings. This file is used to setup the EJB client context for a deployment that is used for remote EJB invocations

EJB invocations from a remote server instance

jbosscmp-jdbc.xml

META-INF of an EJB jar

 

CMP deployment descriptor. Used to map CMP entity beans to a database. The format is largely unchanged from previous versions.

 

ra.xml

META-INF of a rar archive

 

Spec deployment descriptor for resource adaptor deployments

IronJacamar Reference Guide Schema

ironjacamar.xml

META-INF of a rar archive

 

JBoss deployment descriptor for resource adaptor deployments

IronJacamar Reference Guide

*-jms.xml

META-INF or WEB-INF

 

JMS message destination deployment descriptor, used to deploy message destinations with a deployment

 

*-ds.xml

META-INF or WEB-INF

 

Datasource deployment descriptor, use to bundle datasources with a deployment

DataSource Configuration

application-client.xml

META-INF of an application client jar

Jakarta EE Platform Specification

The spec deployment descriptor for application client deployments

application-client.xml schema

jboss-client.xml

META-INF of an application client jar

 

The WildFly specific deployment descriptor for application client deployments

 

jboss-webservices.xml

META-INF for EJB webservice deployments or WEB-INF for POJO webservice deployments/EJB webservice endpoints bundled in .war

 

The JBossWS 4.0.x specific deployment descriptor for webservice endpoints

 

The purpose of this page is to document tips and techniques that will assist developers in creating fast, secure, and reliable applications. It is also a place to note what you should avoid doing when developing applications.

5. Application Client Reference

As a Jakarta EE compliant server, WildFly 21 contains an application client. An application client is essentially a cut down server instance, that allow you to use EE features such as injection in a client side program.

This article is not a tutorial on application client development, rather it covers the specifics of the WildFly application client. There are tutorials available elsewhere that cover application client basics, such as this one.
Note that the application client is different to the EJB client libraries, it is perfectly possible to write client application that do not use the application client, but instead use the jboss-ejb-client library directly.

5.1. Getting Started

To launch the application client use the appclient.sh or appclient.bat script in the bin directory. For example:

./appclient.sh --host=10.0.0.1 myear.ear#appClient.jar arg1

The --host argument tells the appclient the server to connect to. The next argument is the application client deployment to use, application clients can only run a single deployment, and this deployment must also be deployed on the full server instance that the client is connecting too.

Any arguments after the deployment to use are passed directly through to the application clients main function.

5.2. Connecting to more than one host

If you want to connect to more than one host or make use of the clustering functionality then you need to specify a jboss-ejb-client.properties file rather than a host:

./appclient.sh --ejb-client-properties=my-jboss-ejb-client.properties myear.ear#appClient.jar arg1

5.3. Example

A simple example how to package an application client and use it with WildFly can be within the quickstart appclient which is located on Github .

6. Embedded API

The embedded API can be used to launch within a currently running process.

The embedded server can be reinitialized with a different JBoss Home. However the module directory, module.path system property, and the modules system packages, jboss.modules.system.pkgs system property, are effectively static. This means that creating a new embedded server or host controller within the same VM will not allow overriding the modules directory or the system packages.

You can also set a hint to indicate which log manager is being used. The hint attempts to ensure that JBoss Logging will bind to the correct log manager. It also adds the hinted logging package to the modules system packages.

If using the embedded API with Java 11 you’ll need to add --add-module=java.se to your JVM arguments. See MODULES-372 for details.

6.1. Standalone API

A standalone server allows you to manage the lifecycle of a server within the currently running process. The server can be configured in admin-only mode or fully started and applications can be deployed.

6.1.1. Examples

Simple Example
final StandaloneServer server = EmbeddedProcessFactory.createStandaloneServer(Configuration.Builder.of(jbossHome).build());
server.start();

try {
    // Print the listening address
    final ModelControllerClient client = server.getModelControllerClient();
    final ModelNode address = Operations.createAddress("interface", "public");
    final ModelNode op = Operations.createReadAttributeOperation(address, "inet-address");
    op.get("resolve-expressions").set(true);
    final ModelNode result = client.execute(op);
    if (!Operations.isSuccessfulOutcome((result))) {
        throw new RuntimeException("Failed to get the public inet-address: " + Operations.getFailureDescription(result));
    }
    System.out.printf("Listening on %s%n", Operations.readResult(result).asString());
} finally {
    server.stop();
}
Server in admin-only Example
final StandaloneServer server = EmbeddedProcessFactory.createStandaloneServer(
    Configuration.Builder.of(jbossHome)
        .addCommandArgument("--admin-only")
        .build());
server.start();

try {
    // Print the listening address
    final ModelControllerClient client = server.getModelControllerClient();
    final ModelNode address = Operations.createAddress();
    final ModelNode op = Operations.createReadAttributeOperation(address, "running-mode");
    op.get("resolve-expressions").set(true);
    final ModelNode result = client.execute(op);
    if (!Operations.isSuccessfulOutcome((result))) {
        throw new RuntimeException("Failed to get the running-mode: " + Operations.getFailureDescription(result));
    }
    System.out.printf("Running mode is %s%n", Operations.readResult(result).asString());
} finally {
    server.stop();
}
log4j2 Hint
final StandaloneServer server = EmbeddedProcessFactory.createStandaloneServer(Configuration.Builder.of(jbossHome)
        .setLoggerHint(Configuration.LoggerHint.LOG4J2)
        .build()
);
server.start();

try {
    // Print the listening address
    final ModelControllerClient client = server.getModelControllerClient();
    final ModelNode address = Operations.createAddress("interface", "public");
    final ModelNode op = Operations.createReadAttributeOperation(address, "inet-address");
    op.get("resolve-expressions").set(true);
    final ModelNode result = client.execute(op);
    if (!Operations.isSuccessfulOutcome((result))) {
        throw new RuntimeException("Failed to get the public inet-address: " + Operations.getFailureDescription(result));
    }
    org.apache.logging.log4j.LogManager.getFormatterLogger(Main.class).info("Listening on %s%n", Operations.readResult(result).asString());
} finally {
    server.stop();
}

6.2. Host Controller API

The host controller API creates a host controller in the current process. The host controller is started in admin-only mode therefore servers within the domain cannot be started. However the server configuration can be altered via management operations.

6.2.1. Example

Simple Example
final HostController server = EmbeddedProcessFactory.createHostController(Configuration.Builder.of(jbossHome).build());
server.start();

try {
    // Print the listening address
    final ModelControllerClient client = server.getModelControllerClient();
    final ModelNode address = new ModelNode().setEmptyList();
    final ModelNode op = Operations.createOperation(ClientConstants.READ_CHILDREN_NAMES_OPERATION, address);
    op.get(ClientConstants.CHILD_TYPE).set(ClientConstants.SERVER_GROUP);
    final ModelNode result = client.execute(op);
    if (!Operations.isSuccessfulOutcome(result)) {
        throw new RuntimeException("Failed to get the public inet-address: " + Operations.getFailureDescription(result));
    }
    System.out.println("Available server groups:");
    for (ModelNode value : Operations.readResult(result).asList()) {
        System.out.printf("\t%s%n", value.asString());
    }
} finally {
    server.stop();
}

7. CDI Reference

WildFly uses Weld, the CDI reference implementation as its CDI provider. To activate CDI for a deployment simply add a beans.xml file in any archive in the deployment.

This document is not intended to be a CDI tutorial, it only covers CDI usage that is specific to WildFly. For some general information on CDI see the below links:

7.1. Using CDI Beans from outside the deployment

For WildFly 21 onwards, it is now possible have classes outside the deployment be picked up as CDI beans. In order for this to work you must add a dependency on the external deployment that your beans are coming from, and make sure the META-INF directory of this deployment is imported, so that your deployment has visibility to the beans.xml file (To import beans from outside the deployment they must be in an archive with a beans.xml file).

There are two ways to do this, either using the MANIFEST.MF or using jboss-deployment-structure.xml.

Using MANIFEST.MF you need to add a Dependencies entry, with meta-inf specified after the entry, e.g.

Dependencies: com.my-cdi-module meta-inf, com.my-other-cdi-module meta-inf

Using jboss-deployment-structure.xml you need to add a dependency entry with meta-inf="import", e.g.

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
    <deployment>
        <dependencies>
            <module name="deployment.d1.jar" meta-inf="import"/>
        </dependencies>
    </deployment>
</jboss-deployment-structure>

Note that this can be used to create beans from both modules in the modules directory, and from other deployments.

For more information on class loading and adding dependencies to your deployment please see the Class Loading Guide

7.2. Suppressing implicit bean archives

CDI 1.1 brings new options to packaging of CDI-enabled applications. In addition to well-known explicit bean archives (basically any archive containing the beans.xml file) the specification introduces implicit bean archives.

An implicit bean archive is any archive that contains one or more classes annotated with a bean defining annotation (scope annotation) or one or more session beans. As a result, the beans.xml file is no longer required for CDI to work in your application.

In an implicit bean archive only those classes that are either annotated with bean defining annotations or are session beans are recognized by CDI as beans (other classes cannot be injected).

This has a side-effect, though. Libraries exist that make use of scope annotation (bean defining annotations) for their own convenience but are not designed to run with CDI support. Guava would be an example of such library. If your application bundles such library it will be recognized as a CDI archive and may fail the deployment.

Fortunately, WildFly makes it possible to suppress implicit bean archives and only enable CDI in archives that bundle the beans.xml file. There are two ways to achieve this:

7.2.1. Per-deployment configuration

You can either set this up for your deployment only by adding the following content to the META-INF/jboss-all.xml file of your application:

<jboss xmlns="urn:jboss:1.0">
    <weld xmlns="urn:jboss:weld:1.0" require-bean-descriptor="true"/>
</jboss>

7.2.2. Global configuration

Alternatively, you may configure this for all deployments in your WildFly instance by executing the following command:

/subsystem=weld:write-attribute(name=require-bean-descriptor,value=true)

7.3. Development mode

WildFly 10 introduces a special mode for application development which allows you to inspect and monitor your CDI deployments. This mode is turned off by default and note that some features of the development mode may have negative impact on the performance and/or functionality of the application.

7.3.1. Per-deployment configuration

You can enable it locally in your application web.xml by setting the Servlet initialization parameter org.jboss.weld.development to true:

 <context-param>
   <param-name>org.jboss.weld.development</param-name>
   <param-value>true</param-value>
 </context-param>

7.3.2. Global configuration

Alternatively, you can enable it globally in Weld subsystem by setting development-mode attribute to true:

/subsystem=weld:write-attribute(name=development-mode,value=true)

For more details and example you can check Weld development mode.

Once the development mode is enabled you can check your applications CDI information using Weld Probe - Weld Probe.

7.4. Non-portable mode

CDI 1.1 clarifies some aspects of how CDI protable extensions work. As a result, some extensions that do not use the API properly (but were tolerated in CDI 1.0 environment) may stop working with CDI 1.1.If this is the case of your application you will see an exception like this:

org.jboss.weld.exceptions.IllegalStateException: WELD-001332: BeanManager method getBeans() is not available during application initialization

Fortunatelly, there is a non-portable mode available in WildFly which skips some of the API usage checks and therefore allows the legacy extensions to work as before.

Again, there are two ways to enable the non-portable mode:

7.4.1. Per-deployment configuration

You can either set this up for your deployment only by adding the following content to the META-INF/jboss-all.xml file of your application:

<jboss xmlns="urn:jboss:1.0">
    <weld xmlns="urn:jboss:weld:1.0" non-portable-mode="true" />
</jboss>

7.4.2. Global configuration

Alternatively, you may configure this for all deployments in your WildFly instance by executing the following command:

/subsystem=weld:write-attribute(name=non-portable-mode,value=true)

Note that new portable extensions should always use the BeanManager API properly and thus never required the non-portable mode. The non-portable mode only exists to preserve compatibility with legacy extensions!

8. EE Concurrency Utilities

EE Concurrency Utilities (JSR 236) is a technology introduced with Java EE 7, which adapts well known Java SE concurrency utilities to the Java EE application environment specifics. The Jakarta EE application server is responsible for the creation (and shutdown) of every instance of the EE Concurrency Utilities, and provide these to the applications, ready to use.

The EE Concurrency Utilities support the propagation of the invocation context, capturing the existent context in the application threads to use in their own threads, the same way a logged-in user principal is propagated when a servlet invokes an EJB asynchronously. The propagation of the invocation context includes, by default, the class loading, JNDI and security contexts.

WildFly creates a single default instance of each EE Concurrency Utility type in all configurations within the distribution, as mandated by the specification, but additional instances, perhaps customised to better serve a specific usage, may be created through WildFly’s EE Subsystem Configuration. To learn how to configure EE Concurrency Utilities please refer to EE Concurrency Utilities Configuration. Additionally, the EE subsystem configuration also includes the configuration of which instance should be considered the default instance mandated by the Jakarta EE specification, and such configuration is covered by Default EE Bindings Configuration.

8.1. Context Service

The Context Service ( javax.enterprise.concurrent.ContextService) is a brand new concurrency utility, which applications may use to build contextual proxies from existing objects.

A contextual proxy is an object that sets a invocation context, captured when created, whenever is invoked, before delegating the invocation to the original object.

Usage example:

public void onGet(...) {
  Runnable task = ...;
  Runnable contextualTask = contextService.createContextualProxy(task, Runnable.class);
  // ...
}

WildFly default configurations creates a single default instance of a Context Service, which may be retrieved through @Resource injection:

@Resource
private ContextService contextService;
To retrieve instead a non default Context Service instance, @Resource’s `lookup attribute needs to specify the JNDI name used in the wanted instance configuration. WildFly will always inject the default instance, no matter what’s the name attribute value, if the lookup attribute is not defined.

Applications may alternatively use instead the standard JNDI API:

ContextService contextService = InitialContext.doLookup("java:comp/DefaultContextService");
As mandated by the Jakarta EE specification, the default Context Service instance’s JNDI name is java:comp/DefaultContextService.

8.2. Managed Thread Factory

The Managed Thread Factory ( javax.enterprise.concurrent.ManagedThreadFactory) allows Java EE applications to create Java threads. It is an extension of Java SE’s Thread Factory ( java.util.concurrent.ThreadFactory) adapted to the Jakarta EE platform specifics.

Managed Thread Factory instances are managed by the application server, thus Jakarta EE applications are forbidden to invoke any lifecycle related method.

In case the Managed Thread Factory is configured to use a Context Service, the application’s thread context is captured when a thread creation is requested, and such context is propagated to the thread’s Runnable execution.

Managed Thread Factory threads implement javax.enterprise.concurrent.ManageableThread, which allows an application to learn about termination status.

Usage example:

public void onGet(...) {
  Runnable task = ...;
  Thread thread = managedThreadFactory.newThread(task);
  thread.start();
    // ...
}

WildFly default configurations creates a single default instance of a Managed Thread Factory, which may be retrieved through @Resource injection:

@Resource
private ManagedThreadFactory managedThreadFactory;
To retrieve instead a non default Managed Thread Factory instance, @Resource’s `lookup attribute needs to specify the JNDI name used in the wanted instance configuration. WildFly will always inject the default instance, no matter what’s the name attribute value, in case the lookup attribute is not defined.

Applications may alternatively use instead the standard JNDI API:

ManagedThreadFactory managedThreadFactory = InitialContext.doLookup("java:comp/DefaultManagedThreadFactory");
As mandated by the Jakarta EE specification, the default Managed Thread Factory instance’s JNDI name is java:comp/DefaultManagedThreadFactory.

8.3. Managed Executor Service

The Managed Executor Service ( javax.enterprise.concurrent.ManagedExecutorService) allows Java EE applications to submit tasks for asynchronous execution. It is an extension of Java SE’s Executor Service ( java.util.concurrent.ExecutorService) adapted to the Jakarta EE platform requirements.

Managed Executor Service instances are managed by the application server, thus Jakarta EE applications are forbidden to invoke any lifecycle related method.

In case the Managed Executor Service is configured to use a Context Service, the application’s thread context is captured when the task is submitted, and propagated to the executor thread responsible for the task execution.

Usage example:

public void onGet(...) {
    Runnable task = ...;
    Future future = managedExecutorService.submit(task);
    // ...
}

WildFly default configurations creates a single default instance of a Managed Executor Service, which may be retrieved through @Resource injection:

@Resource
private ManagedExecutorService managedExecutorService;
To retrieve instead a non default Managed Executor Service instance, @Resource’s `lookup attribute needs to specify the JNDI name used in the wanted instance configuration. WildFly will always inject the default instance, no matter what’s the name attribute value, in case the lookup attribute is not defined.

Applications may alternatively use instead the standard JNDI API:

ManagedExecutorService managedExecutorService = InitialContext.doLookup("java:comp/DefaultManagedExecutorService");
As mandated by the Jakarta EE specification, the default Managed Executor Service instance’s JNDI name is java:comp/DefaultManagedExecutorService.

8.4. Managed Scheduled Executor Service

The Managed Scheduled Executor Service ( javax.enterprise.concurrent.ManagedScheduledExecutorService) allows Jakarta EE applications to schedule tasks for asynchronous execution. It is an extension of Java SE’s Executor Service ( java.util.concurrent.ScheduledExecutorService) adapted to the Java EE platform requirements.

Managed Scheduled Executor Service instances are managed by the application server, thus Jakarta EE applications are forbidden to invoke any lifecycle related method.

In case the Managed Scheduled Executor Service is configured to use a Context Service, the application’s thread context is captured when the task is scheduled, and propagated to the executor thread responsible for the task execution.

Usage example:

public void onGet(...) {
    Runnable task = ...;
    ScheduledFuture future = managedScheduledExecutorService.schedule(task, 60, TimeUnit.SECONDS);
    // ...
}

WildFly default configurations creates a single default instance of a Managed Scheduled Executor Service, which may be retrieved through @Resource injection:

@Resource
private ManagedScheduledExecutorService managedScheduledExecutorService;
To retrieve instead a non default Managed Scheduled Executor Service instance, @Resource’s `lookup attribute needs to specify the JNDI name used in the wanted instance configuration. WildFly will always inject the default instance, no matter what’s the name attribute value, in case the lookup attribute is not defined.

Applications may alternatively use instead the standard JNDI API:

ManagedScheduledExecutorService managedScheduledExecutorService = InitialContext.doLookup("java:comp/DefaultManagedScheduledExecutorService");
As mandated by the Jakarta EE specification, the default Managed Scheduled Executor Service instance’s JNDI name is java:comp/DefaultManagedScheduledExecutorService.

9. EJB 3 Reference Guide

This chapter details the extensions that are available when developing Enterprise Java Beans tm on WildFly 21.

Currently there is no support for configuring the extensions using an implementation specific descriptor file.

9.1. Resource Adapter for Message Driven Beans

Each Message Driven Bean must be connected to a resource adapter.

9.1.1. Specification of Resource Adapter using Metadata Annotations

The ResourceAdapter annotation is used to specify the resource adapter with which the MDB should connect.

The value of the annotation is the name of the deployment unit containing the resource adapter. For example jms-ra.rar.

For example:

@MessageDriven(messageListenerInterface = PostmanPat.class)
@ResourceAdapter("ejb3-rar.rar")

9.2. Run-as Principal

Whenever a run-as role is specified for a given method invocation the default anonymous principal is used as the caller principal. This principal can be overridden by specifying a run-as principal.

9.2.1. Specification of Run-as Principal using Metadata Annotations

The RunAsPrincipal annotation is used to specify the run-as principal to use for a given method invocation.

The value of the annotation specifies the name of the principal to use. The actual type of the principal is undefined and should not be relied upon.

Using this annotation without specifying a run-as role is considered an error.

For example:

@RunAs("admin")
@RunAsPrincipal("MyBean")

9.3. Security Domain

Each Enterprise Java Bean tm can be associated with a security domain. Only when an EJB is associated with a security domain will authentication and authorization be enforced.

9.3.1. Specification of Security Domain using Metadata Annotations

The SecurityDomain annotation is used to specify the security domain to associate with the EJB.

The value of the annotation is the name of the security domain to be used.

For example:

@SecurityDomain("other")

9.4. Transaction Timeout

For any newly started transaction a transaction timeout can be specified in seconds.

When a transaction timeout of 0 is used, then the actual transaction timeout will default to the domain configured default.
TODO: add link to tx subsystem

Although this is only applicable when using transaction attribute REQUIRED or REQUIRES_NEW the application server will not detect invalid setups.

New Transactions

Take care that even when transaction attribute REQUIRED is specified, the timeout will only be applicable if a new transaction is started.

9.4.1. Specification of Transaction Timeout with Metadata Annotations

The TransactionTimeout annotation is used to specify the transaction timeout for a given method.

The value of the annotation is the timeout used in the given unit granularity. It must be a positive integer or 0. Whenever 0 is specified the default domain configured timeout is used.

The unit specifies the granularity of the value. The actual value used is converted to seconds. Specifying a granularity lower than SECONDS is considered an error, even when the computed value will result in an even amount of seconds.

For example:@TransactionTimeout(value = 10, unit = TimeUnit.SECONDS)

9.4.2. Specification of Transaction Timeout in the Deployment Descriptor

The trans-timeout element is used to define the transaction timeout for business, home, component, and message-listener interface methods; no-interface view methods; web service endpoint methods; and timeout callback methods.

The trans-timeout element resides in the urn:trans-timeout namespace and is part of the standard container-transaction element as defined in the jboss namespace.

For the rules when a container-transaction is applicable please refer to EJB 3.1 FR 13.3.7.2.1.

Example of trans-timeout

jboss-ejb3.xml

<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:tx="urn:trans-timeout"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd
http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd
urn:trans-timeout http://www.jboss.org/j2ee/schema/trans-timeout-1_0.xsd"
               version="3.1"
               impl-version="2.0">
    <assembly-descriptor>
        <container-transaction>
            <method>
                <ejb-name>BeanWithTimeoutValue</ejb-name>
                <method-name>*</method-name>
                <method-intf>Local</method-intf>
            </method>
            <tx:trans-timeout>
                <tx:timeout>10</tx:timeout>
                <tx:unit>Seconds</tx:unit>
            </tx:trans-timeout>
        </container-transaction>
    </assembly-descriptor>
</jboss:ejb-jar>

9.5. Timer service

The service is responsible to call the registered timeout methods of the different session beans.

A persistent timer will be identified by the name of the EAR, the name of the sub-deployment JAR and the Bean’s name.
If one of those names are changed (e.g. EAR name contain a version) the timer entry became orphaned and the timer event will not longer be fired.

9.5.1. Single event timer

The timer is will be started once at the specified time.

In case of a server restart the timeout method of a persistent timer will only be called directly if the specified time is elapsed.
If the timer is not persistent (since EJB3.1 see 18.2.3) it will be not longer available if JBoss is restarted or the application is redeployed.

9.5.2. Recurring timer

The timer will be started at the specified first occurrence and after that point at each time if the interval is elapsed.
If the timer will be started during the last execution is not finished the execution will be suppressed with a warning to avoid concurrent execution.

In case of server downtime for a persistent timer, the timeout method will be called only once if one, or more than one, interval is elapsed.
If the timer is not persistent (since EJB3.1 see 18.2.3) it will not longer be active after the server is restarted or the application is redeployed.

9.5.3. Calendar timer

The timer will be started if the schedule expression match. It will be automatically deactivated and removed if there will be no next expiration possible, i.e. If you set a specific year.

For example:

@Schedule( ... dayOfMonth="1", month="1", year="2012") +
// start once at 01-01-2012 00:00:00
Programmatic calendar timer

If the timer is persistent it will be fetched at server start and the missed timeouts are called concurrent.
If a persistent timer contains an end date it will be executed once nevertheless how many times the execution was missed. Also a retry will be suppressed if the timeout method throw an Exception.
In case of such expired timer access to the given Timer object might throw a NoMoreTimeoutExcption or NoSuchObjectException.

If the timer is non persistent it will not longer be active after the server is restarted or the application is redeployed.

TODO: clarify whether this should happen concurrently/blocked or even fired only once like a recurring timer!

Annotated calendar timer

If the timer is non persistent it will not activated for missed events during the server is down. In case of server start the timer is scheduled based on the @Schedule annotation.

If the timer is persistent (default if not deactivated by annotation) all missed events are fetched at server start and the annotated timeout method is called concurrent.

TODO: clarify whether this should happen concurrently/blocked or even fired only once like a recurring timer!

9.6. Container interceptors

JBoss AS versions prior to WildFly8 allowed a JBoss specific way to plug-in user application specific interceptors on the server side so that those interceptors get invoked during an EJB invocation. Such interceptors differed from the typical (portable) spec provided Java EE interceptors. The Jakarta EE interceptors are expected to run after the container has done necessary invocation processing which involves security context propagation, transaction management and other such duties. As a result, these Jakarta EE interceptors come too late into the picture, if the user applications have to intercept the call before certain container specific interceptor(s) are run.

9.6.1. Typical EJB invocation call path on the server

A typical EJB invocation looks like this:

Client application

MyBeanInterface bean = lookupBean();
 
bean.doSomething();

The invocation on the bean.doSomething() triggers the following (only relevant portion of the flow shown below):

  1. WildFly specific interceptor (a.k.a container interceptor) 1

  2. WildFly specific interceptor (a.k.a container interceptor) 2

  3. …​.

  4. WildFly specific interceptor (a.k.a container interceptor) N

  5. User application specific Jakarta EE interceptor(s) (if any)

  6. Invocation on the EJB instance’s method

The WildFly specific interceptors include the security context propagation, transaction management and other container provided services. In some cases, the " `container interceptors`" (let’s call them that) might even decide break the invocation flow and not let the invocation proceed (for example: due to the invoking caller not being among the allowed user roles who can invoke the method on the bean).

Previous versions of JBoss AS allowed a way to plug-in the user application specific interceptors (which relied on JBoss AS specific libraries) into this invocation flow so that they do run some application specific logic before the control reaches step#5 above. For example, AS5 allowed the use of JBoss AOP interceptors to do this.

As of WildFly 8, this feature was implemented.

9.6.2. Configuring container interceptors

As you can see from the JIRA https://issues.redhat.com/browse/AS7-5897, one of the goals of this feature implementation was to make sure that we don’t introduce any new WildFly specific library dependencies for the container interceptors. So we decided to allow the Jakarta EE interceptors (which are just POJO classes with lifecycle callback annotations) to be used as container interceptors. As such you won’t need any dependency on any WildFly specific libraries. That will allow us to support this feature for a longer time in future versions of WildFly.

Furthermore, configuring these container interceptors is similar to configuring the Jakarta EE interceptors for EJBs. In fact, it uses the same xsd elements that are allowed in ejb-jar.xml for 3.1 version of ejb-jar deployment descriptor.

Container interceptors can only be configured via deployment descriptors. There’s no annotation based way to configure container interceptors. This was an intentional decision, taken to avoid introducing any WildFly specific library dependency for the annotation.

Configuring the container interceptors can be done in jboss-ejb3.xml file, which then gets placed under the META-INF folder of the EJB deployment, just like the ejb-jar.xml. Here’s an example of how the container interceptor(s) can be configured in jboss-ejb3.xml:

jboss-ejb3.xml
<jboss xmlns="http://www.jboss.com/xml/ns/javaee"
       xmlns:jee="http://java.sun.com/xml/ns/javaee"
       xmlns:ci ="urn:container-interceptors:1.0">
 
    <jee:assembly-descriptor>
        <ci:container-interceptors>
            <!-- Default interceptor -->
            <jee:interceptor-binding>
                <ejb-name>*</ejb-name>
                <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class>
            </jee:interceptor-binding>
            <!-- Class level container-interceptor -->
            <jee:interceptor-binding>
                <ejb-name>AnotherFlowTrackingBean</ejb-name>
                <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class>
            </jee:interceptor-binding>
            <!-- Method specific container-interceptor -->
            <jee:interceptor-binding>
                <ejb-name>AnotherFlowTrackingBean</ejb-name>
                <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class>
                <method>
                    <method-name>echoWithMethodSpecificContainerInterceptor</method-name>
                </method>
            </jee:interceptor-binding>
            <!-- container interceptors in a specific order -->
            <jee:interceptor-binding>
                <ejb-name>AnotherFlowTrackingBean</ejb-name>
                <interceptor-order>
                    <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class>
                    <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class>
                    <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class>
                </interceptor-order>
                <method>
                    <method-name>echoInSpecificOrderOfContainerInterceptors</method-name>
                </method>
            </jee:interceptor-binding>
        </ci:container-interceptors>
    </jee:assembly-descriptor>
</jboss>
  • The usage of urn:container-interceptors:1.0 namespace which allows the container-interceptors elements to be configured

  • The container-interceptors element which contain the interceptor bindings

  • The interceptor bindings themselves are the same elements as what the EJB3.1 xsd allows for standard Jakarta EE interceptors

  • The interceptors can be bound either to all EJBs in the deployment (using the the * wildcard) or individual bean level (using the specific EJB name) or at specific method level for the EJBs.

The xsd for the urn:container-interceptors:1.0 namespace is available here https://github.com/jbossas/jboss-as/blob/master/ejb3/src/main/resources/jboss-ejb-container-interceptors_1_0.xsd

The interceptor classes themselves are simple POJOs and use the @javax.annotation.AroundInvoke to mark the around invoke method which will get invoked during the invocation on the bean. Here’s an example of the interceptor:

Example of container interceptor
public class ClassLevelContainerInterceptor {
    @AroundInvoke
    private Object iAmAround(final InvocationContext invocationContext) throws Exception {
        return this.getClass().getName() + " " + invocationContext.proceed();
    }
 
}

9.6.3. Container interceptor positioning in the interceptor chain

The container interceptors configured for a EJB are guaranteed to be run before the WildFly provided security interceptors, transaction management interceptors and other such interceptors thus allowing the user application specific container interceptors to setup any relevant context data before the invocation proceeds.

9.6.4. Semantic difference between container interceptor(s) and Java EE

interceptor(s) API

Although the container interceptors are modeled to be similar to the Jakarta EE interceptors, there are some differences in the API semantics. One such difference is that invoking on javax.interceptor.InvocationContext.getTarget() method is illegal for container interceptors since these interceptors are invoked way before the EJB components are setup or instantiated.

9.6.5. Testcase

This testcase in the WildFly codebase can be used for reference for implementing container interceptors in user applications https://github.com/wildfly/wildfly/blob/master/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/ejb/container/interceptor/ContainerInterceptorsTestCase.java

9.7. EJB3 Clustered Database Timers

WildFly now supports clustered database backed timers. The clustering support is provided through the database, and as a result it is not intended to be a super high performance solution that supports thousands of timers going off a second, however properly tuned it should provide sufficient performance for most use cases.

Note that database timers can also be used in non-clustered mode.

Note that for this to work correctly the underlying database must support the READ_COMMITTED or SERIALIZABLE isolation mode and the datasource must be configured accordingly

9.7.1. Setup

In order to use clustered timers it is necessary to add a database backed timer store. This can be done from the CLI with the following command:

/subsystem=ejb3/service=timer-service/database-data-store=my-clustered-store:add(allow-execution=true, datasource-jndi-name='java:/MyDatasource', refresh-interval=60000, database='postgresql', partition='mypartition')

An explanation of the parameters is below:

  • allow-execution - If this node is allowed to execute timers. If this is false then timers added on this node will be added to the database for another node to execute. This allows you to limit timer execution to a few nodes in a cluster, which can greatly reduce database load for large clusters.

  • datasource-jndi-name - The datasource to use

  • refresh-interval - The refresh interval in milliseconds. This is the period of time that must elapse before this node will check the database for new timers added by other nodes. A smaller value means that timers will be picked up more quickly, however it will result in more load on the database. This is most important to tune if you are adding timers that will expire quickly. If the node that added the timer cannot execute it (e.g. because it has failed or because allow-execution is false), this timer may not be executed until a node has refreshed.

  • database - Define the type of database that is in use. Some SQL statements are customised by database, and this tells the data store which version of the SQL to use.
    Without this attribute the server try to detected the type automatically, current supported types are postgresql, mysql, oracle, db2, hsql and h2.
    Note that this SQL resides in the file modules/system/layers/base/org/jboss/as/ejb3/main/timers/timer-sql.properties
    And as such is it possible to modify the SQL that is executed or add support for new databases by adding new DB specific SQL to this file (if you do add support for a new database it would be greatly appreciated if you could contribute the SQL back to the project).

  • partition - A node will only see timers from other nodes that have the same partition name. This allows you to break a large cluster up into several smaller clusters, which should improve performance. e.g. instead of having a cluster of 100 nodes, where all hundred are trying to execute and refresh the same timers, you can create 20 clusters of 5 nodes by giving ever group of 5 a different partition name.

Non clustered timers

Note that you can still use the database data store for non-clustered timers, in which case set the refresh interval to zero and make sure that every node has a unique partition name (or uses a different database).

9.7.2. Using clustered timers in a deployment

It is possible to use the data store as default for all applications by changing the default-data-store within the ejb3 subsystem:

    <timer-service thread-pool-name="timer" default-data-store="clustered-store">
        <data-stores>
            <database-data-store name="clustered-store" datasource-jndi-name="java:jboss/datasources/ExampleDS" partition="timer"/>
        </data-stores>
    </timer-service>

Another option is to use a separate data store for specific applications, all that is required is to set the timer data store name in jboss-ejb3.xml:

<?xml version="1.1" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:timer="urn:timer-service:1.0"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd
                     http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
               version="3.1"
               impl-version="2.0">
    <assembly-descriptor>
            <timer:timer>
                <ejb-name>*</ejb-name>
                <timer:persistence-store-name>my-clustered-store</timer:persistence-store-name>
            </timer:timer>
        </assembly-descriptor>
</jboss:ejb-jar>

9.7.3. Programmatically Refresh Timer

In a clustered deployment, multiple nodes updating timer datastore may cause the in-memory timer state to be temporarily out of sync. Some application may find the refresh-interval configuration not sufficient in some cases, and need to programmatically refresh timers. This can be done with EE interceptors configured for those business methods that need this capability, as illustrated in the following steps:

  • Implement an EE interceptor that enables wildfly.ejb.timer.refresh.enabled to true. For example,

import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

/**
 * An interceptor to enable programmatic timer refresh across multiple nodes.
 */
@Interceptor
public class RefreshInterceptor {
    @AroundInvoke
    public Object intercept(InvocationContext context) throws Exception {
        context.getContextData().put("wildfly.ejb.timer.refresh.enabled", Boolean.TRUE);
        return context.proceed();
    }
}
  • Configure the EE interceptor to the target stateless or singleton bean business methods. When wildfly.ejb.timer.refresh.enabled is set to true, calling TimerService.getAllTimers() will first refresh from timer datastore before returning timers. For example,

@Singleton
public class RefreshBean1 ... {

    @Interceptors(RefreshInterceptor.class)
    public void businessMethod1() {
        ...
        // since wildfly.ejb.timer.refresh.enabled is set to true in interceptor for this business method,
        // calling timerService.getAllTimers() will first refresh from timer datastore before returning timers.
        final Collection<Timer> allTimers = timerService.getAllTimers();
        ...
    }
}
  • Applications may configure such an interceptor to certain business methods that require this capability. Alternatively, applications may implement a dedicated business method to programmatically refresh timers, to be invoked by other parts of the application when needed. For example,

    @Interceptors(RefreshInterceptor.class)
    public List<Timer> getAllTimerInfoWithRefresh() {
        return timerService.getAllTimers();
    }

    public void businessMethod1() {
        final LocalBusinessInterface businessObject = sessionContext.getBusinessObject(LocalBusinessInterface.class);
        businessObject.getAllTimerInfoWithRefresh();

        // timer has been programmatically refreshed from datastore.
        // continue with other business logic...
    }

9.7.4. Technical details

Internally every node that is allowed to execute timers schedules a timeout for every timer is knows about. When this timeout expires then this node attempts to 'lock' the timer, by updating its state to running. The query this executes looks like:

UPDATE JBOSS_EJB_TIMER SET TIMER_STATE=? WHERE ID=? AND TIMER_STATE<>? AND NEXT_DATE=?;

Due to the use of a transaction and READ_COMMITTED or SERIALIZABLE isolation mode only one node will succeed in updating the row, and this is the node that the timer will run on.

9.8. EJB IIOP Guide

9.8.1. Enabling IIOP

To enable IIOP you must have the JacORB subsystem installed, and the <iiop/> element present in the ejb3 subsystem configuration. The standalone-full.xml configuration that comes with the distribution has both of these enabled.

The <iiop/> element takes two attributes that control the default behaviour of the server, for full details see EJB3 subsystem configuration guide.

9.8.2. Enabling JTS

To enable JTS simply add a <jts/> element to the transactions subsystem configuration.

It is also necessary to enable the JacORB transactions interceptor as shown below.

<subsystem xmlns="urn:jboss:domain:jacorb:1.1">
  <orb>
    <initializers transactions="on"/>
  </orb>
</subsystem>

9.8.3. Dynamic Stub’s

Downloading stubs directly from the server is no longer supported. If you do not wish to pre-generate your stub classes JDK Dynamic stubs can be used instead. The enable JDK dynamic stubs simply set the com.sun.CORBA.ORBUseDynamicStub system property to true.

9.8.4. Configuring EJB IIOP settings via jboss-ejb3.xml

TODO

9.9. EJB over HTTP

Beginning with WildFly 11 it is now possible to use HTTP as the transport (instead of remoting) for remote EJB and JNDI invocations.

Everything mentioned below is applicable for both JNDI and EJB functionality.

9.9.1. Server Configuration

In order to configure the server the http-invoker needs to be enabled on each virtual host you wish to use in the Undertow subsystem. This is enabled by default in standard configs, but if it has been removed it can be added via:

/subsystem=undertow/server=default-server/host=default-host/setting=http-invoker:add(http-authentication-factory=myfactory, path='/wildfly-services')

The Hhttp-invoker takes two parameters, a path (which defaults to /wildfly-services) and a http-authentication-factory which must be a reference to an Elytron http-authentication-factory.

Note that any deployment that wishes to use this must use Elytron security with the same security domain that corresponds to the HTTP authentication factory.

9.9.2. Performing Invocations

The mechanism for performing invocations is exactly the same as for the remoting based EJB client, the only difference is that instead of a 'remote+http' URI you use a 'http' URI (which must include the path that was configured in the invoker). For example if you are currently using 'remote+ http://localhost:8080' as the target URI, you would change this to 'http://localhost:8080/wildfly-services'.

9.10. jboss-ejb3.xml Reference

jboss-ejb3.xml is a custom deployment descriptor that can be placed in either ejb-jar or war archives. If it is placed in an ejb-jar then it must be placed in the META-INF folder, in a web archive it must be placed in the WEB-INF folder.

The contents of jboss-ejb3.xml are merged with the contents of ejb-jar.xml, with the jboss-ejb3.xml items taking precedence.

9.10.1. Example File

A simple example is shown below:

<?xml version="1.1" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:s="urn:security:1.1"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-spec-2_0.xsd"
               version="3.1"
               impl-version="2.0">
    <enterprise-beans>
        <message-driven>
            <ejb-name>ReplyingMDB</ejb-name>
            <ejb-class>org.jboss.as.test.integration.ejb.mdb.messagedestination.ReplyingMDB</ejb-class>
            <activation-config>
                <activation-config-property>
                    <activation-config-property-name>destination</activation-config-property-name>
                    <activation-config-property-value>java:jboss/mdbtest/messageDestinationQueue
                    </activation-config-property-value>
                </activation-config-property>
            </activation-config>
        </message-driven>
    </enterprise-beans>
    <assembly-descriptor>
        <s:security>
            <ejb-name>DDMyDomainSFSB</ejb-name>
            <s:security-domain>myDomain</s:security-domain>
            <s:run-as-principal>myPrincipal</s:run-as-principal>
        </s:security>
    </assembly-descriptor>
</jboss:ejb-jar>

As you can see the format is largely similar to ejb-jar.xml, in fact they even use the same namespaces, however jboss-ejb3.xml adds some additional namespaces of its own to allow for configuring non-spec info. The format of the standard http://java.sun.com/xml/ns/javaee is well documented elsewhere, this document will cover the non-standard namespaces.

Namespace "http://www.jboss.com/xml/ns/javaee" is bound to "jboss-ejb3-spec-2_0.xsd": this file redefines some elements of "ejb-jar_3_1.xml"
Assembly descriptor namespaces

The following namespaces can all be used in the <assembly-descriptor> element. They can be used to apply their configuration to a single bean, or to all beans in the deployment by using * as the ejb-name.

The security namespace urn:security

This allows you to set the security domain and the run-as principal for an EJB.

<s:security>
  <ejb-name>*</ejb-name>
  <s:security-domain>myDomain</s:security-domain>
  <s:run-as-principal>myPrincipal</s:run-as-principal>
</s:security>
The resource adaptor namespace urn:resource-adapter-binding

This allows you to set the resource adaptor for an MDB.

<r:resource-adapter-binding>
  <ejb-name>*</ejb-name>
  <r:resource-adapter-name>myResourceAdaptor</r:resource-adapter-name>
</r:resource-adapter-binding>
The IIOP namespace urn:iiop

The IIOP namespace is where IIOP settings are configured. As there are quite a large number of options these are covered in the IIOP guide.

The pool namespace urn:ejb-pool:1.0

This allows you to select the pool that is used by the SLSB or MDB. Pools are defined in the server configuration (i.e. standalone.xml or domain.xml)

<p:pool>
  <ejb-name>*</ejb-name>
  <p:bean-instance-pool-ref>my-pool</p:bean-instance-pool-ref>
</p:pool>
The cache namespace urn:ejb-cache:1.0

This allows you to select the cache that is used by the SFSB. Caches are defined in the server configuration (i.e. standalone.xml or domain.xml)

<c:cache>
  <ejb-name>*</ejb-name>
  <c:cache-ref>my-cache</c:cache-ref>
</c:cache>
The clustering namespace urn:clustering:1.0

This namespace is deprecated and as of WildFly 21 its use has no effect. The clustering behavior of EJBs is determined by the profile in use on the server.

9.11. Message Driven Beans Controlled Delivery

There are three mechanisms in WildFly that allow controlling if a specific MDB is actively receiving or not messages:

  • delivery active

  • delivery groups

  • clustered singleton

We will see each one of them in the following sections.

9.11.1. Delivery Active

Delivery active is simply an attribute associated with the MDB that indicates if the MDB is receiving messages or not. If an MDB is not currently receiving messages, the messages will be saved in the queue or topic for later, according to the rules of the topic/queue.

You can configure delivery active using xml or annotations, and you can change its value after deployment using the cli.

  • jboss-ejb3.xml:

In the jboss-ejb3 xml file, configure the value of active as false to mark that the MDB will not be receiving messages as soon as it is deployed:

<?xml version="1.1" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:d="urn:delivery-active:1.2"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"                version="3.1"
               impl-version="2.0">
    <assembly-descriptor>
        <d:delivery>
            <ejb-name>HelloWorldQueueMDB</ejb-name>
            <d:active>false</d:active>
        </d:delivery>
    </assembly-descriptor>
</jboss:ejb-jar>

You can use a wildcard "*" in the place of ejb-name if you want to apply that active value to all MDBs in your application.

  • annotation

Alternatively, you can use the org.jboss.ejb3.annotation.DeliveryActive annotation, as in the example below:

@MessageDriven(name = "HelloWorldMDB", activationConfig = {
 
 @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
 
 @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/HELLOWORLDMDBQueue"),
 
 @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
 
@DeliveryActive(false)
 
public class HelloWorldMDB implements MessageListener {
    public void onMessage(Message rcvMessage) {
      // ...
    }
}
Start-delivery and Stop-Delivery

These management operations dynamically change the value of the active attribute, enabling or disabling delivery for the MDB. at runtime To use them, connect to the WildFly instance you want to manage, then enter the path of the MDB you want to manage delivery for:

[standalone@localhost:9990 /] cd deployment=jboss-helloworld-mdb.war/subsystem=ejb3/message-driven-bean=HelloWorldMDB
 
[standalone@localhost:9990 message-driven-bean=HelloWorldMDB] :stop-delivery
{"outcome" => "success"}
 
[standalone@localhost:9990 message-driven-bean=HelloWorldMDB] :start-delivery
{"outcome" => "success"}

9.11.2. Delivery Groups

Delivery groups provide a straightforward way to manage delivery for a group of MDBs. Every MDB belonging to a delivery group has delivery active if that group is active, and has delivery inactive whenever the group is not active.

You can add a delivery group to the ejb3 subsystem using either the subsystem xml or cli. Next, we will see examples of each case. In those examples we will add only a single delivery group, but keep in mind that you can add as many delivery groups as you need to a WildFly instance.

  • the ejb3 subsystem xml (located in your configuration xml, such as standalone.xml)

<subsystem xmlns="urn:jboss:domain:ejb3:4.0">
    ...
    <mdb>
        ...
        <delivery-groups>
            <delivery-group name="mdb-group-name" active="true"/>
        </delivery-groups>
    </mdb>
    ...
</subsystem>

The example above adds a delivery group named "mdb-group-name" (you can use whatever name suits you best as the group name). The "true" active attribute indicates that all MDBs belonging to that group will have delivery active right after deployment. If you mark that attribute as false, you are indicating that every MDB belonging to the group will not start receiving messages after deployment, a condition that will remain until the group becomes active.

  • jboss-cli

You can add a mdb-delivery-group using the add command as below:

[standalone@localhost:9990 /] ./subsystem=ejb3/mdb-delivery-group=mdb-group-name:add
{"outcome" => "success"}
Reading and Writing the Delivery State of a Delivery Group

You can check whether delivery is active for a group by reading the active attribute, which defaults to true:

[standalone@localhost:9990 /] ./subsystem=ejb3/mdb-delivery-group=mdb-group-name:read-attribute(name=active)
{ "outcome" => "success", "result" => true }

To make the the delivery-group inactive, just write the active attribute with a false value:

[standalone@localhost:9990 /] ./subsystem=ejb3/mdb-delivery-group=mdb-group-name:write-attribute(name=active,value=false)
{"outcome" => "success"}
 
[standalone@localhost:9990 /] ./subsystem=ejb3/mdb-delivery-group=mdb-group-name:read-attribute(name=active)
{ "outcome" => "success", "result" => false }

To make it active again, write the attribute with a true value:

[standalone@localhost:9990 /] ./subsystem=ejb3/mdb-delivery-group=mdb-group-name:write-attribute(name=active,value=true)
{"outcome" => "success"}
 
[standalone@localhost:9990 /] ./subsystem=ejb3/mdb-delivery-group=mdb-group-name:read-attribute(name=active)
{ "outcome" => "success", "result" => true }
Using Delivery Groups

To mark that an MDB belongs to a delivery-group, declare so in the jboss-ejb3.xml file:

<?xml version="1.1" encoding="UTF-8"?>
 
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:d="urn:delivery-active:1.2"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
               version="3.1"
               impl-version="2.0">
    <assembly-descriptor>
        <d:delivery>
            <ejb-name>HelloWorldMDB</ejb-name>
            <d:group>mdb-delivery-group</d:group>
        </d:delivery>
    </assembly-descriptor>
</jboss:ejb-jar>

You can also use a wildcard to mark that all MDBs in your application belong to a delivery-group. In the following example, we add all MDBs in the application to group1, except for HelloWorldMDB, that is added to group2:

<?xml version="1.1" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:d="urn:delivery-active:1.2"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
               version="3.1"
               impl-version="2.0">
    <assembly-descriptor>
        <d:delivery>
            <ejb-name>*</ejb-name>
            <d:group>group1</d:group>
        </d:delivery>
        <d:delivery>
            <ejb-name>HelloWorldMDB</ejb-name>
            <d:group>group2</d:group>
        </d:delivery>
    </assembly-descriptor>
</jboss:ejb-jar>

Another option is to use org.jboss.ejb3.annotation.DeliveryGroup annotation on each MDB class belonging to a group:

@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
 @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
 @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/HELLOWORLDMDBQueue"),
 @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
 
@DeliveryGroup("group2")
 
public class HelloWorldMDB implements MessageListener {
    ...
}

A MDB can belong to more than one delivery group. See the following example:

<?xml version="1.1" encoding="UTF-8"?>
 
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:d="urn:delivery-active:1.2"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
               version="3.1"
               impl-version="2.0">
    <assembly-descriptor>
        <d:delivery>
            <ejb-name>*</ejb-name>
            <d:group>mdb-delivery-group1</d:group>
        </d:delivery>
        <d:delivery>
            <ejb-name>HelloWorldMDB</ejb-name>
            <d:group>mdb-delivery-group2</d:group>
            <d:group>mdb-delivery-group3</d:group>
        </d:delivery>
    </assembly-descriptor>
</jboss:ejb-jar>

In the example above, we use the wildcard to specify that every MDB in the ejb-jar will belong to mdb-delivery-group1. That means that, in order for delivery of messages to be active for those MDBs, mdb-delivery-group1 must be active.

In addition, the configuration above specifies that HelloWorldMDB belongs also to mdb-delivery-group2 and mdb-delivery-group3. So, delivery of messages to HelloWorldMDB will only be active when mdb-delivery-group1, mdb-delivery-group2, and mdb-delivery-group3 are all active.

The same could be specified using the @DeliveryGroup annotation:

@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
 @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
 @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/HELLOWORLDMDBQueue"),
 @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
 
@DeliveryGroup("mdb-delivery-group2")
@DeliveryGroup("mdb-delivery-group3")
 
public class HelloWorldMDB implements MessageListener {
    ...
}

Notice that all the delivery-groups used by an application must be installed in the WildFly server upon deployment, or the deployment will fail with a message stating that the delivery-group is missing.

9.11.3. Clustered Singleton Delivery

Delivery can be marked as singleton in a clustered environment. In this case, only one node in the cluster will have delivery active for that MDB, whereas in all other nodes, delivery will be inactive. This option can be used for applications that are deployed in all nodes of the cluster. Such applications will be active in all nodes of the cluster, except for the MDBs that are marked as clustered singleton. For those MDBs, only one cluster node will be processing their messages. In case that node stops, another node will have delivery activated, guaranteeing that there is always one node processing the messages. This node is what we call the MDB clustered singleton master node.

Notice that applications using clustered singleton delivery can only be deployed in clustered WildFly servers (i.e., servers that are using the ha configuration).

To mark delivery as clustered singleton, you can use the jboss-ejb3.xml or the @ClusteredSingleton annotation:

  • jboss-ejb3.xml:

<?xml version="1.1" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
               xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:c="urn:clustering:1.1"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
               version="3.1"
               impl-version="2.0">
    <assembly-descriptor>
        <c:clustering>
            <ejb-name>HelloWorldMDB</ejb-name>
            <c:clustered-singleton>true</c:clustered-singleton>
        </c:clustering>
    </assembly-descriptor>
</jboss:ejb-jar>

As in the previous jboss-ejb3.xml examples, a wildcard can be used in the place of the ejb-name to indicate that all MDBs in the application are singleton clustered.

  • annotation

You can use the org.jboss.ejb3.annotation.ClusteredSingleton annotation to mark an MDB as clustered singleton:

@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
 @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
 @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/HELLOWORLDMDBQueue"),
 @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge") })
 
@ClusteredSingleton
 
public class HelloWorldMDB implements MessageListener { ... }

9.11.4. Using Multiple MDB Delivery Control Mechanisms

The previous delivery control mechanisms can be used together in a single MDB. In this case, they work as a set of restrictions for delivery to be active in a MDB.

For example, if an MDB belongs to one or more delivery groups and is also a clustered singleton MDB, the delivery will be active for that MDB only if the delivery groups are active in the cluster node that was elected as the singleton master.

Also, if you use jboss-cli to stopDelivery on a MDB that belongs to one or more delivery groups, the MDB will stop receiving messages in case all groups were active. If one or more of the groups associated with the MDB was not active, the MDB will continue in the same, inactive state. But, once all groups become active, the MDB will still be prevented from receiving messages, unless a startDelivery operation is executed to revert the previously executed stopDelivery operation.

Invoking stopDelivery on an MDB that is marked as clustered singleton will work in a similar way: no visible effect if the current node is not the clustered singleton master; but it will stop delivery of messages for that MDB if the current node is the clustered singleton master. If the current node is not the master, but eventually becomes so, the delivery of messages will not be active for that MDB, unless a startDelivery operation is invoked.

In other words, when more than one delivery control mechanism is used in conjunction, they act as a set of restrictions that need all to be true in order for the MDB to receive messages:

  • * MDB belongs to one delivery-group + stop-delivery was invoked*: the delivery group needs to be active and the delivery needs to be restarted (via start-delivery) in order for that MDB to start receiving messages;

  • * MDB belongs to one delivery-group + MDB is clustered singleton*: the delivery group needs to be active and the current node needs to be the clustered singleton master node in order for that MDB to start receiving messages;

  • * MDB belongs to one delivery-group + MDB is clustered singleton + stop-delivery was invoked*: as above, the delivery-group has to be active, the current cluster node must be the clustered singleton master node, plus, start-delivery needs to be invoked on that MDB, only with these three factors being true the MDB will start receiving messages.

  • * MDB belongs to multiple delivery-groups + stop-delivery was invoked*: all the delivery groups need to be active and the delivery needs to be restarted (via start-delivery) in order for that MDB to start receiving messages;

  • * MDB belongs to multiple delivery-groups + MDB is clustered singleton*: all the delivery groups need to be active and the current node needs to be the clustered singleton master node in order for that MDB to start receiving messages;

  • * MDB belongs to multiple delivery-groups + MDB is clustered singleton + stop-delivery was invoked*: as above, all delivery-groups must be active, and current cluster node has to be the clustered singleton master node, plus, start-delivery needs to be invoked on that MDB, only with these three factors being true the MDB will start receiving messages.

9.12. Securing EJBs

The Jakarta EE spec specifies certain annotations (like @RolesAllowed, @PermitAll, @DenyAll) which can be used on EJB implementation classes and/or the business method implementations of the beans. Like with all other configurations, these security related configurations can also be done via the deployment descriptor (ejb-jar.xml). We won’t be going into the details of Jakarta EE specific annotations/deployment descriptor configurations in this chapter but instead will be looking at the vendor specific extensions to the security configurations.

9.12.1. Security Domain

The Jakarta EE spec doesn’t mandate a specific way to configure security domain for a bean. It leaves it to the vendor implementations to allow such configurations, the way they wish. In WildFly 21, the use of @org.jboss.ejb3.annotation.SecurityDomain annotation allows the developer to configure the security domain for a bean. Here’s an example:

import org.jboss.ejb3.annotation.SecurityDomain;
 
import javax.ejb.Stateless;
 
@Stateless
@SecurityDomain("other")
public class MyBean ...
{
   ...
}

The use of @SecurityDomain annotation lets the developer to point the container to the name of the security domain which is configured in the EJB3 subsystem in the standalone/domain configuration. The configuration of the security domain in the EJB3 subsystem is out of the scope of this chapter.

An alternate way of configuring a security domain, instead of using annotation, is to use jboss-ejb3.xml deployment descriptor. Here’s an example of how the configuration will look like:

<?xml version="1.0" encoding="UTF-8"?>
<jboss:jboss
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:s="urn:security:1.1"
         xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-spec-2_0.xsd"
         version="3.1" impl-version="2.0">
 
    <assembly-descriptor>
        <s:security>
   <!-- Even wildcard * is supported -->
            <ejb-name>MyBean</ejb-name>
            <!-- Name of the security domain which is configured in the EJB3 subsystem -->
            <s:security-domain>other</s:security-domain>
        </s:security>
    </assembly-descriptor>
</jboss:jboss>

As you can see we use the security-domain element to configure the security domain.

The jboss-ejb3.xml is expected to be placed in the .jar/META-INF folder of a .jar deployment or .war/WEB-INF folder of a .war deployment.

9.12.2. Absence of security domain configuration but presence of other

security metadata

Let’s consider the following example bean:

@Stateless
public class FooBean {
 
 @RolesAllowed("bar")
 public void doSomething() {
  ..
 }
...
}

As you can see the doSomething method is configured to be accessible for users with role "bar". However, the bean isn’t configured for any specific security domain. Prior to WildFly 21, the absence of an explicitly configured security domain on the bean would leave the bean unsecured, which meant that even if the doSomething method was configured with @RolesAllowed("bar") anyone even without the "bar" role could invoke on the bean.

In WildFly 21, the presence of any security metadata (like @RolesAllowed, @PermitAll, @DenyAll, @RunAs, @RunAsPrincipal) on the bean or any business method of the bean, makes the bean secure, even in the absence of an explicitly configured security domain. In such cases, the security domain name is default to "other". Users can explicitly configure an security domain for the bean if they want to using either the annotation or deployment descriptor approach explained earlier.

9.12.3. Access to methods without explicit security metadata, on a secured

bean

Consider this example bean:

@Stateless
public class FooBean {
 
 @RolesAllowed("bar")
 public void doSomething() {
  ..
 }
 
 
 public void helloWorld() {
  ...
    }
}

As you can see the doSomething method is marked for access for only users with role "bar". That enables security on the bean (with security domain defaulted to "other"). However, notice that the method helloWorld doesn’t have any specific security configurations.

In WildFly 21, such methods which have no explicit security configurations, in a secured bean, will be treated similar to a method with @DenyAll configuration. What that means is, no one is allowed access to the helloWorld method. This behaviour can be controlled via the jboss-ejb3.xml deployment descriptor at a per bean level or a per deployment level as follows:

<?xml version="1.0" encoding="UTF-8"?>
<jboss:jboss
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:s="urn:security:1.1"
        xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-spec-2_0.xsd"
        version="3.1" impl-version="2.0">
 
    <assembly-descriptor>
        <s:security>
   <!-- Even wildcard * is supported where * is equivalent to all EJBs in the deployment -->
            <ejb-name>FooBean</ejb-name>
            <s:missing-method-permissions-deny-access>false</s:missing-method-permissions-deny-access>
        </s:security>
    </assembly-descriptor>
</jboss:jboss>

Notice the use of <missing-method-permissions-deny-access> element. The value for this element can either be true or false. If this element isn’t configured then it is equivalent to a value of true i.e. no one is allowed access to methods, which have no explicit security configurations, on secured beans. Setting this to false allows access to such methods for all users i.e. the behaviour will be switched to be similar to @PermitAll.

This behaviour can also be configured at the EJB3 subsystem level so that it applies to all EJB3 deployments on the server, as follows:

<subsystem xmlns="urn:jboss:domain:ejb3:1.4">
...
            <default-missing-method-permissions-deny-access value="true"/>
...
</subsystem>

Again, the default-missing-method-permissions-deny-access element accepts either a true or false value. A value of true makes the behaviour similar to @DenyAll and a value of false makes it behave like @PermitAll

9.13. EJB Client Interceptors

9.13.1. Implementing Client Interceptors

The EJB client supports the notion of client side interceptors. These are interceptors that are run before an invocation is dispatched, and can modify various properties of the request before it is sent, as well as modifying parameters and the return value.

These interceptors are represented by the class org.jboss.ejb.client.EJBClientInterceptor, and are generally registered placing interceptor class names in META-INF/services/org.jboss.ejb.client.EJBClientInterceptor.

For more details about what can be modified refer to the EJB client JavaDoc.

9.13.2. Accessing invocation context data

It is possible for client interceptors to access data from the invocation context context data map used in the server invocation (i.e. InvocationContext.getContextData()). To access a specific key you must call org.jboss.ejb.client.EJBClientInvocationContext.addReturnedContextDataKey(String key) with the name of the key you are interested in. This method must be called from the handleInvocation method of the interceptor.

If there is data in the context map under this specific key then it will be send back to the client and will be available in the handleInvocationResult in the client invocations context data map.

9.14. EJB on Kubernetes

If the WildFly server is deployed on Kubernetes then there are several points that you need to bear in mind when you use EJBs.

When deploying on Kubernetes you should consider the use of the WildFly Operator. It manages the Kubernetes objects in WildFly friendly way. For example, it uses StatefulSet for the correct handling of EJB remoting and transaction recovery processing.

The rest of this chapter assumes the StatefulSet is used as the Kubernetes API object for managing the WildFly server.

The StatefulSet provides a guarantee of persistent storage and network hostname stability over the restarts of the pod.

These two guarantees are particularly important for the transaction manager which is a stateful component. The persistent storage over restarts is needed as the transaction log is usually stored at the file system. If the transaction manager creates a transaction log record it’s created only at the transaction log particular to the WildFly instance. The hostname stability is needed as the WildFly may be contacted via EJB remote call with transaction propagation. The WildFly has to be reachable under the same hostname even after pod restarts. As the transaction log is bound to the particular WildFly instance it may be finished only there.

9.14.1. EJB calls on Kubernetes

The EJB caller has two options on how to configure the remote call. It can be defined either as a remote outbound connection (see details at Admin Guide, section Outbound Connections) or you may use a direct InitialContext lookup in your code.

If you use either case then for the Kubernetes you need to adjust the configuration of the target node. For the target hostname, you need to use the DNS name of the very first pod managed by StatefulSet.

The StatefulSet guarantees depend on the ordering of the pods. The pods are named in the prescribed order. If you scale your application up to 3 replicas you may expect your pods will have names such as wildfly-server-0, wildfly-server-1, wildfly-server-2.

It’s expected a headless services to be used along with the StatefulSet. With the headless service, there is ensured the DNS hostname for the pod. If the application uses the WildFly Operator, a headless service will be created with a name such as wildfly-server-headless. Then the DNS name of the very first pod will be wildfly-server-0.wildfly-server-headless.

The use of the hosname wildfly-server-0.wildfly-server-headless guarantees that the EJB call may reach any WildFly instance connected to the cluster. It’s a bootstrap connection which is used to initialize the EJB client which gathers the structure of the WildFly cluster as the next step.

9.14.2. EJB configuration for Kubernetes

These are steps you need to process in order to run EJB remote calls. Some steps are related to the server configuration, the other ones on your application.

  • The clustering has to be set correctly, see the High Availability Guide, section of Kubernetes discovery.

  • All the socket-binding must define the client mapping for the DNS value mapped by StatefulSet headless service. For example if the application is named wildfly-server and the StatefulSet headless service is named wildfly-server-headless then the http socket binding has to be defined in the following way:

<socket-binding name="http" port="${jboss.http.port:8080}">
   <client-mapping destination-address="${jboss.node.name}.wildfly-server-headless"/>
</socket-binding>
  • A small workaround is needed for the remote EJB transaction recovery on Kubernetes (the issue could be tracked at WFCORE-4668). The WildFly application server has to be configured with property wildfly.config.url. The wildfly.config.url points to a XML configuration file. If we consider one being placed at $JBOSS_HOME/standalone/configuration/wildfly-config.xml then the property is setup as JAVA_OPTS="$JAVA_OPTS -Dwildfly.config.url=$JBOSS_HOME/standalone/configuration/wildfly-config.xml". The wildfly-config.xml defines the EJB recovery authentication to be used during transaction recovery for remote EJB calls. The target server has to configure a user that is permitted to receive the EJB remote calls. Such a user is then configured by standard means of security configuration. Let’s say there is configured a user on the target server. The user is created with script $JBOSS_HOME/bin/add-user.sh under the ApplicationRealm. Then the caller WildFly uses the configuration in wildfly-config.xml this way (you may copy the content below, but replace the >>PASTE_…​_HERE<< with user and password you configured):

<configuration>
  <authentication-client xmlns="urn:elytron:1.0">
  <authentication-rules>
          <rule use-configuration="jta">
              <match-abstract-type name="jta" authority="jboss"/>
      </rule>
      </authentication-rules>
      <authentication-configurations>
       <configuration name="jta">
               <sasl-mechanism-selector selector="DIGEST-MD5"/>
               <providers>
                   <use-service-loader />
           </providers>
       <set-user-name name=">>PASTE_USER_NAME_HERE<<"/>
           <credentials>
                    <clear-password password=">>PASTE_PASSWORD_HERE<<"/>
           </credentials>
               <set-mechanism-realm name="ApplicationRealm" />
           </configuration>
      </authentication-configurations>
  </authentication-client>
</configuration>

9.15. EJB Deployment Runtime Resources

Enterprise bean deployment exposes certain management runtime resources to help users inspect enterprise bean metadata and monitor invocation statistics. Bean metadata is configured in the application via deployment descriptor and annotations. Stateless, stateful, singleton session beans and message-driven beans support a common set of resources, and also resources specific to the bean type. For example, these are some of the common enterprise bean resources:

  • jndi-names

  • component-class-name

  • declared-roles

  • transaction-type

  • stateful-timeout

  • activation-config

Users can view these enterprise bean resources via WildFly CLI or Administration Console. The following sections provides sample CLI and Administration Console output for each enterprise bean type. For complete details, refer to WildFly Model Reference Documentation

9.15.1. Stateless Session Bean Runtime Resources

To view the management runtime resources for a deployed stateless session bean in CLI, run the following CLI command:

/deployment=<DEPLOYMENT-NAME>/subsystem=ejb3/stateless-session-bean=<BEAN-NAME>:read-resource(include-runtime)

The following is a sample output for a stateless session bean named ManagedStatelessBean in deployment ejb-management.jar:

/deployment=ejb-management.jar/subsystem=ejb3/stateless-session-bean=ManagedStatelessBean:read-resource(include-runtime)
{
    "outcome" => "success",
    "result" => {
        "async-methods" => ["void async(int, int)"],
        "business-local" => ["sample.ManagedStatelessBean"],
        "business-remote" => ["sample.BusinessInterface"],
        "component-class-name" => "sample.ManagedStatelessBean",
        "declared-roles" => [
            "Role3",
            "Role2",
            "Role1"
        ],
        "execution-time" => 160L,
        "invocations" => 3L,
        "jndi-names" => [
            "java:global/ejb-management/ManagedStatelessBean!sample.BusinessInterface",
            "java:module/ManagedStatelessBean!sample.BusinessInterface",
            "java:app/ejb-management/ManagedStatelessBean!sample.BusinessInterface",
            "java:global/ejb-management/ManagedStatelessBean!sample.ManagedStatelessBean",
            "java:module/ManagedStatelessBean!sample.ManagedStatelessBean",
            "java:app/ejb-management/ManagedStatelessBean!sample.ManagedStatelessBean"
        ],
        "methods" => {"doIt" => {
            "execution-time" => 160L,
            "invocations" => 3L,
            "wait-time" => 10L
        }},
        "peak-concurrent-invocations" => 1L,
        "pool-available-count" => 64,
        "pool-create-count" => 1,
        "pool-current-size" => 1,
        "pool-max-size" => 64,
        "pool-name" => "slsb-strict-max-pool",
        "pool-remove-count" => 0,
        "run-as-role" => "Role3",
        "security-domain" => "other",
        "timeout-method" => "public void sample.ManagedStatelessBean.timeout(javax.ejb.Timer)",
        "timers" => [{
            "time-remaining" => 4735224L,
            "next-timeout" => 1577768415000L,
            "calendar-timer" => true,
            "persistent" => false,
            "info" => "timer1",
            "schedule" => {
                "year" => "*",
                "month" => "*",
                "day-of-month" => "*",
                "day-of-week" => "*",
                "hour" => "0",
                "minute" => "0",
                "second" => "15",
                "timezone" => undefined,
                "start" => undefined,
                "end" => undefined
            }
        }],
        "transaction-type" => "CONTAINER",
        "wait-time" => 10L,
        "service" => {"timer-service" => undefined}
    }
}

To view it in WildFly Administration Console, go to the Management Model section of the target deployment. For example,

images/ejb/stateless-management-resource.png

9.15.2. Stateful Session Bean Runtime Resources

To view the management runtime resources for a deployed stateful session bean in CLI, run the following CLI command:

/deployment=<DEPLOYMENT-NAME>/subsystem=ejb3/stateful-session-bean=<BEAN-NAME>:read-resource(include-runtime)

The following is a sample output for a stateful session bean named ManagedStatefulBean2 in deployment ejb-management.jar:

/deployment=ejb-management.jar/subsystem=ejb3/stateful-session-bean=ManagedStatefulBean2:read-resource(include-runtime)
{
    "outcome" => "success",
    "result" => {
        "after-begin-method" => "private void sample.ManagedStatefulBean2.afterBegin()",
        "after-completion-method" => "private void sample.ManagedStatefulBean2.afterCompletion()",
        "async-methods" => ["void async(int, int)"],
        "before-completion-method" => "private void sample.ManagedStatefulBean2.beforeCompletion()",
        "business-local" => ["sample.ManagedStatefulBean2"],
        "business-remote" => ["sample.BusinessInterface"],
        "cache-size" => 0,
        "component-class-name" => "sample.ManagedStatefulBean2",
        "declared-roles" => [
            "Role3",
            "Role2",
            "Role1"
        ],
        "execution-time" => 163L,
        "invocations" => 4L,
        "jndi-names" => [
            "java:app/ejb-management/ManagedStatefulBean2!sample.BusinessInterface",
            "java:global/ejb-management/ManagedStatefulBean2!sample.BusinessInterface",
            "java:module/ManagedStatefulBean2!sample.BusinessInterface",
            "java:app/ejb-management/ManagedStatefulBean2!sample.ManagedStatefulBean2",
            "java:global/ejb-management/ManagedStatefulBean2!sample.ManagedStatefulBean2",
            "java:module/ManagedStatefulBean2!sample.ManagedStatefulBean2"
        ],
        "methods" => {
            "doIt" => {
                "execution-time" => 163L,
                "invocations" => 3L,
                "wait-time" => 3L
            },
            "remove" => {
                "execution-time" => 0L,
                "invocations" => 1L,
                "wait-time" => 1L
            }
        },
        "passivated-count" => 0,
        "passivation-capable" => false,
        "peak-concurrent-invocations" => 1L,
        "remove-methods" => [
            {
                "bean-method" => "void remove()",
                "retain-if-exception" => false
            },
            {
                "bean-method" => "void removeTrue()",
                "retain-if-exception" => true
            },
            {
                "bean-method" => "void removeFalse()",
                "retain-if-exception" => false
            }
        ],
        "run-as-role" => "Role3",
        "security-domain" => "other",
        "stateful-timeout" => "2 HOURS",
        "total-size" => 0,
        "transaction-type" => "BEAN",
        "wait-time" => 4L,
        "service" => undefined
    }
}

To view it in WildFly Administration Console, go to the Management Model section of the target deployment. For example,

images/ejb/stateful-management-resource.png

9.15.3. Singleton Bean Runtime Resources

To view the management runtime resources for a deployed singleton bean in CLI, run the following CLI command:

/deployment=<DEPLOYMENT-NAME>/subsystem=ejb3/singleton-bean=<BEAN-NAME>:read-resource(include-runtime)

The following is a sample output for a singleton bean named ManagedSingletonBean in deployment ejb-management.jar:

/deployment=ejb-management.jar/subsystem=ejb3/singleton-bean=ManagedSingletonBean:read-resource(include-runtime)
{
    "outcome" => "success",
    "result" => {
        "async-methods" => ["void async(int, int)"],
        "business-local" => ["sample.ManagedSingletonBean"],
        "business-remote" => ["sample.BusinessInterface"],
        "component-class-name" => "sample.ManagedSingletonBean",
        "concurrency-management-type" => undefined,
        "declared-roles" => [
            "Role3",
            "Role2",
            "Role1"
        ],
        "depends-on" => undefined,
        "execution-time" => 156L,
        "init-on-startup" => false,
        "invocations" => 3L,
        "jndi-names" => [
            "java:module/ManagedSingletonBean!sample.ManagedSingletonBean",
            "java:global/ejb-management/ManagedSingletonBean!sample.ManagedSingletonBean",
            "java:app/ejb-management/ManagedSingletonBean!sample.ManagedSingletonBean",
            "java:app/ejb-management/ManagedSingletonBean!sample.BusinessInterface",
            "java:global/ejb-management/ManagedSingletonBean!sample.BusinessInterface",
            "java:module/ManagedSingletonBean!sample.BusinessInterface"
        ],
        "methods" => {"doIt" => {
            "execution-time" => 156L,
            "invocations" => 3L,
            "wait-time" => 0L
        }},
        "peak-concurrent-invocations" => 1L,
        "run-as-role" => "Role3",
        "security-domain" => "other",
        "timeout-method" => "public void sample.ManagedSingletonBean.timeout(javax.ejb.Timer)",
        "timers" => [{
            "time-remaining" => 4304279L,
            "next-timeout" => 1577768415000L,
            "calendar-timer" => true,
            "persistent" => false,
            "info" => "timer1",
            "schedule" => {
                "year" => "*",
                "month" => "*",
                "day-of-month" => "*",
                "day-of-week" => "*",
                "hour" => "0",
                "minute" => "0",
                "second" => "15",
                "timezone" => undefined,
                "start" => undefined,
                "end" => undefined
            }
        }],
        "transaction-type" => "CONTAINER",
        "wait-time" => 0L,
        "service" => {"timer-service" => undefined}
    }
}

To view it in WildFly Administration Console, go to the Management Model section of the target deployment. For example,

images/ejb/singleton-management-resource.png

9.15.4. Message-driven Bean Runtime Resources

To view the management runtime resources for a deployed message-driven bean in CLI, run the following CLI command:

/deployment=<DEPLOYMENT-NAME>/subsystem=ejb3/message-driven-bean=<BEAN-NAME>:read-resource(include-runtime)

The following is a sample output for a message-driven bean named ManagedMDB in deployment ejb-management.jar:

/deployment=ejb-management.jar/subsystem=ejb3/message-driven-bean=ManagedMDB:read-resource(include-runtime)
{
    "outcome" => "success",
    "result" => {
        "activation-config" => [
            ("destinationType" => "javax.jms.Queue"),
            ("destination" => "java:/queue/ManagedMDB-queue")
        ],
        "component-class-name" => "sample.ManagedMDB",
        "declared-roles" => [
            "Role3",
            "Role2",
            "Role1"
        ],
        "delivery-active" => true,
        "execution-time" => 0L,
        "invocations" => 0L,
        "message-destination-link" => undefined,
        "message-destination-type" => undefined,
        "messaging-type" => "javax.jms.MessageListener",
        "methods" => {},
        "peak-concurrent-invocations" => 0L,
        "pool-available-count" => 16,
        "pool-create-count" => 0,
        "pool-current-size" => 0,
        "pool-max-size" => 16,
        "pool-name" => "mdb-strict-max-pool",
        "pool-remove-count" => 0,
        "run-as-role" => "Role3",
        "security-domain" => "other",
        "timeout-method" => "public void sample.ManagedMDB.timeout(javax.ejb.Timer)",
        "timers" => [{
            "time-remaining" => 4213581L,
            "next-timeout" => 1577768415000L,
            "calendar-timer" => true,
            "persistent" => false,
            "info" => "timer1",
            "schedule" => {
                "year" => "*",
                "month" => "*",
                "day-of-month" => "*",
                "day-of-week" => "*",
                "hour" => "0",
                "minute" => "0",
                "second" => "15",
                "timezone" => undefined,
                "start" => undefined,
                "end" => undefined
            }
        }],
        "transaction-type" => "CONTAINER",
        "wait-time" => 0L,
        "service" => {"timer-service" => undefined}
    }
}

To view it in WildFly Administration Console, go to the Management Model section of the target deployment. For example,

images/ejb/mdb-management-resource.png

10. JPA Reference Guide

10.1. Introduction

The WildFly JPA subsystem implements the JPA 2.2 container-managed requirements. Deploys the persistence unit definitions, the persistence unit/context annotations and persistence unit/context references in the deployment descriptor. JPA Applications use the Hibernate (version 5.3) persistence provider, which is included with WildFly. The JPA subsystem uses the standard SPI (javax.persistence.spi.PersistenceProvider) to access the Hibernate persistence provider and some additional extensions as well.

During application deployment, JPA use is detected (e.g. persistence.xml or @PersistenceContext/Unit annotations) and injects Hibernate dependencies into the application deployment. This makes it easy to deploy JPA applications.

In the remainder of this documentation, "entity manager" refers to an instance of the javax.persistence.EntityManager class. Javadoc for the JPA interfacesand JPA 2.2 specification.

The index of the Hibernate documentation is at http://hibernate.org/orm/documentation/5.3/

10.2. Update your Persistence.xml for Hibernate

The persistence provider class name in Hibernate is org.hibernate.jpa.HibernatePersistenceProvider.

Your persistence.xml can specify:

<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

Or remove the persistence provider class name from your persistence.xml (so the default provider will be used).

10.3. Entity manager

The entity manager (javax.persistence.EntityManager class) is similar to the Hibernate Session class; applications use it to create/read/update/delete data (and related operations). Applications can use application-managed or container-managed entity managers. Keep in mind that the entity manager is not thread safe, don’t share the same entity manager instance with multiple threads.

Internally, the entity manager, has a persistence context for managing entities. You can think of the persistence context as being closely associated with the entity manager.

10.4. Container-managed entity manager

When you inject a container-managed entity managers into an application variable, it is treated like an (EE container controlled) Java proxy object, that will be associated with an underlying EntityManager instance, for each started JTA transaction and is flushed/closed when the JTA transaction commits. Such that when your application code invokes EntityManager.anyMethod(), the current JTA transaction is searched (using persistence unit name as key) for the underlying EntityManager instance, if not found, a new EntityManager instance is created and associated with the current JTA transaction, to be reused for the next EntityManager invocation. Use the @PersistenceContext annotation, to inject a container-managed entity manager into a javax.persistence.EntityManager variable.

10.5. Application-managed entity manager

An application-managed entity manager is kept around until the application closes it. The scope of the application-managed entity manager is from when the application creates it and lasts until the application closes it. Use the @PersistenceUnit annotation, to inject a persistence unit into a javax.persistence.EntityManagerFactory variable. The EntityManagerFactory can return an application-managed entity manager.

10.6. Persistence Context

The JPA persistence context contains the entities managed by the entity manager (via the JPA persistence provider). The underlying entity manager maintains the persistence context. The persistence context acts like a first level (transactional) cache for interacting with the datasource. Loaded entities are placed into the persistence context before being returned to the application. Entities changes are also placed into the persistence context (to be saved in the database when the transaction commits).

10.7. Transaction-scoped Persistence Context

The transaction-scoped persistence context coordinates with the (active) JTA transaction. When the transaction commits, the persistence context is flushed to the datasource (entity objects are detached but may still be referenced by application code). All entity changes that are expected to be saved to the datasource, must be made during a transaction. Entities read outside of a transaction will be detached when the entity manager invocation completes. Example transaction-scoped persistence context is below.

@Stateful  // will use container managed transactions
public class CustomerManager {
  @PersistenceContext(unitName = "customerPU") // default type is PersistenceContextType.TRANSACTION
  EntityManager em;
  public customer createCustomer(String name, String address) {
    Customer customer = new Customer(name, address);
    em.persist(customer);  // persist new Customer when JTA transaction completes (when method ends).
                           // internally:
                           //    1. Look for existing "customerPU" persistence context in active JTA transaction and use if found.
                           //    2. Else create new "customerPU" persistence context (e.g. instance of org.hibernate.ejb.HibernatePersistence)
                           //       and put in current active JTA transaction.
    return customer;       // return Customer entity (will be detached from the persistence context when caller gets control)
  }  // Transaction.commit will be called, Customer entity will be persisted to the database and "customerPU" persistence context closed

10.8. Extended Persistence Context

The (ee container managed) extended persistence context can span multiple transactions and allows data modifications to be queued up (without an active JTA transaction), to be applied during completion of next JTA transaction. The Container-managed extended persistence context can only be injected into a stateful session bean.

@PersistenceContext(type = PersistenceContextType.EXTENDED, unitName = "inventoryPU")
EntityManager em;

10.8.1. Extended Persistence Context Inheritance

JPA 2.2 specification section 7.6.3.1
 
If a stateful session bean instantiates a stateful session bean (executing in the same EJB container instance) which also has such an extended persistence context with the same synchronization type, the extended persistence context of the first stateful session bean is inherited by the second stateful session bean and bound to it, and this rule recursively applies independently of whether transactions are active or not at the point of the creation of the stateful session beans. If the stateful session beans differ in declared synchronization type, the EJBException is thrown by the container.  If the persistence context has been inherited by any stateful session beans, the container does not close the persistence context until all such stateful session beans have been removed or otherwise destroyed.

By default, the current stateful session bean being created, will ( deeply) inherit the extended persistence context from any stateful session bean executing in the current Java thread. The deep inheritance of extended persistence context includes walking multiple levels up the stateful bean call stack (inheriting from parent beans). The deep inheritance of extended persistence context includes sibling beans. For example, parentA references child beans beanBwithXPC & beanCwithXPC. Even though parentA doesn’t have an extended persistence context, beanBwithXPC & beanCwithXPC will share the same extended persistence context.

Some other EE application servers, use shallow inheritance, where stateful session bean only inherit from the parent stateful session bean (if there is a parent bean). Sibling beans do not share the same extended persistence context unless their (common) parent bean also has the same extended persistence context.

Applications can include a (top-level) jboss-all.xml deployment descriptor that specifies either the (default) DEEP extended persistence context inheritance or SHALLOW.

The WF/docs/schema/jboss-jpa_1_0.xsd describes the jboss-jpa deployment descriptor that may be included in the jboss-all.xml. Below is an example of using SHALLOW extended persistence context inheritance:

<jboss>
<jboss-jpa xmlns="http://www.jboss.com/xml/ns/javaee">
<extended-persistence inheritance="SHALLOW"/>
</jboss-jpa>
</jboss>

Below is an example of using DEEP extended persistence inheritance:

<jboss>
<jboss-jpa xmlns="http://www.jboss.com/xml/ns/javaee">
<extended-persistence inheritance="DEEP"/>
</jboss-jpa>
</jboss>

The AS console/cli can change the default extended persistence context setting (DEEP or SHALLOW). The following cli commands will read the current JPA settings and enable SHALLOW extended persistence context inheritance for applications that do not include the jboss-jpa deployment descriptor:

/jboss-cli.sh

cd subsystem=jpa
:read-resource
:write-attribute(name=default-extended-persistence-inheritance,value="SHALLOW")

10.9. Entities

JPA allows use of your (pojo) plain old Java class to represent a database table row.

@PersistenceContext EntityManager em;
Integer bomPk = getIndexKeyValue();
BillOfMaterials bom = em.find(BillOfMaterials.class, bomPk); // read existing table row into BillOfMaterials class
 
BillOfMaterials createdBom = new BillOfMaterials("...");     // create new entity
em.persist(createdBom);  // createdBom is now managed and will be saved to database when the current JTA transaction completes

The entity lifecycle is managed by the underlying persistence provider.

  • New (transient): an entity is new if it has just been instantiated using the new operator, and it is not associated with a persistence context. It has no persistent representation in the database and no identifier value has been assigned.

  • Managed (persistent): a managed entity instance is an instance with a persistent identity that is currently associated with a persistence context.

  • Detached: the entity instance is an instance with a persistent identity that is no longer associated with a persistence context, usually because the persistence context was closed or the instance was evicted from the context.

  • Removed: a removed entity instance is an instance with a persistent identity, associated with a persistence context, but scheduled for removal from the database.

10.10. Deployment

The persistence.xml contains the persistence unit configuration (e.g. datasource name) and as described in the JPA 2.0 spec (section 8.2), the jar file or directory whose META-INF directory contains the persistence.xml file is termed the root of the persistence unit. In Java EE environments, the root of a persistence unit must be one of the following (quoted directly from the JPA 2.0 specification):

"

  • an EJB-JAR file

  • the WEB-INF/classes directory of a WAR file

  • a jar file in the WEB-INF/lib directory of a WAR file

  • a jar file in the EAR library directory

  • an application client jar file

The persistence.xml can specify either a JTA datasource or a non-JTA datasource. The JTA datasource is expected to be used within the EE environment (even when reading data without an active transaction). If a datasource is not specified, the default-datasource will instead be used (must be configured).

Java Persistence 1.0 supported use of a jar file in the root of the EAR as the root of a persistence unit. This use is no longer supported. Portable applications should use the EAR library directory for this case instead.

"

Question: Can you have a EAR/META-INF/persistence.xml?

Answer: No, the above may deploy but it could include other archives also in the EAR, so you may have deployment issues for other reasons. Better to put the persistence.xml in an EAR/lib/somePuJar.jar.

10.11. Troubleshooting

The org.jboss.as.jpa logging can be enabled to get the following information:

  • INFO - when persistence.xml has been parsed, starting of persistence unit service (per deployed persistence.xml), stopping of persistence unit service

  • DEBUG - informs about entity managers being injected, creating/reusing transaction scoped entity manager for active transaction

  • TRACE - shows how long each entity manager operation took in milliseconds, application searches for a persistence unit, parsing of persistence.xml

To enable TRACE, open the as/standalone/configuration/standalone.xml (or as/domain/configuration/domain.xml) file. Search for <subsystem xmlns="urn:jboss:domain:logging:1.0"> and add the org.jboss.as.jpa category. You need to change the console-handler level from INFO to TRACE.

<subsystem xmlns="urn:jboss:domain:logging:1.0">
     <console-handler name="CONSOLE">
      <level name="TRACE" />
      ...
     </console-handler>
 
     </periodic-rotating-file-handler>
     <logger category="com.arjuna">
        <level name="WARN" />
     </logger>
 
     <logger category="org.jboss.as.jpa">
        <level name="TRACE" />
     </logger>
 
     <logger category="org.apache.tomcat.util.modeler">
        <level name="WARN" />
     </logger>
     ...

To see what is going on at the JDBC level, enable jboss.jdbc.spy TRACE and add spy="true" to the datasource.

<datasource jndi-name="java:jboss/datasources/..." pool-name="..." enabled="true" spy="true">
<logger category="jboss.jdbc.spy">
  <level name="TRACE"/>
</logger>

To troubleshoot issues with the Hibernate second level cache, try enabling trace for org.hibernate.SQL + org.hibernate.cache.infinispan
org.infinispan:

<subsystem xmlns="urn:jboss:domain:logging:1.0">
     <console-handler name="CONSOLE">
      <level name="TRACE" />
      ...
     </console-handler>
 
     </periodic-rotating-file-handler>
     <logger category="com.arjuna">
        <level name="WARN" />
     </logger>
 
     <logger category="org.hibernate.SQL">
        <level name="TRACE" />
     </logger>
 
     <logger category="org.hibernate">
        <level name="TRACE" />
     </logger>
      <logger category="org.infinispan">
        <level name="TRACE" />
     </logger>
 
     <logger category="org.apache.tomcat.util.modeler">
        <level name="WARN" />
     </logger>
     ...

10.12. Using the Infinispan second level cache

To enable the second level cache with Hibernate, just set the hibernate.cache.use_second_level_cache property to true or set shared-cache-mode to one of the following:

  • ENABLE_SELECTIVE

  • DISABLE_SELECTIVE

  • ALL

Infinispan is the cache provider for JPA applications, so you don’t need to specify anything in addition. The Infinispan version that is included in WildFly is expected to work with the Hibernate version that is included with WildFly. Example persistence.xml settings:

<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="2lc_example_pu">
   <description>example of enabling the second level cache.</description>
   <jta-data-source>java:jboss/datasources/mydatasource</jta-data-source>
   <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
</persistence-unit>
</persistence>

Here is an example of enabling the second level cache for a Hibernate native API hibernate.cfg.xml file:

<property name="hibernate.cache.region.factory_class" value="org.infinispan.hibernate.cache.v53.InfinispanRegionFactory"/>
<property name="hibernate.cache.infinispan.shared" value="false"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>

The Hibernate native API application will also need a MANIFEST.MF:

Dependencies: org.infinispan,org.hibernate

Infinispan Hibernate/JPA second level cache provider documentation contains advanced configuration information but you should bear in mind that when Hibernate runs within WildFly 21, some of those configuration options, such as region factory, are not needed. Moreover, the application server providers you with option of selecting a different cache container for Infinispan via hibernate.cache.infinispan.container persistence property. To reiterate, this property is not mandatory and a default container is already deployed for by the application server to host the second level cache.

Here is an example of what the Hibernate cache settings may currently be in your standalone.xml:

 <cache-container name="hibernate" module="org.infinispan.hibernate-cache">
     <local-cache name="entity">
         <transaction mode="NON_XA"/>
         <object-memory size="10000"/>
         <expiration max-idle="100000"/>
     </local-cache>
     <local-cache name="local-query">
         <object-memory size="10000"/>
         <expiration max-idle="100000"/>
     </local-cache>
     <local-cache name="timestamps"/>
 </cache-container>

Below is an example of customizing the "entity", "immutable-entity", "local-query", "pending-puts", "timestamps" cache configuration may look like:

 <cache-container name="hibernate" module="org.infinispan.hibernate-cache" default-cache="immutable-entity">
    <local-cache name="entity">
        <transaction mode="NONE"/>
        <eviction max-entries="-1"/>
        <expiration max-idle="120000"/>
    </local-cache>
    <local-cache name="immutable-entity">
        <transaction mode="NONE"/>
        <eviction max-entries="-1"/>
        <expiration max-idle="120000"/>
    </local-cache>
    <local-cache name="local-query">
        <eviction max-entries="-1"/>
        <expiration max-idle="300000"/>
    </local-cache>
    <local-cache name="pending-puts">
        <transaction mode="NONE"/>
        <eviction strategy="NONE"/>
        <expiration max-idle="60000"/>
    </local-cache>
    <local-cache name="timestamps">
        <transaction mode="NONE"/>
        <eviction strategy="NONE"/>
    </local-cache>
</cache-container>

Persistence.xml to use the above custom settings:

<properties>
    <property name="hibernate.cache.use_second_level_cache" value="true"/>
    <property name="hibernate.cache.use_query_cache" value="true"/>
    <property name="hibernate.cache.infinispan.immutable-entity.cfg" value="immutable-entity"/>
    <property name="hibernate.cache.infinispan.timestamps.cfg" value="timestamps"/>
    <property name="hibernate.cache.infinispan.pending-puts.cfg" value="pending-puts"/>
</properties>

WildFly includes Hibernate Search. If you want to use the bundled version of Hibernate Search, which requires to use the default Hibernate ORM persistence provider, this will be automatically enabled. Having this enabled means that, provided your application includes any entity which is annotated with org.hibernate.search.annotations.Indexed, the module org.hibernate.search.orm:main will be made available to your deployment; this will also include the required version of Apache Lucene.

If you do not want this module to be exposed to your deployment, set the persistence property wildfly.jpa.hibernate.search.module to either none to not automatically inject any Hibernate Search module, or to any other module identifier to inject a different module. For example you could set wildfly.jpa.hibernate.search.module=org.hibernate.search.orm:5.11.0.Alpha1 to use the experimental version 5.11.0.Alpha1 instead of the provided module; in this case you’ll have to download and add the custom modules to the application server as other versions are not included. When setting wildfly.jpa.hibernate.search.module=none you might also opt to include Hibernate Search and its dependencies within your application but we highly recommend the modules approach.

10.14. Packaging the Hibernate JPA persistence provider with your application

WildFly allows the packaging of Hibernate persistence provider jars with the application. The JPA deployer will detect the presence of a persistence provider in the application and jboss.as.jpa.providerModule needs to be set to application.

<?xml version="1.0" encoding="UTF-8"?> +
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="1.0"> +
<persistence-unit name="myOwnORMVersion_pu"> +
<description>Hibernate Persistence Unit.</description> +
<jta-data-source>java:jboss/datasources/PlannerDS</jta-data-source> +
<properties> +
<property name="jboss.as.jpa.providerModule" value="application" /> +
</properties> +
</persistence-unit> +
</persistence>

10.15. Migrating from OpenJPA

You need to copy the OpenJPA jar (e.g. openjpa-all.jar) into the WildFly modules/org/apache/openjpa/main folder and update modules/org/apache/openjpa/main/module.xml to include the same jar file name that you copied in. This will help you get your application that depends on OpenJPA, to deploy on WildFly.

 <module xmlns="urn:jboss:module:1.1" name="org.apache.openjpa">
    <resources>
        <resource-root path="jipijapa-openjpa-1.0.1.Final.jar"/>
        <resource-root path="openjpa-all.jar">
           <filter>
              <exclude path="javax/**" />
           </filter>
        </resource-root>
    </resources>
 
    <dependencies>
        <module name="javax.annotation.api"/>
        <module name="javax.enterprise.api"/>
        <module name="javax.persistence.api"/>
        <module name="javax.transaction.api"/>
        <module name="javax.validation.api"/>
        <module name="javax.xml.bind.api"/>
        <module name="org.jboss.as.jpa.spi"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.jandex"/>
    </dependencies>
</module>

You need to copy the EclipseLink jar (e.g. eclipselink-2.6.0.jar or eclipselink.jar as in the example below) into the WildFly modules/org/eclipse/persistence/main folder and update modules/org/eclipse/persistence/main/module.xml to include the EclipseLink jar (take care to use the jar name that you copied in). If you happen to leave the EclipseLink version number in the jar name, the module.xml should reflect that. This will help you get your application that depends on EclipseLink, to deploy on WildFly.

 <module xmlns="urn:jboss:module:1.1" name="org.eclipse.persistence">
    <resources>
        <resource-root path="jipijapa-eclipselink-10.0.0.Final.jar"/>
        <resource-root path="eclipselink.jar">           <filter>
              <exclude path="javax/**" />
           </filter>
        </resource-root>
    </resources>
 
    <dependencies>
        <module name="asm.asm"/>
        <module name="javax.api"/>
        <module name="javax.annotation.api"/>
        <module name="javax.enterprise.api"/>
        <module name="javax.persistence.api"/>
        <module name="javax.transaction.api"/>
        <module name="javax.validation.api"/>
        <module name="javax.xml.bind.api"/>
        <module name="org.antlr"/>
        <module name="org.apache.commons.collections"/>
        <module name="org.dom4j"/>
        <module name="org.jboss.as.jpa.spi"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.vfs"/>
    </dependencies>
</module>

You should then be able to deploy applications with persistence.xml that include;

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

10.17. Native Hibernate use

Applications that use the Hibernate API directly, can be referred to as native Hibernate applications. Native Hibernate applications, can choose to use the Hibernate jars included with WildFly or they can package their own copy of the Hibernate jars. Applications that utilize JPA will automatically have the Hibernate classes injected onto the application deployment classpath. Meaning that JPA applications, should expect to use the Hibernate jars included in WildFly.

Example MANIFEST.MF entry to add dependency for Hibernate native applications:

Manifest-Version: 1.0
...
Dependencies: org.hibernate

10.18. Injection of Hibernate Session and SessionFactory

You can inject a org.hibernate.Session and org.hibernate.SessionFactory directly, just as you can do with EntityManagers and EntityManagerFactorys.

import org.hibernate.Session;
import org.hibernate.SessionFactory;
@Stateful public class MyStatefulBean ... {
   @PersistenceContext(unitName="crm") Session session1;
   @PersistenceContext(unitName="crm2", type=EXTENDED) Session extendedpc;
   @PersistenceUnit(unitName="crm") SessionFactory factory;
}

10.19. Hibernate ORM 5.1 native API bytecode transformer

The Hibernate ORM 5.1 native API bytecode transformer, can rewrite application bytecode, to handle APIs that have changed between Hibernate ORM 5.1.x + 5.3.x. For applications that use the Hibernate ORM 5.1 native APIs, you may either rewrite them for Hibernate ORM 5.3 or use the transformer, to rewrite your application byte-code during application deployment (only the in-memory copy of your application is rewritten). If your application is only using the JPA specification APIs, you do not need to transform your application.

For details on the Hibernate 5.3 native API changes, review the ORM 5.2 + ORM 5.3 migration guides.

The Hibernate ORM 5.1 transformer is already deprecated, meaning it could be removed in the next release. For this reason, we made it easy to enable the transformer via either a system property or jboss-deployment-structure change.

<jboss-deployment-structure>
    <deployment>
        <transformers>
            <transformer class="org.jboss.as.hibernate.Hibernate51CompatibilityTransformer"/>
        </transformers>
        <dependencies>
            <module name="org.hibernate" export="true" />
        </dependencies>
    </deployment>
    <sub-deployment name="main.war">
        <transformers>
            <transformer class="org.jboss.as.hibernate.Hibernate51CompatibilityTransformer"/>
        </transformers>
    </sub-deployment>
</jboss-deployment-structure>
If enabled, the following transformations will be made to application classes compiled with Hibernate 5.1:

TRACE + DEBUG level logging can be enabled via the "org.jboss.as.hibernate.transformer" logger category. Example output:

Hibernate51CompatibilityTransformer transformed application classes in 'deployment.org.jboss.as.test.compat.jpa.hibernate.transformer.VerifyHibernate51CompatibilityPropertyAndJDSEnabledTransformerTestCase.ear', class 'org/jboss/as/test/compat/jpa/hibernate/transformer/BitSetType' is calling method org/hibernate/type/AbstractSingleColumnStandardBasicType.replace, which must be changed to use SharedSessionContractImplementor as parameter.
System Property Purpose

Default

Hibernate51CompatibilityTransformer

if true, the transformer will transform ORM 5.1.x native calls to, ORM 5.3 native calls, in every application deployment

false

Hibernate51CompatibilityTransformer.disableAmbiguousChanges

disable transformation of org.hibernate.Query.setFirstResult(int) + org.hibernate.Query.setMaxResults(int), since these methods are in both Hibernate ORM 5.1.x + 5.3.x

false

Hibernate51CompatibilityTransformer.showTransformedClassFolder

specifies the folder name to create bytecode level description of applications run through the transformer. The specified folder must already exist. If the transformer actually makes a change to your application, a (boolean) class variable will be added "$org_jboss_as_hibernate_Hibernate51CompatibilityTransformer_transformed$", that ensures that the application is only transformed once

disabled

10.20. Hibernate properties

WildFly automatically sets the following Hibernate properties (if not already set in persistence unit definition):

Property Purpose

hibernate.id.new_generator_mappings =true

New applications should let this default to true, older applications with existing data might need to set to false (see note below). It really depends on whether your application uses the @GeneratedValue(AUTO) which will generates new key values for newly created entities. The application can override this value (in the persistence.xml).

hibernate.transaction.jta.platform= instance of org.hibernate.service.jta.platform.spi.JtaPlatform interface

The transaction manager, user transaction and transaction synchronization registry is passed into Hibernate via this class.

hibernate.ejb.resource_scanner = instance of org.hibernate.ejb.packaging.Scanner interface

Instance of entity scanning class is passed in that knows how to use the AS annotation indexer (for faster deployment).

hibernate.transaction.manager_lookup_class

This property is removed if found in the persistence.xml (could conflict with JtaPlatform)

hibernate.session_factory_name = qualified persistence unit name

Is set to the application name + persistence unit name (application can specify a different value but it needs to be unique across all application deployments on the AS instance).

hibernate.session_factory_name_is_jndi = false

only set if the application didn’t specify a value for hibernate.session_factory_name.

hibernate.ejb.entitymanager_factory_name = qualified persistence unit name

Is set to the application name + persistence unit name (application can specify a different value but it needs to be unique across all application deployments on the AS instance).

hibernate.query.jpaql_strict_compliance=true

 

hibernate.auto_quote_keyword=false

 

hibernate.implicit_naming_strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl

hibernate.model.generator_name_as_sequence_name=true

hibernate.jpa.compliance.transaction=true

hibernate.jpa.compliance.closed=true

hibernate.jpa.compliance.query=true

hibernate.jpa.compliance.list=true

hibernate.jpa.compliance.caching=true

hibernate.jpa.compliance.proxy=true

hibernate.enable_lazy_load_no_trans=false

hibernate.jpa.compliance.global_id_generators=true

hibernate.search.index_uninverting_allowed=true

 

if hibernate.id.new_generator_mappings is true:

  • @GeneratedValue(AUTO) maps to org.hibernate.id.enhanced.SequenceStyleGenerator

  • @GeneratedValue(TABLE) maps to org.hibernate.id.enhanced.TableGenerator

  • @GeneratedValue(SEQUENCE) maps to org.hibernate.id.enhanced.SequenceStyleGenerator

if hibernate.id.new_generator_mappings is false:

  • @GeneratedValue(AUTO) maps to Hibernate "native"

  • @GeneratedValue(TABLE) maps to org.hibernate.id.MultipleHiLoPerTableGenerator

  • @GeneratedValue(SEQUENCE) to Hibernate "seqhilo"

10.21. Persistence unit properties

The following properties are supported in the persistence unit definition (in the persistence.xml file):

Property Purpose

jboss.as.jpa.providerModule

name of the persistence provider module (default is org.hibernate). Should be application, if a persistence provider is packaged with the application. See note below about some module names that are built in (based on the provider).

jboss.as.jpa.adapterModule

name of the integration classes that help WildFly to work with the persistence provider.

jboss.as.jpa.adapterClass

class name of the integration adapter.

jboss.as.jpa.managed

set to false to disable container managed JPA access to the persistence unit. The default is true, which enables container managed JPA access to the persistence unit. This is typically set to false for Spring applications.

jboss.as.jpa.classtransformer

set to false to disable class transformers for the persistence unit. Set to true, to allow entity class enhancing/rewriting.

wildfly.jpa.default-unit

set to true to choose the default persistence unit in an application. This is useful if you inject a persistence context without specifying the unitName (@PersistenceContext EntityManager em) but have multiple persistence units specified in your persistence.xml.

wildfly.jpa.twophasebootstrap

persistence providers (like Hibernate ORM 4.3+ via EntityManagerFactoryBuilder), allow a two phase persistence unit bootstrap, which improves JPA integration with CDI. Setting the wildfly.jpa.twophasebootstrap hint to false, disables the two phase bootstrap (for the persistence unit that contains the hint).

wildfly.jpa.applicationdatasource

set to true when using an application defined DataSource or resource reference to a global DataSource.

wildfly.jpa.allowdefaultdatasourceuse

set to false to prevent persistence unit from using the default data source. Defaults to true. This is only important for persistence units that do not specify a datasource.

jboss.as.jpa.deferdetach

Controls whether a transaction scoped persistence context used in a non-JTA transaction thread will detach loaded entities after each EntityManager invocation or when the persistence context is closed (e.g. business method ends). Defaults to false (entities are cleared after EntityManager invocation) and if set to true, the detach is deferred until the context is closed.

wildfly.jpa.skipquerydetach

Controls whether a transaction scoped persistence context used in a non-JTA transaction thread will detach Query results immediately. Defaults to false (Query results are detached immediately) and if set to true, the detach is deferred until the persistence context is closed.

wildfly.jpa.hibernate.search.module

Controls which version of Hibernate Search to include on classpath. Only makes sense when using Hibernate as JPA implementation. The default is auto; other valid values are none or a full module identifier to use an alternative version.

jboss.as.jpa.scopedname

Specify the qualified (application scoped) persistence unit name to be used. By default, this is internally set to the application name + persistence unit name. The hibernate.cache.region_prefix will default to whatever you set jboss.as.jpa.scopedname to. Make sure you set the jboss.as.jpa.scopedname value to a value not already in use by other applications deployed on the same application server instance.

wildfly.jpa.allowjoinedunsync

If set to true, allows an SynchronizationType.UNSYNCHRONIZED persistence context that has been joined to the active JTA transaction, to be propagated into a SynchronizationType.SYNCHRONIZED persistence context. Otherwise, an IllegalStateException exception would of been thrown that complains that an unsychronized persistence context cannot be propagated into a synchronized persistence context. Defaults to false.

wildfly.jpa.skipmixedsynctypechecking

Set to true to disable the throwing of an IllegalStateException exception when propagating an SynchronizationType.UNSYNCHRONIZED persistence context into a SynchronizationType.SYNCHRONIZED persistence context. This is a workaround intended to allow applications that used to incorrectly not get IllegalStateException exception with extended persistence contexts, to avoid the IllegalStateException, so they don’t have to change their application right away (for compatibility purposes). This hint may be deprecated in a future release. See WFLY-7108 for more details. Defaults to false.

wildfly.jpa.regionfactory

Only applies to Hibernate ORM 5.3+, set to false to disable automatic use of Infinispan as second level cache (hibernate.cache.region.factory_class).

wildfly.jpa.jtaplatform

Only applies to Hibernate ORM 5.3+, set to false to disable automatic configuring of the JTA integration platform (hibernate.transaction.jta.platform).

10.22. Determine the persistence provider module

As mentioned above, if the jboss.as.jpa.providerModule property is not specified, the provider module name is determined by the provider name specified in the persistence.xml. The mapping is:

Provider Name Module name

blank

org.hibernate

org.hibernate.jpa.HibernatePersistenceProvider

org.hibernate

org.hibernate.ogm.jpa.HibernateOgmPersistence

org.hibernate.ogm

oracle.toplink.essentials.PersistenceProvider

oracle.toplink

oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider

oracle.toplink

org.eclipse.persistence.jpa.PersistenceProvider

org.eclipse.persistence

org.datanucleus.api.jpa.PersistenceProviderImpl

org.datanucleus

org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider

org.datanucleus:appengine

org.apache.openjpa.persistence.PersistenceProviderImpl

org.apache.openjpa

10.23. Binding EntityManagerFactory/EntityManager to JNDI

By default WildFly does not bind the entity manager factory to JNDI. However, you can explicitly configure this in the persistence.xml of your application by setting the jboss.entity.manager.factory.jndi.name hint. The value of that property should be the JNDI name to which the entity manager factory should be bound.

You can also bind a container managed (transaction scoped) entity manager to JNDI as well, }}via hint jboss.entity.manager.jndi.name\{ }{{. As a reminder, a transaction scoped entity manager (persistence context), acts as a proxy that always gets an unique underlying entity manager (at the persistence provider level).

Here’s an example:

persistence.xml

<?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="myPU">
      <!-- If you are running in a production environment, add a managed
         data source, the example data source is just for proofs of concept! -->
      <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
      <properties>
         <!-- Bind entity manager factory to JNDI at java:jboss/myEntityManagerFactory -->
         <property name="jboss.entity.manager.factory.jndi.name" value="java:jboss/myEntityManagerFactory" />
         <property name="jboss.entity.manager.jndi.name" value="java:/myEntityManager"/>
       </properties>
   </persistence-unit>
</persistence>
@Stateful
public class ExampleSFSB {
  public void createSomeEntityWithTransactionScopedEM(String name) {
    Context context = new InitialContext();
    javax.persistence.EntityManager entityManager = (javax.persistence.EntityManager) context.lookup("java:/myEntityManager");
    SomeEntity someEntity = new SomeEntity();
    someEntity.setName(name);    entityManager.persist(name);
  }
}

10.24. Tips for using the latest Hibernate ORM

11. JTA Reference

WildFly uses Narayana as the implementation on of the JTA specification. Narayana manages transactions in the application server.

11.1. Transactions in Enterprise Java applications

Transactions are one of the core functionalities provided by the container for the applications. A developer can manage transactions either with the programmatic approach - with API defined by JTA specification. Or he can use annotations. There are two types.

  • first - EJB annotations, their meaning and capabilities are defined under EJB specification and are valid when used in the EJB component

  • second - CDI annotations, their meaning is defined under JTA specification

11.1.1. Transactions managed with programmatic JTA API

The JTA API is defined under javax.transaction package. The package could be considered a bit misguiding as it presents classes which are expected to be used by application developer. These classes are intended as an API for the application server (as the WildFly is).

The user is expected to interact with javax.transaction.UserTransaction which defines the transaction boundaries. The UserTransaction could be used in case the transaction is not defined by annotation at the method - aka. the transaction is not managed by the container. Those are places like servlets, CDI bean which is not annotated with @Transactional and EJBs defined as bean managed.

UserTransaction is available via CDI injection

@Inject
UserTransaction txn;

or with EJB @Resource injection where you can additionally define the JNDI name to be looked-up. The specification says it’s java:comp/UserTransaction.

@Resource(lookup = "java:comp/UserTransaction")
UserTransaction txn;

The code can then look like

@WebServlet(name="TestServlet", urlPatterns={"/"})
public class TestServlet extends HttpServlet {
    private static final Logger LOG = Logger.getLogger(TestServlet.class);

    @Inject
    private UserTransaction txn;

    @PersistenceContext
    private EntityManager em;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            txn.begin();

            em.persist(new TestEntity(1, "Mr. Transaction"));

            txn.commit();
          } catch (NotSupportedException beginExceptions) {
              LOG.errorf(beginExceptions, "Cannot start transaction: '%s'", txn);
          } catch (SecurityException | IllegalStateException | RollbackException
                  | HeuristicMixedException | HeuristicRollbackException commitExceptions) {
              LOG.errorf(commitExceptions, "Cannot commit transaction: '%s'", txn);
          } catch (SystemException systemException) {
              LOG.errorf(systemException, "Unexpected error condition on work with transaction: '%s'", txn);
          }
    }
}

javax.transaction.TransactionManager is not meant to be used by business logic but if you need to register a synchronization or you need to change transaction timeout (before the begin() method is called) then it will be the option for you.

The TransactionManager could be taken with injection and looked-up with the JNDI name

@Inject
TransactionManager tm;

// or

@Resource(lookup = "java:/TransactionManager")
TransactionManager tm;

11.1.2. Transactions in CDI beans

If you start using CDI beans then you can manage transactions either programmatically or you can use annotations. The @Transactional defines transaction boundaries (start of the method starts the transaction, while the transaction is finished at its end). If the method finishes sucessfully the transaction is committed. If the transaction ends with RuntimeException then it’s rolled-back.

When you define the method to be @Transactional you define the behaviour of incoming (or non-existent) transactional context. Please refer the to documentation for Transactional.TxType.

It’s important to note that the TxType influences the transaction management only when called with the managed CDI bean. If you call the method directly - without the CDI container wraps the invocation then the TxType has no effect.

@RequestScope
public class MyCDIBean {
  @Inject
  MyCDIBean myBean;

  @Transactional(TxType.REQUIRED)
  public void mainMethod() {
    // CDI container does not wrap the invocation
    // no new transaction is started
    innerFunctionality();

    // CDI container starts a new transaction
    // the method uses TxType.REQUIRES_NEW and is called from the CDI bean
    myBean.innerFunctionality();
  }

  @Transactional(TxType.REQUIRES_NEW)
  private void innerFunctionality() {
    // some business logic
  }
}
the exception handling could be influenced by attributes rollbackOn and dontRollbackOn (of the @Transactional annotation)
if you use the @Transactional for managing transactions boundaries you won’t be permitted to use the UserTransaction methods. If you do so you can expect a runtime exception being thrown.

The CDI introduces as well a new scope for use with transactions - @TransactionScoped.

11.1.3. Transactions in EJBs

Transaction management in EJB is administered with two annotations: @TransactionManagement @TransactionAttribute.

you can define the same behaviour when you use the ejb-jar.xml descriptor instead of the annotations

The WildFly provides specific annotation org.jboss.ejb3.annotation.TransactionTimeout which gives you chance to change transaction timeout for particular bean/method.

when you use message-driven bean then the @TransactionTimeout does not work and you need to define the timeout through the @ActivationConfigProperty: @ActivationConfigProperty(propertyName="transactionTimeout", propertyValue="1")

The default behaviour of an EJB is to be

  • container managed - transaction boundaries are driven by annotations

  • when the EJB method is invoked - a new transaction is started when no transaction context is available, or the method joins the existing transactions when the transaction context is passed by the call

It’s the same transactional behaviour as if the EJB is annotated with

@TransactionManagement(TransactionManagementType.CONTAINER)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
Container managed transactions

Using the @TransactionManagement(TransactionManagementType.CONTAINER) means the container is responsible to manage transactions. The boundary of the transaction is defined by the start and end of the method and you influence the behaviour by using @TransactionAttribute.

If java.lang.RuntimeException is thrown the transaction is rolled back. EJBContext could be used to define the transaction should be rolled-back by the end of the method when setRollbackOnly is used.

@Stateless
public class MyBean {
  @PersistenceContext
  private EntityManager em;

  @Resource
  EJBContext ctx;

  public void method() {
    em.persist(new TestEntity());
    // at the end of the method the rollback is called
    ctx.setRollbackOnly();
  }
}
the EJBContext let you get the UserTransaction but you are not allowed to do any operation with that when you run container managed transaction. You can expect to receive a runtime exception in such case.
Bean managed transactions

Using the @TransactionManagement(TransactionManagementType.BEAN) means the transaction will be managed manually with the use of the JTA API. That’s with the UserTransaction injections and methods on it. You can inject the EJBContext to get the UserTransaction instance too.

if a call is made from the container-managed method, passing the transaction context to the bean managed method then the context is suspended. It’s similar(!) to call transaction managed bean annotated with @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
Transaction synchronization

JTA API gives a chance to react to the event of a finishing transaction. The definition says that transaction manager announces the even of beforeCompletion and afterCompletion which are defined by the interface javax.transaction.Synchronization. The beforeCompletion callback is invoked at time the transaction manager starts to commit the global transaction. The invocation is processed in the transaction context. The afterCompletion is invoked after the transaction is committed or rolled-back (and is processed outside of the transaction context).

The user needs just to create a simple Java POJO and implement the interface.

public class MySynchronization
        implements javax.transaction.Synchronization {
  @Override
  public void beforeCompletion() {
    System.out.println("Transaction is about to be finished"):
  }

  @Override
  public void afterCompletion(int status) {
    System.out.println("Transaction finished with status " + status):
  }
}

For registration of the synchronization callback, the use can inject the javax.transaction.TransactionSynchronizationRegistry. (the mandated JNDI location for the object is at java:comp/TransactionSynchronizationRegistry) and then to register the synchronization instance. The instance is bound to the currently active transaction.

@Resource
TransactionSynchronizationRegistry transactionSynchronizationRegistry;

public void method() {
  transactionSynchronizationRegistry
    .registerInterposedSynchronization(new MySynchronization());
}

The transaction synchronization registry adds other useful methods which are putResource(Object key, Object value) and getResource(Object key). Their purpose is saving data objects alongside the transaction context. When the transaction is active you can store and retrieve the saved data. When the transaction is finished and there is no transaction context available (e.g. at afterCompletion) the java.lang.IllegalStateException is thrown.

The other option for the user is to use the transaction object to register the synchronization.

@Resource(lookup = "java:/TransactionManager")
TransactionManager tm;

public void method() {
tm.getTransaction().registerSynchronization(new MySynchronization());

When the user runs the Stateful Session Bean he can implement interface javax.ejb.SessionSynchronization (or to use annotations) for the definition of the synchronization callbacks onto the bean. The session synchronization defines three methods. Of these three methods afterBegin is not connected to the transaction synchronization so we will not discuss it further. The following example works with annotations but the bean may just implement the SessionSynchronization interface and it would work the same way.

// only(!) SFSB can use the capability of SessionSynchronization
@Stateful
public class MyStatefulBean {
  public void method() {
    System.out.println("Running an important business logic...");
    Thread.sleep(42000);
  }

  @BeforeCompletion
  public void beforeCompletion() {
    System.out.println("Transaction is about to be finished"):
  }

  @AfterCompletion
  public void afterCompletion(boolean committed) {
    System.out.println("Transaction finished with the outcome "
      + (committed ? "committed" : "rolled-back")):
  }
}
for more information about CDI and registration of transaction synchronization look at the article about Narayana integration of CDI events.

11.2. Transactions subsystem class loading

The WildFly classloading is based on the jboss modules which define the modular class loading system. The transactions for CDI comes as the extension and because of it this extension has to be available at the application classpath. If the application/deployment uses annotations @Transactional or @TransactionScoped then class loading handling is done automatically.

There is one limitation with the CDI with this approach. If your application adds the transactional annotations dynamically (you adds the annotations dynamically during runtime) then the transaction module has to be explicitly added to the application classpath.

This can be done with creating META-INF/MANIFEST.MF or with use of jboss-deployment-structure.xml descriptor. The MANIFEST.MF could look like

Manifest-Version: 1.0
Dependencies: org.jboss.jts export services

11.3. Transactions troubleshooting

The Narayana component is configured to log only messages with level WARN (see category com.arjuna in the standalone-*.xml). If you struggle issues of the transactional handling you can get a better insight into transaction processing by setting the level to TRACE.

/subsystem=logging/logger=com.arjuna:write-attribute(name=level,value=TRACE)

The TRACE could overwhelm you with information from the transactions subsystem. Let’s quickly review what are the most important points to look at in the log.

It’s beneficial to understand how the two-phase commit works.

An example of the log messages produces by Narayana is (the content is shortened for sake of brevity)

[section 1]
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.begin
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) StateManager::StateManager( 2, 0 )
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::BasicAction()
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::Begin() for action-id 0:ffff0a28050c:-a09a5fe:5c598d64:3b
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::actionInitialise() for action-id 0:ffff0a28050c:-a09a5fe:5c598d64:3b
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) ActionHierarchy::ActionHierarchy(1)
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) ActionHierarchy::add(0:ffff0a28050c:-a09a5fe:5c598d64:3b, 1)
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::addChildThread () action 0:ffff0a28050c:-a09a5fe:5c598d64:3b adding Thread[default task-1,5,main]
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::addChildThread () action 0:ffff0a28050c:-a09a5fe:5c598d64:3b adding Thread[default task-1,5,main] result = true
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) TransactionReaper::insert ( BasicAction: 0:ffff0a28050c:-a09a5fe:5c598d64:3b status: ActionStatus.RUNNING, 300 )
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.arjuna] (default task-1) ReaperElement::ReaperElement ( BasicAction: 0:ffff0a28050c:-a09a5fe:5c598d64:3b status: ActionStatus.RUNNING, 300 )
2019-02-05 14:19:39,745 TRACE [com.arjuna.ats.jta] (default task-1) TransactionImple.registerSynchronization - Class: class org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization HashCode: 1114413551 toString: org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization@426c99ef


[section 2]
TRACE [com.arjuna.ats.jta] (default task-1) TransactionImple.enlistResource ( TestXAResource(TestXAResourceCommon(id:944, xid:null, timeout:299, prepareReturn:0)) )
TRACE [com.arjuna.ats.jta] (default task-1) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
TRACE [com.arjuna.ats.arjuna] (default task-1) OutputObjectState::OutputObjectState()
TRACE [com.arjuna.ats.arjuna] (default task-1) FileSystemStore.write_committed(0:ffff0a28050c:-a09a5fe:5c598d64:43, EISNAME)
TRACE [com.arjuna.ats.arjuna] (default task-1) ShadowingStore.write_state(0:ffff0a28050c:-a09a5fe:5c598d64:43, EISNAME, StateType.OS_ORIGINAL)
TRACE [com.arjuna.ats.arjuna] (default task-1) ShadowingStore.genPathName(0:ffff0a28050c:-a09a5fe:5c598d64:43, EISNAME, StateType.OS_ORIGINAL)
TRACE [com.arjuna.ats.arjuna] (default task-1) FileSystemStore.genPathName(0:ffff0a28050c:-a09a5fe:5c598d64:43, EISNAME, 11)
TRACE [com.arjuna.ats.arjuna] (default task-1) FileSystemStore.openAndLock(data/tx-object-store/ShadowNoFileLockStore/defaultStore/EISNAME/0_ffff0a28050c_-a09a5fe_5c598d64_43, FileLock.F_WRLCK, true)
TRACE [com.arjuna.ats.arjuna] (default task-1) FileSystemStore.closeAndUnlock(data/tx-object-store/ShadowNoFileLockStore/defaultStore/EISNAME/0_ffff0a28050c_-a09a5fe_5c598d64_43, null, java.io.FileOutputStream@72d0d91)
TRACE [com.arjuna.ats.arjuna] (default task-1) StateManager::StateManager( 1, 0 )
TRACE [com.arjuna.ats.arjuna] (default task-1) AbstractRecord::AbstractRecord (0:ffff0a28050c:-a09a5fe:5c598d64:45, 1)
TRACE [com.arjuna.ats.jta] (default task-1) XAResourceRecord.XAResourceRecord ( < formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a28050c:-a09a5fe:5c598d64:3b, node_name=1, branch_uid=0:ffff0a28050c:-a09a5fe:5c598d64:44, subordinatenodename=null, eis_name=java:/TestXAResource >, TestXAResource(TestXAResourceCommon(id:944, xid:null, timeout:300, prepareReturn:0)) ), record id=0:ffff0a28050c:-a09a5fe:5c598d64:45
TRACE [com.arjuna.ats.arjuna] (default task-1) RecordList::insert(RecordList: empty) : appending /StateManager/AbstractRecord/XAResourceRecord for 0:ffff0a28050c:-a09a5fe:5c598d64:45

[section 3]
TRACE [com.arjuna.ats.jta] (default task-1) BaseTransaction.commit
TRACE [com.arjuna.ats.jta] (default task-1) TransactionImple.commitAndDisassociate
TRACE [com.arjuna.ats.jta] (default task-1) TransactionImple.getStatus: javax.transaction.Status.STATUS_ACTIVE
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::End() for action-id 0:ffff0a28050c:-a09a5fe:5c598d64:3b

[section 4]
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::prepare () for action-id 0:ffff0a28050c:-a09a5fe:5c598d64:3b
TRACE [com.arjuna.ats.jta] (default task-1) XAResourceRecord.topLevelPrepare for XAResourceRecord < resource:TestXAResource(TestXAResourceCommon(id:944, xid:< formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a28050c:-a09a5fe:5c598d64:3b, node_name=1, branch_uid=0:ffff0a28050c:-a09a5fe:5c598d64:44, subordinatenodename=null, eis_name=java:/TestXAResource >, timeout:300, prepareReturn:0)), txid:< formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a28050c:-a09a5fe:5c598d64:3b, node_name=1, branch_uid=0:ffff0a28050c:-a09a5fe:5c598d64:44, subordinatenodename=null, eis_name=java:/TestXAResource >, heuristic: TwoPhaseOutcome.FINISH_OK, product: Crash Recovery Test/EAP Test, jndiName: java:/TestXAResource com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecord@6454bcb3 >, record id=0:ffff0a28050c:-a09a5fe:5c598d64:45
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::doPrepare() result for action-id (0:ffff0a28050c:-a09a5fe:5c598d64:3b) on record id: (0:ffff0a28050c:-a09a5fe:5c598d64:45) is (TwoPhaseOutcome.PREPARE_OK) node id: (1)
TRACE [com.arjuna.ats.arjuna] (default task-1) RecordList::insert(RecordList: empty) : appending /StateManager/AbstractRecord/XAResourceRecord for 0:ffff0a28050c:-a09a5fe:5c598d64:45
TRACE [com.arjuna.ats.arjuna] (default task-1) OutputObjectState::OutputObjectState(0:ffff0a28050c:-a09a5fe:5c598d64:3b, /StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction)
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::save_state ()
TRACE [com.arjuna.ats.arjuna] (default task-1) StateManager.packHeader for object-id 0:ffff0a28050c:-a09a5fe:5c598d64:3b birth-date 1549372780127
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::save_state - next record to pack is a 171 record /StateManager/AbstractRecord/XAResourceRecord should save it? = true

[section 5]
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::phase2Commit() for action-id 0:ffff0a28050c:-a09a5fe:5c598d64:3b
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::doCommit (XAResourceRecord < resource:TestXAResource(TestXAResourceCommon(id:944, xid:< formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a28050c:-a09a5fe:5c598d64:3b, node_name=1, branch_uid=0:ffff0a28050c:-a09a5fe:5c598d64:44, subordinatenodename=null, eis_name=java:/TestXAResource >, timeout:300, prepareReturn:0)), txid:< formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a28050c:-a09a5fe:5c598d64:3b, node_name=1, branch_uid=0:ffff0a28050c:-a09a5fe:5c598d64:44, subordinatenodename=null, eis_name=java:/TestXAResource >, heuristic: TwoPhaseOutcome.FINISH_OK, product: Crash Recovery Test/EAP Test, jndiName: java:/TestXAResource com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecord@6454bcb3 >)
TRACE [com.arjuna.ats.jta] (default task-1) XAResourceRecord.topLevelCommit for XAResourceRecord < resource:TestXAResource(TestXAResourceCommon(id:944, xid:< formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a28050c:-a09a5fe:5c598d64:3b, node_name=1, branch_uid=0:ffff0a28050c:-a09a5fe:5c598d64:44, subordinatenodename=null, eis_name=java:/TestXAResource >, timeout:300, prepareReturn:0)), txid:< formatId=131077, gtrid_length=29, bqual_length=36, tx_uid=0:ffff0a28050c:-a09a5fe:5c598d64:3b, node_name=1, branch_uid=0:ffff0a28050c:-a09a5fe:5c598d64:44, subordinatenodename=null, eis_name=java:/TestXAResource >, heuristic: TwoPhaseOutcome.FINISH_OK, product: Crash Recovery Test/EAP Test, jndiName: java:/TestXAResource com.arjuna.ats.internal.jta.resources.arjunacore.XAResourceRecord@6454bcb3 >, record id=0:ffff0a28050c:-a09a5fe:5c598d64:45
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::doCommit() result for action-id (0:ffff0a28050c:-a09a5fe:5c598d64:3b) on record id: (0:ffff0a28050c:-a09a5fe:5c598d64:45) is (TwoPhaseOutcome.FINISH_OK) node id: (1)

[section 6]
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::updateState() for action-id 0:ffff0a28050c:-a09a5fe:5c598d64:3b
TRACE [com.arjuna.ats.arjuna] (default task-1) FileSystemStore.remove_committed(0:ffff0a28050c:-a09a5fe:5c598d64:3b, /StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction)
TRACE [com.arjuna.ats.arjuna] (default task-1) ShadowingStore.remove_state(0:ffff0a28050c:-a09a5fe:5c598d64:3b, /StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction, StateType.OS_ORIGINAL)
TRACE [com.arjuna.ats.arjuna] (default task-1) FileSystemStore.closeAndUnlock(data/tx-object-store/ShadowNoFileLockStore/defaultStore/StateManager/BasicAction/TwoPhaseCoordinator/AtomicAction/0_ffff0a28050c_-a09a5fe_5c598d64_3b, null, null)
TRACE [com.arjuna.ats.arjuna] (default task-1) BasicAction::End() result for action-id (0:ffff0a28050c:-a09a5fe:5c598d64:3b) is (TwoPhaseOutcome.FINISH_OK) node id: (1)
TRACE [com.arjuna.ats.jta] (default task-1) SynchronizationImple.afterCompletion - Class: class org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization HashCode: 1685304571 toString: org.wildfly.transaction.client.AbstractTransaction$AssociatingSynchronization@6473b4fb
TRACE [com.arjuna.ats.jta] (default task-1) SynchronizationImple.afterCompletion - Class: class org.wildfly.transaction.client.provider.jboss.JBossLocalTransactionProvider$1 HashCode: 1429380276 toString: org.wildfly.transaction.client.provider.jboss.JBossLocalTransactionProvider$1@55329cb4
TRACE [com.arjuna.ats.arjuna] (default task-1) TransactionReaper::remove ( BasicAction: 0:ffff0a28050c:-a09a5fe:5c598d64:3b status: ActionStatus.COMMITTED )
  • It’s good to consider to follow with the thread id (in the log above it’s default-task-1). The transaction could be suspended and started at the different thread but it’s not usual.

  • The log shows the Narayana processes the two-phase commit. Bear in mind that the example above shows only one resource to be part of the two-phase commit handling. That’s intentional for the log not being too long.

  • the section-1 refers to the point where the transaction is started. The JTA synchronizations are registered and the transaction is added to be handled by transaction reaper (the transaction reaper is an independent thread taking care of transaction timeouts, see more at section Transaction timeouts in the Narayana documentation).

  • At this place consider the BasicAction (a Narayana abstration for the transaction) is identified by string 0:ffff0a28050c:-a09a5fe:5c598d64:3b. It refers to the transaction id. You can track it through the log and follow what is happening with the particular transaction.

  • the section-2 refers to the part of business logic processing. That’s the time when a database insertion is run or JMS sends a message to a queue. That’s where you spot message containing enlistResource. After the resource is enlisted to the transaction the transaction manager saves a record persistently under transaction log store.

  • the section-3 refers to the time when the transaction is about to be committed. That means all business logic was finished (that could be the time a method annotated with @Transactional reached its end).

  • the section-4 refers to the first phase of 2PC which is prepare. You can see XAResourceRecord.topLevelPrepare informing what’s the global transaction id (already defined at the start of the transaction) and the branch id (particular to each resource). The resource is then prepared.

  • when whole prepare phase finishes Narayana saves the state into object store

  • the section-5 refers to the second phase of 2PC which is commit. You can see XAResourceRecord.topLevelCommit with similar information as for prepare.

  • the section-6 shows the transaction is finished, information about the transaction is removed from the Narayana object store and unregistered from the transaction reaper.

For more grained troubleshooting you can consider using Byteman tool.

11.4. Transactions configuration

Configuration related to the behaviour of the Narayana transaction manager is covered under transactions subsystem. For the details of the configuration options please check the description in the transactions subsystem model and see the Narayana documentation.

To check the subsystem model you can use the WildFly model reference or you can list all the configuration options of the subsystem in jboss-cli

/subsystem=transactions:read-resource-description(recursive=true)

12. JNDI Reference

WildFly offers several mechanisms to retrieve components by name. Every WildFly instance has it’s own local JNDI namespace ( java:) which is unique per JVM. The layout of this namespace is primarily governed by the Jakarta EE specification. Applications which share the same WildFly instance can use this namespace to intercommunicate. In addition to local JNDI, a variety of mechanisms exist to access remote components.
  • Client JNDI - This is a mechanism by which remote components can be accessed using the JNDI APIs, but without network round-trips . This approach is the most efficient, and removes a potential single point of failure . For this reason, it is highly recommended to use Client JNDI over traditional remote JNDI access. However, to make this possible, it does require that all names follow a strict layout, so user customizations are not possible. Currently only access to remote EJBs is supported via the ejb: namespace. Future revisions will likely add a JMS client JNDI namespace.

  • Traditional Remote JNDI - This is a more familiar approach to EE application developers, where the client performs a remote component name lookup against a server, and a proxy/stub to the component is serialized as part of the name lookup and returned to the client. The client then invokes a method on the proxy which results in another remote network call to the underlying service. In a nutshell, traditional remote JNDI involves two calls to invoke an EE component, whereas Client JNDI requires one. It does however allow for customized names, and for a centralised directory for multiple application servers. This centralized directory is, however, a single point of failure.

  • EE Application Client / Server-To-Server Delegation - This approach is where local names are bound as an alias to a remote name using one of the above mechanisms. This is useful in that it allows applications to only ever reference standard portable Jakarta EE names in both code and deployment descriptors. It also allows for the application to be unaware of network topology details/ This can even work with Java SE clients by using the little known EE Application Client feature. This feature allows you to run an extremely minimal AS server around your application, so that you can take advantage of certain core services such as naming and injection.

13. Local JNDI

The Jakarta EE platform specification defines the following JNDI contexts:

  • java:comp - The namespace is scoped to the current component (i.e. EJB)

  • java:module - Scoped to the current module

  • java:app - Scoped to the current application

  • java:global - Scoped to the application server

In addition to the standard namespaces, WildFly also provides the following two global namespaces:

  • java:jboss

  • java:/

Only entries within the java:jboss/exported context are accessible over remote JNDI.
For web deployments java:comp is aliased to java:module, so EJB’s deployed in a war do not have their own comp namespace.

13.1. Binding entries to JNDI

There are several methods that can be used to bind entries into JNDI in WildFly.

13.1.1. Using a deployment descriptor

For Jakarta EE applications the recommended way is to use a deployment descriptor to create the binding. For example the following web.xml binds the string "Hello World" to java:global/mystring and the string "Hello Module" to java:comp/env/hello (any non absolute JNDI name is relative to java:comp/env context).

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <env-entry>
        <env-entry-name>java:global/mystring</env-entry-name>
        <env-entry-type>java.lang.String</env-entry-type>
        <env-entry-value>Hello World</env-entry-value>
    </env-entry>
    <env-entry>
        <env-entry-name>hello</env-entry-name>
        <env-entry-type>java.lang.String</env-entry-type>
        <env-entry-value>Hello Module</env-entry-value>
    </env-entry>
</web-app>

For more details, see the Java EE Platform Specification.

13.1.2. Programatically

Jakarta EE Applications

Standard Jakarta EE applications may use the standard JNDI API, included with Java SE, to bind entries in the global namespaces (the standard java:comp, java:module and java:app namespaces are read-only, as mandated by the Jakarta EE Platform Specification).

  InitialContext initialContext = new InitialContext();
  initialContext.bind("java:global/a", 100);
There is no need to unbind entries created programatically, since WildFly tracks which bindings belong to a deployment, and the bindings are automatically removed when the deployment is undeployed.
WildFly Modules and Extensions

With respect to code in WildFly Modules/Extensions, which is executed out of a Jakarta EE application context, using the standard JNDI API may result in a UnsupportedOperationException if the target namespace uses a WritableServiceBasedNamingStore. To work around that, the bind() invocation needs to be wrapped using WildFly proprietary APIs:

  InitialContext initialContext = new InitialContext();
  WritableServiceBasedNamingStore.pushOwner(serviceTarget);
  try {
    initialContext.bind("java:global/a", 100);
  } finally {
    WritableServiceBasedNamingStore.popOwner();
  }
The ServiceTarget removes the bind when uninstalled, thus using one out of the module/extension domain usage should be avoided, unless entries are removed using unbind().

13.1.3. Naming Subsystem Configuration

It is also possible to bind to one of the three global namespaces using configuration in the naming subsystem. This can be done by either editing the standalone.xml/domain.xml file directly, or through the management API.

Four different types of bindings are supported:

  • Simple - A primitive or java.net.URL entry (default is java.lang.String).

  • Object Factory - This allows to to specify the javax.naming.spi.ObjectFactory that is used to create the looked up value.

  • External Context - An external context to federate, such as an LDAP Directory Service

  • Lookup - The allows to create JNDI aliases, when this entry is looked up it will lookup the target and return the result.

An example standalone.xml might look like:

<subsystem xmlns="urn:jboss:domain:naming:2.0" >
  <bindings>
    <simple name="java:global/a" value="100" type="int" />
    <simple name="java:global/jbossDocs" value="https://docs.jboss.org" type="java.net.URL" />
    <object-factory name="java:global/b" module="com.acme" class="org.acme.MyObjectFactory" />
    <external-context name="java:global/federation/ldap/example" class="javax.naming.directory.InitialDirContext" cache="true">
      <environment>
        <property name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory" />
        <property name="java.naming.provider.url" value="ldap://ldap.example.com:389" />
        <property name="java.naming.security.authentication" value="simple" />
        <property name="java.naming.security.principal" value="uid=admin,ou=system" />
        <property name="java.naming.security.credentials" value="secret" />
      </environment>
    </external-context>
    <lookup name="java:global/c" lookup="java:global/b" />
 </bindings>
</subsystem>

The CLI may also be used to bind an entry. As an example:

/subsystem=naming/binding=java\:global\/mybinding:add(binding-type=simple, type=long, value=1000)
WildFly’s Administrator Guide includes a section describing in detail the Naming subsystem configuration.

13.2. Retrieving entries from JNDI

13.2.1. Resource Injection

For Jakarta EE applications the recommended way to lookup a JNDI entry is to use @Resource injection:

  @Resource(lookup = "java:global/mystring")
  private String myString;
 
  @Resource(name = "hello")
  private String hello;
 
  @Resource
  ManagedExecutorService executor;

Note that @Resource is more than a JNDI lookup, it also binds an entry in the component’s JNDI environment. The new bind JNDI name is defined by @Resource’s `name attribute, which value, if unspecified, is the Java type concatenated with / and the field’s name, for instance java.lang.String/myString. More, similar to when using deployment descriptors to bind JNDI entries. unless the name is an absolute JNDI name, it is considered relative to java:comp/env. For instance, with respect to the field named myString above, the @Resource’s `lookup attribute instructs WildFly to lookup the value in java:global/mystring, bind it in java:comp/env/java.lang.String/myString, and then inject such value into the field.

With respect to the field named hello, there is no lookup attribute value defined, so the responsibility to provide the entry’s value is delegated to the deployment descriptor. Considering that the deployment descriptor was the web.xml previously shown, which defines an environment entry with same hello name, then WildFly inject the valued defined in the deployment descriptor into the field.

The executor field has no attributes specified, so the bind’s name would default to java:comp/env/javax.enterprise.concurrent.ManagedExecutorService/executor, but there is no such entry in the deployment descriptor, and when that happens it’s up to WildFly to provide a default value or null, depending on the field’s Java type. In this particular case WildFly would inject the default instance of a managed executor service, the value in java:comp/DefaultManagedExecutorService, as mandated by the EE Concurrency Utilities 1.0 Specification (JSR 236).

13.2.2. Standard Java SE JNDI API

Jakarta EE applications may use, without any additional configuration needed, the standard JNDI API to lookup an entry from JNDI:

  String myString = (String) new InitialContext().lookup("java:global/mystring");

or simply

  String myString = InitialContext.doLookup("java:global/mystring");

14. Remote JNDI Access

WildFly supports two different types of remote JNDI.

14.1. http-remoting:

The http-remoting: protocol implementation is provided by JBoss Remote Naming project, and uses http upgrade to lookup items from the servers local JNDI. To use it, you must have the appropriate jars on the class path, if you are maven user can be done simply by adding the following to your pom.xml dependencies:

<dependency>
  <groupId>org.wildfly</groupId>
  <artifactId>wildfly-ejb-client-bom</artifactId>
  <version>11.0.0.Final</version>
  <type>pom</type>
</dependency>

If you are not using maven a shaded jar that contains all required classes
can be found in the bin/client directory of WildFly’s distribution.

final Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
env.put(Context.PROVIDER_URL, "http-remoting://localhost:8080");
// the property below is required ONLY if there is no ejb client configuration loaded (such as a
// jboss-ejb-client.properties in the class path) and the context will be used to lookup EJBs
env.put("jboss.naming.client.ejb.context", true);
InitialContext remoteContext = new InitialContext(env);
RemoteCalculator ejb = (RemoteCalculator) remoteContext.lookup("wildfly-http-remoting-ejb/CalculatorBean!"
                + RemoteCalculator.class.getName());
The http-remoting client assumes JNDI names in remote lookups are relative to java:jboss/exported namespace, a lookup of an absolute JNDI name will fail.

14.2. ejb:

The ejb: namespace implementation is provided by the jboss-ejb-client library, and allows the lookup of EJB’s using their application name, module name, ejb name and interface type. To use it, you must have the appropriate jars on the class path, if you are maven user can be done simply by adding the following to your pom.xml dependencies:

<dependency>
  <groupId>org.wildfly</groupId>
  <artifactId>wildfly-ejb-client-bom</artifactId>
  <version>11.0.0.Final</version>
  <type>pom</type>
</dependency>

If you are not using maven a shaded jar that contains all required classes
can be found in the bin/client directory of WildFly’s distribution.

This is a client side JNDI implementation. Instead of looking up an EJB on the server the lookup name contains enough information for the client side library to generate a proxy with the EJB information. When you invoke a method on this proxy it will use the current EJB client context to perform the invocation. If the current context does not have a connection to a server with the specified EJB deployed then an error will occur. Using this protocol it is possible to look up EJB’s that do not actually exist, and no error will be thrown until the proxy is actually used. The exception to this is stateful session beans, which need to connect to a server when they are created in order to create the session bean instance on the server.

final Properties env = new Properties();
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
InitialContext remoteContext = new InitialContext(env);
MyRemoteInterface myRemote = (MyRemoteInterface) remoteContext.lookup("ejb:myapp/myejbjar/MyEjbName\!com.test.MyRemoteInterface");
MyStatefulRemoteInterface myStatefulRemote = (MyStatefulRemoteInterface) remoteContext.lookup("ejb:myapp/myejbjar/MyStatefulName\!comp.test.MyStatefulRemoteInterface?stateful");

The first example is a lookup of a singleton, stateless or EJB 2.x home interface. This lookup will not hit the server, instead a proxy will be generated for the remote interface specified in the name. The second example is for a stateful session bean, in this case the JNDI lookup will hit the server, in order to tell the server to create the SFSB session.

For more details on how the server connections are configured, including the required jboss ejb client setup, please see EJB invocations from a remote client using JNDI.

15. JAX-RS Reference Guide

This page outlines the three options you have for deploying JAX-RS applications in WildFly 21. These three methods are specified in the JAX-RS 2.0 specification in section 2.3.2.

15.1. Subclassing javax.ws.rs.core.Application and using @ApplicationPath

This is the easiest way and does not require any xml configuration. Simply include a subclass of javax.ws.rs.core.Application in your application, and annotate it with the path that you want your JAX-RS classes to be available. For example:

@ApplicationPath("/mypath")
public class MyApplication extends Application {
}

This will make your JAX-RS resources available under / mywebappcontext /mypath.

Note that that the path is /mypath not /mypath/*

15.2. Subclassing javax.ws.rs.core.Application and using web.xml

If you do not wish to use @ApplicationPath but still need to subclass Application you can set up the JAX-RS mapping in web.xml:

public class MyApplication extends Application {
}
<servlet-mapping>
   <servlet-name>com.acme.MyApplication</servlet-name>
   <url-pattern>/hello/*</url-pattern>
</servlet-mapping>

This will make your JAX-RS resources available under / mywebappcontext /hello.

You can also use this approach to override an application path set with the @ApplicationPath annotation.

15.3. Using web.xml

If you don’t wan’t to subclass Application you can set the JAX-RS mapping in web.xml as follows:

<servlet-mapping>
   <servlet-name>javax.ws.rs.core.Application</servlet-name>
   <url-pattern>/hello/*</url-pattern>
</servlet-mapping>

This will make your JAX-RS resources available under / mywebappcontext /hello.

Note that you only have to add the mapping, not the corresponding servlet. The server is responsible for adding the corresponding servlet automatically.

[[Web_(Undertow)_Reference_Guide]] = Sharing sessions between wars in an ear

Undertow allows you to share sessions between wars in an ear, if it is explicitly configured to do so. Note that if you use this feature your applications may not be portable, as this is not a standard servlet feature.

In order to enable this you must include a shared-session-config element in the jboss-all.xml file in the META-INF directory of the ear:

<jboss xmlns="urn:jboss:1.0">
    <shared-session-config xmlns="urn:jboss:shared-session-config:2.0">
        <session-config>
            <cookie-config>
                <path>/</path>
            </cookie-config>
        </session-config>
    </shared-session-config>
</jboss>

This element is used to configure the shared session manager that will be used by all wars in the ear. For full details of all the options provided by this file please see the schema at https://github.com/wildfly/wildfly/blob/master/undertow/src/main/resources/schema/shared-session-config_2_0.xsd, however in general it mimics the options that are available in jboss-web.xml for configuring the session.

16. Webservices reference guide

The Web Services functionalities of WildFly are provided by the JBossWS project integration.

The latest project documentation is available here.

This section covers the most relevant topics for the JBossWS version available on WildFly 21.

16.1. JAX-WS User Guide

The Java API for XML-Based Web Services (JAX-WS / JSR-224) defines the mapping between WSDL and Java as well as the classes to be used for accessing webservices and publishing them. JBossWS implements the latest JAX-WS specification, hence users can reference it for any vendor agnostic webservice usage need. Below is a brief overview of the most basic functionalities.

16.1.1. Web Service Endpoints

JAX-WS simplifies the development model for a web service endpoint a great deal. In short, an endpoint implementation bean is annotated with JAX-WS annotations and deployed to the server. The server automatically generates and publishes the abstract contract (i.e. wsdl+schema) for client consumption. All marshalling/unmarshalling is delegated to JAXB.

Plain old Java Object (POJO)

Let’s take a look at simple POJO endpoint implementation. All endpoint associated metadata is provided via JSR-181 annotations

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class JSEBean01
{
   @WebMethod
   public String echo(String input)
   {
      ...
   }
}
The endpoint as a web application

A JAX-WS java service endpoint (JSE) is deployed as a web application. Here is a sample web.xml descriptor:

<web-app ...>
  <servlet>
    <servlet-name>TestService</servlet-name>
    <servlet-class>org.jboss.test.ws.jaxws.samples.jsr181pojo.JSEBean01</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>TestService</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>
Packaging the endpoint

A JSR-181 java service endpoint (JSE) is packaged as a web application in a war file.

<war warfile="${build.dir}/libs/jbossws-samples-jsr181pojo.war" webxml="${build.resources.dir}/samples/jsr181pojo/WEB-INF/web.xml">
  <classes dir="${build.dir}/classes">
    <include name="org/jboss/test/ws/samples/jsr181pojo/JSEBean01.class"/>
  </classes>
</war>

Note, only the endpoint implementation bean and web.xml are required.

Accessing the generated WSDL

A successfully deployed service endpoint will show up in the WildFly managent console. You can get the deployed endpoint wsdl address there too.

Note, it is also possible to generate the abstract contract off line using JBossWS tools. For details of that please see Bottom-Up (Java to WSDL).
EJB3 Stateless Session Bean (SLSB)

The JAX-WS programming model supports the same set of annotations on EJB3 stateless session beans as on POJO endpoints.

@Stateless
@Remote(EJB3RemoteInterface.class)
@RemoteBinding(jndiBinding = "/ejb3/EJB3EndpointInterface")

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class EJB3Bean01 implements EJB3RemoteInterface
{
   @WebMethod
   public String echo(String input)
   {
      ...
   }
}

Above you see an EJB-3.0 stateless session bean that exposes one method both on the remote interface and as an endpoint operation.

Packaging the endpoint

A JSR-181 EJB service endpoint is packaged as an ordinary ejb deployment.

<jar jarfile="${build.dir}/libs/jbossws-samples-jsr181ejb.jar">
  <fileset dir="${build.dir}/classes">
    <include name="org/jboss/test/ws/samples/jsr181ejb/EJB3Bean01.class"/>
    <include name="org/jboss/test/ws/samples/jsr181ejb/EJB3RemoteInterface.class"/>
  </fileset>
</jar>
Accessing the generated WSDL

A successfully deployed service endpoint will show up in the WildFly managent console. You can get the deployed endpoint wsdl address there too.

Note, it is also possible to generate the abstract contract off line using JBossWS tools. For details of that please see Bottom-Up (Java to WSDL).
Endpoint Provider

JAX-WS services typically implement a native Java service endpoint interface (SEI), perhaps mapped from a WSDL port type, either directly or via the use of annotations.

Java SEIs provide a high level Java-centric abstraction that hides the details of converting between Java objects and their XML representations for use in XML-based messages. However, in some cases it is desirable for services to be able to operate at the XML message level. The Provider interface offers an alternative to SEIs and may be implemented by services wishing to work at the XML message level.

A Provider based service instances invoke method is called for each message received for the service.

@WebServiceProvider(wsdlLocation = "WEB-INF/wsdl/Provider.wsdl")
@ServiceMode(value = Service.Mode.PAYLOAD)
public class ProviderBeanPayload implements Provider<Source>
{
   public Source invoke(Source req)
   {
      // Access the entire request PAYLOAD and return the response PAYLOAD
   }
}

Note, Service.Mode.PAYLOAD is the default and does not have to be declared explicitly. You can also use Service.Mode.MESSAGE to access the entire SOAP message (i.e. with MESSAGE the Provider can also see SOAP Headers)

The abstract contract for a provider endpoint cannot be derived/generated automatically. Therefore it is necessary to specify the wsdlLocation with the @ WebServiceProvider annotation.

16.1.2. Web Service Clients

Service

Service is an abstraction that represents a WSDL service. A WSDL service is a collection of related ports, each of which consists of a port type bound to a particular protocol and available at a particular endpoint address.

For most clients, you will start with a set of stubs generated from the WSDL. One of these will be the service, and you will create objects of that class in order to work with the service (see "static case" below).

Service Usage
Static case

Most clients will start with a WSDL file, and generate some stubs using JBossWS tools like wsconsume. This usually gives a mass of files, one of which is the top of the tree. This is the service implementation class.

The generated implementation class can be recognised as it will have two public constructors, one with no arguments and one with two arguments, representing the wsdl location (a java.net.URL) and the service name (a javax.xml.namespace.QName) respectively.

Usually you will use the no-argument constructor. In this case the WSDL location and service name are those found in the WSDL. These are set implicitly from the @WebServiceClient annotation that decorates the generated class.

The following code snippet shows the generated constructors from the generated class:

// Generated Service Class

@WebServiceClient(name="StockQuoteService", targetNamespace="http://example.com/stocks", wsdlLocation="http://example.com/stocks.wsdl")
public class StockQuoteService extends javax.xml.ws.Service
{
   public StockQuoteService()
   {
      super(new URL("http://example.com/stocks.wsdl"), new QName("http://example.com/stocks", "StockQuoteService"));
   }

   public StockQuoteService(String wsdlLocation, QName serviceName)
   {
      super(wsdlLocation, serviceName);
   }

   ...
}

Section Dynamic Proxy explains how to obtain a port from the service and how to invoke an operation on the port. If you need to work with the XML payload directly or with the XML representation of the entire SOAP message, have a look at Dispatch.

Dynamic case

In the dynamic case, when nothing is generated, a web service client uses Service.create to create Service instances, the following code illustrates this process.

URL wsdlLocation = new URL("http://example.org/my.wsdl");
QName serviceName = new QName("http://example.org/sample", "MyService");
Service service = Service.create(wsdlLocation, serviceName);
Handler Resolver

JAX-WS provides a flexible plug-in framework for message processing modules, known as handlers, that may be used to extend the capabilities of a JAX-WS runtime system. Handler Framework describes the handler framework in detail. A Service instance provides access to a HandlerResolver via a pair of getHandlerResolver / setHandlerResolver methods that may be used to configure a set of handlers on a per-service, per-port or per-protocol binding basis.

When a Service instance is used to create a proxy or a Dispatch instance then the handler resolver currently registered with the service is used to create the required handler chain. Subsequent changes to the handler resolver configured for a Service instance do not affect the handlers on previously created proxies, or Dispatch instances.

Executor

Service instances can be configured with a java.util.concurrent.Executor. The executor will then be used to invoke any asynchronous callbacks requested by the application. The setExecutor and getExecutor methods of Service can be used to modify and retrieve the executor configured for a service.

Dynamic Proxy

You can create an instance of a client proxy using one of getPort methods on the Service.

/**
 * The getPort method returns a proxy. A service client
 * uses this proxy to invoke operations on the target
 * service endpoint. The <code>serviceEndpointInterface</code>
 * specifies the service endpoint interface that is supported by
 * the created dynamic proxy instance.
 **/
public <T> T getPort(QName portName, Class<T> serviceEndpointInterface)
{
   ...
}

/**
 * The getPort method returns a proxy. The parameter
 * <code>serviceEndpointInterface</code> specifies the service
 * endpoint interface that is supported by the returned proxy.
 * In the implementation of this method, the JAX-WS
 * runtime system takes the responsibility of selecting a protocol
 * binding (and a port) and configuring the proxy accordingly.
 * The returned proxy should not be reconfigured by the client.
 *
 **/
public <T> T getPort(Class<T> serviceEndpointInterface)
{
   ...
}

The service endpoint interface (SEI) is usually generated using tools. For details see Top Down (WSDL to Java)

A generated static Service usually also offers typed methods to get ports. These methods also return dynamic proxies that implement the SEI.

@WebServiceClient(name = "TestEndpointService", targetNamespace = "http://org.jboss.ws/wsref",
   wsdlLocation = "http://localhost.localdomain:8080/jaxws-samples-webserviceref?wsdl")

public class TestEndpointService extends Service
{
    ...

    public TestEndpointService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    @WebEndpoint(name = "TestEndpointPort")
    public TestEndpoint getTestEndpointPort()
    {
        return (TestEndpoint)super.getPort(TESTENDPOINTPORT, TestEndpoint.class);
    }
}
WebServiceRef

The @WebServiceRef annotation is used to declare a reference to a Web service. It follows the resource pattern exemplified by the javax.annotation.Resource annotation in JSR-250.

There are two uses to the WebServiceRef annotation:

  1. To define a reference whose type is a generated service class. In this case, the type and value element will both refer to the generated service class type. Moreover, if the reference type can be inferred by the field/method declaration the annotation is applied to, the type and value elements MAY have the default value (Object.class, that is). If the type cannot be inferred, then at least the type element MUST be present with a non-default value.

  2. To define a reference whose type is a SEI. In this case, the type element MAY be present with its default value if the type of the reference can be inferred from the annotated field/method declaration, but the value element MUST always be present and refer to a generated service class type (a subtype of javax.xml.ws.Service). The wsdlLocation element, if present, overrides theWSDL location information specified in the WebService annotation of the referenced generated service class.

    public class EJB3Client implements EJB3Remote
    {
       @WebServiceRef
       public TestEndpointService service4;
    
       @WebServiceRef
       public TestEndpoint port3;
Dispatch

XMLWeb Services use XML messages for communication between services and service clients. The higher level JAX-WS APIs are designed to hide the details of converting between Java method invocations and the corresponding XML messages, but in some cases operating at the XML message level is desirable. The Dispatch interface provides support for this mode of interaction.

Dispatch supports two usage modes, identified by the constants javax.xml.ws.Service.Mode.MESSAGE and javax.xml.ws.Service.Mode.PAYLOAD respectively:

Message In this mode, client applications work directly with protocol-specific message structures. E.g., when used with a SOAP protocol binding, a client application would work directly with a SOAP message.

Message Payload In this mode, client applications work with the payload of messages rather than the messages themselves. E.g., when used with a SOAP protocol binding, a client application would work with the contents of the SOAP Body rather than the SOAP message as a whole.

Dispatch is a low level API that requires clients to construct messages or message payloads as XML and requires an intimate knowledge of the desired message or payload structure. Dispatch is a generic class that supports input and output of messages or message payloads of any type.

Service service = Service.create(wsdlURL, serviceName);
Dispatch dispatch = service.createDispatch(portName, StreamSource.class, Mode.PAYLOAD);

String payload = "<ns1:ping xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
dispatch.invokeOneWay(new StreamSource(new StringReader(payload)));

payload = "<ns1:feedback xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
Source retObj = (Source)dispatch.invoke(new StreamSource(new StringReader(payload)));
Asynchronous Invocations

The BindingProvider interface represents a component that provides a protocol binding for use by clients, it is implemented by proxies and is extended by the Dispatch interface.

BindingProvider instances may provide asynchronous operation capabilities. When used, asynchronous operation invocations are decoupled from the BindingProvider instance at invocation time such that the response context is not updated when the operation completes. Instead a separate response context is made available using the Response interface.

public void testInvokeAsync() throws Exception
{
   URL wsdlURL = new URL("http://" + getServerHost() + ":8080/jaxws-samples-asynchronous?wsdl");
   QName serviceName = new QName(targetNS, "TestEndpointService");
   Service service = Service.create(wsdlURL, serviceName);
   TestEndpoint port = service.getPort(TestEndpoint.class);
   Response response = port.echoAsync("Async");
   // access future
   String retStr = (String) response.get();
   assertEquals("Async", retStr);
}
Oneway Invocations

@Oneway indicates that the given web method has only an input message and no output. Typically, a oneway method returns the thread of control to the calling application prior to executing the actual business method.

@WebService (name="PingEndpoint")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class PingEndpointImpl
{
   private static String feedback;

   @WebMethod
   @Oneway
   publicvoid ping()
   {
      log.info("ping");
      feedback = "ok";
   }

   @WebMethod
   public String feedback()
   {
      log.info("feedback");
      return feedback;
   }
}
Timeout Configuration

There are two properties to configure the http connection timeout and client receive time out:

public void testConfigureTimeout() throws Exception
{
   //Set timeout until a connection is established
   ((BindingProvider)port).getRequestContext().put("javax.xml.ws.client.connectionTimeout", "6000");

   //Set timeout until the response is received
   ((BindingProvider) port).getRequestContext().put("javax.xml.ws.client.receiveTimeout", "1000");

   port.echo("testTimeout");
}

16.1.3. Common API

This sections describes concepts that apply equally to Web Service Endpoints and Web Service Clients.

Handler Framework

The handler framework is implemented by a JAX-WS protocol binding in both client and server side runtimes. Proxies, and Dispatch instances, known collectively as binding providers, each use protocol bindings to bind their abstract functionality to specific protocols.

Client and server-side handlers are organized into an ordered list known as a handler chain. The handlers within a handler chain are invoked each time a message is sent or received. Inbound messages are processed by handlers prior to binding provider processing. Outbound messages are processed by handlers after any binding provider processing.

Handlers are invoked with a message context that provides methods to access and modify inbound and outbound messages and to manage a set of properties. Message context properties may be used to facilitate communication between individual handlers and between handlers and client and service implementations. Different types of handlers are invoked with different types of message context.

Logical Handler

Handlers that only operate on message context properties and message payloads. Logical handlers are protocol agnostic and are unable to affect protocol specific parts of a message. Logical handlers are handlers that implement javax.xml.ws.handler.LogicalHandler.

Protocol Handler

Handlers that operate on message context properties and protocol specific messages. Protocol handlers are specific to a particular protocol and may access and change protocol specific aspects of a message. Protocol handlers are handlers that implement any interface derived from javax.xml.ws.handler.Handler except javax.xml.ws.handler.LogicalHandler.

Service endpoint handlers

On the service endpoint, handlers are defined using the @HandlerChain annotation.

@WebService
@HandlerChain(file = "jaxws-server-source-handlers.xml")
public class SOAPEndpointSourceImpl
{
   ...
}

The location of the handler chain file supports 2 formats

\1. An absolute java.net.URL in externalForm. (ex: http://myhandlers.foo.com/handlerfile1.xml)

\2. A relative path from the source file or class file. (ex: bar/handlerfile1.xml)

Service client handlers

On the client side, handler can be configured using the @HandlerChain annotation on the SEI or dynamically using the API.

Service service = Service.create(wsdlURL, serviceName);
Endpoint port = (Endpoint)service.getPort(Endpoint.class);

BindingProvider bindingProvider = (BindingProvider)port;
List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add(new LogHandler());
handlerChain.add(new AuthorizationHandler());
handlerChain.add(new RoutingHandler());
bindingProvider.getBinding().setHandlerChain(handlerChain); // important!
Message Context

MessageContext is the super interface for all JAX-WS message contexts. It extends Map<String,Object> with additional methods and constants to manage a set of properties that enable handlers in a handler chain to share processing related state. For example, a handler may use the put method to insert a property in the message context that one or more other handlers in the handler chain may subsequently obtain via the get method.

Properties are scoped as either APPLICATION or HANDLER. All properties are available to all handlers for an instance of an MEP on a particular endpoint. E.g., if a logical handler puts a property in the message context, that property will also be available to any protocol handlers in the chain during the execution of an MEP instance. APPLICATION scoped properties are also made available to client applications (see section 4.2.1) and service endpoint implementations. The defaultscope for a property is HANDLER.

Logical Message Context

Logical Handlers are passed a message context of type LogicalMessageContext when invoked. LogicalMessageContext extends MessageContext with methods to obtain and modify the message payload, it does not provide access to the protocol specific aspects of amessage. A protocol binding defines what component of a message are available via a logical message context. The SOAP binding defines that a logical handler deployed in a SOAP binding can access the contents of the SOAP body but not the SOAP headers whereas the XML/HTTP binding defines that a logical handler can access the entire XML payload of a message.

SOAP Message Context

SOAP handlers are passed a SOAPMessageContext when invoked. SOAPMessageContext extends MessageContext with methods to obtain and modify the SOAP message payload.

Fault Handling

An implementation may thow a SOAPFaultException

public void throwSoapFaultException()
{
   SOAPFactory factory = SOAPFactory.newInstance();
   SOAPFault fault = factory.createFault("this is a fault string!", new QName("http://foo", "FooCode"));
   fault.setFaultActor("mr.actor");
   fault.addDetail().addChildElement("test");
   thrownew SOAPFaultException(fault);
}

or an application specific user exception

public void throwApplicationException() throws UserException
{
   thrownew UserException("validation", 123, "Some validation error");
}
In case of the latter, JBossWS generates the required fault wrapper beans at runtime if they are not part of the deployment

16.1.4. JAX-WS Annotations

javax.xml.ws.ServiceMode

The ServiceMode annotation is used to specify the mode for a provider class, i.e. whether a provider wants to have access to protocol message payloads (e.g. a SOAP body) or the entire protocol messages (e.g. a SOAP envelope).

javax.xml.ws.WebFault

The WebFault annotation is used when mapping WSDL faults to Java exceptions, see section 2.5. It is used to capture the name of the fault element used when marshalling the JAXB type generated from the global element referenced by the WSDL fault message. It can also be used to customize the mapping of service specific exceptions to WSDL faults.

javax.xml.ws.RequestWrapper

The RequestWrapper annotation is applied to the methods of an SEI. It is used to capture the JAXB generated request wrapper bean and the element name and namespace for marshalling / unmarshalling the bean. The default value of localName element is the operationName as defined in WebMethod annotation and the default value for the targetNamespace element is the target namespace of the SEI.When starting from Java, this annotation is used to resolve overloading conflicts in document literal mode. Only the className element is required in this case.

javax.xml.ws.ResponseWrapper

The ResponseWrapper annotation is applied to the methods of an SEI. It is used to capture the JAXB generated response wrapper bean and the element name and namespace for marshalling / unmarshalling the bean. The default value of the localName element is the operationName as defined in the WebMethod appended with "Response" and the default value of the targetNamespace element is the target namespace of the SEI. When starting from Java, this annotation is used to resolve overloading conflicts in document literal mode. Only the className element is required in this case.

javax.xml.ws.WebServiceClient

The WebServiceClient annotation is specified on a generated service class (see 2.7). It is used to associate a class with a specific Web service, identify by a URL to a WSDL document and the qualified name of a wsdl:service element.

javax.xml.ws.WebEndpoint

The WebEndpoint annotation is specified on the getPortName() methods of a generated service class (see 2.7). It is used to associate a get method with a specific wsdl:port, identified by its local name (a NCName).

javax.xml.ws.WebServiceProvider

The WebServiceProvider annotation is specified on classes that implement a strongly typed javax.xml.ws.Provider. It is used to declare that a class that satisfies the requirements for a provider (see 5.1) does indeed define a Web service endpoint, much like the WebService annotation does for SEI-based endpoints.

The WebServiceProvider and WebService annotations are mutually exclusive.

javax.xml.ws.BindingType

The BindingType annotation is applied to an endpoint implementation class. It specifies the binding to use when publishing an endpoint of this type.

The default binding for an endpoint is the SOAP 1.1/HTTP one.

javax.xml.ws.WebServiceRef

The WebServiceRef annotation is used to declare a reference to a Web service. It follows the resource pattern exemplified by the javax.annotation.Resource annotation in JSR-250 [JBWS:32]. The WebServiceRef annotation is required to be honored when running on the Jakarta EE platform, where it is subject to the common resource injection rules described by the platform specification [JBWS:33].

javax.xml.ws.WebServiceRefs

The WebServiceRefs annotation is used to declare multiple references to Web services on a single class. It is necessary to work around the limition against specifying repeated annotations of the same type on any given class, which prevents listing multiple javax.ws.WebServiceRef annotations one after the other. This annotation follows the resource pattern exemplified by the javax.annotation.Resources annotation in JSR-250.

Since no name and type can be inferred in this case, each WebServiceRef annotation inside a WebServiceRefs MUST contain name and type elements with non-default values. The WebServiceRef annotation is required to be honored when running on the Jakarta EE platform, where it is subject to the common resource injection rules described by the platform specification.

javax.xml.ws.Action

The Action annotation is applied to the methods of a SEI. It used to generate the wsa:Action on wsdl:input and wsdl:output of each wsdl:operation mapped from the annotated methods.

javax.xml.ws.FaultAction

The FaultAction annotation is used within the Action annotation to generate the wsa:Action element on the wsdl:fault element of each wsdl:operation mapped from the annotated methods.

16.1.5. JSR-181 Annotations

JSR-181 defines the syntax and semantics of Java Web Service (JWS) metadata and default values.

javax.jws.WebService

Marks a Java class as implementing a Web Service, or a Java interface as defining a Web Service interface.

javax.jws.WebMethod

Customizes a method that is exposed as a Web Service operation.

javax.jws.OneWay

Indicates that the given web method has only an input message and no output. Typically, a oneway method returns the thread of control to the calling application prior to executing the actual business method. A JSR-181 processor is REQUIRED to report an error if an operation marked @Oneway has a return value, declares any checked exceptions or has any INOUT or OUT parameters.

javax.jws.WebParam

Customizes the mapping of an individual parameter to a Web Service message part and XML element.

javax.jws.WebResult

Customizes the mapping of the return value to a WSDL part and XML element.

javax.jws.SOAPBinding

Specifies the mapping of the Web Service onto the SOAP message protocol.

The SOAPBinding annotation has a target of TYPE and METHOD. The annotation may be placed on a method if and only if the SOAPBinding.style is DOCUMENT. Implementations MUST report an error if the SOAPBinding annotation is placed on a method with a SOAPBinding.style of RPC. Methods that do not have a SOAPBinding annotation accept the SOAPBinding behavior defined on the type.

javax.jws.HandlerChain

The @HandlerChain annotation associates the Web Service with an externally defined handler chain.

It is an error to combine this annotation with the @SOAPMessageHandlers annotation.

The @HandlerChain annotation MAY be present on the endpoint interface and service implementation bean. The service implementation bean’s @HandlerChain is used if @HandlerChain is present on both.

The @HandlerChain annotation MAY be specified on the type only. The annotation target includes METHOD and FIELD for use by JAX-WS-2.x.

16.2. JAX-WS Tools

The JAX-WS tools provided by JBossWS can be used in a variety of ways. First we will look at server-side development strategies, and then proceed to the client.

16.2.1. Server side

When developing a Web Service Endpoint (the server-side) you have the option of starting from Java ( bottom-up development), or from the abstact contract (WSDL) that defines your service ( top-down development). If this is a new service (no existing contract), the bottom-up approach is the fastest route; you only need to add a few annotations to your classes to get a service up and running. However, if you are developing a service with an already defined contract, it is far simpler to use the top-down approach, since the provided tool will generate the annotated code for you.

Bottom-up use cases:

  • Exposing an already existing EJB3 bean as a Web Service

  • Providing a new service, and you want the contract to be generated for you

Top-down use cases:

  • Replacing the implementation of an existing Web Service, and you can’t break compatibility with older clients

  • Exposing a service that conforms to a contract specified by a third party (e.g. a vender that calls you back using an already defined protocol).

  • Creating a service that adheres to the XML Schema and WSDL you developed by hand up front

The following JAX-WS command line tools are included in JBossWS:

Command Description

wsprovide

Generates JAX-WS portable artifacts, and provides the abstract contract. Used for bottom-up development.

wsconsume

Consumes the abstract contract (WSDL and Schema files), and produces artifacts for both a server and client. Used for top-down and client development

Bottom-Up (Using wsprovide)

The bottom-up strategy involves developing the Java code for your service, and then annotating it using JAX-WS annotations. These annotations can be used to customize the contract that is generated for your service. For example, you can change the operation name to map to anything you like. However, all of the annotations have sensible defaults, so only the @WebService annotation is required.

This can be as simple as creating a single class:

package echo;
 
@javax.jws.WebService
public class Echo
{
   public String echo(String input)
   {
      return input;
   }
}

A JSE or EJB3 deployment can be built using this class, and it is the only Java code needed to deploy on JBossWS. The WSDL, and all other Java artifacts called "wrapper classes" will be generated for you at deploy time. This actually goes beyond the JAX-WS specification, which requires that wrapper classes be generated using an offline tool. The reason for this requirement is purely a vender implementation problem, and since we do not believe in burdening a developer with a bunch of additional steps, we generate these as well. However, if you want your deployment to be portable to other application servers, you will unfortunately need to use a tool and add the generated classes to your deployment.

This is the primary purpose of the wsprovide tool, to generate portable JAX-WS artifacts. Additionally, it can be used to "provide" the abstract contract (WSDL file) for your service. This can be obtained by invoking wsprovide using the "-w" option:

$ javac -d . -classpath jboss-jaxws.jar Echo.java
$ wsprovide -w echo.Echo
Generating WSDL:
EchoService.wsdl
Writing Classes:
echo/jaxws/Echo.class
echo/jaxws/EchoResponse.class

Inspecting the WSDL reveals a service called EchoService:

<service name='EchoService'>
 <port binding='tns:EchoBinding' name='EchoPort'>
  <soap:address location='REPLACE_WITH_ACTUAL_URL'/>
 </port>
</service>

As expected, this service defines one operation, " echo":

<portType name='Echo'>
 <operation name='echo' parameterOrder='echo'>
  <input message='tns:Echo_echo'/>
  <output message='tns:Echo_echoResponse'/>
 </operation>
</portType>
Remember that when deploying on JBossWS you do not need to run this tool. You only need it for generating portable artifacts and/or the abstract contract for your service.

Let’s create a POJO endpoint for deployment on WildFly. A simple web.xml needs to be created:

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">
 
  <servlet>
    <servlet-name>Echo</servlet-name>
    <servlet-class>echo.Echo</servlet-class>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>Echo</servlet-name>
    <url-pattern>/Echo</url-pattern>
  </servlet-mapping>
</web-app>

The web.xml and the single class can now be used to create a war:

$ mkdir -p WEB-INF/classes
$ cp -rp echo WEB-INF/classes/
$ cp web.xml WEB-INF
$ jar cvf echo.war WEB-INF
added manifest
adding: WEB-INF/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/echo/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/echo/Echo.class(in = 340) (out= 247)(deflated 27%)
adding: WEB-INF/web.xml(in = 576) (out= 271)(deflated 52%)

The war can then be deployed to the JBoss Application Server.The war can then be deployed to the JBoss Application Server; this will internally invoke wsprovide, which will generate the WSDL. If deployment was successful, and you are using the default settings, it should be available in the server management console.

For a portable JAX-WS deployment, the wrapper classes generated earlier could be added to the deployment.

Top-Down (Using wsconsume)

The top-down development strategy begins with the abstract contract for the service, which includes the WSDL file and zero or more schema files. The wsconsume tool is then used to consume this contract, and produce annotated Java classes (and optionally sources) that define it.

wsconsume may have problems with symlinks on Unix systems

Using the WSDL file from the bottom-up example, a new Java implementation that adheres to this service can be generated. The "-k" option is passed to wsconsume to preserve the Java source files that are generated, instead of providing just classes:

$ wsconsume -k EchoService.wsdl
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java

The following table shows the purpose of each generated file:

File Purpose

Echo.java

Service Endpoint Interface

Echo_Type.java

Wrapper bean for request message

EchoResponse.java

Wrapper bean for response message

ObjectFactory.java

JAXB XML Registry

package-info.java

Holder for JAXB package annotations

EchoService.java

Used only by JAX-WS clients

Examining the Service Endpoint Interface reveals annotations that are more explicit than in the class written by hand in the bottom-up example, however, these evaluate to the same contract:

@WebService(name = "Echo", targetNamespace = "http://echo/")
public interface Echo {
    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "echo", targetNamespace = "http://echo/", className = "echo.Echo_Type")
    @ResponseWrapper(localName = "echoResponse", targetNamespace = "http://echo/", className = "echo.EchoResponse")
    public String echo(
        @WebParam(name = "arg0", targetNamespace = "")
        String arg0);
 
}

The only missing piece (besides for packaging) is the implementation class, which can now be written, using the above interface.

package echo;
 
@javax.jws.WebService(endpointInterface="echo.Echo")
public class EchoImpl implements Echo
{
   public String echo(String arg0)
   {
      return arg0;
   }
}

16.2.2. Client Side

Before going to detail on the client-side it is important to understand the decoupling concept that is central to Web Services. Web Services are not the best fit for internal RPC, even though they can be used in this way. There are much better technologies for this (CORBA, and RMI for example). Web Services were designed specifically for interoperable coarse-grained correspondence. There is no expectation or guarantee that any party participating in a Web Service interaction will be at any particular location, running on any particular OS, or written in any particular programming language. So because of this, it is important to clearly separate client and server implementations. The only thing they should have in common is the abstract contract definition. If, for whatever reason, your software does not adhere to this principal, then you should not be using Web Services. For the above reasons, the recommended methodology for developing a client is to follow the top-down approach , even if the client is running on the same server.

Let’s repeat the process of the top-down section, although using the deployed WSDL, instead of the one generated offline by wsprovide. The reason why we do this is just to get the right value for soap:address. This value must be computed at deploy time, since it is based on container configuration specifics. You could of course edit the WSDL file yourself, although you need to ensure that the path is correct.

Offline version:

<service name='EchoService'>
  <port binding='tns:EchoBinding' name='EchoPort'>
   <soap:address location='REPLACE_WITH_ACTUAL_URL'/>
  </port>
</service>

Online version:

<service name="EchoService">
  <port binding="tns:EchoBinding" name="EchoPort">
    <soap:address location="http://localhost.localdomain:8080/echo/Echo"/>
  </port>
</service>

Using the online deployed version with wsconsume:

$ wsconsume -k http://localhost:8080/echo/Echo?wsdl
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java

The one class that was not examined in the top-down section, was EchoService.java. Notice how it stores the location the WSDL was obtained from.

@WebServiceClient(name = "EchoService", targetNamespace = "http://echo/", wsdlLocation = "http://localhost:8080/echo/Echo?wsdl")
public class EchoService extends Service
{
    private final static URL ECHOSERVICE_WSDL_LOCATION;
 
    static {
        URL url = null;
        try
        {
           url = new URL("http://localhost:8080/echo/Echo?wsdl");
        }
        catch (MalformedURLException e)
        {
           e.printStackTrace();
        }
        ECHOSERVICE_WSDL_LOCATION = url;
    }
 
    public EchoService(URL wsdlLocation, QName serviceName)
    {
         super(wsdlLocation, serviceName);
    }
 
    public EchoService()
    {
         super(ECHOSERVICE_WSDL_LOCATION, new QName("http://echo/", "EchoService"));
    }
 
    @WebEndpoint(name = "EchoPort")
    public Echo getEchoPort()
    {
         return (Echo)super.getPort(new QName("http://echo/", "EchoPort"), Echo.class);
    }
}

As you can see, this generated class extends the main client entry point in JAX-WS, javax.xml.ws.Service. While you can use Service directly, this is far simpler since it provides the configuration info for you. The only method we really care about is the getEchoPort() method, which returns an instance of our Service Endpoint Interface. Any WS operation can then be called by just invoking a method on the returned interface.

It’s not recommended to refer to a remote WSDL URL in a production application. This causes network I/O every time you instantiate the Service Object. Instead, use the tool on a saved local copy, or use the URL version of the constructor to provide a new WSDL location.

All that is left to do, is write and compile the client:

import echo.*;
 
public class EchoClient
{
   public static void main(String args[])
   {
      if (args.length != 1)
      {
          System.err.println("usage: EchoClient <message>");
          System.exit(1);
      }
 
      EchoService service = new EchoService();
      Echo echo = service.getEchoPort();
      System.out.println("Server said: " + echo.echo(args0));
   }
}

It is easy to change the endpoint address of your operation at runtime, setting the ENDPOINT_ADDRESS_PROPERTY as shown below:

EchoService service = new EchoService();
      Echo echo = service.getEchoPort();
 
      /* Set NEW Endpoint Location */
      String endpointURL = "http://NEW_ENDPOINT_URL";
      BindingProvider bp = (BindingProvider)echo;
      bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);
 
      System.out.println("Server said: " + echo.echo(args0));

16.3. wsconsume

wsconsume is a command line tool and ant task that "consumes" the abstract contract (WSDL file) and produces portable JAX-WS service and client artifacts.

16.3.1. Command Line Tool

The command line tool has the following usage:

usage: wsconsume [options] <wsdl-url>
options:
  -h, --help                  Show this help message
  -b, --binding=<file>        One or more JAX-WS or JAXB binding files
  -k, --keep                  Keep/Generate Java source
  -c  --catalog=<file>        Oasis XML Catalog file for entity resolution
  -j  --clientjar=<name>      Create a jar file of the generated artifacts for calling the webservice
  -p  --package=<name>        The target package for generated source
  -w  --wsdlLocation=<loc>    Value to use for @WebServiceClient.wsdlLocation
  -o, --output=<directory>    The directory to put generated artifacts
  -s, --source=<directory>    The directory to put Java source
  -t, --target=<2.0|2.1|2.2>  The JAX-WS specification target
  -q, --quiet                 Be somewhat more quiet
  -v, --verbose               Show full exception stack traces
  -l, --load-consumer         Load the consumer and exit (debug utility)
  -e, --extension             Enable SOAP 1.2 binding extension
  -a, --additionalHeaders     Enables processing of implicit SOAP headers
  -n, --nocompile             Do not compile generated sources
The wsdlLocation is used when creating the Service to be used by clients and will be added to the @WebServiceClient annotation, for an endpoint implementation based on the generated service endpoint interface you will need to manually add the wsdlLocation to the @WebService annotation on your web service implementation and not the service endpoint interface.
Examples

Generate artifacts in Java class form only:

wsconsume Example.wsdl

Generate source and class files:

wsconsume -k Example.wsdl

Generate source and class files in a custom directory:

wsconsume -k -o custom Example.wsdl

Generate source and class files in the org.foo package:

wsconsume -k -p org.foo Example.wsdl

Generate source and class files using multiple binding files:

wsconsume -k -b wsdl-binding.xml -b schema1-binding.xml -b schema2-binding.xml

16.3.2. Maven Plugin

The wsconsume tools is included in the org.jboss.ws.plugins:jaxws-tools-maven-plugin plugin. The plugin has two goals for running the tool, wsconsume and wsconsume-test, which basically do the same during different maven build phases (the former triggers the sources generation during generate-sources phase, the latter during the generate-test-sources one).

The wsconsume plugin has the following parameters:

Attribute Description Default

bindingFiles

JAXWS or JAXB binding file

true

classpathElements

Each classpathElement provides alibrary file to be added to classpath

$\{project.compileClasspathElements}or$\{project.testClasspathElements}

catalog

Oasis XML Catalog file for entity resolution

none

targetPackage

The target Java package for generated code.

generated

bindingFiles

One or more JAX-WS or JAXB binding file

none

wsdlLocation

Value to use for @WebServiceClient.wsdlLocation

generated

outputDirectory

The output directory for generated artifacts.

$\{project.build.outputDirectory}or$\{project.build.testOutputDirectory}

sourceDirectory

The output directory for Java source.

$\{project.build.directory}/wsconsume/java

verbose

Enables more informational output about command progress.

false

wsdls

The WSDL files or URLs to consume

n/a

extension

Enable SOAP 1.2 binding extension.

false

encoding

The charset encoding to use for generated sources.

$\{project.build.sourceEncoding}

argLine

An optional additional argline to be used when running in fork mode;can be used to set endorse dir, enable debugging, etc.Example<argLine>-Djava.endorsed.dirs=…​</argLine>

none

fork

Whether or not to run the generation task in a separate VM.

false

target

A preference for the JAX-WS specification target

Depends on the underlying stack and endorsed dirs if any

Examples

You can use wsconsume in your own project build simply referencing the jaxws-tools-maven-plugin in the configured plugins in your pom.xml file.

The following example makes the plugin consume the test.wsdl file and generate SEI and wrappers' java sources. The generated sources are then compiled together with the other project classes.

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Beta1</version>
      <configuration>
        <wsdls>
          <wsdl>${basedir}/test.wsdl</wsdl>
        </wsdls>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsconsume</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

You can also specify multiple wsdl files, as well as force the target package, enable SOAP 1.2 binding and turn the tool’s verbose mode on:

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Beta1</version>
      <configuration>
       <wsdls>
        <wsdl>${basedir}/test.wsdl</wsdl>
        <wsdl>${basedir}/test2.wsdl</wsdl>
       </wsdls>
       <targetPackage>foo.bar</targetPackage>
       <extension>true</extension>
       <verbose>true</verbose>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsconsume</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Finally, if the wsconsume invocation is required for consuming a wsdl to be used in your testsuite only, you might want to use the wsconsume-test goal as follows:

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Beta1</version>
      <configuration>
        <wsdls>
          <wsdl>${basedir}/test.wsdl</wsdl>
        </wsdls>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsconsume-test</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Plugin stack dependencyThe plugin itself does not have an explicit dependency to a JBossWS stack, as it’s meant for being used with implementations of any supported version of the JBossWS SPI. So the user is expected to set a dependency in his own pom.xml to the desired JBossWS stack version. The plugin will rely on the that for using the proper tooling.

<dependencies>
  <dependency>
    <groupId>org.jboss.ws.cxf</groupId>
    <artifactId>jbossws-cxf-client</artifactId>
    <version>4.0.0.GA</version>
  </dependency>
</dependencies>
Be careful when using this plugin with the Maven War Plugin as that include any project dependency into the generated application war archive. You might want to set <scope>provided</scope> for the JBossWS stack dependency to avoid that.
Up to version 1.1.2.Final, the artifactId of the plugin was maven-jaxws-tools-plugin.

16.3.3. Ant Task

The wsconsume Ant task ( org.jboss.ws.tools.ant.WSConsumeTask) has the following attributes:

Attribute Description Default

fork

Whether or not to run the generation task in a separate VM.

true

keep

Keep/Enable Java source code generation.

false

catalog

Oasis XML Catalog file for entity resolution

none

package

The target Java package for generated code.

generated

binding

A JAX-WS or JAXB binding file

none

wsdlLocation

Value to use for @WebServiceClient.wsdlLocation

generated

encoding

The charset encoding to use for generated sources

n/a

destdir

The output directory for generated artifacts.

"output"

sourcedestdir

The output directory for Java source.

value of destdir

target

The JAX-WS specification target. Allowed values are 2.0, 2.1 and 2.2

 

verbose

Enables more informational output about command progress.

false

wsdl

The WSDL file or URL

n/a

extension

Enable SOAP 1.2 binding extension.

false

additionalHeaders

Enables processing of implicit SOAP headers

false

Users also need to put streamBuffer.jar and stax-ex.jar to the classpath of the ant task to generate the appropriate artefacts.
The wsdlLocation is used when creating the Service to be used by clients and will be added to the @WebServiceClient annotation, for an endpoint implementation based on the generated service endpoint interface you will need to manually add the wsdlLocation to the @WebService annotation on your web service implementation and not the service endpoint interface.

Also, the following nested elements are supported:

Element Description Default

binding

A JAXWS or JAXB binding file

none

jvmarg

Allows setting of custom jvm arguments

 

Examples

Generate JAX-WS source and classes in a separate JVM with separate directories, a custom wsdl location attribute, and a list of binding files from foo.wsdl:

<wsconsume
  fork="true"
  verbose="true"
  destdir="output"
  sourcedestdir="gen-src"
  keep="true"
  wsdllocation="handEdited.wsdl"
  wsdl="foo.wsdl">
  <binding dir="binding-files" includes="*.xml" excludes="bad.xml"/>
</wsconsume>

16.4. wsprovide

wsprovide is a command line tool, Maven plugin and Ant task that generates portable JAX-WS artifacts for a service endpoint implementation. It also has the option to "provide" the abstract contract for offline usage.

16.4.1. Command Line Tool

The command line tool has the following usage:

usage: wsprovide [options] <endpoint class name>
options:
  -h, --help                  Show this help message
  -k, --keep                  Keep/Generate Java source
  -w, --wsdl                  Enable WSDL file generation
  -a, --address The generated port soap:address in wsdl
  -c. --classpath=<path>      The classpath that contains the endpoint
  -o, --output=<directory>    The directory to put generated artifacts
  -r, --resource=<directory>  The directory to put resource artifacts
  -s, --source=<directory>    The directory to put Java source
  -e, --extension             Enable SOAP 1.2 binding extension
  -q, --quiet                 Be somewhat more quiet
  -t, --show-traces           Show full exception stack traces
Examples

Generating wrapper classes for portable artifacts in the "generated" directory:

wsprovide -o generated foo.Endpoint

Generating wrapper classes and WSDL in the "generated" directory

wsprovide -o generated -w foo.Endpoint

Using an endpoint that references other jars

wsprovide -o generated -c application1.jar:application2.jar foo.Endpoint

16.4.2. Maven Plugin

The wsprovide tools is included in the org.jboss.ws.plugins:jaxws-tools- maven- plugin plugin. The plugin has two goals for running the tool, wsprovide and wsprovide-test, which basically do the same during different Maven build phases (the former triggers the sources generation during process-classes phase, the latter during the process-test-classes one).

The wsprovide plugin has the following parameters:

Attribute Description Default

testClasspathElements

Each classpathElement provides alibrary file to be added to classpath

$\{project.compileClasspathElements}or$\{project.testClasspathElements}

outputDirectory

The output directory for generated artifacts.

$\{project.build.outputDirectory}or$\{project.build.testOutputDirectory}

resourceDirectory

The output directory for resource artifacts (WSDL/XSD).

$\{project.build.directory}/wsprovide/resources

sourceDirectory

The output directory for Java source.

$\{project.build.directory}/wsprovide/java

extension

Enable SOAP 1.2 binding extension.

false

generateWsdl

Whether or not to generate WSDL.

false

verbose

Enables more informational output about command progress.

false

portSoapAddress

The generated port soap:address in the WSDL

 

endpointClass

Service Endpoint Implementation.

 

Examples

You can use wsprovide in your own project build simply referencing the maven-jaxws-tools-plugin in the configured plugins in your pom.xml file.

The following example makes the plugin provide the wsdl file and artifact sources for the specified endpoint class:

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Beta1</version>
      <configuration>
        <verbose>true</verbose>
        <endpointClass>org.jboss.test.ws.plugins.tools.wsprovide.TestEndpoint</endpointClass>
        <generateWsdl>true</generateWsdl>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsprovide</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

The following example does the same, but is meant for use in your own testsuite:

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Beta1</version>
      <configuration>
        <verbose>true</verbose>
        <endpointClass>org.jboss.test.ws.plugins.tools.wsprovide.TestEndpoint2</endpointClass>
        <generateWsdl>true</generateWsdl>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsprovide-test</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Plugin stack dependencyThe plugin itself does not have an explicit dependency to a JBossWS stack, as it’s meant for being used with implementations of any supported version of the JBossWS SPI. So the user is expected to set a dependency in his own pom.xml to the desired JBossWS stack version. The plugin will rely on the that for using the proper tooling.

<dependencies>
  <dependency>
    <groupId>org.jboss.ws.cxf</groupId>
    <artifactId>jbossws-cxf-client</artifactId>
    <version>5.0.0.CR1</version>
  </dependency>
</dependencies>
Be careful when using this plugin with the Maven War Plugin as that include any project dependency into the generated application war archive. You might want to set <scope>provided</scope> for the JBossWS stack dependency to avoid that.
Up to version 1.1.2.Final, the artifactId of the plugin was maven-jaxws-tools-plugin.

16.4.3. Ant Task

The wsprovide ant task ( org.jboss.ws.tools.ant.WSProvideTask) has the following attributes:

Attribute Description Default

fork

Whether or not to run the generation task in a separate VM.

true

keep

Keep/Enable Java source code generation.

false

destdir

The output directory for generated artifacts.

"output"

resourcedestdir

The output directory for resource artifacts (WSDL/XSD).

value of destdir

sourcedestdir

The output directory for Java source.

value of destdir

extension

Enable SOAP 1.2 binding extension.

false

genwsdl

Whether or not to generate WSDL.

false

address

The generated port soap:address in wsdl.

 

verbose

Enables more informational output about command progress.

false

sei

Service Endpoint Implementation.

 

classpath

The classpath that contains the service endpoint implementation.

"."

Examples

Executing wsprovide in verbose mode with separate output directories for source, resources, and classes:

<target name="test-wsproivde" depends="init">
  <taskdef name="wsprovide" classname="org.jboss.ws.tools.ant.WSProvideTask">
    <classpath refid="core.classpath"/>
  </taskdef>
  <wsprovide
    fork="false"
    keep="true"
    destdir="out"
    resourcedestdir="out-resource"
    sourcedestdir="out-source"
    genwsdl="true"
    verbose="true"
    sei="org.jboss.test.ws.jaxws.jsr181.soapbinding.DocWrappedServiceImpl">
    <classpath>
      <pathelement path="${tests.output.dir}/classes"/>
    </classpath>
  </wsprovide>
</target>

16.5. Advanced User Guide

16.5.1. Logging

Logging of inbound and outbound messages is a common need. Different approaches are available for achieving that:

JAX-WS Handler approach

A portable way of performing logging is writing a simple JAX-WS handler dumping the messages that are passed in it; the handler can be added to the desired client/endpoints (programmatically / using @HandlerChain JAX-WS annotation).

The predefined client and endpoint configuration mechanism allows user to add the logging handler to any client/endpoint or to some of them only (in which case the @EndpointConfig annotation / JBossWS API is required though).

Apache CXF approach

Apache CXF also comes with logging interceptors that can be easily used to log messages to the console or configured client/server log files. Those interceptors can be added to client, endpoint and buses in multiple ways:

System property

Setting the org.apache.cxf.logging.enabled system property to true causes the logging interceptors to be added to any Bus instance being created on the JVM.

On WildFly, the system property is easily set by adding what follows to the standalone / domain server configuration just after the extensions section:
<system-properties>
  <property name="org.apache.cxf.logging.enabled" value="true"/>
</system-properties>
Manual interceptor addition and logging feature

Logging interceptors can be selectively added to endpoints using the Apache CXF annotations @org.apache.cxf.interceptor.InInterceptors and @org.apache.cxf.interceptor.OutInterceptors. The same is achieved on client side by programmatically adding new instances of the logging interceptors to the client or the bus.

Alternatively, Apache CXF also comes with a org.apache.cxf.feature.LoggingFeature that can be used on clients and endpoints (either annotating them with @org.apache.cxf.feature.Features or directly with @org.apache.cxf.annotations.Logging).

Please refer to the Apache CXF documentation for more details.

16.5.2. WS-* support

JBossWS includes most of the WS-* specification functionalities through the integration with Apache CXF. In particular, the whole WS-Security Policy framework is fully supported, enabling full contract driven configuration of complex features like WS-Security.

In details information available further down in this documentation book.

16.5.3. Address rewrite

JBossWS allows users to configure the soap:address attribute in the wsdl contract of deployed services.

Server configuration options

The configuration options are part of the webservices subsystem section of the application server domain model.

<subsystem xmlns="urn:jboss:domain:webservices:1.1" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  xmlns:jaxwsconfig="urn:jboss:jbossws-jaxws-config:4.0">
  <wsdl-host>localhost</wsdl-host>
  <modify-wsdl-address>true</modify-wsdl-address>
<!--
  <wsdl-port>8080</wsdl-port>
  <wsdl-secure-port>8443</wsdl-secure-port>
-->
</subsystem>

If the content of <soap:address> in the wsdl is a valid URL, JBossWS will not rewrite it unless modify-wsdl-address is true. If the content of <soap:address> is not a valid URL instead, JBossWS will always rewrite it using the attribute values given below. Please note that the variable $\{jboss.bind.address} can be used to set the address which the application is bound to at each startup.

The wsdl-secure-port and wsdl-port attributes are used to explicitly define the ports to be used for rewriting the SOAP address. If these attributes are not set, the ports will be identified by querying the list of installed connectors. If multiple connectors are found the port of the first connector is used.

Dynamic rewrite

When the application server is bound to multiple addresses or non-trivial real-world network architectures cause request for different external addresses to hit the same endpoint, a static rewrite of the soap:address may not be enough. JBossWS allows for both the soap:address in the wsdl and the wsdl address in the console to be rewritten with the host use in the client request. This way, users always get the right wsdl address assuming they’re connecting to an instance having the endpoint they’re looking for. To trigger this behaviour, the jbossws.undefined.host value has to be specified for the wsdl-host element.

<wsdl-host>jbossws.undefined.host</wsdl-host>
<modify-wsdl-address>true</modify-wsdl-address>

Of course, when a confidential transport address is required, the addresses are always rewritten using https protocol and the port currently configured for the https/ssl connector.

16.5.4. Configuration through deployment descriptor

The jboss-webservices.xml deployment descriptor can be used to provide additional configuration for a given deployment. The expected location of it is:

  • META-INF/jboss-webservices.xml for EJB webservice deployments

  • WEB-INF/jboss-webservices.xml for POJO webservice deployments and EJB webservice endpoints bundled in war archives

The structure of file is the following (schemas are available here):

<webservices>
  <context-root/>?
  <config-name/>?
  <config-file/>?
  <property>*
    <name/>
    <value/>
  </property>
  <port-component>*
    <ejb-name/>
    <port-component-name/>
    <port-component-uri/>?
    <auth-method/>?
    <transport-guarantee/>?
    <secure-wsdl-access/>?
  </port-component>
  <webservice-description>*
    <webservice-description-name/>
    <wsdl-publish-location/>?
  </webservice-description>
</webservices>
context-root element

Element <context-root> can be used to customize context root of webservices deployment.

<webservices>
  <context-root>foo</context-root>
</webservices>
config-name and config-file elements

Elements <config-name> and <config-file> can be used to associate any endpoint provided in the deployment with a given endpoint configuration. Endpoint configuration are either specified in the referenced config file or in the WildFly domain model (webservices subsystem). For further details on the endpoint configurations and their management in the domain model, please see the related documentation.

<webservices>
  <config-name>Standard WSSecurity Endpoint</config-name>
  <config-file>META-INF/custom.xml</config-file>
</webservices>
property element

<property> elements can be used to setup simple property values to configure the ws stack behavior. Allowed property names and values are mentioned in the guide under related topics.

<property>
  <name>prop.name</name>
  <value>prop.value</value>
</property>
port-component element

Element <port-component> can be used to customize EJB endpoint target URI or to configure security related properties.

<webservices>
  <port-component>
    <ejb-name>TestService</ejb-name>
    <port-component-name>TestServicePort</port-component-name>
    <port-component-uri>/*</port-component-uri>
    <auth-method>BASIC</auth-method>
    <transport-guarantee>NONE</transport-guarantee>
    <secure-wsdl-access>true</secure-wsdl-access>
  </port-component>
</webservices>
webservice-description element

Element <webservice-description> can be used to customize (override) webservice WSDL publish location.

<webservices>
  <webservice-description>
    <webservice-description-name>TestService</webservice-description-name>
    <wsdl-publish-location>file:///bar/foo.wsdl</wsdl-publish-location>
  </webservice-description>
</webservices>

16.5.5. Schema validation of SOAP messages

Apache CXF has a feature for validating incoming and outgoing SOAP messages on both client and server side. The validation is performed against the relevant schema in the endpoint wsdl contract (server side) or the wsdl contract used for building up the service proxy (client side).

Schema validation can be turned on programmatically on client side

((BindingProvider)proxy).getRequestContext().put("schema-validation-enabled", true);

or using the @org.apache.cxf.annotations.SchemaValidation annotation on server side

import javax.jws.WebService;
import org.apache.cxf.annotations.SchemaValidation;
 
@WebService(...)
@SchemaValidation
public class ValidatingHelloImpl implements Hello {
   ...
}

Alternatively, any endpoint and client running in-container can be associated to a JBossWS predefined configuration having the schema-validation-enabled property set to true in the referenced config file.

Finally, JBossWS also allows for server-wide (default) setup of schema validation by using the Standard-Endpoint-Config and Standard-Client-Config special configurations (which apply to any client / endpoint unless a different configuration is specified for them)

<subsystem xmlns="urn:jboss:domain:webservices:1.2">
    ...
    <endpoint-config name="Standard-Endpoint-Config">
        <property name="schema-validation-enabled" value="true"/>
    </endpoint-config>
    ...
    <client-config name="Standard-Client-Config">
        <property name="schema-validation-enabled" value="true"/>
    </client-config>
</subsystem>

16.5.6. JAXB Introductions

As Kohsuke Kawaguchi wrote on his blog, one common complaint from the JAXB users is the lack of support for binding 3rd party classes. The scenario is this: you are trying to annotate your classes with JAXB annotations to make it XML bindable, but some of the classes are coming from libraries and JDK, and thus you cannot put necessary JAXB annotations on it.

To solve this JAXB has been designed to provide hooks for programmatic introduction of annotations to the runtime.

This is currently leveraged by the JBoss JAXB Introductions project, using which users can define annotations in XML and make JAXB see those as if those were in the class files (perhaps coming from 3rd party libraries).

Take a look at the JAXB Introductions page on the wiki and at the examples in the sources.

16.5.7. WSDL system properties expansion

16.5.8. Predefined client and endpoint configurations

JBossWS permits extra setup configuration data to be predefined and associated with an endpoint or a client. Configurations can include JAX-WS handlers and key/value property declarations that control JBossWS and Apache CXF internals. Predefined configurations can be used for JAX-WS client and JAX-WS endpoint setup.

Configurations can be defined in the webservice subsystem and in an application’s deployment descriptor file. There can be many configuration definitions in the webservice subsystem and in an application. Each configuration must have a name that is unique within the server. Configurations defined in an application are local to the application. Endpoint implementations declare the use of a specific configuration through the use of the org.jboss.ws.api.annotation.EndpointConfig annotation. An endpoint configuration defined in the webservices subsystem is available to all deployed applications on the server container and can be referenced by name in the annotation. An endpoint configuration defined in an application must be referenced by both deployment descriptor file name and configuration name by the annotation.

Handlers

Each endpoint configuration may be associated with zero or more PRE and POST handler chains. Each handler chain may include JAXWS handlers. For outbound messages the PRE handler chains are executed before any handler that is attached to the endpoint using the standard means, such as with annotation @HandlerChain, and POST handler chains are executed after those objects have executed. For inbound messages the POST handler chains are executed before any handler that is attached to the endpoint using the standard means and the PRE handler chains are executed after those objects have executed.

* Server inbound messages
Client --> ... --> POST HANDLER --> ENDPOINT HANDLERS --> PRE HANDLERS --> Endpoint

* Server outbound messages
Endpoint --> PRE HANDLER --> ENDPOINT HANDLERS --> POST HANDLERS --> ... --> Client

The same applies for client configurations.

Properties

Key/value properties are used for controlling both some Apache CXF internals and some JBossWS options. Specific supported values are mentioned where relevant in the rest of the documentation.

Assigning configurations

Endpoints and clients are assigned configuration through different means. Users can explicitly require a given configuration or rely on container defaults. The assignment process can be split up as follows:

  • Explicit assignment through annotations (for endpoints) or API programmatic usage (for clients)

  • Automatic assignment of configurations from default descriptors

  • Automatic assignment of configurations from container

Endpoint configuration assignment

The explicit configuration assignment is meant for developer that know in advance their endpoint or client has to be setup according to a specified configuration. The configuration is either coming from a descriptor that is included in the application deployment, or is included in the application server webservices subsystem management model.

Endpoint Configuration Deployment Descriptor

Jakarta EE archives that can contain JAX-WS client and endpoint implementations can also contain predefined client and endpoint configuration declarations. All endpoint/client configuration definitions for a given archive must be provided in a single deployment descriptor file, which must be an implementation of schema jbossws-jaxws-config. Many endpoint/client configurations can be defined in the deployment descriptor file. Each configuration must have a name that is unique within the server on which the application is deployed. The configuration name can’t be referred to by endpoint/client implementations outside the application. Here is an example of a descriptor, containing two endpoint configurations:

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
<endpoint-config>
<config-name>org.jboss.test.ws.jaxws.jbws3282.Endpoint4Impl</config-name>
<pre-handler-chains>
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-name>Log Handler</javaee:handler-name>
<javaee:handler-class>org.jboss.test.ws.jaxws.jbws3282.LogHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</pre-handler-chains>
<post-handler-chains>
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-name>Routing Handler</javaee:handler-name>
<javaee:handler-class>org.jboss.test.ws.jaxws.jbws3282.RoutingHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</post-handler-chains>
</endpoint-config>
<endpoint-config>
<config-name>EP6-config</config-name>
<post-handler-chains>
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-name>Authorization Handler</javaee:handler-name>
<javaee:handler-class>org.jboss.test.ws.jaxws.jbws3282.AuthorizationHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</post-handler-chains>
</endpoint-config>
</jaxws-config>

Similarly, client configurations can be specified in descriptors (still implementing the schema mentioned above):

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
<client-config>
<config-name>Custom Client Config</config-name>
<pre-handler-chains>
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-name>Routing Handler</javaee:handler-name>
<javaee:handler-class>org.jboss.test.ws.jaxws.clientConfig.RoutingHandler</javaee:handler-class>
</javaee:handler>
<javaee:handler>
<javaee:handler-name>Custom Handler</javaee:handler-name>
<javaee:handler-class>org.jboss.test.ws.jaxws.clientConfig.CustomHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</pre-handler-chains>
</client-config>
<client-config>
<config-name>Another Client Config</config-name>
<post-handler-chains>
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-name>Routing Handler</javaee:handler-name>
<javaee:handler-class>org.jboss.test.ws.jaxws.clientConfig.RoutingHandler</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</post-handler-chains>
</client-config>
</jaxws-config>
Application server configurations

WildFly allows declaring JBossWS client and server predefined configurations in the webservices subsystem section of the server model. As a consequence it is possible to declare server-wide handlers to be added to the chain of each endpoint or client assigned to a given configuration.

Please refer to the WildFly documentation for details on managing the webservices subsystem such as adding, removing and modifying handlers and properties.

The allowed contents in the webservices subsystem are defined by the schema included in the application server.

Standard configurations

Clients running in-container as well as endpoints are assigned standard configurations by default. The defaults are used unless different configurations are set as described on this page. This enables administrators to tune the default handler chains for client and endpoint configurations. The names of the default client and endpoint configurations, used in the webservices subsystem are Standard-Client-Config and Standard-Endpoint-Config respectively.

Handlers classloading

When setting a server-wide handler, please note the handler class needs to be available through each ws deployment classloader. As a consequence proper module dependencies might need to be specified in the deployments that are going to leverage a given predefined configuration. A shortcut is to add a dependency to the module containing the handler class in one of the modules which are already automatically set as dependencies to any deployment, for instance org.jboss.ws.spi.

Examples
JBoss AS 7.2 default configurations
<subsystem xmlns="urn:jboss:domain:webservices:2.0">
<!-- ... -->
<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" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
</pre-handler-chain>
</endpoint-config>
<client-config name="Standard-Client-Config"/>
</subsystem>
A configuration file for a deployment specific ws-security endpoint

setup

<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:javaee="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
<endpoint-config>
<config-name>Custom WS-Security Endpoint</config-name>
<property>
<property-name>ws-security.signature.properties</property-name>
<property-value>bob.properties</property-value>
</property>
<property>
<property-name>ws-security.encryption.properties</property-name>
<property-value>bob.properties</property-value>
</property>
<property>
<property-name>ws-security.signature.username</property-name>
<property-value>bob</property-value>
</property>
<property>
<property-name>ws-security.encryption.username</property-name>
<property-value>alice</property-value>
</property>
<property>
<property-name>ws-security.callback-handler</property-name>
<property-value>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback</property-value>
</property>
</endpoint-config>
</jaxws-config>
JBoss AS 7.2 default configurations modified to default to SOAP

messages schema-validation on

<subsystem xmlns="urn:jboss:domain:webservices:2.0">
<!-- ... -->
<endpoint-config name="Standard-Endpoint-Config">
<property name="schema-validation-enabled" value="true"/>
</endpoint-config>
<!-- ... -->
<client-config name="Standard-Client-Config">
<property name="schema-validation-enabled" value="true"/>
</client-config>
</subsystem>
EndpointConfig annotation

Once a configuration is available to a given application, the org.jboss.ws.api.annotation.EndpointConfig annotation is used to assign an endpoint configuration to a JAX-WS endpoint implementation. When assigning a configuration that is defined in the webservices subsystem only the configuration name is specified. When assigning a configuration that is defined in the application, the relative path to the deployment descriptor and the configuration name must be specified.

@EndpointConfig(configFile = "WEB-INF/my-endpoint-config.xml", configName = "Custom WS-Security Endpoint")
public class ServiceImpl implements ServiceIface
{
public String sayHello()
{
return "Secure Hello World!";
}
}
JAXWS Feature

The most practical way of setting a configuration is using org.jboss.ws.api.configuration.ClientConfigFeature, a JAXWS Feature extension provided by JBossWS:

import org.jboss.ws.api.configuration.ClientConfigFeature;
 
...
 
Service service = Service.create(wsdlURL, serviceName);
Endpoint port = service.getPort(Endpoint.class, new ClientConfigFeature("META-INF/my-client-config.xml", "Custom Client Config"));
port.echo("Kermit");
 
... or ....
 
port = service.getPort(Endpoint.class, new ClientConfigFeature("META-INF/my-client-config.xml", "Custom Client Config"), true); //setup properties too from the configuration
port.echo("Kermit");
... or ...
 
port = service.getPort(Endpoint.class, new ClientConfigFeature(null, testConfigName)); //reads from current container configurations if available
port.echo("Kermit");

JBossWS parses the specified configuration file. The configuration file must be found as a resource by the classloader of the current thread. The jbossws-jaxws-config schema defines the descriptor contents and is included in the jbossws-spi artifact.

Explicit setup through API

Alternatively, JBossWS API comes with facility classes that can be used for assigning configurations when building a client. JAXWS handlers read from client configurations as follows:

import org.jboss.ws.api.configuration.ClientConfigUtil;
import org.jboss.ws.api.configuration.ClientConfigurer;
 
...
 
Service service = Service.create(wsdlURL, serviceName);
Endpoint port = service.getPort(Endpoint.class);
BindingProvider bp = (BindingProvider)port;
ClientConfigUtil.setConfigHandlers(bp, "META-INF/my-client-config.xml", "Custom Client Config 1");
port.echo("Kermit");
 
...
 
ClientConfigurer configurer = ClientConfigUtil.resolveClientConfigurer();
configurer.setConfigHandlers(bp, "META-INF/my-client-config.xml", "Custom Client Config 2");
port.echo("Kermit");
 
...
 
configurer.setConfigHandlers(bp, "META-INF/my-client-config.xml", "Custom Client Config 3");
port.echo("Kermit");
 
 
...
 
configurer.setConfigHandlers(bp, null, "Container Custom Client Config"); //reads from current container configurations if available
port.echo("Kermit");
  1. similarly, properties are read from client configurations as follows:

import org.jboss.ws.api.configuration.ClientConfigUtil;
import org.jboss.ws.api.configuration.ClientConfigurer;
 
...
 
Service service = Service.create(wsdlURL, serviceName);
Endpoint port = service.getPort(Endpoint.class);
 
ClientConfigUtil.setConfigProperties(port, "META-INF/my-client-config.xml", "Custom Client Config 1");
port.echo("Kermit");
 
...
 
ClientConfigurer configurer = ClientConfigUtil.resolveClientConfigurer();
configurer.setConfigProperties(port, "META-INF/my-client-config.xml", "Custom Client Config 2");
port.echo("Kermit");
 
...
 
configurer.setConfigProperties(port, "META-INF/my-client-config.xml", "Custom Client Config 3");
port.echo("Kermit");
 
 
...
 
configurer.setConfigProperties(port, null, "Container Custom Client Config"); //reads from current container configurations if available
port.echo("Kermit");

...

configurer.setConfigProperties(port, null, null); //reads from current Elytron client configuration if available
port.echo("Kermit");

The default ClientConfigurer implementation parses the specified configuration file, if any, after having resolved it as a resources using the current thread context classloader. The jbossws-jaxws-config schema defines the descriptor contents and is included in the jbossws-spi artifact.

If WildFly Elytron client configuration is present, the client will automatically use SSL context and credentials (for HTTP Basic authentication or Username Token Profile) from this configuration if these were not already configured.

Automatic configuration from default descriptors

In some cases, the application developer might not be aware of the configuration that will need to be used for its client and endpoint implementation, perhaps because that’s a concern of the application deployer. In other cases, explicit usage (compile time dependency) of JBossWS API might not be accepted. To cope with such scenarios, JBossWS allows including default client ( jaxws-client-config.xml) and endpoint ( jaxws-endpoint-config.xml) descriptor within the application (in its root), which are parsed for getting configurations any time a configuration file name is not specified.

If the configuration name is also not specified, JBossWS automatically looks for a configuration named the same as

  • the endpoint implementation class (full qualified name), in case of JAX-WS endpoints;

  • the service endpoint interface (full qualified name), in case of JAX-WS clients.

No automatic configuration name is selected for Dispatch clients.

So, for instance, an endpoint implementation class org.foo.bar.EndpointImpl for which no pre-defined configuration is explicitly set will cause JBossWS to look for a org.foo.bar.EndpointImpl named configuration within a jaxws-endpoint-config.xml descriptor in the root of the application deployment. Similarly, on client side, a client proxy implementing org.foo.bar.Endpoint interface (SEI) will have the setup read from a org.foo.bar.Endpoint named configuration in jaxws-client-config.xml descriptor.

Automatic configuration assignment from container setup

JBossWS fall-backs to getting predefined configurations from the container setup whenever no explicit configuration has been provided and the default descriptors are either not available or do not contain relevant configurations. This gives additional control on the JAX-WS client and endpoint setup to administrators, as the container setup can be managed independently from the deployed applications.
JBossWS hence accesses the webservices subsystem the same as explained above for explicitly named configuration; the default configuration names used for look are

  • the endpoint implementation class (full qualified name), in case of JAX-WS endpoints;

  • the service endpoint interface (full qualified name), in case of JAX-WS clients.
    Dispatch clients are not automatically configured. If no configuration is found using names computed as above, the Standard-Client-Config and Standard-Endpoint-Config configurations are used for clients and endpoints respectively

16.5.9. Authentication

Authentication

Here the simplest way to authenticate a web service user with JBossWS is explained.

First we secure the access to the SLSB as we would do for normal (non web service) invocations: this can be easily done through the @RolesAllowed, @PermitAll, @DenyAll annotation. The allowed user roles can be set with these annotations both on the bean class and on any of its business methods.

@Stateless
@RolesAllowed("friend")
public class EndpointEJB implements EndpointInterface
{
  ...
}

Similarly POJO endpoints are secured the same way as we do for normal web applications in web.xml:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>All resources</web-resource-name>
    <url-pattern>/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>friend</role-name>
  </auth-constraint>
</security-constraint>
 
<security-role>
  <role-name>friend</role-name>
</security-role>
Specify the security domain

Next, specify the security domain for this deployment. This is performed using the @SecurityDomain annotation for EJB3 endpoints

@Stateless
@SecurityDomain("JBossWS")
@RolesAllowed("friend")
public class EndpointEJB implements EndpointInterface
{
  ...
}

or modifying the jboss-web.xml for POJO endpoints

<jboss-web>
<security-domain>JBossWS</security-domain>
</jboss-web>

The security domain as well as its the authentication and authorization mechanisms are defined differently depending on the application server version in use.

Use BindingProvider to set principal/credential

A web service client may use the javax.xml.ws.BindingProvider interface to set the username/password combination

URL wsdlURL = new File("resources/jaxws/samples/context/WEB-INF/wsdl/TestEndpoint.wsdl").toURL();
QName qname = new QName("http://org.jboss.ws/jaxws/context", "TestEndpointService");
Service service = Service.create(wsdlURL, qname);
port = (TestEndpoint)service.getPort(TestEndpoint.class);
 
BindingProvider bp = (BindingProvider)port;
bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "kermit");
bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "thefrog");
Using HTTP Basic Auth for security

To enable HTTP Basic authentication you use the @WebContext annotation on the bean class

@Stateless
@SecurityDomain("JBossWS")
@RolesAllowed("friend")
@WebContext(contextRoot="/my-cxt", urlPattern="/*", authMethod="BASIC", transportGuarantee="NONE", secureWSDLAccess=false)
public class EndpointEJB implements EndpointInterface
{
  ...
}

For POJO endpoints, we modify the web.xml adding the auth-method element:

<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Test Realm</realm-name>
</login-config>
JASPI Authentication

A Java Authentication SPI (JASPI) provider can be configured in WildFly security subsystem to authenticate SOAP messages:

<security-domain name="jaspi">
<authentication-jaspi>
<login-module-stack name="jaas-lm-stack">
<login-module code="UsersRoles" flag="required">
<module-option name="usersProperties" value="jbossws-users.properties"/>
<module-option name="rolesProperties" value="jbossws-roles.properties"/>
</login-module>
</login-module-stack>
<auth-module code="org.jboss.wsf.stack.cxf.jaspi.module.UsernameTokenServerAuthModule" login-module-stack-ref="jaas-lm-stack"/>
</authentication-jaspi>
</security-domain>
For further information on configuring security domains in WildFly, please refer to here.

Here org.jboss.wsf.stack.cxf.jaspi.module.UsernameTokenServerAuthModule is the class implementing javax.security.auth.message.module.ServerAuthModule, which delegates to the proper login module to perform authentication using the credentials from WS-Security UsernameToken in the incoming SOAP message. Alternative implementations of ServerAuthModule can be implemented and configured.

To enable JASPI authentication, the endpoint deployment needs to specify the security domain to use; that can be done in two different ways:

  • Setting the jaspi.security.domain property in the jboss-webservices.xml descriptor

<?xml version="1.1" encoding="UTF-8"?>
<webservices
xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="1.2"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">
 
<property>
<name>jaspi.security.domain</name>
<value>jaspi</value>
</property>
 
</webservices>
  • Referencing (through @EndpointConfig annotation) an endpoint config that sets the jaspi.security.domain property

@EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "jaspiSecurityDomain")
public class ServiceEndpointImpl implements ServiceIface {

The jaspi.security.domain property is specified as follows in the referenced descriptor:

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
<endpoint-config>
<config-name>jaspiSecurityDomain</config-name>
<property>
<property-name>jaspi.security.domain</property-name>
<property-value>jaspi</property-value>
</property>
</endpoint-config>
</jaxws-config>
If the JASPI security domain is specified in both jboss-webservices.xml and config file referenced by @EndpointConfig annotation, the JASPI security domain specified in jboss-webservices.xml will take precedence.

16.5.10. Apache CXF integration

JBossWS integration layer with Apache CXF

All JAX-WS functionalities provided by JBossWS on top of WildFly are currently served through a proper integration of the JBoss Web Services stack with most of the Apache CXF project modules.

Apache CXF is an open source services framework. It allows building and developing services using frontend programming APIs (including JAX-WS), with services speaking a variety of protocols such as SOAP and XML/HTTP over a variety of transports such as HTTP and JMS.

The integration layer ( JBossWS-CXF in short hereafter) is mainly meant for:

  • allowing using standard webservices APIs (including JAX-WS) on WildFly; this is performed internally leveraging Apache CXF without requiring the user to deal with it;

  • allowing using Apache CXF advanced features (including WS-*) on top of WildFly without requiring the user to deal with / setup / care about the required integration steps for running in such a container.

In order for achieving the goals above, the JBossWS-CXF integration supports the JBoss ws endpoint deployment mechanism and comes with many internal customizations on top of Apache CXF.

In the next sections a list of technical suggestions and notes on the integration is provided; please also refer to the Apache CXF official documentation for in-depth details on the CXF architecture.

Building WS applications the JBoss way

The Apache CXF client and endpoint configuration as explained in the Apache CXF official user guide is heavily based on Spring. Apache CXF basically parses Spring cxf.xml descriptors; those may contain any basic bean plus specific ws client and endpoint beans which CXF has custom parsers for. Apache CXF can be used to deploy webservice endpoints on any servlet container by including its libraries in the deployment; in such a scenario Spring basically serves as a convenient configuration option, given direct Apache CXF API usage won’t be very handy. Similar reasoning applies on client side, where a Spring based descriptor offers a shortcut for setting up Apache CXF internals.

This said, nowadays almost any Apache CXF functionality can be configured and used through direct API usage, without Spring. As a consequence of that and given the considerations in the sections below, the JBossWS integration with Apache CXF does not rely on Spring descriptors.

Portable applications

WildFly is much more then a servlet container; it actually provides users with a fully compliant target platform for Jakarta EE applications.

Generally speaking, users are encouraged to write portable applications by relying only on JAX-WS specification whenever possible. That would by the way ensure easy migrations to and from other compliant platforms. Being a Jakarta EE container, WildFly already comes with a JAX-WS compliant implementation, which is basically Apache CXF plus the JBossWS-CXF integration layer. So users just need to write their JAX-WS application; no need for embedding any Apache CXF or any ws related dependency library in user deployments. Please refer to the JAX-WS User Guide section of the documentation for getting started.

WS-* usage (including WS-Security, WS-Addressing, WS-ReliableMessaging, …​) should also be configured in the most portable way; that is by relying on proper WS-Policy assertions on the endpoint WSDL contracts, so that client and endpoint configuration is basically a matter of setting few ws context properties. The WS-* related sections of this documentation cover all the details on configuring applications making use of WS-* through policies.

As a consequence of the reasoning above, the JBossWS-CXF integration is currently built directly on the Apache CXF API and aims at allowing users to configure webservice clients and endpoints without Spring descriptors.

Direct Apache CXF API usage

Whenever users can’t really meet their application requirements with JAX-WS plus WS-Policy, it is of course still possible to rely on direct Apache CXF API usage (given that’s included in the AS), loosing the Java EE portability of the application. That could be the case of a user needing specific Apache CXF functionalities, or having to consume WS-* enabled endpoints advertised through legacy wsdl contracts without WS-Policy assertions.

On server side, direct Apache CXF API usage might not be always possible or end up being not very easy. For this reason, the JBossWS integration comes with a convenient alternative through customization options in the jboss-webservices.xml descriptor described below on this page. Properties can be declared in jboss-webservices.xml to control Apache CXF internals like interceptors, features, etc.

Bus usage
Creating a Bus instance

Most of the Apache CXF features are configurable using the org.apache.cxf.Bus class. While for basic JAX-WS usage the user might never need to explicitly deal with Bus, using Apache CXF specific features generally requires getting a handle to a org.apache.cxf.Bus instance. This can happen on client side as well as in a ws endpoint or handler business code.

New Bus instances are produced by the currently configured org.apache.cxf.BusFactory implementation the following way:

Bus bus = BusFactory.newInstance().createBus();

The algorithm for selecting the actual implementation of BusFactory to be used leverages the Service API, basically looking for optional configurations in META-INF/services/…​ location using the current thread context classloader. JBossWS-CXF integration comes with its own implementation of BusFactory, org.jboss.wsf.stack.cxf.client.configuration.JBossWSBusFactory, that allows for seamless setup of JBossWS customizations on top of Apache CXF. So, assuming the JBossWS-CXF libraries are available in the current thread context classloader, the JBossWSBusFactory is automatically retrieved by the BusFactory.newInstance() call above.

JBossWS users willing to explicitly use functionalities of org.apache.cxf.bus.CXFBusFactory , get the same API with JBossWS additions through JBossWSBusFactory:

Map<Class, Object> myExtensions = new HashMap<Class, Object>();
myExtensions.put(...);
Bus bus = new JBossWSBusFactory().createBus(myExtensions);
Using existing Bus instances

Apache CXF keeps reference to a global default Bus instance as well as to a thread default bus for each thread. That is performed through static members in org.apache.cxf.BusFactory , which also comes with the following methods in the public API:

public static synchronized Bus getDefaultBus()
public static synchronized Bus getDefaultBus(boolean createIfNeeded)
public static synchronized void setDefaultBus(Bus bus)
public static Bus getThreadDefaultBus()
public static Bus getThreadDefaultBus(boolean createIfNeeded)
public static void setThreadDefaultBus(Bus bus)

Please note that the default behaviour of getDefaultBus() / getDefaultBus(true) / getThreadDefaultBus() / getThreadDefaultBus(true) is to create a new Bus instance if that’s not set yet. Moreover getThreadDefaultBus() and getThreadDefaultBus(true) first fallback to retrieving the configured global default bus before actually trying creating a new instance (and the created new instance is set as global default bus if that was not set there yet).

The drawback of this mechanism (which is basically fine in JSE environment) is that when running in WildFly container you need to be careful in order not to (mis)use a bus over multiple applications (assuming the Apache CXF classes are loaded by the same classloader, which is currently the case with WildFly).

Here is a list of general suggestions to avoid problems when running in-container:

  • forget about the global default bus; you don’t need that, so don’t do getDefaultBus() / getDefaultBus(true) / setDefaultBus() in your code;

  • avoid getThreadDefaultBus() / getThreadDefaultBus(true) unless you already know for sure the default bus is already set;

  • keep in mind thread pooling whenever you customize a thread default bus instance (for instance adding bus scope interceptors, …​), as that thread and bus might be later reused; so either shutdown the bus when you’re done or explicitly remove it from the BusFactory thread association.

Finally, remember that each time you explictly create a new Bus instance (factory.createBus()) that is set as thread default bus and global default bus if those are not set yet. The JAXWS Provider implementation also creates Bus instances internally, in particular the JBossWS version of JAXWS Provider makes sure the default bus is never internally used and instead a new Bus is created if required (more details on this in the next paragraph).

Bus selection strategies for JAXWS clients

JAXWS clients require an Apache CXF Bus to be available; the client is registered within the Bus and the Bus affects the client behavior (e.g. through the configured CXF interceptors). The way a bus is internally selected for serving a given JAXWS client is very important, especially for in-container clients; for this reason, JBossWS users can choose the preferred Bus selection strategy. The strategy is enforced in the javax.xml.ws.spi.Provider implementation from the JBossWS integration, being that called whenever a JAXWS Service (client) is requested.

Thread bus strategy (THREAD_BUS)

Each time the vanilla JAXWS api is used to create a Bus, the JBossWS-CXF integration will automatically make sure a Bus is currently associated to the current thread in the BusFactory. If that’s not the case, a new Bus is created and linked to the current thread (to prevent the user from relying on the default Bus). The Apache CXF engine will then create the client using the current thread Bus.

This is the default strategy, and the most straightforward one in Java SE environments; it lets users automatically reuse a previously created Bus instance and allows using customized Bus that can possibly be created and associated to the thread before building up a JAXWS client.

The drawback of the strategy is that the link between the Bus instance and the thread needs to be eventually cleaned up (when not needed anymore). This is really evident in a Jakarta EE environment (hence when running in-container), as threads from pools (e.g. serving web requests) are re-used.

When relying on this strategy, the safest approach to be sure of cleaning up the link is to surround the JAXWS client with a try/finally block as below:

try {
  Service service = Service.create(wsdlURL, serviceQName);
  MyEndpoint port = service.getPort(MyEndpoint.class);
  //...
} finally {
  BusFactory.setThreadDefaultBus(null);
  // OR (if you don't need the bus and the client anymore)
   Bus bus = BusFactory.getThreadDefaultBus(false);
  bus.shutdown(true);
}
New bus strategy (NEW_BUS)

Another strategy is to have the JAXWS Provider from the JBossWS integration create a new Bus each time a JAXWS client is built. The main benefit of this approach is that a fresh bus won’t rely on any formerly cached information (e.g. cached WSDL / schemas) which might have changed after the previous client creation. The main drawback is of course worse performance as the Bus creation takes time.

If there’s a bus already associated to the current thread before the JAXWS client creation, that is automatically restored when returning control to the user; in other words, the newly created bus will be used only for the created JAXWS client but won’t stay associated to the current thread at the end of the process. Similarly, if the thread was not associated to any bus before the client creation, no bus will be associated to the thread at the end of the client creation.

Thread context classloader bus strategy (TCCL_BUS)

The last strategy is to have the bus created for serving the client be associated to the current thread context classloader (TCCL). That basically means the same Bus instance is shared by JAXWS clients running when the same TCCL is set. This is particularly interesting as each web application deployment usually has its own context classloader, so this strategy is possibly a way to keep the number of created Bus instances bound to the application number in WildFly container.

If there’s a bus already associated to the current thread before the JAXWS client creation, that is automatically restored when returning control to the user; in other words, the bus corresponding to the current thread context classloader will be used only for the created JAXWS client but won’t stay associated to the current thread at the end of the process. If the thread was not associated to any bus before the client creation, a new bus will be created (and later user for any other client built with this strategy and the same TCCL in place); no bus will be associated to the thread at the end of the client creation.

Strategy configuration

Users can request a given Bus selection strategy to be used for the client being built by specifying one of the following JBossWS features (which extend javax . xml . ws . WebServiceFeature):

Feature Strategy

org.jboss.wsf.stack.cxf.client.UseThreadBusFeature

THREAD_BUS

org.jboss.wsf.stack.cxf.client.UseNewBusFeature

NEW_BUS

org.jboss.wsf.stack.cxf.client.UseTCCLBusFeature

TCCL_BUS

The feature is specified as follows:

Service service = Service.create(wsdlURL, serviceQName, new UseThreadBusFeature());

If no feature is explicitly specified, the system default strategy is used, which can be modified through the org.jboss.ws.cxf.jaxws-client.bus.strategy system property when starting the JVM. The valid values for the property are THREAD_BUS, NEW_BUS and TCCL_BUS. The default is THREAD_BUS.

Server Side Integration Customization

The JBossWS-CXF server side integration takes care of internally creating proper Apache CXF structures (including a Bus instance, of course) for the provided ws deployment. Should the deployment include multiple endpoints, those would all live within the same Apache CXF Bus, which would of course be completely separated by the other deployments' bus instances.

While JBossWS sets sensible defaults for most of the Apache CXF configuration options on server side, users might want to fine tune the Bus instance that’s created for their deployment; a jboss-webservices.xml descriptor can be used for deployment level customizations.

Deployment descriptor properties

The jboss-webservices.xml descriptor can be used to provide property values.

<webservices xmlns="http://www.jboss.com/xml/ns/javaee" version="1.2">
  ...
  <property>
    <name>...</name>
    <value>...</value>
  </property>
  ...
</webservices>

JBossWS-CXF integration comes with a set of allowed property names to control Apache CXF internals.

WorkQueue configuration

Apache CXF uses WorkQueue instances for dealing with some operations (e.g. @Oneway requests processing). A WorkQueueManager is installed in the Bus as an extension and allows for adding / removing queues as well as controlling the existing ones.

On server side, queues can be provided by using the cxf.queue.<queue-name>.* properties in jboss-webservices.xml (e.g. cxf.queue.default.maxQueueSize for controlling the max queue size of the default workqueue). At deployment time, the JBossWS integration can add new instances of AutomaticWorkQueueImpl to the currently configured WorkQueueManager; the properties below are used to fill in parameter into the AutomaticWorkQueueImpl constructor:

Property Default value

cxf.queue.<queue-name>.maxQueueSize

256

cxf.queue.<queue-name>.initialThreads

0

cxf.queue.<queue-name>.highWaterMark

25

cxf.queue.<queue-name>.lowWaterMark

5

cxf.queue.<queue-name>.dequeueTimeout

120000

Policy alternative selector

The Apache CXF policy engine supports different strategies to deal with policy alternatives. JBossWS-CXF integration currently defaults to the MaximalAlternativeSelector, but still allows for setting different selector implementation using the cxf.policy.alternativeSelector property in jboss-webservices.xml.

MBean management

Apache CXF allows managing its MBean objects that are installed into the WildFly MBean server. The feature is enabled on a deployment basis through the cxf.management.enabled property in jboss-webservices.xml. The cxf.management.installResponseTimeInterceptors property can also be used to control installation of CXF response time interceptors, which are added by default when enabling MBean management, but might not be desired in some cases. Here is an example:

<webservices xmlns="http://www.jboss.com/xml/ns/javaee" version="1.2">
  <property>
    <name>cxf.management.enabled</name>
    <value>true</value>
  </property>
  <property>
    <name>cxf.management.installResponseTimeInterceptors</name>
    <value>false</value>
  </property>
</webservices>
Schema validation

Schema validation of exchanged messages can also be enabled in jboss-webservices.xml. Further details available here.

Interceptors

The jboss-webservices.xml descriptor also allows specifying the cxf.interceptors.in and cxf.interceptors.out properties; those allows declaring interceptors to be attached to the Bus instance that’s created for serving the deployment.

<?xml version="1.1" encoding="UTF-8"?>
<webservices
xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="1.2"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">
 
<property>
<name>cxf.interceptors.in</name>
<value>org.jboss.test.ws.jaxws.cxf.interceptors.BusInterceptor</value>
</property>
<property>
<name>cxf.interceptors.out</name>
<value>org.jboss.test.ws.jaxws.cxf.interceptors.BusCounterInterceptor</value>
</property>
</webservices>
Features

The jboss-webservices.xml descriptor also allows specifying the cxf.features property; that allows declaring features to be attached to any endpoint belonging to the Bus instance that’s created for serving the deployment.

<?xml version="1.1" encoding="UTF-8"?>
<webservices
xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="1.2"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">
 
<property>
<name>cxf.features</name>
<value>org.apache.cxf.feature.FastInfosetFeature</value>
</property>
</webservices>
WS-Discovery enablement

WS-Discovery support can be turned on in jboss-webservices for the current deployment. Further details available here.

Apache CXF interceptors

Apache CXF supports declaring interceptors using one of the following approaches:

  • Annotation usage on endpoint classes ( @org.apache.cxf.interceptor.InInterceptor, @org.apache.cxf.interceptor.OutInterceptor)

  • Direct API usage on client side (through the org.apache.cxf.interceptor.InterceptorProvider interface)

  • Spring descriptor usage ( cxf.xml)

As the Spring descriptor usage is not supported, the JBossWS integration adds an additional descriptor based approach to avoid requiring modifications to the actual client/endpoint code. Users can declare interceptors within predefined client and endpoint configurations by specifying a list of interceptor class names for the cxf.interceptors.in and cxf.interceptors.out properties.

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
<endpoint-config>
<config-name>org.jboss.test.ws.jaxws.cxf.interceptors.EndpointImpl</config-name>
<property>
<property-name>cxf.interceptors.in</property-name>
<property-value>org.jboss.test.ws.jaxws.cxf.interceptors.EndpointInterceptor,org.jboss.test.ws.jaxws.cxf.interceptors.FooInterceptor</property-value>
</property>
<property>
<property-name>cxf.interceptors.out</property-name>
<property-value>org.jboss.test.ws.jaxws.cxf.interceptors.EndpointCounterInterceptor</property-value>
</property>
</endpoint-config>
</jaxws-config>

A new instance of each specified interceptor class will be added to the client or endpoint the configuration is assigned to. The interceptor classes must have a no-argument constructor.

Apache CXF features

Apache CXF supports declaring features using one of the following approaches:

  • Annotation usage on endpoint classes ( @org.apache.cxf.feature.Features)

  • Direct API usage on client side (through extensions of the org.apache.cxf.feature.AbstractFeature class)

  • Spring descriptor usage ( cxf.xml)

As the Spring descriptor usage is not supported, the JBossWS integration adds an additional descriptor based approach to avoid requiring modifications to the actual client/endpoint code. Users can declare features within predefined client and endpoint configurations by specifying a list of feature class names for the cxf.features property.

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
<endpoint-config>
<config-name>Custom FI Config</config-name>
<property>
<property-name>cxf.features</property-name>
<property-value>org.apache.cxf.feature.FastInfosetFeature</property-value>
</property>
</endpoint-config>
</jaxws-config>

A new instance of each specified feature class will be added to the client or endpoint the configuration is assigned to. The feature classes must have a no-argument constructor.

Properties driven bean creation

Sections above explain how to declare CXF interceptors and features through properties either in a client/endpoint predefined configuration or in a jboss-webservices.xml descriptor. By getting the feature/interceptor class name only specified, the container simply tries to create a bean instance using the class default constructor. This sets a limitation on the feature/interceptor configuration, unless custom extensions of vanilla CXF classes are provided, with the default constructor setting properties before eventually using the super constructor.

To cope with this issue, JBossWS integration comes with a mechanism for configuring simple bean hierarchies when building them up from properties. Properties can have bean reference values, that is strings starting with ##. Property reference keys are used to specify the bean class name and the value for for each attribute. So for instance the following properties:

Key Value

cxf.features

foo, bar

##foo

org.jboss.Foo

##foo.par

34

##bar

org.jboss.Bar

##bar.color

blue

would result into the stack installing two feature instances, the same that would have been created by

import org.Bar;
import org.Foo;
 
...
 
Foo foo = new Foo();
foo.setPar(34);
Bar bar = new Bar();
bar.setColor("blue");

The mechanism assumes that the classes are valid beans with proper getter and setter methods; value objects are cast to the correct primitive type by inspecting the class definition. Nested beans can of course be configured.

HTTPConduit configuration

HTTP transport setup in Apache CXF is achieved through org.apache.cxf.transport.http.HTTPConduit configurations. When running on top of the JBossWS integration, conduits can be programmatically modified using the Apache CXF API as follows:

import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
 
//set chunking threshold before using a JAX-WS port client
...
HTTPConduit conduit = (HTTPConduit)ClientProxy.getClient(port).getConduit();
HTTPClientPolicy client = conduit.getClient();
 
client.setChunkingThreshold(8192);
...

Users can also control the default values for the most common HTTPConduit parameters by setting specific system properties; the provided values will override Apache CXF defaut values.

Property Description

cxf.client.allowChunking

A boolean to tell Apache CXF whether to allow send messages using chunking.

cxf.client.chunkingThreshold

An integer value to tell Apache CXF the threshold at which switching from non-chunking to chunking mode.

cxf.client.connectionTimeout

A long value to tell Apache CXF how many milliseconds to set the connection timeout to

cxf.client.receiveTimeout

A long value to tell Apache CXF how many milliseconds to set the receive timeout to

cxf.client.connection

A string to tell Apache CXF to use Keep-Alive or close connection type

cxf.tls-client.disableCNCheck

A boolean to tell Apache CXF whether disabling CN host name check or not

The vanilla Apache CXF defaults apply when the system properties above are not set.

16.5.11. WS-Addressing

JBoss Web Services inherits full WS-Addressing capabilities from the underlying Apache CXF implementation. Apache CXF provides support for 2004-08 and 1.0 versions of WS-Addressing.

Enabling WS-Addressing

WS-Addressing can be turned on in multiple standard ways:

  • consuming a WSDL contract that specifies a WS-Addressing assertion / policy

  • using the @javax.xml.ws.soap.Addressing annotation

  • using the javax.xml.ws.soap.AddressingFeature feature

The supported addressing policy elements are:
[http://www.w3.org/2005/02/addressing/wsdl]UsingAddressing
[http://schemas.xmlsoap.org/ws/2004/08/addressing/policy]UsingAddressing
[http://www.w3.org/2006/05/addressing/wsdl]UsingAddressing
[http://www.w3.org/2007/05/addressing/metadata]Addressing

Alternatively, Apache CXF proprietary ways are also available:

  • specifying the  [http://cxf.apache.org/ws/addressing]addressing feature for a given client/endpoint

  • using the org.apache.cxf.ws.addressing.WSAddressingFeature feature through the API

  • manually configuring the Apache CXF addressing interceptors ( org.apache.cxf.ws.addressing.MAPAggregator and org.apache.cxf.ws.addressing.soap.MAPCodec)

  • setting the org.apache.cxf.ws.addressing.using property in the message context

Please refer to the the Apache CXF documentation for further information on the proprietary WS-Addressing setup and configuration details.

WS-Addressing Policy

The WS-Addressing support is also perfectly integrated with the Apache CXF WS-Policy engine.

This basically means that the WSDL contract generation for code-first endpoint deployment is policy-aware: users can annotate endpoints with the @ javax.xml.ws.soap. Addressing annotation and expect the published WSDL contract to contain proper WS-Addressing policy (assuming no wsdlLocation is specified in the endpoint’s @WebService annotation).

Similarly, on client side users do not need to manually specify the javax.xml.ws.soap.AddressingFeature feature, as the policy engine is able to properly process the WS-Addressing policy in the consumed WSDL and turn on addressing as requested.

Example

Here is an example showing how to simply enable WS-Addressing through WS-Policy.

Endpoint

A simple JAX-WS endpoint is prepared using a java-first approach; WS-Addressing is enforced through @Addressing annotation and no wsdlLocation is provided in @WebService:

package org.jboss.test.ws.jaxws.samples.wsa;
 
import javax.jws.WebService;
import javax.xml.ws.soap.Addressing;
import org.jboss.logging.Logger;
 
@WebService
(
   portName = "AddressingServicePort",
   serviceName = "AddressingService",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wsaddressing",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsa.ServiceIface"
)
@Addressing(enabled=true, required=true)
public class ServiceImpl implements ServiceIface
{
   private Logger log = Logger.getLogger(this.getClass());
 
   public String sayHello(String name)
   {
      return "Hello " + name + "!";
   }
}

The WSDL contract that’s generated at deploy time and published looks like this:

<wsdl:definitions ....>
...
  <wsdl:binding name="AddressingServiceSoapBinding" type="tns:ServiceIface">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsaw:UsingAddressing wsdl:required="true"/>
    <wsp:PolicyReference URI="#AddressingServiceSoapBinding_WSAM_Addressing_Policy"/>
 
    <wsdl:operation name="sayHello">
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="sayHello">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="sayHelloResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
 
  </wsdl:binding>
  <wsdl:service name="AddressingService">
    <wsdl:port binding="tns:AddressingServiceSoapBinding" name="AddressingServicePort">
      <soap:address location="http://localhost:8080/jaxws-samples-wsa"/>
    </wsdl:port>
  </wsdl:service>
    <wsp:Policy wsu:Id="AddressingServiceSoapBinding_WSAM_Addressing_Policy"
       xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <wsam:Addressing xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">
        <wsp:Policy/>
      </wsam:Addressing>
    </wsp:Policy>
</wsdl:definitions>
Client

Since the WS-Policy engine is on by default, the client side code is basically a pure JAX-WS client app:

QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wsaddressing", "AddressingService");
URL wsdlURL = new URL("http://localhost:8080/jaxws-samples-wsa?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class);
proxy.sayHello("World");

16.5.12. WS-Security

WS-Security overview

WS-Security provides the means to secure your services beyond transport level protocols such as HTTPS. Through a number of standards such as XML-Encryption, and headers defined in the WS-Security standard, it allows you to:

  • Pass authentication tokens between services.

  • Encrypt messages or parts of messages.

  • Sign messages.

  • Timestamp messages.

WS-Security makes heavy use of public and private key cryptography. It is helpful to understand these basics to really understand how to configure WS-Security. With public key cryptography, a user has a pair of public and private keys. These are generated using a large prime number and a key function.

images/Public_key_making.png

The keys are related mathematically, but cannot be derived from one another. With these keys we can encrypt messages. For example, if Bob wants to send a message to Alice, he can encrypt a message using her public key. Alice can then decrypt this message using her private key. Only Alice can decrypt this message as she is the only one with the private key.

images/Public_key_encryption-mod.svg.png

Messages can also be signed. This allows you to ensure the authenticity of the message. If Alice wants to send a message to Bob, and Bob wants to be sure that it is from Alice, Alice can sign the message using her private key. Bob can then verify that the message is from Alice by using her public key.

images/250px-Public_key_making.svg.png

JBoss WS-Security support

JBoss Web Services supports many real world scenarios requiring WS-Security functionalities. This includes signature and encryption support through X509 certificates, authentication and authorization through username tokens as well as all ws-security configurations covered by WS- SecurityPolicy specification.

As well as for other WS-* features, the core of WS-Security functionalities is provided through the Apache CXF engine. On top of that the JBossWS integration adds few configuration enhancements to simplify the setup of WS-Security enabled endpoints.

Apache CXF WS-Security implementation

Apache CXF features a top class WS-Security module supporting multiple configurations and easily extendible.

The system is based on interceptors that delegate to Apache WSS4J for the low level security operations. Interceptors can be configured in different ways, either through Spring configuration files or directly using Apache CXF client API. Please refer to the Apache CXF documentation if you’re looking for more details.

Recent versions of Apache CXF, however, introduced support for WS-Security Policy, which aims at moving most of the security configuration into the service contract (through policies), so that clients can easily be configured almost completely automatically from that. This way users do not need to manually deal with configuring / installing the required interceptors; the Apache CXF WS-Policy engine internally takes care of that instead.

WS-Security Policy support

WS-SecurityPolicy describes the actions that are required to securely communicate with a service advertised in a given WSDL contract. The WSDL bindings / operations reference WS-Policy fragments with the security requirements to interact with the service. The WS-SecurityPolicy specification allows for specifying things like asymmetric/symmetric keys, using transports (https) for encryption, which parts/headers to encrypt or sign, whether to sign then encrypt or encrypt then sign, whether to include timestamps, whether to use derived keys, etc.

However some mandatory configuration elements are not covered by WS-SecurityPolicy, basically because they’re not meant to be public / part of the published endpoint contract; those include things such as keystore locations, usernames and passwords, etc. Apache CXF allows configuring these elements either through Spring xml descriptors or using the client API / annotations. Below is the list of supported configuration properties:

ws-security.username The username used for UsernameToken policy assertions

ws-security.password

The password used for UsernameToken policy assertions. If not specified, the callback handler will be called.

ws-security.callback-handler

The WSS4J security CallbackHandler that will be used to retrieve passwords for keystores and UsernameTokens.

ws-security.signature.properties

The properties file/object that contains the WSS4J properties for configuring the signature keystore and crypto objects

ws-security.encryption.properties

The properties file/object that contains the WSS4J properties for configuring the encryption keystore and crypto objects

ws-security.signature.username

The username or alias for the key in the signature keystore that will be used. If not specified, it uses the the default alias set in the properties file. If that’s also not set, and the keystore only contains a single key, that key will be used.

ws-security.encryption.username

The username or alias for the key in the encryption keystore that will be used. If not specified, it uses the the default alias set in the properties file. If that’s also not set, and the keystore only contains a single key, that key will be used. For the web service provider, the useReqSigCert keyword can be used to accept (encrypt to) any client whose public key is in the service’s truststore (defined in ws-security.encryption.properties.)

ws-security.signature.crypto

Instead of specifying the signature properties, this can point to the full WSS4J Crypto object. This can allow easier "programmatic" configuration of the Crypto information."

ws-security.encryption.crypto

Instead of specifying the encryption properties, this can point to the full WSS4J Crypto object. This can allow easier "programmatic" configuration of the Crypto information."

ws-security.enable.streaming

Enable streaming (StAX based) processing of WS-Security messages

Here is an example of configuration using the client API:

Map<String, Object> ctx = ((BindingProvider)port).getRequestContext();
ctx.put("ws-security.encryption.properties", properties);
port.echoString("hello");

Please refer to the Apache CXF documentation for additional configuration details.

JBossWS configuration additions

In order for removing the need of Spring on server side for setting up WS-Security configuration properties not covered by policies, the JBossWS integration allows for getting those pieces of information from a defined endpoint configuration. Endpoint configurationscan include property declarations and endpoint implementations can be associated with a given endpoint configuration using the @EndpointConfig annotation.

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:javaee="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <endpoint-config>
    <config-name>Custom WS-Security Endpoint</config-name>
    <property>
      <property-name>ws-security.signature.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.signature.username</property-name>
      <property-value>bob</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.username</property-name>
      <property-value>alice</property-value>
    </property>
    <property>
      <property-name>ws-security.callback-handler</property-name>
      <property-value>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback</property-value>
    </property>
  </endpoint-config>
</jaxws-config>
import javax.jws.WebService;
import org.jboss.ws.api.annotation.EndpointConfig;
 
@WebService
(
   portName = "SecurityServicePort",
   serviceName = "SecurityService",
   wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceIface"
)
@EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint")
public class ServiceImpl implements ServiceIface
{
   public String sayHello()
   {
      return "Secure Hello World!";
   }
}
Apache CXF annotations

The JBossWS configuration additions allow for a descriptor approach to the WS-Security Policy engine configuration. If you prefer to provide the same information through an annotation approach, you can leverage the Apache CXF @org.apache.cxf.annotations.EndpointProperties annotation:

@WebService(
   ...
)
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.properties", value = "bob.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "bob.properties"),
      @EndpointProperty(key = "ws-security.signature.username", value = "bob"),
      @EndpointProperty(key = "ws-security.encryption.username", value = "alice"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback")
      }
)
public class ServiceImpl implements ServiceIface {
   ...
}
Examples

In this section some sample of WS-Security service endpoints and clients are provided. Please note they’re only meant as tutorials; you should really careful isolate the ws-security policies / assertion that best suite your security needs before going to production environment.

The following sections provide directions and examples on understanding some of the configuration options for WS-Security engine. Please note the implementor remains responsible for assessing the application requirements and choosing the most suitable security policy for them.
Signature and encryption
Endpoint

First of all you need to create the web service endpoint using JAX-WS. While this can generally be achieved in different ways, it’s required to use a contract-first approach when using WS-Security, as the policies declared in the wsdl are parsed by the Apache CXF engine on both server and client sides. So, here is an example of WSDL contract enforcing signature and encryption using X 509 certificates (the referenced schema is omitted):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" name="SecurityService"
  xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:wsp="http://www.w3.org/ns/ws-policy"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        xmlns:wsaws="http://www.w3.org/2005/08/addressing"
        xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" schemaLocation="SecurityService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <portType name="ServiceIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
  </portType>
  <binding name="SecurityServicePortBinding" type="tns:ServiceIface">
    <wsp:PolicyReference URI="#SecurityServiceSignThenEncryptPolicy"/>
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="SecurityService">
    <port name="SecurityServicePort" binding="tns:SecurityServicePortBinding">
      <soap:address location="http://localhost:8080/jaxws-samples-wssePolicy-sign-encrypt"/>
    </port>
  </service>
 
  <wsp:Policy wsu:Id="SecurityServiceSignThenEncryptPolicy" xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
    <wsp:ExactlyOne>
      <wsp:All>
        <sp:AsymmetricBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <wsp:Policy>
            <sp:InitiatorToken>
              <wsp:Policy>
                <sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
                  <wsp:Policy>
                    <sp:WssX509V1Token11/>
                  </wsp:Policy>
                  </sp:X509Token>
              </wsp:Policy>
            </sp:InitiatorToken>
            <sp:RecipientToken>
              <wsp:Policy>
                <sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Never">
                  <wsp:Policy>
                    <sp:WssX509V1Token11/>
                  </wsp:Policy>
                </sp:X509Token>
              </wsp:Policy>
            </sp:RecipientToken>
            <sp:AlgorithmSuite>
              <wsp:Policy>
                <sp:TripleDesRsa15/>
              </wsp:Policy>
            </sp:AlgorithmSuite>
            <sp:Layout>
              <wsp:Policy>
                <sp:Lax/>
              </wsp:Policy>
            </sp:Layout>
            <sp:IncludeTimestamp/>
            <sp:EncryptSignature/>
            <sp:OnlySignEntireHeadersAndBody/>
            <sp:SignBeforeEncrypting/>
          </wsp:Policy>
        </sp:AsymmetricBinding>
        <sp:SignedParts xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <sp:Body/>
        </sp:SignedParts>
        <sp:EncryptedParts xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <sp:Body/>
        </sp:EncryptedParts>
        <sp:Wss10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <wsp:Policy>
            <sp:MustSupportRefIssuerSerial/>
          </wsp:Policy>
        </sp:Wss10>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>
</definitions>

The service endpoint can be generated using the wsconsume tool and then enriched with a @EndpointConfig annotation:

package org.jboss.test.ws.jaxws.samples.wsse.policy.basic;
 
import javax.jws.WebService;
import org.jboss.ws.api.annotation.EndpointConfig;
 
@WebService
(
   portName = "SecurityServicePort",
   serviceName = "SecurityService",
   wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceIface"
)
@EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint")
public class ServiceImpl implements ServiceIface
{
   public String sayHello()
   {
      return "Secure Hello World!";
   }
}

The referenced jaxws-endpoint-config.xml descriptor is used to provide a custom endpoint configuration with the required server side configuration properties; this tells the engine which certificate / key to use for signature / signature verification and for encryption / decryption:

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:javaee="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <endpoint-config>
    <config-name>Custom WS-Security Endpoint</config-name>
    <property>
      <property-name>ws-security.signature.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.signature.username</property-name>
      <property-value>bob</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.username</property-name>
      <property-value>alice</property-value>
    </property>
    <property>
      <property-name>ws-security.callback-handler</property-name>
      <property-value>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback</property-value>
    </property>
  </endpoint-config>
</jaxws-config>
  1. the bob.properties configuration file is also referenced above; it includes the WSS4J Crypto properties which in turn link to the keystore file, type and the alias/password to use for accessing it:

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=password
org.apache.ws.security.crypto.merlin.keystore.alias=bob
org.apache.ws.security.crypto.merlin.keystore.file=bob.jks

A callback handler for the letting Apache CXF access the keystore is also provided:

package org.jboss.test.ws.jaxws.samples.wsse.policy.basic;
 
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
 
public class KeystorePasswordCallback implements CallbackHandler {
   private Map<String, String> passwords = new HashMap<String, String>();
 
   public KeystorePasswordCallback() {
      passwords.put("alice", "password");
      passwords.put("bob", "password");
   }
 
   /**
    * It attempts to get the password from the private
    * alias/passwords map.
    */
   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
      for (int i = 0; i < callbacks.length; i++) {
         WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];
 
         String pass = passwords.get(pc.getIdentifier());
         if (pass != null) {
            pc.setPassword(pass);
            return;
         }
      }
   }
 
   /**
    * Add an alias/password pair to the callback mechanism.
    */
   public void setAliasPassword(String alias, String password) {
      passwords.put(alias, password);
   }
}

Assuming the bob.jks keystore has been properly generated and contains Bob’s (server) full key (private/certificate + public key) as well as Alice’s (client) public key, we can proceed to packaging the endpoint. Here is the expected content (the endpoint is a POJO one in a war archive, but EJB3 endpoints in jar archives are of course also supported):

alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-samples-wsse-policy-sign-encrypt.war
     0 Thu Jun 16 18:50:48 CEST 2011 META-INF/
   140 Thu Jun 16 18:50:46 CEST 2011 META-INF/MANIFEST.MF
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/
   586 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/web.xml
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/
  1687 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/KeystorePasswordCallback.class
   383 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/ServiceIface.class
  1070 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/ServiceImpl.class
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/
   705 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHello.class
  1069 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHelloResponse.class
  1225 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/jaxws-endpoint-config.xml
     0 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/
  4086 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService.wsdl
   653 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService_schema1.xsd
  1820 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/classes/bob.jks
   311 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/classes/bob.properties

As you can see, the jaxws classes generated by the tools are of course also included, as well as a basic web.xml referencing the endpoint bean:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
   version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
   <servlet>
      <servlet-name>TestService</servlet-name>
      <servlet-class>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceImpl</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>TestService</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>
</web-app>
If you’re deploying the endpoint archive on WildFly, remember to add a dependency to org.apache.ws.security module in the MANIFEST.MF file.
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 17.0-b16 (Sun Microsystems Inc.)
Dependencies: org.apache.ws.security
Client

You start by consuming the published WSDL contract using the wsconsume tool on client side too. Then you simply invoke the the endpoint as a standard JAX-WS one:

QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class);
 
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.CALLBACK_HANDLER, new KeystorePasswordCallback());
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.SIGNATURE_PROPERTIES,
     Thread.currentThread().getContextClassLoader().getResource("META-INF/alice.properties"));
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.ENCRYPT_PROPERTIES,
     Thread.currentThread().getContextClassLoader().getResource("META-INF/alice.properties"));
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.SIGNATURE_USERNAME, "alice");
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.ENCRYPT_USERNAME, "bob");
 
proxy.sayHello();

As you can see, the WS-Security properties are set in the request context. Here the KeystorePasswordCallback is the same as on server side above, you might want/need different implementation in real world scenarios, of course.
The alice.properties file is the client side equivalent of the server side bob.properties and references the alice.jks keystore file, which has been populated with Alice’s (client) full key (private/certificate + public key) as well as Bob’s (server) public key.

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=password
org.apache.ws.security.crypto.merlin.keystore.alias=alice
org.apache.ws.security.crypto.merlin.keystore.file=META-INF/alice.jks

The Apache CXF WS-Policy engine will digest the security requirements in the contract and ensure a valid secure communication is in place for interacting with the server endpoint.

Endpoint serving multiple clients

The server side configuration described above implies the endpoint is configured for serving a given client which a service agreement has been established for. In some real world scenarios though, the same server might be expected to be able to deal with (including decrypting and encrypting) messages coming from and being sent to multiple clients. Apache CXF supports that through the useReqSigCert value for the ws-security.encryption.username configuration parameter.

Of course the referenced server side keystore then needs to contain the public key of all the clients that are expected to be served.

Authentication and authorization

The Username Token Profile can be used to provide client’s credentials to a WS-Security enabled target endpoint.

Apache CXF provides means for setting basic password callback handlers on both client and server sides to set/check passwords; the ws-security.username and ws-security.callback-handler properties can be used similarly as shown in the signature and encryption example. Things become more interesting when requiring a given user to be authenticated (and authorized) against a security domain on the target application server.

On server side, you need to install two additional interceptors that act as bridges towards the application server authentication layer:

  • an interceptor for performing authentication and populating a valid SecurityContext; the provided interceptor should extend org.apache.cxf.ws.interceptor.security.AbstractUsernameTokenInInterceptor, in particular JBossWS integration comes with org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingInterceptor for this;

  • an interceptor for performing authorization; CXF requires that to extend org.apache.cxf.interceptor.security.AbstractAuthorizingInInterceptor, for instance the SimpleAuthorizingInterceptor can be used for simply mapping endpoint operations to allowed roles.

So, here follows an example of WS-SecurityPolicy endpoint using Username Token Profile for authenticating through the application server security domain system.

Endpoint

As in the other example, we start with a wsdl contract containing the proper WS-Security Policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" name="SecurityService"
  xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        xmlns:wsaws="http://www.w3.org/2005/08/addressing">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" schemaLocation="SecurityService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <message name="greetMe">
    <part name="parameters" element="tns:greetMe"/>
  </message>
  <message name="greetMeResponse">
    <part name="parameters" element="tns:greetMeResponse"/>
  </message>
  <portType name="ServiceIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
    <operation name="greetMe">
      <input message="tns:greetMe"/>
      <output message="tns:greetMeResponse"/>
    </operation>
  </portType>
  <binding name="SecurityServicePortBinding" type="tns:ServiceIface">
    <wsp:PolicyReference URI="#SecurityServiceUsernameUnsecureTransportPolicy"/>
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="greetMe">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="SecurityService">
    <port name="SecurityServicePort" binding="tns:SecurityServicePortBinding">
      <soap:address location="http://localhost:8080/jaxws-samples-wsse-username-jaas"/>
    </port>
  </service>
 
  <wsp:Policy wsu:Id="SecurityServiceUsernameUnsecureTransportPolicy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
                    <wsp:Policy>
                        <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                            <wsp:Policy>
                                <sp:WssUsernameToken10/>
                            </wsp:Policy>
                        </sp:UsernameToken>
                    </wsp:Policy>
                </sp:SupportingTokens>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>
 
</definitions>
If you want to send hash / digest passwords, you can use a policy such as what follows:
<wsp:Policy wsu:Id="SecurityServiceUsernameHashPasswordPolicy">
    <wsp:ExactlyOne>
        <wsp:All>
            <sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
                <wsp:Policy>
                    <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                        <wsp:Policy>
                            <sp:HashPassword/>
                        </wsp:Policy>
                    </sp:UsernameToken>
                </wsp:Policy>
            </sp:SupportingTokens>
        </wsp:All>
    </wsp:ExactlyOne>
</wsp:Policy>

Please note the specified JBoss security domain needs to be properly configured for computing digests.

The service endpoint can be generated using the wsconsume tool and then enriched with a @EndpointConfig annotation and @InInterceptors annotation to add the two interceptors mentioned above for JAAS integration:

package org.jboss.test.ws.jaxws.samples.wsse.policy.jaas;
 
import javax.jws.WebService;
import org.apache.cxf.interceptor.InInterceptors;
import org.jboss.ws.api.annotation.EndpointConfig;
 
@WebService
(
   portName = "SecurityServicePort",
   serviceName = "SecurityService",
   wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.ServiceIface"
)
@EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint")
@InInterceptors(interceptors = {
      "org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor",
      "org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.POJOEndpointAuthorizationInterceptor"}
)
public class ServiceImpl implements ServiceIface
{
   public String sayHello()
   {
      return "Secure Hello World!";
   }
 
   public String greetMe()
   {
      return "Greetings!";
   }
}

The POJOEndpointAuthorizationInterceptor is included into the deployment and deals with the roles cheks:

package org.jboss.test.ws.jaxws.samples.wsse.policy.jaas;
 
import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.interceptor.security.SimpleAuthorizingInterceptor;
 
public class POJOEndpointAuthorizationInterceptor extends SimpleAuthorizingInterceptor
{
 
   public POJOEndpointAuthorizationInterceptor()
   {
      super();
      readRoles();
   }
 
   private void readRoles()
   {
      //just an example, this might read from a configuration file or such
      Map<String, String> roles = new HashMap<String, String>();
      roles.put("sayHello", "friend");
      roles.put("greetMe", "snoopies");
      setMethodRolesMap(roles);
   }
}

The jaxws-endpoint-config.xml descriptor is used to provide a custom endpoint configuration with the required server side configuration properties; in particular for this Username Token case that’s just a CXF configuration option for leaving the username token validation to the configured interceptors:

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:javaee="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <endpoint-config>
    <config-name>Custom WS-Security Endpoint</config-name>
    <property>
      <property-name>ws-security.validate.token</property-name>
      <property-value>false</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

In order for requiring a given JBoss security domain to be used to protect access to the endpoint (a POJO one in this case), we declare that in a jboss-web.xml descriptor (the JBossWS security domain is used):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_4_0.dtd">
<jboss-web>
   <security-domain>java:/jaas/JBossWS</security-domain>
</jboss-web

Finally, the web.xml is as simple as usual:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
   version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
   <servlet>
      <servlet-name>TestService</servlet-name>
      <servlet-class>org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.ServiceImpl</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>TestService</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>
</web-app>

The endpoint is packaged into a war archive, including the JAXWS classes generated by wsconsume:

alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-samples-wsse-policy-username-jaas.war
     0 Thu Jun 16 18:50:48 CEST 2011 META-INF/
   155 Thu Jun 16 18:50:46 CEST 2011 META-INF/MANIFEST.MF
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/
   585 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/web.xml
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/
   982 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/POJOEndpointAuthorizationInterceptor.class
   412 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/ServiceIface.class
  1398 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/ServiceImpl.class
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/
   701 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/GreetMe.class
  1065 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/GreetMeResponse.class
   705 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHello.class
  1069 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHelloResponse.class
   556 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/jaxws-endpoint-config.xml
   241 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/jboss-web.xml
     0 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/
  3183 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService.wsdl
  1012 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService_schema1.xsd
If you’re deploying the endpoint archive on WildFly, remember to add a dependency to org.apache.ws.security and org.apache.cxf module (due to the @InInterceptor annotation) in the MANIFEST.MF file.
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 17.0-b16 (Sun Microsystems Inc.)
Dependencies: org.apache.ws.security,org.apache.cxf
Client

Here too you start by consuming the published WSDL contract using the wsconsume tool. Then you simply invoke the the endpoint as a standard JAX-WS one:

QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class);
 
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.USERNAME, "kermit");
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.CALLBACK_HANDLER,
      "org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.UsernamePasswordCallback");
 
proxy.sayHello();

The UsernamePasswordCallback class is shown below and is responsible for setting the passwords on client side just before performing the invocations:

package org.jboss.test.ws.jaxws.samples.wsse.policy.jaas;
 
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
 
public class UsernamePasswordCallback implements CallbackHandler
{
   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
   {
      WSPasswordCallback pc = (WSPasswordCallback)callbacks[0];
      if ("kermit".equals(pc.getIdentifier()))
         pc.setPassword("thefrog");
   }
}

If everything has been done properly, you should expect to calls to sayHello() fail when done with user "snoopy" and pass with user "kermit" (and credential "thefrog"); moreover, you should get an authorization error when trying to call greetMe() with user "kermit", as that does not have the "snoopies" role.

Secure transport

Another quite common use case is using WS-Security Username Token Profile over a secure transport (HTTPS). A scenario like this is implemented similarly to what’s described in the previous example, except for few differences explained below.

First of all, here is an excerpt of a wsdl wth a sample security policy for Username Token over HTTPS:

...
 
<binding name="SecurityServicePortBinding" type="tns:ServiceIface">
  <wsp:PolicyReference URI="#SecurityServiceBindingPolicy"/>
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
  <operation name="sayHello">
    <soap:operation soapAction=""/>
    <input>
      <soap:body use="literal"/>
    </input>
    <output>
      <soap:body use="literal"/>
    </output>
  </operation>
</binding>
<service name="SecurityService">
   <port name="SecurityServicePort" binding="tns:SecurityServicePortBinding">
      <soap:address location="https://localhost:8443/jaxws-samples-wsse-policy-username"/>
   </port>
</service>
 
<wsp:Policy wsu:Id="SecurityServiceBindingPolicy">
   <wsp:ExactlyOne>
      <wsp:All>
         <foo:unknownPolicy xmlns:foo="http://cxf.apache.org/not/a/policy"/>
      </wsp:All>
      <wsp:All>
         <wsaws:UsingAddressing xmlns:wsaws="http://www.w3.org/2006/05/addressing/wsdl"/>
         <sp:TransportBinding>
            <wsp:Policy>
               <sp:TransportToken>
                  <wsp:Policy>
                     <sp:HttpsToken RequireClientCertificate="false"/>
                  </wsp:Policy>
               </sp:TransportToken>
               <sp:Layout>
                  <wsp:Policy>
                     <sp:Lax/>
                  </wsp:Policy>
               </sp:Layout>
               <sp:IncludeTimestamp/>
               <sp:AlgorithmSuite>
                  <wsp:Policy>
                     <sp:Basic128/>
                  </wsp:Policy>
               </sp:AlgorithmSuite>
            </wsp:Policy>
         </sp:TransportBinding>
         <sp:Wss10>
            <wsp:Policy>
               <sp:MustSupportRefKeyIdentifier/>
            </wsp:Policy>
         </sp:Wss10>
         <sp:SignedSupportingTokens>
            <wsp:Policy>
               <sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
                  <wsp:Policy>
                     <sp:WssUsernameToken10/>
                  </wsp:Policy>
               </sp:UsernameToken>
            </wsp:Policy>
         </sp:SignedSupportingTokens>
      </wsp:All>
   </wsp:ExactlyOne>
</wsp:Policy>

The endpoint then needs of course to be actually available on HTTPS only, so we have a web.xml setting the transport-guarantee such as below:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
   version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
   <servlet>
      <servlet-name>TestService</servlet-name>
      <servlet-class>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceImpl</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>TestService</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>
 
   <security-constraint>
    <web-resource-collection>
      <web-resource-name>TestService</web-resource-name>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
      <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
  </security-constraint>
</web-app>
Secure conversation

Apache CXF supports WS-SecureConversation specification, which is about improving performance by allowing client and server to negotiate initial security keys to be used for later communication encryption/signature. This is done by having two policies in the wsdl contract, an outer one setting the security requirements to actually communicate with the endpoint and a bootstrap one, related to the communication for establishing the secure conversation keys. The client will be automatically sending an initial message to the server for negotiating the keys, then the actual communication to the endpoint takes place. As a consequence, Apache CXF needs a way to specify which WS-Security configuration properties are intended for the bootstrap policy and which are intended for the actual service policy. To accomplish this, properties intended for the bootstrap policy are appended with .sct.

...
((BindingProvider)proxy).getRequestContext().put("ws-security.signature.username.sct", "alice");
((BindingProvider)proxy).getRequestContext().put("ws-security.encryption.username.sct", "bob");
...
@WebService(
   ...
)
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.encryption.properties.sct", value = "bob.properties"),
      @EndpointProperty(key = "ws-security.signature.properties.sct", value = "bob.properties"),
      ...
      }
)
public class ServiceImpl implements ServiceIface {
   ...
}

16.5.13. WS-Trust and STS

WS-Trust overview

WS-Trust is a Web service specification that defines extensions to WS-Security. It is a general framework for implementing security in a distributed system. The standard is based on a centralized Security Token Service, STS, which is capable of authenticating clients and issuing tokens containing various kinds of authentication and authorization data. The specification describes a protocol used for issuance, exchange, and validation of security tokens, however the following specifications play an important role in the WS-Trust architecture: WS-SecurityPolicy 1.2, SAML 2.0, Username Token Profile, X.509 Token Profile, SAML Token Profile, and Kerberos Token Profile.

The WS-Trust extensions address the needs of applications that span multiple domains and requires the sharing of security keys by providing a standards based trusted third party web service (STS) to broker trust relationships between a Web service requester and a Web service provider. This architecture also alleviates the pain of service updates that require credential changes by providing a common location for this information. The STS is the common access point from which both the requester and provider retrieves and verifies security tokens.

There are three main components of the WS-Trust specification.

  • The Security Token Service (STS), a web service that issues, renews, and validates security tokens.

  • The message formats for security token requests and responses.

  • The mechanisms for key exchange

Security Token Service

The Security Token Service, STS, is the core of the WS-Trust specification. It is a standards based mechanism for authentication and authorization. The STS is an implementation of the WS-Trust specification’s protocol for issuing, exchanging, and validating security tokens, based on token format, namespace, or trust boundaries. The STS is a web service that acts as a trusted third party to broker trust relationships between a Web service requester and a Web service provider. It is a common access point trusted by both requester and provider to provide interoperable security tokens. It removes the need for a direct relationship between the two. Because the STS is a standards based mechanism for authentication, it helps ensure interoperability across realms and between different platforms.

The STS’s WSDL contract defines how other applications and processes interact with it. In particular the WSDL defines the WS-Trust and WS-Security policies that a requester must fulfill in order to successfully communicate with the STS’s endpoints. A web service requester consumes the STS’s WSDL and with the aid of an STSClient utility, generates a message request compliant with the stated security policies and submits it to the STS endpoint. The STS validates the request and returns an appropriate response.

Apache CXF support

Apache CXF is an open-source, fully featured Web services framework. The JBossWS open source project integrates the JBoss Web Services (JBossWS) stack with the Apache CXF project modules thus providing WS-Trust and other JAX-WS functionality in WildFly. This integration makes it easy to deploy CXF STS implementations, however WildFly can run any WS-Trust compliant STS. In addition the Apache CXF API provides a STSClient utility to facilitate web service requester communication with its STS.

Detailed information about the Apache CXF’s WS-Trust implementation can be found here.

A Basic WS-Trust Scenario

Here is an example of a basic WS-Trust scenario. It is comprised of a Web service requester (ws-requester), a Web service provider (ws-provider), and a Security Token Service (STS). The ws-provider requires a SAML 2.0 token issued from a designed STS to be presented by the ws-requester using asymmetric binding. These communication requirements are declared in the ws-provider’s WSDL. The STS requires ws-requester credentials be provided in a WSS UsernameToken format request using symmetric binding. The STS’s response is provided containing a SAML 2.0 token. These communication requirements are declared in the STS’s WSDL.

  1. A ws-requester contacts the ws-provider and consumes its WSDL. Upon finding the security token issuer requirement, it creates and configures a STSClient with the information it requires to generate a proper request.

  2. The STSClient contacts the STS and consumes its WSDL. The security policies are discovered. The STSClient creates and sends an authentication request, with appropriate credentials.

  3. The STS verifies the credentials.

  4. In response, the STS issues a security token that provides proof that the ws-requester has authenticated with the STS.

  5. The STClient presents a message with the security token to the ws-provider.

  6. The ws-provider verifies the token was issued by the STS, thus proving the ws-requester has successfully authenticated with the STS.

  7. The ws-provider executes the requested service and returns the results to the the ws-requester.

Web service provider

This section examines the crucial elements in providing endpoint security in the web service provider described in the basic WS-Trust scenario. The components that will be discussed are.

  • web service provider’s WSDL

  • web service provider’s Interface and Implementation classes.

  • ServerCallbackHandler class

  • Crypto properties and keystore files

  • MANIFEST.MF

Web service provider WSDL

The web service provider is a contract-first endpoint. All the WS-trust and security policies for it are declared in the WSDL, SecurityService.wsdl. For this scenario a ws-requester is required to present a SAML 2.0 token issued from a designed STS. The address of the STS is provided in the WSDL. An asymmetric binding policy is used to encrypt and sign the SOAP body of messages that pass back and forth between ws-requester and ws-provider. X.509 certificates are use for the asymmetric binding. The rules for sharing the public and private keys in the SOAP request and response messages are declared. A detailed explanation of the security settings are provided in the comments in the listing below.

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" name="SecurityService"
        xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns="http://schemas.xmlsoap.org/wsdl/"
        xmlns:wsp="http://www.w3.org/ns/ws-policy"
        xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        xmlns:wsaws="http://www.w3.org/2005/08/addressing"
        xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
        xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" schemaLocation="SecurityService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <portType name="ServiceIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
  </portType>
  <!--
        The wsp:PolicyReference binds the security requirments on all the STS endpoints.
        The wsp:Policy wsu:Id="#AsymmetricSAML2Policy" element is defined later in this file.
  -->
  <binding name="SecurityServicePortBinding" type="tns:ServiceIface">
    <wsp:PolicyReference URI="#AsymmetricSAML2Policy" />
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
        <wsp:PolicyReference URI="#Input_Policy" />
      </input>
      <output>
        <soap:body use="literal"/>
        <wsp:PolicyReference URI="#Output_Policy" />
      </output>
    </operation>
  </binding>
  <service name="SecurityService">
    <port name="SecurityServicePort" binding="tns:SecurityServicePortBinding">
      <soap:address location="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust/SecurityService"/>
    </port>
  </service>

  <wsp:Policy wsu:Id="AsymmetricSAML2Policy">
        <wsp:ExactlyOne>
            <wsp:All>
  <!--
        The wsam:Addressing element, indicates that the endpoints of this
        web service MUST conform to the WS-Addressing specification.  The
        attribute wsp:Optional="false" enforces this assertion.
  -->
                <wsam:Addressing wsp:Optional="false">
                    <wsp:Policy />
                </wsam:Addressing>
  <!--
        The sp:AsymmetricBinding element indicates that security is provided
        at the SOAP layer. A public/private key combinations is required to
        protect the message.  The initiator will use it's private key to sign
        the message and the recipient's public key is used to encrypt the message.
        The recipient of the message will use it's private key to decrypt it and
        initiator's public key to verify the signature.
  -->
                <sp:AsymmetricBinding>
                    <wsp:Policy>
  <!--
        The sp:InitiatorToken element specifies the elements required in
        generating the initiator request to the ws-provider's service.
  -->
                        <sp:InitiatorToken>
                            <wsp:Policy>
  <!--
        The sp:IssuedToken element asserts that a SAML 2.0 security token is
        expected from the STS using a public key type.  The
        sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
        attribute instructs the runtime to include the initiator's public key
        with every message sent to the recipient.

        The sp:RequestSecurityTokenTemplate element directs that all of the
        children of this element will be copied directly into the body of the
        RequestSecurityToken (RST) message that is sent to the STS when the
        initiator asks the STS to issue a token.
  -->
                                <sp:IssuedToken
                                    sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                                    <sp:RequestSecurityTokenTemplate>
                                        <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>
                                        <t:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey</t:KeyType>
                                    </sp:RequestSecurityTokenTemplate>
                                    <wsp:Policy>
                                        <sp:RequireInternalReference />
                                    </wsp:Policy>
  <!--
        The sp:Issuer element defines the STS's address and endpoint information
        This information is used by the STSClient.
  -->
                                    <sp:Issuer>
                                        <wsaws:Address>http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts/SecurityTokenService</wsaws:Address>
                                        <wsaws:Metadata xmlns:wsdli="http://www.w3.org/2006/01/wsdl-instance"
                                                        wsdli:wsdlLocation="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts/SecurityTokenService?wsdl">
                                            <wsaw:ServiceName xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
                                                            xmlns:stsns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
                                                            EndpointName="UT_Port">stsns:SecurityTokenService</wsaw:ServiceName>
                                        </wsaws:Metadata>
                                    </sp:Issuer>
                                </sp:IssuedToken>
                            </wsp:Policy>
                        </sp:InitiatorToken>
  <!--
        The sp:RecipientToken element asserts the type of public/private key-pair
        expected from the recipient.  The
        sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
        attribute indicates that the initiator's public key will never be included
        in the reply messages.
 
        The sp:WssX509V3Token10 element indicates that an X509 Version 3 token
        should be used in the message.
  -->
                        <sp:RecipientToken>
                            <wsp:Policy>
                                <sp:X509Token
                                    sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
                                    <wsp:Policy>
                                        <sp:WssX509V3Token10 />
                                        <sp:RequireIssuerSerialReference />
                                    </wsp:Policy>
                                </sp:X509Token>
                            </wsp:Policy>
                        </sp:RecipientToken>
<!--
     The sp:Layout element,  indicates the layout rules to apply when adding
     items to the security header.  The sp:Lax sub-element indicates items
     are added to the security header in any order that conforms to
     WSS: SOAP Message Security.
-->
                        <sp:Layout>
                            <wsp:Policy>
                                <sp:Lax />
                            </wsp:Policy>
                        </sp:Layout>
                        <sp:IncludeTimestamp />
                        <sp:OnlySignEntireHeadersAndBody />
 <!--
     The sp:AlgorithmSuite element, requires the Basic256 algorithm suite
     be used in performing cryptographic operations.
-->
                        <sp:AlgorithmSuite>
                            <wsp:Policy>
                                <sp:Basic256 />
                            </wsp:Policy>
                        </sp:AlgorithmSuite>
                    </wsp:Policy>
                </sp:AsymmetricBinding>
<!--
    The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
    to be supported by the STS.  These particular elements generally refer
    to how keys are referenced within the SOAP envelope.  These are normally
    handled by CXF.
-->
                <sp:Wss11>
                    <wsp:Policy>
                        <sp:MustSupportRefIssuerSerial />
                        <sp:MustSupportRefThumbprint />
                        <sp:MustSupportRefEncryptedKey />
                    </wsp:Policy>
                </sp:Wss11>
<!--
    The sp:Trust13 element declares controls for WS-Trust 1.3 options.
    They are policy assertions related to exchanges specifically with
    client and server challenges and entropy behaviors.  Again these are
    normally handled by CXF.
-->
                <sp:Trust13>
                    <wsp:Policy>
                        <sp:MustSupportIssuedTokens />
                        <sp:RequireClientEntropy />
                        <sp:RequireServerEntropy />
                    </wsp:Policy>
                </sp:Trust13>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>

    <wsp:Policy wsu:Id="Input_Policy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:EncryptedParts>
                    <sp:Body />
                </sp:EncryptedParts>
                <sp:SignedParts>
                    <sp:Body />
                    <sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="From" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="FaultTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="ReplyTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="MessageID" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="RelatesTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="Action" Namespace="http://www.w3.org/2005/08/addressing" />
                </sp:SignedParts>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>

    <wsp:Policy wsu:Id="Output_Policy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:EncryptedParts>
                    <sp:Body />
                </sp:EncryptedParts>
                <sp:SignedParts>
                    <sp:Body />
                    <sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="From" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="FaultTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="ReplyTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="MessageID" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="RelatesTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="Action" Namespace="http://www.w3.org/2005/08/addressing" />
                </sp:SignedParts>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>
</definitions>
Web service provider Interface

The web service provider interface class, ServiceIface, is a simple straight forward web service definition.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service;
 
import javax.jws.WebMethod;
import javax.jws.WebService;
 
@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy"
)
public interface ServiceIface
{
   @WebMethod
   String sayHello();
}
Web service provider Implementation

The web service provider implementation class, ServiceImpl, is a simple POJO. It uses the standard WebService annotation to define the service endpoint. In addition there are two Apache CXF annotations, EndpointProperties and EndpointProperty used for configuring the endpoint for the CXF runtime. These annotations come from the Apache WSS4J project, which provides a Java implementation of the primary WS-Security standards for Web Services. These annotations are programmatically adding properties to the endpoint. With plain Apache CXF, these properties are often set via the <jaxws:properties> element on the <jaxws:endpoint> element in the Spring config; these annotations allow the properties to be configured in the code.

WSS4J uses the Crypto interface to get keys and certificates for encryption/decryption and for signature creation/verification. As is asserted by the WSDL, X509 keys and certificates are required for this service. The WSS4J configuration information being provided by ServiceImpl is for Crypto’s Merlin implementation. More information will be provided about this in the keystore section.

The first EndpointProperty statement in the listing is declaring the user’s name to use for the message signature. It is used as the alias name in the keystore to get the user’s cert and private key for signature. The next two EndpointProperty statements declares the Java properties file that contains the (Merlin) crypto configuration information. In this case both for signing and encrypting the messages. WSS4J reads this file and extra required information for message handling. The last EndpointProperty statement declares the ServerCallbackHandler implementation class. It is used to obtain the user’s password for the certificates in the keystore file.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service;
 
import javax.jws.WebService;
 
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
 
@WebService
(
   portName = "SecurityServicePort",
   serviceName = "SecurityService",
   wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServiceIface"
)
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "myservicekey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "serviceKeystore.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "serviceKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServerCallbackHandler")
})
public class ServiceImpl implements ServiceIface
{
   public String sayHello()
   {
      return "WS-Trust Hello World!";
   }
}
ServerCallbackHandler

ServerCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature. A certificates' password is not discoverable. The creator of the certificate must record the password he assigns and provide it when requested through the CallbackHandler. In this scenario skpass is the password for user myservicekey.

 package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service;
 
import java.util.HashMap;
import java.util.Map;
 
import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;
 
public class ServerCallbackHandler extends PasswordCallbackHandler
{
 
   public ServerCallbackHandler()
   {
      super(getInitMap());
   }
 
   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("myservicekey", "skpass");
      return passwords;
   }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File serviceKeystore.properties contains this information.

File servicestore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=sspass
org.apache.ws.security.crypto.merlin.keystore.alias=myservicekey
org.apache.ws.security.crypto.merlin.keystore.file=servicestore.jks
MANIFEST.MF

When deployed on WildFly this application requires access to the JBossWs and CXF APIs provided in module org.jboss.ws.cxf.jbossws-cxf-client. The dependency statement directs the server to provide them at deployment.

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.7.0_25-b15 (Oracle Corporation)
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client
Security Token Service (STS)

This section examines the crucial elements in providing the Security Token Service functionality described in the basic WS-Trust scenario. The components that will be discussed are.

  • STS’s WSDL

  • STS’s implementation class.

  • STSCallbackHandler class

  • Crypto properties and keystore files

  • MANIFEST.MF

  • Server configuration files

STS WSDL

The STS is a contract-first endpoint. All the WS-trust and security policies for it are declared in the WSDL, ws-trust-1.4-service.wsdl. A symmetric binding policy is used to encrypt and sign the SOAP body of messages that pass back and forth between ws-requester and the STS. The ws-requester is required to authenticate itself by providing WSS UsernameToken credentials. The rules for sharing the public and private keys in the SOAP request and response messages are declared. A detailed explanation of the security settings are provided in the comments in the listing below.

 <?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
        targetNamespace="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
        xmlns:tns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
        xmlns:wstrust="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
        xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns:wsap10="http://www.w3.org/2006/05/addressing/wsdl"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        xmlns:wsp="http://www.w3.org/ns/ws-policy"
    xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">
 
  <wsdl:types>
    <xs:schema elementFormDefault="qualified" targetNamespace='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>
 
      <xs:element name='RequestSecurityToken' type='wst:AbstractRequestSecurityTokenType' />
      <xs:element name='RequestSecurityTokenResponse' type='wst:AbstractRequestSecurityTokenType' />
 
      <xs:complexType name='AbstractRequestSecurityTokenType' >
        <xs:sequence>
          <xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
        </xs:sequence>
        <xs:attribute name='Context' type='xs:anyURI' use='optional' />
        <xs:anyAttribute namespace='##other' processContents='lax' />
      </xs:complexType>
      <xs:element name='RequestSecurityTokenCollection' type='wst:RequestSecurityTokenCollectionType' />
      <xs:complexType name='RequestSecurityTokenCollectionType' >
        <xs:sequence>
          <xs:element name='RequestSecurityToken' type='wst:AbstractRequestSecurityTokenType' minOccurs='2' maxOccurs='unbounded'/>
        </xs:sequence>
      </xs:complexType>
 
      <xs:element name='RequestSecurityTokenResponseCollection' type='wst:RequestSecurityTokenResponseCollectionType' />
      <xs:complexType name='RequestSecurityTokenResponseCollectionType' >
        <xs:sequence>
          <xs:element ref='wst:RequestSecurityTokenResponse' minOccurs='1' maxOccurs='unbounded' />
        </xs:sequence>
        <xs:anyAttribute namespace='##other' processContents='lax' />
      </xs:complexType>
 
    </xs:schema>
  </wsdl:types>
 
  <!-- WS-Trust defines the following GEDs -->
  <wsdl:message name="RequestSecurityTokenMsg">
    <wsdl:part name="request" element="wst:RequestSecurityToken" />
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseMsg">
    <wsdl:part name="response"
            element="wst:RequestSecurityTokenResponse" />
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenCollectionMsg">
    <wsdl:part name="requestCollection"
            element="wst:RequestSecurityTokenCollection"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseCollectionMsg">
    <wsdl:part name="responseCollection"
            element="wst:RequestSecurityTokenResponseCollection"/>
  </wsdl:message>
 
  <!-- This portType an example of a Requestor (or other) endpoint that
         Accepts SOAP-based challenges from a Security Token Service -->
  <wsdl:portType name="WSSecurityRequestor">
    <wsdl:operation name="Challenge">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>
 
 
  <!-- This portType is an example of an STS supporting full protocol -->
<!--
    The wsdl:portType and data types are XML elements defined by the
    WS_Trust specification.  The wsdl:portType defines the endpoints
    supported in the STS implementation.  This WSDL defines all operations
    that an STS implementation can support.
-->
  <wsdl:portType name="STS">
    <wsdl:operation name="Cancel">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/CancelFinal" message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Issue">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal" message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Renew">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/RenewFinal" message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Validate">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/ValidateFinal" message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="KeyExchangeToken">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KET" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/KETFinal" message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="RequestCollection">
      <wsdl:input message="tns:RequestSecurityTokenCollectionMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
  </wsdl:portType>
 
  <!-- This portType is an example of an endpoint that accepts
         Unsolicited RequestSecurityTokenResponse messages -->
  <wsdl:portType name="SecurityTokenResponseService">
    <wsdl:operation name="RequestSecurityTokenResponse">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>
 
<!--
    The wsp:PolicyReference binds the security requirments on all the STS endpoints.
    The wsp:Policy wsu:Id="UT_policy" element is later in this file.
-->
  <wsdl:binding name="UT_Binding" type="wstrust:STS">
    <wsp:PolicyReference URI="#UT_policy" />
      <soap:binding style="document"
          transport="http://schemas.xmlsoap.org/soap/http" />
      <wsdl:operation name="Issue">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" />
          <wsdl:input>
              <wsp:PolicyReference
               URI="#Input_policy" />
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <wsp:PolicyReference
               URI="#Output_policy" />
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="Validate">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate" />
          <wsdl:input>
              <wsp:PolicyReference
               URI="#Input_policy" />
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <wsp:PolicyReference
               URI="#Output_policy" />
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="Cancel">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel" />
          <wsdl:input>
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="Renew">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew" />
          <wsdl:input>
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="KeyExchangeToken">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KeyExchangeToken" />
          <wsdl:input>
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="RequestCollection">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/RequestCollection" />
          <wsdl:input>
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
  </wsdl:binding>

  <wsdl:service name="SecurityTokenService">
      <wsdl:port name="UT_Port" binding="tns:UT_Binding">
         <soap:address location="http://localhost:8080/SecurityTokenService/UT" />
      </wsdl:port>
  </wsdl:service>

  <wsp:Policy wsu:Id="UT_policy">
      <wsp:ExactlyOne>
         <wsp:All>
<!--
    The sp:UsingAddressing element, indicates that the endpoints of this
    web service conforms to the WS-Addressing specification.  More detail
    can be found here: [http://www.w3.org/TR/2006/CR-ws-addr-wsdl-20060529]
-->
            <wsap10:UsingAddressing/>
<!--
    The sp:SymmetricBinding element indicates that security is provided
    at the SOAP layer and any initiator must authenticate itself by providing
    WSS UsernameToken credentials.
-->
            <sp:SymmetricBinding
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
<!--
    In a symmetric binding, the keys used for encrypting and signing in both
    directions are derived from a single key, the one specified by the
    sp:ProtectionToken element.  The sp:X509Token sub-element declares this
    key to be a X.509 certificate and the
    IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never"
    attribute adds the requirement that the token MUST NOT be included in
    any messages sent between the initiator and the recipient; rather, an
    external reference to the token should be used.  Lastly the WssX509V3Token10
    sub-element declares that the Username token presented by the initiator
    should be compliant with Web Services Security UsernameToken Profile
    1.0 specification. [ http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf ]
-->
                  <sp:ProtectionToken>
                     <wsp:Policy>
                        <sp:X509Token
                           sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
                           <wsp:Policy>
                              <sp:RequireDerivedKeys />
                              <sp:RequireThumbprintReference />
                              <sp:WssX509V3Token10 />
                           </wsp:Policy>
                        </sp:X509Token>
                     </wsp:Policy>
                  </sp:ProtectionToken>
<!--
    The sp:AlgorithmSuite element, requires the Basic256 algorithm suite
    be used in performing cryptographic operations.
-->
                  <sp:AlgorithmSuite>
                     <wsp:Policy>
                        <sp:Basic256 />
                     </wsp:Policy>
                  </sp:AlgorithmSuite>
<!--
    The sp:Layout element,  indicates the layout rules to apply when adding
    items to the security header.  The sp:Lax sub-element indicates items
    are added to the security header in any order that conforms to
    WSS: SOAP Message Security.
-->
                  <sp:Layout>
                     <wsp:Policy>
                        <sp:Lax />
                     </wsp:Policy>
                  </sp:Layout>
                  <sp:IncludeTimestamp />
                  <sp:EncryptSignature />
                  <sp:OnlySignEntireHeadersAndBody />
               </wsp:Policy>
            </sp:SymmetricBinding>
<!--
    The sp:SignedSupportingTokens element declares that the security header
    of messages must contain a sp:UsernameToken and the token must be signed.
    The attribute IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"
    on sp:UsernameToken indicates that the token MUST be included in all
    messages sent from initiator to the recipient and that the token MUST
    NOT be included in messages sent from the recipient to the initiator.
    And finally the element sp:WssUsernameToken10 is a policy assertion
    indicating the Username token should be as defined in  Web Services
    Security UsernameToken Profile 1.0
-->
            <sp:SignedSupportingTokens
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:UsernameToken
                     sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                     <wsp:Policy>
                        <sp:WssUsernameToken10 />
                     </wsp:Policy>
                  </sp:UsernameToken>
               </wsp:Policy>
            </sp:SignedSupportingTokens>
<!--
    The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
    to be supported by the STS.  These particular elements generally refer
    to how keys are referenced within the SOAP envelope.  These are normally
    handled by CXF.
-->
            <sp:Wss11
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:MustSupportRefKeyIdentifier />
                  <sp:MustSupportRefIssuerSerial />
                  <sp:MustSupportRefThumbprint />
                  <sp:MustSupportRefEncryptedKey />
               </wsp:Policy>
            </sp:Wss11>
<!--
    The sp:Trust13 element declares controls for WS-Trust 1.3 options.
    They are policy assertions related to exchanges specifically with
    client and server challenges and entropy behaviors.  Again these are
    normally handled by CXF.
-->
            <sp:Trust13
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:MustSupportIssuedTokens />
                  <sp:RequireClientEntropy />
                  <sp:RequireServerEntropy />
               </wsp:Policy>
            </sp:Trust13>
         </wsp:All>
      </wsp:ExactlyOne>
   </wsp:Policy>

   <wsp:Policy wsu:Id="Input_policy">
      <wsp:ExactlyOne>
         <wsp:All>
            <sp:SignedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
               <sp:Header Name="To"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="From"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="FaultTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="ReplyTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="MessageID"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="RelatesTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="Action"
                  Namespace="http://www.w3.org/2005/08/addressing" />
            </sp:SignedParts>
            <sp:EncryptedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
            </sp:EncryptedParts>
         </wsp:All>
      </wsp:ExactlyOne>
   </wsp:Policy>

   <wsp:Policy wsu:Id="Output_policy">
      <wsp:ExactlyOne>
         <wsp:All>
            <sp:SignedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
               <sp:Header Name="To"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="From"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="FaultTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="ReplyTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="MessageID"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="RelatesTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="Action"
                  Namespace="http://www.w3.org/2005/08/addressing" />
            </sp:SignedParts>
            <sp:EncryptedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
            </sp:EncryptedParts>
         </wsp:All>
      </wsp:ExactlyOne>
   </wsp:Policy>
 
</wsdl:definitions>
STS Implementation

The Apache CXF’s STS, SecurityTokenServiceProvider, is a web service provider that is compliant with the protocols and functionality defined by the WS-Trust specification. It has a modular architecture. Many of its components are configurable or replaceable and there are many optional features that are enabled by implementing and configuring plug-ins. Users can customize their own STS by extending from SecurityTokenServiceProvider and overriding the default settings. Extensive information about the CXF’s STS configurable and pluggable components can be found here.

This STS implementation class, SimpleSTS, is a POJO that extends from SecurityTokenServiceProvider. Note that the class is defined with a WebServiceProvider annotation and not a WebService annotation. This annotation defines the service as a Provider-based endpoint, meaning it supports a more messaging-oriented approach to Web services. In particular, it signals that the exchanged messages will be XML documents of some type. SecurityTokenServiceProvider is an implementation of the javax.xml.ws.Provider interface. In comparison the WebService annotation defines a (service endpoint interface) SEI-based endpoint which supports message exchange via SOAP envelopes.

As was done in the ServiceImpl class, the WSS4J annotations EndpointProperties and EndpointProperty are providing endpoint configuration for the CXF runtime. This was previous described here.

The InInterceptors annotation is used to specify a JBossWS integration interceptor to be used for authenticating incoming requests; JAAS integration is used here for authentication, the username/passoword coming from the UsernameToken in the ws-requester message are used for authenticating the requester against a security domain on the application server hosting the STS deployment.

In this implementation we are customizing the operations of token issuance, token validation and their static properties.

StaticSTSProperties is used to set select properties for configuring resources in the STS. You may think this is a duplication of the settings made with the WSS4J annotations. The values are the same but the underlaying structures being set are different, thus this information must be declared in both places.

The setIssuer setting is important because it uniquely identifies the issuing STS. The issuer string is embedded in issued tokens and, when validating tokens, the STS checks the issuer string value. Consequently, it is important to use the issuer string in a consistent way, so that the STS can recognize the tokens that it has issued.

The setEndpoints call allows the declaration of a set of allowed token recipients by address. The addresses are specified as reg-ex patterns.

TokenIssueOperation and TokenValidateOperation have a modular structure. This allows custom behaviors to be injected into the processing of messages. In this case we are overriding the SecurityTokenServiceProvider’s default behavior and performing SAML token processing and validation. CXF provides an implementation of a SAMLTokenProvider and SAMLTokenValidator which we are using rather than writing our own.

Learn more about the SAMLTokenProvider here.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.xml.ws.WebServiceProvider;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.operation.TokenValidateOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.sts.token.validator.SAMLTokenValidator;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;

@WebServiceProvider(serviceName = "SecurityTokenService",
      portName = "UT_Port",
      targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
      wsdlLocation = "WEB-INF/wsdl/ws-trust-1.4-service.wsdl")
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.STSCallbackHandler"),
      //to let the JAAS integration deal with validation through the interceptor below
      @EndpointProperty(key = "ws-security.validate.token", value = "false")

})
@InInterceptors(interceptors = {"org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor"})
public class SampleSTS extends SecurityTokenServiceProvider
{
   public SampleSTS() throws Exception
   {
      super();

      StaticSTSProperties props = new StaticSTSProperties();
      props.setSignaturePropertiesFile("stsKeystore.properties");
      props.setSignatureUsername("mystskey");
      props.setCallbackHandlerClass(STSCallbackHandler.class.getName());
      props.setIssuer("DoubleItSTSIssuer");

      List<ServiceMBean> services = new LinkedList<ServiceMBean>();
      StaticService service = new StaticService();
      service.setEndpoints(Arrays.asList(
              "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
              "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
              "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService"
              ));
      services.add(service);

      TokenIssueOperation issueOperation = new TokenIssueOperation();
      issueOperation.setServices(services);
      issueOperation.getTokenProviders().add(new SAMLTokenProvider());
      issueOperation.setStsProperties(props);

      TokenValidateOperation validateOperation = new TokenValidateOperation();
      validateOperation.getTokenValidators().add(new SAMLTokenValidator());
      validateOperation.setStsProperties(props);

      this.setIssueOperation(issueOperation);
      this.setValidateOperation(validateOperation);
   }
}
STSCallbackHandler

STSCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts;
 
import java.util.HashMap;
import java.util.Map;
 
import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;
 
public class STSCallbackHandler extends PasswordCallbackHandler
{
   public STSCallbackHandler()
   {
      super(getInitMap());
   }
 
   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("mystskey", "stskpass");
      return passwords;
   }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File stsKeystore.properties contains this information.

File servicestore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=stsspass
org.apache.ws.security.crypto.merlin.keystore.file=stsstore.jks
MANIFEST.MF

When deployed on WildFly, this application requires access to the JBossWs and CXF APIs provided in modules org.jboss.ws.cxf.jbossws-cxf-client and org.apache.cxf. The Apache CXF internals, org.apache.cxf.impl, are needed to build the STS configuration in the SampleSTS constructor. The dependency statement directs the server to provide them at deployment.

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.7.0_25-b15 (Oracle Corporation)
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client,org.apache.cxf.impl
Security Domain

The STS requires a JBoss security domain be configured. The jboss-web.xml descriptor declares a named security domain,"JBossWS-trust-sts" to be used by this service for authentication. This security domain requires two properties files and the addition of a security-domain declaration in the JBoss server configuration file.

For this scenario the domain needs to contain user alice, password clarinet, and role friend. See the listings below for jbossws-users.properties and jbossws-roles.properties. In addition the following XML must be added to the JBoss security subsystem in the server configuration file. Replace " SOME_PATH" with appropriate information.

 <security-domain name="JBossWS-trust-sts">
  <authentication>
    <login-module code="UsersRoles" flag="required">
      <module-option name="usersProperties" value="/SOME_PATH/jbossws-users.properties"/>
      <module-option name="unauthenticatedIdentity" value="anonymous"/>
      <module-option name="rolesProperties" value="/SOME_PATH/jbossws-roles.properties"/>
    </login-module>
  </authentication>
</security-domain>

jboss-web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" ">
<jboss-web>
  <security-domain>java:/jaas/JBossWS-trust-sts</security-domain>
</jboss-web>

jbossws-users.properties

# A sample users.properties file for use with the UsersRolesLoginModule
alice=clarinet

jbossws-roles.properties

# A sample roles.properties file for use with the UsersRolesLoginModule
alice=friend

WS-MetadataExchange and interoperability

To achieve better interoperability, you might consider allowing the STS endpoint to reply to WS-MetadataExchange messages directed to the /mex URL sub-path (e.g. http://localhost:8080/jaxws-samples-wsse-policy-trust-sts/SecurityTokenService/mex). This can be done by tweaking the url-pattern for the underlying endpoint servlet, for instance by adding a web.xml descriptor as follows to the deployment:<?xml version="1.0" encoding="UTF-8"?>
<web-app
version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">;
<servlet>
<servlet-name>TestSecurityTokenService</servlet-name>
<servlet-class>org.jboss.test.ws.jaxws.samples.wsse.policy.trust.SampleSTS</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestSecurityTokenService</servlet-name>
<url-pattern>/SecurityTokenService/*</url-pattern>
</servlet-mapping>
</web-app>
As a matter of fact, at the time of writing some webservices implementations (including Metro) assume the /mex URL as the default choice for directing WS-MetadataExchange requests to and use that to retrieve STS wsdl contracts.
Web service requester

This section examines the crucial elements in calling a web service that implements endpoint security as described in the basic WS-Trust scenario. The components that will be discussed are.

  • web service requester’s implementation

  • ClientCallbackHandler

  • Crypto properties and keystore files

Web service requester Implementation

The ws-requester, the client, uses standard procedures for creating a reference to the web service in the first four line. To address the endpoint security requirements, the web service’s "Request Context" is configured with the information needed in message generation. In addition, the STSClient that communicates with the STS is configured with similar values. Note the key strings ending with a ".it" suffix. This suffix flags these settings as belonging to the STSClient. The internal CXF code assigns this information to the STSClient that is auto-generated for this service call.

There is an alternate method of setting up the STSCLient. The user may provide their own instance of the STSClient. The CXF code will use this object and not auto-generate one. This is used in the ActAs and OnBehalfOf examples. When providing the STSClient in this way, the user must provide a org.apache.cxf.Bus for it and the configuration keys must not have the ".it" suffix.

QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ServiceIface proxy = (ServiceIface) service.getPort(ServiceIface.class);

// set the security related configuration information for the service "request"
Map<String, Object> ctx = ((BindingProvider) proxy).getRequestContext();
ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
   Thread.currentThread().getContextClassLoader().getResource(
   "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
   Thread.currentThread().getContextClassLoader().getResource(
   "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");
ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");


//-- Configuration settings that will be transfered to the STSClient
// "alice" is the name provided for the WSS Username. Her password will
// be retreived from the ClientCallbackHander by the STSClient.
ctx.put(SecurityConstants.USERNAME + ".it", "alice");
ctx.put(SecurityConstants.CALLBACK_HANDLER + ".it", new ClientCallbackHandler());
ctx.put(SecurityConstants.ENCRYPT_PROPERTIES + ".it",
   Thread.currentThread().getContextClassLoader().getResource(
   "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.ENCRYPT_USERNAME + ".it", "mystskey");
// alias name in the keystore to get the user's public key to send to the STS
ctx.put(SecurityConstants.STS_TOKEN_USERNAME + ".it", "myclientkey");
// Crypto property configuration to use for the STS
ctx.put(SecurityConstants.STS_TOKEN_PROPERTIES + ".it",
   Thread.currentThread().getContextClassLoader().getResource(
   "META-INF/clientKeystore.properties"));
// write out an X509Certificate structure in UseKey/KeyInfo
ctx.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO + ".it", "true");
// Setting indicates the  STSclient should not try using the WS-MetadataExchange
// call using STS EPR WSA address when the endpoint contract does not contain
// WS-MetadataExchange info.
ctx.put("ws-security.sts.disable-wsmex-call-using-epr-address", "true");

proxy.sayHello();
ClientCallbackHandler

ClientCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature. Note that "alice" and her password have been provided here. This information is not in the (JKS) keystore but provided in the WildFly security domain. It was declared in file jbossws-users.properties.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared;

import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;

public class ClientCallbackHandler implements CallbackHandler {

    public void handle(Callback[] callbacks) throws IOException,
            UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof WSPasswordCallback) {
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                if ("myclientkey".equals(pc.getIdentifier())) {
                    pc.setPassword("ckpass");
                    break;
                } else if ("alice".equals(pc.getIdentifier())) {
                    pc.setPassword("clarinet");
                    break;
                }
            }
        }
    }
}
Requester Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File clientKeystore.properties contains this information.

File clientstore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=cspass
org.apache.ws.security.crypto.merlin.keystore.alias=myclientkey
org.apache.ws.security.crypto.merlin.keystore.file=META-INF/clientstore.jks

PicketLink provides facilities for building up an alternative to the Apache CXF Security Token Service implementation.

Similarly to the previous implementation, the STS is served through a WebServiceProvider annotated POJO:

 package org.jboss.test.ws.jaxws.samples.wsse.policy.trust;
 
import javax.annotation.Resource;
import javax.xml.ws.Service;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.WebServiceProvider;
 
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.interceptor.InInterceptors;
import org.picketlink.identity.federation.core.wstrust.PicketLinkSTS;
 
@WebServiceProvider(serviceName = "PicketLinkSTS", portName = "PicketLinkSTSPort", targetNamespace = "urn:picketlink:identity-federation:sts", wsdlLocation = "WEB-INF/wsdl/PicketLinkSTS.wsdl")
@ServiceMode(value = Service.Mode.MESSAGE)
//be sure to have dependency on org.apache.cxf module when on AS7, otherwise Apache CXF annotations are ignored
@EndpointProperties(value = {
@EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
@EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
@EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.STSCallbackHandler"),
@EndpointProperty(key = "ws-security.validate.token", value = "false") //to let the JAAS integration deal with validation through the interceptor below
})
@InInterceptors(interceptors =
 
)
public class PicketLinkSTService extends PicketLinkSTS {
@Resource
public void setWSC(WebServiceContext wctx)
Unknown macro: { this.context = wctx; }
 
}

The @WebServiceProvider annotation references the following WS-Policy enabled wsdl contract; please note the wsdl operations, messages and such must match the PicketLinkSTS implementation:

<?xml version="1.0"?>
<wsdl:definitions name="PicketLinkSTS" targetNamespace="urn:picketlink:identity-federation:sts"
    xmlns:tns="urn:picketlink:identity-federation:sts"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:wsap10="http://www.w3.org/2006/05/addressing/wsdl"
    xmlns:wsp="http://www.w3.org/ns/ws-policy"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
    xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/">
  <wsdl:types>
    <xs:schema elementFormDefault="qualified" targetNamespace='http://docs.oasis-open.org/ws-sx/ws-trust/200512' xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name='RequestSecurityToken' type='wst:AbstractRequestSecurityTokenType' />
      <xs:element name='RequestSecurityTokenResponse' type='wst:AbstractRequestSecurityTokenType' />
      <xs:complexType name='AbstractRequestSecurityTokenType' >
        <xs:sequence>
          <xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
        </xs:sequence>
        <xs:attribute name='Context' type='xs:anyURI' use='optional' />
        <xs:anyAttribute namespace='##other' processContents='lax' />
      </xs:complexType>
      <xs:element name='RequestSecurityTokenCollection' type='wst:RequestSecurityTokenCollectionType' />
      <xs:complexType name='RequestSecurityTokenCollectionType' >
        <xs:sequence>
          <xs:element name='RequestSecurityToken' type='wst:AbstractRequestSecurityTokenType' minOccurs='2' maxOccurs='unbounded'/>
        </xs:sequence>
      </xs:complexType>
      <xs:element name='RequestSecurityTokenResponseCollection' type='wst:RequestSecurityTokenResponseCollectionType' />
      <xs:complexType name='RequestSecurityTokenResponseCollectionType' >
        <xs:sequence>
          <xs:element ref='wst:RequestSecurityTokenResponse' minOccurs='1' maxOccurs='unbounded' />
        </xs:sequence>
        <xs:anyAttribute namespace='##other' processContents='lax' />
      </xs:complexType>
    </xs:schema>
  </wsdl:types>

  <wsdl:message name="RequestSecurityTokenMsg">
    <wsdl:part name="request" element="wst:RequestSecurityToken" />
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseCollectionMsg">
    <wsdl:part name="responseCollection"
            element="wst:RequestSecurityTokenResponseCollection"/>
  </wsdl:message>

  <wsdl:portType name="SecureTokenService">
    <wsdl:operation name="IssueToken">
      <wsdl:input wsap10:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsap10:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal" message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="STSBinding" type="tns:SecureTokenService">
    <wsp:PolicyReference URI="#UT_policy" />
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="IssueToken">
      <soap12:operation soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" style="document"/>
      <wsdl:input>
        <wsp:PolicyReference URI="#Input_policy" />
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsp:PolicyReference URI="#Output_policy" />
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="PicketLinkSTS">
    <wsdl:port name="PicketLinkSTSPort" binding="tns:STSBinding">
      <soap12:address location="http://localhost:8080/picketlink-sts/PicketLinkSTS"/>
    </wsdl:port>
  </wsdl:service>

  <wsp:Policy wsu:Id="UT_policy">
      <wsp:ExactlyOne>
         <wsp:All>
            <wsap10:UsingAddressing/>
            <sp:SymmetricBinding
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:ProtectionToken>
                     <wsp:Policy>
                        <sp:X509Token
                           sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
                           <wsp:Policy>
                              <sp:RequireDerivedKeys />
                              <sp:RequireThumbprintReference />
                              <sp:WssX509V3Token10 />
                           </wsp:Policy>
                        </sp:X509Token>
                     </wsp:Policy>
                  </sp:ProtectionToken>
                  <sp:AlgorithmSuite>
                     <wsp:Policy>
                        <sp:Basic256 />
                     </wsp:Policy>
                  </sp:AlgorithmSuite>
                  <sp:Layout>
                     <wsp:Policy>
                        <sp:Lax />
                     </wsp:Policy>
                  </sp:Layout>
                  <sp:IncludeTimestamp />
                  <sp:EncryptSignature />
                  <sp:OnlySignEntireHeadersAndBody />
               </wsp:Policy>
            </sp:SymmetricBinding>
            <sp:SignedSupportingTokens
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:UsernameToken
                     sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                     <wsp:Policy>
                        <sp:WssUsernameToken10 />
                     </wsp:Policy>
                  </sp:UsernameToken>
               </wsp:Policy>
            </sp:SignedSupportingTokens>
            <sp:Wss11
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:MustSupportRefKeyIdentifier />
                  <sp:MustSupportRefIssuerSerial />
                  <sp:MustSupportRefThumbprint />
                  <sp:MustSupportRefEncryptedKey />
               </wsp:Policy>
            </sp:Wss11>
            <sp:Trust13
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:MustSupportIssuedTokens />
                  <sp:RequireClientEntropy />
                  <sp:RequireServerEntropy />
               </wsp:Policy>
            </sp:Trust13>
         </wsp:All>
      </wsp:ExactlyOne>
   </wsp:Policy>

   <wsp:Policy wsu:Id="Input_policy">
      <wsp:ExactlyOne>
         <wsp:All>
            <sp:SignedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
               <sp:Header Name="To"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="From"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="FaultTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="ReplyTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="MessageID"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="RelatesTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="Action"
                  Namespace="http://www.w3.org/2005/08/addressing" />
            </sp:SignedParts>
            <sp:EncryptedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
            </sp:EncryptedParts>
         </wsp:All>
      </wsp:ExactlyOne>
   </wsp:Policy>

   <wsp:Policy wsu:Id="Output_policy">
      <wsp:ExactlyOne>
         <wsp:All>
            <sp:SignedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
               <sp:Header Name="To"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="From"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="FaultTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="ReplyTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="MessageID"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="RelatesTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="Action"
                  Namespace="http://www.w3.org/2005/08/addressing" />
            </sp:SignedParts>
            <sp:EncryptedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
            </sp:EncryptedParts>
         </wsp:All>
      </wsp:ExactlyOne>
   </wsp:Policy>

</wsdl:definitions>

Differently from the Apache CXF STS example described above, the PicketLink based STS gets its configuration from a picketlink-sts.xml descriptor which must be added in WEB-INF into the deployment; please refer to the PicketLink documentation for further information:

<PicketLinkSTS xmlns="urn:picketlink:identity-federation:config:1.0"
    STSName="PicketLinkSTS" TokenTimeout="7200" EncryptToken="false">
    <KeyProvider ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager">
        <Auth Key="KeyStoreURL" Value="stsstore.jks"/>
        <Auth Key="KeyStorePass" Value="stsspass"/>
        <Auth Key="SigningKeyAlias" Value="mystskey"/>
        <Auth Key="SigningKeyPass" Value="stskpass"/>
        <ValidatingAlias Key="http://localhost:8080/jaxws-samples-wsse-policy-trust/SecurityService" Value="myservicekey"/>
    </KeyProvider>
    <TokenProviders>
            <TokenProvider ProviderClass="org.picketlink.identity.federation.core.wstrust.plugins.saml.SAML11TokenProvider"
                TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"
            TokenElement="Assertion"
            TokenElementNS="urn:oasis:names:tc:SAML:1.0:assertion"/>
            <TokenProvider ProviderClass="org.picketlink.identity.federation.core.wstrust.plugins.saml.SAML20TokenProvider"
                TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0"
            TokenElement="Assertion"
            TokenElementNS="urn:oasis:names:tc:SAML:2.0:assertion"/>
    </TokenProviders>
</PicketLinkSTS>

Finally, the PicketLink alternative approach of course requires different WildFly module dependencies to be declared in the MANIFEST.MF:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.6.0_26-b03 (Sun Microsystems Inc.)
Dependencies: org.apache.ws.security,org.apache.cxf,org.picketlink

Here is how the PicketLink STS endpoint is packaged:

alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-samples-wsse-policy-trustPicketLink-sts.war
     0 Mon Sep 03 17:38:38 CEST 2012 META-INF/
   174 Mon Sep 03 17:38:36 CEST 2012 META-INF/MANIFEST.MF
     0 Mon Sep 03 17:38:38 CEST 2012 WEB-INF/
     0 Mon Sep 03 17:38:38 CEST 2012 WEB-INF/classes/
     0 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/classes/org/
     0 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/classes/org/jboss/
     0 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/classes/org/jboss/test/
     0 Mon Sep 03 16:35:52 CEST 2012 WEB-INF/classes/org/jboss/test/ws/
     0 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/classes/org/jboss/test/ws/jaxws/
     0 Mon Sep 03 16:35:52 CEST 2012 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/
     0 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/
     0 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/
     0 Mon Sep 03 16:35:52 CEST 2012 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/trust/
  1686 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/trust/PicketLinkSTService.class
  1148 Mon Sep 03 16:35:52 CEST 2012 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/trust/STSCallbackHandler.class
   251 Mon Sep 03 17:38:34 CEST 2012 WEB-INF/jboss-web.xml
     0 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/wsdl/
  9070 Mon Sep 03 17:38:34 CEST 2012 WEB-INF/wsdl/PicketLinkSTS.wsdl
  1267 Mon Sep 03 17:38:34 CEST 2012 WEB-INF/classes/picketlink-sts.xml
  1054 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/classes/stsKeystore.properties
  3978 Mon Sep 03 16:35:50 CEST 2012 WEB-INF/classes/stsstore.jks
ActAs WS-Trust Scenario

The ActAs feature is used in scenarios that require composite delegation. It is commonly used in multi-tiered systems where an application calls a service on behalf of a logged in user or a service calls another service on behalf of the original caller.

ActAs is nothing more than a new sub-element in the RequestSecurityToken (RST). It provides additional information about the original caller when a token is negotiated with the STS. The ActAs element usually takes the form of a token with identity claims such as name, role, and authorization code, for the client to access the service.

The ActAs scenario is an extension of the basic WS-Trust scenario. In this example the ActAs service calls the ws-service on behalf of a user. There are only a couple of additions to the basic scenario’s code. An ActAs web service provider and callback handler have been added. The ActAs web services' WSDL imposes the same security policies as the ws-provider. UsernameTokenCallbackHandler is new. It is a utility that generates the content for the ActAs element. And lastly there are a couple of code additions in the STS to support the ActAs request.

Web service provider

This section examines the web service elements from the basic WS-Trust scenario that have been changed to address the needs of the ActAs example. The components are

  • ActAs web service provider’s WSDL

  • ActAs web service provider’s Interface and Implementation classes.

  • ActAsCallbackHandler class

  • UsernameTokenCallbackHandler

  • Crypto properties and keystore files

  • MANIFEST.MF

Web service provider WSDL

The ActAs web service provider’s WSDL is a clone of the ws-provider’s WSDL. The wsp:Policy section is the same. There are changes to the service endpoint, targetNamespace, portType, binding name, and service.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy" name="ActAsService"
             xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsp="http://www.w3.org/ns/ws-policy"
             xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
             xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
             xmlns:wsaws="http://www.w3.org/2005/08/addressing"
             xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
             xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
                    schemaLocation="ActAsService_schema1.xsd"/>
        </xsd:schema>
    </types>
    <message name="sayHello">
        <part name="parameters" element="tns:sayHello"/>
    </message>
    <message name="sayHelloResponse">
        <part name="parameters" element="tns:sayHelloResponse"/>
    </message>
    <portType name="ActAsServiceIface">
        <operation name="sayHello">
            <input message="tns:sayHello"/>
            <output message="tns:sayHelloResponse"/>
        </operation>
    </portType>
    <binding name="ActAsServicePortBinding" type="tns:ActAsServiceIface">
        <wsp:PolicyReference URI="#AsymmetricSAML2Policy" />
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="sayHello">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Input_Policy" />
            </input>
            <output>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Output_Policy" />
            </output>
        </operation>
    </binding>
    <service name="ActAsService">
        <port name="ActAsServicePort" binding="tns:ActAsServicePortBinding">
            <soap:address location="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-actas/ActAsService"/>
        </port>
    </service>
 
</definitions>
Web Service Interface

The web service provider interface class, ActAsServiceIface, is a simple web service definition.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;
 
import javax.jws.WebMethod;
import javax.jws.WebService;
 
@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
)
public interface ActAsServiceIface
{
   @WebMethod
   String sayHello();
}
Web Service Implementation

The web service provider implementation class, ActAsServiceImpl, is a simple POJO. It uses the standard WebService annotation to define the service endpoint and two Apache WSS4J annotations, EndpointProperties and EndpointProperty used for configuring the endpoint for the CXF runtime. The WSS4J configuration information provided is for WSS4J’s Crypto Merlin implementation.

ActAsServiceImpl is calling ServiceImpl acting on behalf of the user. Method setupService performs the requisite configuration setup.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;
 
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.STSClient;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServiceIface;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared.WSTrustAppUtils;
 
import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
 
@WebService
(
   portName = "ActAsServicePort",
   serviceName = "ActAsService",
   wsdlLocation = "WEB-INF/wsdl/ActAsService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas.ActAsServiceIface"
)
 
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "myactaskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value =  "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas.ActAsCallbackHandler")
})
 
public class ActAsServiceImpl implements ActAsServiceIface
{
   public String sayHello() {
      try {
         ServiceIface proxy = setupService();
         return "ActAs " + proxy.sayHello();
      } catch (MalformedURLException e) {
         e.printStackTrace();
      }
      return null;
   }
 
   private  ServiceIface setupService()throws MalformedURLException {
      ServiceIface proxy = null;
      Bus bus = BusFactory.newInstance().createBus();
 
      try {
         BusFactory.setThreadDefaultBus(bus);
 
         final String serviceURL = "http://" + WSTrustAppUtils.getServerHost() + ":8080/jaxws-samples-wsse-policy-trust/SecurityService";
         final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
         final URL wsdlURL = new URL(serviceURL + "?wsdl");
         Service service = Service.create(wsdlURL, serviceName);
         proxy = (ServiceIface) service.getPort(ServiceIface.class);
 
         Map<String, Object> ctx = ((BindingProvider) proxy).getRequestContext();
         ctx.put(SecurityConstants.CALLBACK_HANDLER, new ActAsCallbackHandler());
 
         ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("actasKeystore.properties" ));
         ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myactaskey" );
         ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("../../META-INF/clientKeystore.properties" ));
         ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");
 
         STSClient stsClient = new STSClient(bus);
         Map<String, Object> props = stsClient.getProperties();
         props.put(SecurityConstants.USERNAME, "alice");
         props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
         props.put(SecurityConstants.STS_TOKEN_USERNAME, "myactaskey" );
         props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("actasKeystore.properties" ));
         props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");
 
         ctx.put(SecurityConstants.STS_CLIENT, stsClient);
 
      } finally {
         bus.shutdown(true);
      }
 
      return proxy;
   }
 
}
ActAsCallbackHandler

ActAsCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature. This class has been revised to return the passwords for this service, myactaskey and the "actas" user, alice.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;
 
import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;
import java.util.HashMap;
import java.util.Map;
 
public class ActAsCallbackHandler extends PasswordCallbackHandler {
 
   public ActAsCallbackHandler()
   {
      super(getInitMap());
   }
 
   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("myactaskey", "aspass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
UsernameTokenCallbackHandler

The ActAs and OnBeholdOf sub-elements of the RequestSecurityToken are required to be defined as WSSE Username Tokens. This utility generates the properly formated element.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared;
 
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.delegation.DelegationCallback;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.message.token.UsernameToken;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
 
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
import java.util.Map;
 
/**
* A utility to provide the 3 different input parameter types for jaxws property
* "ws-security.sts.token.act-as" and "ws-security.sts.token.on-behalf-of".
* This implementation obtains a username and password via the jaxws property
* "ws-security.username" and "ws-security.password" respectively, as defined
* in SecurityConstants.  It creates a wss UsernameToken to be used as the
* delegation token.
*/
 
public class UsernameTokenCallbackHandler implements CallbackHandler {
 
   public void handle(Callback[] callbacks)
      throws IOException, UnsupportedCallbackException {
      for (int i = 0; i < callbacks.length; i++) {
         if (callbacks[i] instanceof DelegationCallback) {
            DelegationCallback callback = (DelegationCallback) callbacks[i];
            Message message = callback.getCurrentMessage();
 
            String username =
               (String)message.getContextualProperty(SecurityConstants.USERNAME);
            String password =
               (String)message.getContextualProperty(SecurityConstants.PASSWORD);
            if (username != null) {
               Node contentNode = message.getContent(Node.class);
               Document doc = null;
               if (contentNode != null) {
                  doc = contentNode.getOwnerDocument();
               } else {
                  doc = DOMUtils.createDocument();
               }
               UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
               callback.setToken(usernameToken.getElement());
            }
         } else {
            throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
         }
      }
   }
 
   /**
    * Provide UsernameToken as a string.
    * @param ctx
    * @return
    */
   public String getUsernameTokenString(Map<String, Object> ctx){
      Document doc = DOMUtils.createDocument();
      String result = null;
      String username = (String)ctx.get(SecurityConstants.USERNAME);
      String password = (String)ctx.get(SecurityConstants.PASSWORD);
      if (username != null) {
         UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
         result = toString(usernameToken.getElement().getFirstChild().getParentNode());
      }
      return result;
   }
 
   /**
    *
    * @param username
    * @param password
    * @return
    */
   public String getUsernameTokenString(String username, String password){
      Document doc = DOMUtils.createDocument();
      String result = null;
      if (username != null) {
         UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
         result = toString(usernameToken.getElement().getFirstChild().getParentNode());
      }
      return result;
   }
 
   /**
    * Provide UsernameToken as a DOM Element.
    * @param ctx
    * @return
    */
   public Element getUsernameTokenElement(Map<String, Object> ctx){
      Document doc = DOMUtils.createDocument();
      Element result = null;
      UsernameToken usernameToken = null;
         String username = (String)ctx.get(SecurityConstants.USERNAME);
      String password = (String)ctx.get(SecurityConstants.PASSWORD);
      if (username != null) {
         usernameToken = createWSSEUsernameToken(username,password, doc);
         result = usernameToken.getElement();
      }
      return result;
   }
 
   /**
    *
    * @param username
    * @param password
    * @return
    */
   public Element getUsernameTokenElement(String username, String password){
      Document doc = DOMUtils.createDocument();
      Element result = null;
      UsernameToken usernameToken = null;
      if (username != null) {
         usernameToken = createWSSEUsernameToken(username,password, doc);
         result = usernameToken.getElement();
      }
      return result;
   }
 
   private UsernameToken createWSSEUsernameToken(String username, String password, Document doc) {
 
      UsernameToken usernameToken = new UsernameToken(true, doc,
         (password == null)? null: WSConstants.PASSWORD_TEXT);
      usernameToken.setName(username);
      usernameToken.addWSUNamespace();
      usernameToken.addWSSENamespace();
      usernameToken.setID("id-" + username);
 
      if (password != null){
         usernameToken.setPassword(password);
      }
 
      return usernameToken;
   }
 
 
   private String toString(Node node) {
      String str = null;
 
      if (node != null) {
         DOMImplementationLS lsImpl = (DOMImplementationLS)
            node.getOwnerDocument().getImplementation().getFeature("LS", "3.0");
         LSSerializer serializer = lsImpl.createLSSerializer();
         serializer.getDomConfig().setParameter("xml-declaration", false); //by default its true, so set it to false to get String without xml-declaration
         str = serializer.writeToString(node);
      }
      return str;
   }
 
}
Crypto properties and keystore files

The ActAs service must provide its own credentials. The requisite properties file, actasKeystore.properties, and keystore, actasstore.jks, were created.

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=aapass
org.apache.ws.security.crypto.merlin.keystore.alias=myactaskey
org.apache.ws.security.crypto.merlin.keystore.file=actasstore.jks
MANIFEST.MF

When deployed on WildFly this application requires access to the JBossWs and CXF APIs provided in modules org.jboss.ws.cxf.jbossws-cxf-client and org.apache.cxf. The Apache CXF internals, org.apache.cxf.impl, are needed in handling the ActAs and OnBehalfOf extensions. The dependency statement directs the server to provide them at deployment.

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.7.0_25-b15 (Oracle Corporation)
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client, org.apache.cxf.impl
Security Token Service

This section examines the STS elements from the basic WS-Trust scenario that have been changed to address the needs of the ActAs example. The components are.

  • STS’s implementation class.

  • STSCallbackHandler class

STS Implementation class

The initial description of SampleSTS can be found here.

The declaration of the set of allowed token recipients by address has been extended to accept ActAs addresses and OnBehalfOf addresses. The addresses are specified as reg-ex patterns.

The TokenIssueOperation requires class, UsernameTokenValidator be provided in order to validate the contents of the OnBehalfOf claims and class, UsernameTokenDelegationHandler to be provided in order to process the token delegation request of the ActAs on OnBehalfOf user.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts;
 
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
 
import javax.xml.ws.WebServiceProvider;
 
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.operation.TokenValidateOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.delegation.UsernameTokenDelegationHandler;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.sts.token.validator.SAMLTokenValidator;
import org.apache.cxf.sts.token.validator.UsernameTokenValidator;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;
 
@WebServiceProvider(serviceName = "SecurityTokenService",
      portName = "UT_Port",
      targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
      wsdlLocation = "WEB-INF/wsdl/ws-trust-1.4-service.wsdl")
//be sure to have dependency on org.apache.cxf module when on AS7, otherwise Apache CXF annotations are ignored
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts.STSCallbackHandler"),
      @EndpointProperty(key = "ws-security.validate.token", value = "false") //to let the JAAS integration deal with validation through the interceptor below
})
@InInterceptors(interceptors = {"org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor"})
public class SampleSTS extends SecurityTokenServiceProvider
{
   public SampleSTS() throws Exception
   {
      super();
 
      StaticSTSProperties props = new StaticSTSProperties();
      props.setSignatureCryptoProperties("stsKeystore.properties");
      props.setSignatureUsername("mystskey");
      props.setCallbackHandlerClass(STSCallbackHandler.class.getName());
      props.setIssuer("DoubleItSTSIssuer");
 
      List<ServiceMBean> services = new LinkedList<ServiceMBean>();
      StaticService service = new StaticService();
      service.setEndpoints(Arrays.asList(
         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
 
         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",
         "http://\\[::1\\