Friday, August 1, 2014

EJB 3.1 invocations by remote clients on JBOSS 7

How to write EJB 3.1 clients on JBOSS 7.1

EJB invocation from a remote client using JNDI

  1. Deploy the EJBs on the server
  2. Create a Initial Context instance by specifying the following properties
    1. name = java.naming.factory.url.pkgs
    2. value = org.jboss.ejb.client.naming
        See the below code:

public class JndiLookUp {
    private static Context initialContext;
   
    private static final String PKG_INTERFACES = "org.jboss.ejb.client.naming";

    public static Context getInitialContext() throws NamingException {
        if (initialContext == null) {
            Properties properties = new Properties();
            properties.put(Context.URL_PKG_PREFIXES, PKG_INTERFACES);
           // properties.put("jboss.naming.client.ejb.context", true);

            initialContext = new InitialContext(properties);
        }
        return initialContext;
    }

}

3. Create a new file with name 'jboss-ejb-client.properties' and add it the ejb module class path. It is at same level as META-INF directory of ejbmodule
4. Add the following properties to the jboss-ejb-client.properties file

remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=localhost
remote.connection.default.port=4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=nitesh
remote.connection.default.password=nk

username and password properties are required from JBOSS 7.1 hence. These names can be create be add-user.bat utility at JBOSS_HOME/bin.

5. Add jboss-client.jar to the project class path. This jar can be found at:
JBOSS_HOME/bin/client/jboss-client-7.1.0.Final.jar

With the above steps we are ready to write the client code.

public class EjbClient {
           RemoteCounter counter =  (RemoteCounter) doLookup( SingletonCounterBean.class, RemoteCounter.class );
        
        System.out.println("count"+ counter.getTheValue() );
         System.out.println( counter.increment() );        
    }
   
    private static Object doLookup(  Class<?> beanClz, Class<?> interfaceClz ) {
        Context context = null;
        Object bean = null;
        try {
            // 1. Obtaining Context
            context = JndiLookUp.getInitialContext();
            // 2. Generate JNDI Lookup name
            String lookupName = getLookupName(beanClz, interfaceClz );
            // 3. Lookup and cast
            bean = context.lookup(lookupName);

        } catch (NamingException e) {
            e.printStackTrace();
        }
        return bean;
    }
   
    private static String getLookupName( Class<?> beanClz, Class<?> interfaceClz) {
        /*The app name is the EAR name of the deployed EJB without .ear
        suffix. Since we haven't deployed the application as a .ear, the app
        name for us will be an empty string */
        String appName = "ejbprojear";

        /* The module name is the JAR name of the deployed EJB without the
        .jar suffix.*/
        String moduleName = "ejbproj1";

        /* AS7 allows each deployment to have an (optional) distinct name.
        This can be an empty string if distinct name is not specified.*/
        String distinctName = "";

        // The EJB bean implementation class name
        String beanName = beanClz.getSimpleName();
       
        System.out.println("Simple name =" + beanName );

        // Fully qualified remote interface name
        final String interfaceName = interfaceClz.getName();

        // Create a look up string name
        String name = "ejb:" + appName + "/" + moduleName + "/" +
                distinctName    + "/" + beanName + "!" + interfaceName;
        return name;
    }
}

Some useful links:

  1. EJB invocation from a remote client via JNDI
  2. Remote naming  

EJB invocation from a Remote server instance

Below tutorial explains how to invoke on EJBs deployed on one AS7 instance from another AS7 instance.

Some useful links.

  1. EJB invocation from a remote server instance 



Monday, July 28, 2014

EJB 3.1 and JTA

Configuring JTA and EJB 3.1 with JBOSS 7.1.1 final

  Please see the post on how to configure the different JTA data sources on JBOSS7


Bean managed JTA transactions

EJB 3.1 and JPA

Some fundamentals tips to start with JPA and ejb 3.1 with JBOSS 7.1.1 final

Add the data sources to the JBOSS_HOME/standalone/configuration/standalone.xml

<subsystem xmlns="urn:jboss:domain:datasources:1.0">
            <datasources>
                <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
                    <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
                    <driver>h2</driver>
                    <security>
                        <user-name>sa</user-name>
                        <password>sa</password>
                    </security>
                </datasource>
                <datasource jndi-name="java:jboss/datasources/MySqlDS" pool-name="MySqlDS" enabled="true" use-java-context="true">
                    <connection-url>jdbc:mysql://localhost:3306/nit_test</connection-url>
                    <driver>mysqlDriver</driver>
                    <security>
                        <user-name>root</user-name>
                        <password>root</password>
                    </security>
                </datasource>
                <drivers>
                    <driver name="h2" module="com.h2database.h2">
                        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                    </driver>
                    <driver name="mysqlDriver" module="com.mysql">
                        <driver-class>com.mysql.jdbc.Driver</driver-class>
                        <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
                    </driver>
                </drivers>
            </datasources>
        </subsystem>
       

Choose the right JDBC driver.
Some drivers do not support two phase commit. Hence a choice must be made for the right driver.
For example MySQL has DataSource classes like com.mysql.jdbc.jdbc2.optional.MysqlDataSource and com.mysql.jdbc.jdbc2.optional.MysqlXADataSource. Please chooce them wisely. For a list of JDBC Drivers, please refer to: http://docs.oracle.com/cd/E19798-01/821-1751/ghhvc/index.html - See more at: http://www.developerscrappad.com/435/java/java-ee/ejb-3-x-jpa-bean-managed-transaction-with-javax-ejb-usertransaction/#sthash.OPPE5fx7.dpuf
For example mysql datasources classes like com.mysql.jdbc.jdbc2.optional.MysqlDataSource
and com.mysql.jdbc.jdbc2.optional.MysqlXADataSource.
Check oracle documentation JDBC data sources

Add Connection jars to JBOSS modules

Create a directory in JBOSS_HOME/modules/com/mysql/main ( if not already present )
Add mysql-connector-java-x.x.x.jar to this directory.

Edit the module.xmla shown below:

<module xmlns="urn:jboss:module:1.1" name="com.mysql">
    <resources>
        <resource-root path="mysql-connector-java-5.1.31-bin.jar"/>
    </resources>

    <dependencies>
      <module name="javax.api"/>
    </dependencies>
</module>

Add persistence.xml to the EJB project

Add persistence.xml to the META-INF of the project.

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
        <persistence-unit name="Counter">
               <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <jta-data-source>java:jboss/datasources/MySqlDS</jta-data-source>
      <class>com.goraksh.test.JPACounterEntity</class>
      <exclude-unlisted-classes>true</exclude-unlisted-classes>
    
        </persistence-unit>
</persistence>

Here is the jta-data-source is the JNDI name of the mysql data source configured in the standalone.xml

Using managed JTA with EJB 3.1 with JBOSS 7.1.1

Managed JTA transactions

For example MySQL has DataSource classes like com.mysql.jdbc.jdbc2.optional.MysqlDataSource and com.mysql.jdbc.jdbc2.optional.MysqlXADataSource. Please chooce them wisely. For a list of JDBC Drivers, please refer to: http://docs.oracle.com/cd/E19798-01/821-1751/ghhvc/index.html - See more at: http://www.developerscrappad.com/435/java/java-ee/ejb-3-x-jpa-bean-managed-transaction-with-javax-ejb-usertransaction/#sthash.OPPE5fx7.dpuf

Wednesday, June 25, 2014

Basics of Spring MVC with JBoss 7.1

Using JBoss 7.1.1 as the Application server.

Following files of concern for basic debugging

1. \jboss\jboss-as-7.1.1.Final\standalone\configuration\standalone.xml -->  This files contains the EE configurations files.

Use  deployment scanner to assign the different war,ear locations to be loaded for Jboss deployment.


Like the below contents has two deployment scanner for two different web apps
a.) One app1*.war resides in the standalone\deployments dir of JBoss home
b.) Another app2*.war resides in the eclipse runtime jboss tools dir. This dir is automatically chosen by eclipse when deploying an app on JBoss server.
To configure a Jboss sever with eclipse ( kepler ) : Add the url :
 http://download.jboss.org/jbosstools/updates/stable/kepler/ to eclipse help-->New software-->works with

Then in eclipse preferences-->server add the Jboss7.1.* Runtime.
Then eclipse ''servers'' view perspective add the desired web app to the server


<subsystem xmlns="urn:jboss:domain:deployment-scanner:1.1">
            <deployment-scanner name="customscaner" path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" deployment-timeout="120"/>
            <deployment-scanner name="jbosstoolsscanner1" path="E:\workspace\.metadata\.plugins\org.jboss.ide.eclipse.as.core\JBoss_7.1_Runtime_Server1403588064851\deploy" scan-interval="5000" deployment-timeout="120"/>
        </subsystem>

Use domain logging to configure the different log levels and the log files. 

The below is the snippet from standalone.xml

<subsystem xmlns="urn:jboss:domain:logging:1.1">
            <console-handler name="CONSOLE">
                <level name="INFO"/>
                <formatter>
......
........
</subsystem>

Springs Context and Web Context Configurations


Sample web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/spring-context.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/user/*</url-pattern>
</servlet-mapping>
</web-app>


contextConfigLocation parameter values gives the path of the spring context file to be loaded by the dispatcher servlet.

spring-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.goraksh" />
<mvc:annotation-driven />
       <mvc:default-servlet-handler/>
<bean id="userDAO" class="com.goraksh.UserDAO">
        <property name="dataSrc" ref="userDataSrc"/>
    </bean>
    
<bean id="userDataSrc" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!--  max active connections by default is 8 -->
        <property name="driverClassName" value="${jdbc.security.driverClassName}"/>
        <property name="url" value="${jdbc.security.url}"/>
        <property name="username" value="${jdbc.security.username}"/>
        <property name="password" value="${jdbc.security.password}"/>
    </bean>
<bean id="securityTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSrc" ref="userDataSrc"/>
</bean>
<context:property-placeholder location="classpath:jdbc.properties"/>
</beans>

Certains subtleties for new bees
Dispatcher servlet can be used only for the servlet and jsp files residing in the WEB-INF directory.
For the static resources like static htmls, css, js, etc. Dispatcher servlet mapping will not work.

So if I change from Url pattern to <url-pattern>/*</url-pattern> instead of <url-pattern>/user/*</url-pattern>

and removes the lines <mvc:default-servlet-handler/> from the spring-context.xml then an static html file, say hello.html, residing directly inside the web app context but outside the WEB-INF directory will not be loaded. The logs will report the the desired Dispatcher servlet could not find the mapping for ..../hello.html. !!!

To get away with this problem, there are multiple approaches

1. Give a more precise URI for View classes to handled by Dispatcher servlet. Hence the need for /user/*. So all URIs contains ''user'' alone will be handled by Dispatcher servlet.

2. To handler the static components, which cannot be loaded by Dispatcher, I have used
<mvc:default-servlet-handler/> in the spring-context.xml

3. This is an an alternate to step 2
Instead of step#2 , you can also use <mvc:resources mapping="/*" location="/" /> in the spring-context.xml. <mvc:resources mapping="/*" location="/" /> will replace the line <mvc:default-servlet-handler/>. This step is workable only for spring version 3.0.4 and above.

See the Stack Over Discussion