Buscar este blog

domingo, 17 de enero de 2016

JBoss - Datasources and JNDI aliases

Almost all web app requires access to a database. This is done by creating a datasource object in the server and by making it accessible to the apps by using its JNDI references.
So, when you want to deploy a new web app in your server, you usually do the following steps:
  1. Declare a new Datasource (or XA-Datasource) in the server wich points to the database
  2. Configure the web app to lookup the JNDI entry in which you declare the Datasource

Cool. But you may find yourself in some situations when this may not be the best solution. I´m thinking in two scenarios:
  1. Multiple web apps access to the same database
  2. One web app wishes to switch between databases in the same environment

The solution is to use JNDI aliases. This allows you to use one JNDI entry which, in turns, returns the value of another JNDI, just like a proxy.
As JBoss doc states (https://docs.jboss.org/author/display/AS71/JNDI+Reference), three different types of bindings are supported:
  • Simple - A primitive or string.
  • ObjectFactory - This allows to specify the javax.naming.spi.ObjectFactory that is used to create the looked up value.
  • Lookup - This allows to create JNDI aliases. When this entry is looked up, it will lookup the target and return the result.

This is an example of use of the lookup binding type:
/subsystem=naming/binding="java:/alias/datasource":add(binding-type=lookup, lookup="java:jboss/datasources/pruebas")
/subsystem=naming/binding="java:/alias/datasource":read-attribute(name=lookup)

(...)

/subsystem=naming/binding="java:/alias/datasource":write-attribute(name=lookup,value="java:jboss/datasources/pruebas2")
:reload

Here I assume that there are two datasources previously created, accesibles in java:jboss/datasources/pruebas2 and java:jboss/datasources/pruebas2. First I created a new JNDI which points to the first one and then update its value to the second one.


Now I will analyze more in deep the two scenarios presented.

Multiples web apps access to the same database

Suppose you have have multiple web apps who need to access to the same database (yes, this is not a good architecture, but imagine that for some legacy reasons they have to). In the future each app would access to its own database, so you configure them to use a different datasource.

What you would do is to create multiple datasources in your server, all of them pointing to the same database. But if the database location changes, for example the IT department decides to move them to a new server, you must to reconfigure all datasources to point to this new location.

By using multiple JNDI entries with binding lookup type you can configure just one datasource and reference it from multiple JNDI keys.

One web app wishes to switch between databases in the same environment

The other scenario could be when you have a single web app and multiple database environments. For example, you have two databases in your Test environment and you want to switch between then in order to make different tests. Again, the best solution is to have multiple full environments and deploy your app in each one, but this is not a ideal world.

What you would do is to create multiple datasources in your server, each one pointing to one different database. But you also need to reconfigure your web app each time you want to switch between them.

By using a single JNDI entry with binding lookup type you can configure your app to pick the datasource from it, and internally reference the desired datasource.


Note. I found a great post about JNDI use in http://middlewaremagic.com/jboss/?p=1690

sábado, 9 de enero de 2016

Maven jaxb2 plugin - Generate class from XSD Schema with custom bindings file

In a previous post (http://trabajosdesisifo.blogspot.com.es/2015/04/generate-classes-from-xsd-xmlrootelement.html) I talked about how to generate java classes from XSDs and WSDLs files. When I worked with XSD Schema files I was using org.jvnet.jaxb2.maven2 / maven-jaxb2-plugin, now I post the equivalent with org.codehaus.mojo / maven-jaxb2-plugin a newer version.

My XSD and XJB files are located under /src/main/resources/META-INF/xsd/consultaVersion directory.
File consultaVersion.xsd:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="aplicacion">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="nombre"/>
        <xs:element type="xs:string" name="version"/>
        <xs:element type="xs:date" name="fecha"/>
        <xs:element type="xs:string" name="observaciones"/>
        <xs:element type="xs:anyURI" name="urlDescarga"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

File bindings.xjb:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings version="2.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">

 <jaxb:globalBindings generateIsSetMethod="true" localScoping="toplevel">
  <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime" parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime" printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />
 </jaxb:globalBindings>


 <jaxb:bindings schemaLocation="consultaVersion.xsd" node="/xs:schema">
  <jaxb:schemaBindings>
   <jaxb:package name="es.sisifo.myproject.framework.service.versionado.dto" />
  </jaxb:schemaBindings>
 </jaxb:bindings>

</jaxb:bindings>

Note that with this binding file dateTime fields are converted to java Calendar type.

And this is my pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>es.sisifo.myproject</groupId>
 <artifactId>desktop-framwork</artifactId>
 <version>0.0.1-SNAPSHOT</version>

 <properties>
  (...)
  <java.version>1.7</java.version>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 </properties>

 <build>
  <pluginManagement>
   <plugins>
    <!--This plugin's configuration is used to store Eclipse m2e settings 
     only. It has no influence on the Maven build itself. -->
    <plugin>
     <groupId>org.eclipse.m2e</groupId>
     <artifactId>lifecycle-mapping</artifactId>
     <version>1.0.0</version>
     <configuration>
      <lifecycleMappingMetadata>
       <pluginExecutions>
        <pluginExecution>
         <pluginExecutionFilter>
          <groupId>
           org.codehaus.mojo
          </groupId>
          <artifactId>
           jaxb2-maven-plugin
          </artifactId>
          <versionRange>
           [2.2,)
          </versionRange>
          <goals>
           <goal>xjc</goal>
          </goals>
         </pluginExecutionFilter>
         <action>
          <ignore></ignore>
         </action>
        </pluginExecution>
       </pluginExecutions>
      </lifecycleMappingMetadata>
     </configuration>
    </plugin>
   </plugins>
  </pluginManagement>

  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.3</version>
    <configuration>
     <target>${java.version}</target>
     <source>${java.version}</source>
    </configuration>
   </plugin>
  
  
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <version>2.2</version>
    <executions>
     <execution>
      <id>Generate-clases-xsd</id>
      <phase>generate-sources</phase>
      <goals>
       <goal>xjc</goal>
      </goals>
     </execution>
    </executions>
    <configuration>
     <outputDirectory>${basedir}/target/xjc/generated</outputDirectory>
     <sources>
      <source>${basedir}/src/main/resources/META-INF/xsd/consultaVersion/consultaVersion.xsd</source>
     </sources>
     <xjbSources>
      <xjbSource>${basedir}/src/main/resources/META-INF/xsd/consultaVersion/bindings.xjb</xjbSource>
     </xjbSources>
     <target>2.1</target>
     <generateEpisode>false</generateEpisode>
     <encoding>${project.build.sourceEncoding}</encoding>      
    </configuration>
   </plugin>
  </plugins>

 </build>

 <dependencies>
  (... Nothing special ...)
 </dependencies>
</project>


Aditional info:

sábado, 2 de enero de 2016

JBoss - EJB - java.lang.ClassCastException: org.xnio.SingleOption cannot be cast to org.xnio.Option

This exception is thrown during a Context.lookup() in order to get a remote EJB in JBoss EAP 6.x
18:20:10,906 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/ejemplo].[spring]] (http-localhost/127.0.0.1:8080-3) JBWEB000236: Servlet.service() for servlet spring threw exception: java.lang.ClassCastException: org.xnio.SingleOption cannot be cast to org.xnio.Option
 at org.xnio.Option.fromString(Option.java:155) [xnio-api-3.0.7.GA.jar:3.0.7.GA]
 at org.xnio.OptionMap$Builder.parseAll(OptionMap.java:316) [xnio-api-3.0.7.GA.jar:3.0.7.GA]
 at org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration.getOptionMapFromProperties(PropertiesBasedEJBClientConfiguration.java:234) [jboss-ejb-client-1.0.24.Final-redhat-1.jar:1.0.24.Final-redhat-1]
 at org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration.parseProperties(PropertiesBasedEJBClientConfiguration.java:221) [jboss-ejb-client-1.0.24.Final-redhat-1.jar:1.0.24.Final-redhat-1]
 at org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration.<init>(PropertiesBasedEJBClientConfiguration.java:118) [jboss-ejb-client-1.0.24.Final-redhat-1.jar:1.0.24.Final-redhat-1]
 at org.jboss.ejb.client.naming.ejb.EjbNamingContext.createIdentifiableEjbClientContext(EjbNamingContext.java:255) [jboss-ejb-client-1.0.24.Final-redhat-1.jar:1.0.24.Final-redhat-1]
 at org.jboss.ejb.client.naming.ejb.EjbNamingContext.setupScopedEjbClientContextIfNeeded(EjbNamingContext.java:123) [jboss-ejb-client-1.0.24.Final-redhat-1.jar:1.0.24.Final-redhat-1]
 at org.jboss.ejb.client.naming.ejb.EjbNamingContext.<init>(EjbNamingContext.java:98) [jboss-ejb-client-1.0.24.Final-redhat-1.jar:1.0.24.Final-redhat-1]
 at org.jboss.ejb.client.naming.ejb.ejbURLContextFactory.getObjectInstance(ejbURLContextFactory.java:38) [jboss-ejb-client-1.0.24.Final-redhat-1.jar:1.0.24.Final-redhat-1]
 at org.jboss.as.naming.InitialContext.lookup(InitialContext.java:101)
 at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:183)
 at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:179)
 at javax.naming.InitialContext.lookup(InitialContext.java:411) [rt.jar:1.7.0_21]

Solution.

Add the following dependencies to the jboss-deployment-structure.xml:
  • org.jboss.xnio
  • org.jboss.remoting3
  • org.jboss.ejb-client

<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
 <deployment>
  <dependencies>
   <module name="org.jboss.xnio" export="true" />
   <module name="org.jboss.remoting3" export="true" />
   <module name="org.jboss.ejb-client" export="true" />
  </dependencies>
  
  <exclude-subsystems>
   <subsystem name="logging" />
  </exclude-subsystems>

  <exclusions>
   <module name="org.apache.log4j" />
   <module name="org.slf4j" />
   <module name="org.log4j" />
   <module name="org.jboss.logging" />
  </exclusions>
 </deployment>
</jboss-deployment-structure>