How to fix a RAC database startup problem with orachk in 5 minutes ?

New TFA Collector bundles ORAchk and other RAC tools

TFA Collector Features

Installation of TFA Lite /  ORACHK

Note orachk is now bundled with TFA collector  
Use the MOS article below to download TFA collector 
    TFA Collector - Tool for Enhanced Diagnostic Gathering (Doc ID 1513912.2)

Extract and install orachk as root user 
root@grac41 t]# ls
installTFALite  TFACollectorDocV121250.pdf  TFALite_121250.zip
[root@grac41 t]# ./installTFALite
Starting TFA installation
Enter a location for installing TFA (/tfa will be appended if not supplied) [/home/oracle/t/tfa]: 
/home/oracle/TFA
...
---------------------------------.
|            TFA Users            |
+-----------+-----------+---------+
| User Name | User Type | Status  |
+-----------+-----------+---------+
| asmadmin  | GROUP     | Allowed |
| grid      | USER      | Allowed |
| oinstall  | GROUP     | Allowed |
| oracle    | USER      | Allowed |
'-----------+-----------+---------'
Summary of TFA Installation:
.------------------------------------------------------------.
|                           grac41                           |
+---------------------+--------------------------------------+
| Parameter           | Value                                |
+---------------------+--------------------------------------+
| Install location    | /home/oracle/TFA/tfa/grac41/tfa_home |
| Repository location | /home/oracle/TFA/tfa/repository      |
| Repository usage    | 0 MB out of 2982 MB                  |
'---------------------+--------------------------------------'
.------------------------------------------------------------.
|                           grac42                           |
+---------------------+--------------------------------------+
| Parameter           | Value                                |
+---------------------+--------------------------------------+
| Install location    | /home/oracle/TFA/tfa/grac42/tfa_home |
| Repository location | /home/oracle/TFA/tfa/repository      |
| Repository usage    | 0 MB out of 2982 MB                  |
'---------------------+--------------------------------------'
.------------------------------------------------------------.
|                           grac43                           |
+---------------------+--------------------------------------+
| Parameter           | Value                                |
+---------------------+--------------------------------------+
| Install location    | /home/oracle/TFA/tfa/grac43/tfa_home |
| Repository location | /home/oracle/TFA/tfa/repository      |
| Repository usage    | 0 MB out of 2982 MB                  |
'---------------------+--------------------------------------'
TFA is successfully installed...

 

Problem description

 
Either starting RAC instance with sqlplus or srvctl fails with errors :  

[oracle@grac43 dbs]$  sqlplus / as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Tue Jun 23 13:01:15 2015
Copyright (c) 1982, 2013, Oracle.  All rights reserved.
Connected to an idle instance.
SQL>  startup nomount
ORA-01078: failure in processing system parameters
ORA-01565: error in identifying file '+DATA/grac4/spfilegrac4.ora'
ORA-17503: ksfdopn:2 Failed to open file +DATA/grac4/spfilegrac4.ora
ORA-01034: ORACLE not available
ORA-27123: unable to attach to shared memory segment
Linux-x86_64 Error: 13: Permission denied
Additional information: 26
Additional information: 229382

Run Orack and review the HTML file for Errors and Warnings


[root@grac41 orachk]# ./orachk -v
ORACHK  VERSION: 12.1.0.2.3_20150305

[root@grac41 orachk]# ./orachk
CRS stack is running and CRS_HOME is not set. Do you want to set CRS_HOME to /u01/app/11204/grid?[y/n][y]


Check generated HTML file for WARNINGS and ERRORS 
..
Cluster Wide Status 
WARNING => RDBMS software owner UID does not match across cluster

DATA FROM GRAC41 - RDBMS SOFTWARE OWNER UID ACROSS CLUSTER 
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),500(vboxsf),54322(dba),506(asmdba)

DATA FROM GRAC42 - RDBMS SOFTWARE OWNER UID ACROSS CLUSTER 
uid=54321(oracle) gid=54321(oinstall) groups=54321(oinstall),500(vboxsf),54322(dba),506(asmdba)

DATA FROM GRAC43 - RDBMS SOFTWARE OWNER UID ACROSS CLUSTER 
uid=501(grid) gid=54321(oinstall) groups=54321(oinstall),500(vboxsf),54322(dba),504(asmadmin),506(asmdba),507(asmoper) 

-> Here we see easily can see  that uid on GRAC43 is wrong  

Fix the error and verify database status  
[root@grac43 bin]# chown oracle oracle
[root@grac43 bin]# chmod 6751 oracle
[root@grac43 bin]# ls -l oracle
-rwsr-s--x. 1 oracle asmadmin 239732402 Jul 21  2014 oracle
[grid@grac43 ~]$ srvctl start instance -d grac4 -i grac43
[oracle@grac43 dbs]$ srvctl status database -d grac4
Instance grac41 is running on node grac41
Instance grac42 is running on node grac42
Instance grac43 is running on node grac43



WebDriver a perfect API testing your JEE application

Overview

  • Selenium WebDriver marks a leap forward in terms of browser automation
  • WebDriver can be used by multiple Languages : Java, C#, PHP, Phyton, Perl, JS, …
  • Selenium-WebDriver makes direct calls to the browser and can issue Buttons clicks , ..
  • Selenium-WebDriver supports multiple Browers like Firefox , Chrome, HtmlUnitDriver,  …
  • HtmlUnitDriver is a  headless (GUI-less) browser simulator ( good for Load Testing )
  • Before switching to HtmlUnitDriver you may first use  a GUI based Driver like FirefoxDriver

Preparing Test Environment

For testing WebDriver we use 2 Wildfly instances :
Instance 1 (Port 8081 ) : Production  Server  
   publishes our Website to be tested - Session Scoped Bean using following annotations
      @Named("jPATestBean")
      @SessionScoped 
Instance 2 ( Port 8180) : Test Server 
   Simulates a Webbrowser - using following annotations   
      @RunAsClient annotation 
   This project only has a single Java test Class 


Note: The WFJPA2EL-1.0 Web application is deployed to both Server 

 

Testing the same Webapplication running on  different Application Servers

The main purpose of these tests [ test1() and test2() ] are:

  • Review the Page and verify the Page title
  • Dynamically click  the JSF button j_idt8:cBtn32
  • Use View Page Source from your firefox Browser  to find out your IDs for your Button.  Sample:
    <td><input id=“j_idt8:cBtn32” type=”submit” name=”j_idt8:cBtn32″ value=”Check running RAC Instances and JPA Version ” /></td>
  • Verify that we are connecting to the correct  RAC database named:  BANKA
  • Test  using different URLs
    http://localhost:8081/WFJPA2EL-1.0/     http://localhost:8180/WFJPA2EL-1.0/
  • Sleep between HTTP request to allow users to read the HTML page
Java Code
@Test
@RunAsClient
public void test1() throws InterruptedException
{
testJPARunAsClient("http://localhost:8081/WFJPA2EL-1.0/");
}

@Test
@RunAsClient
public void test2() throws InterruptedException
{
testJPARunAsClient("http://localhost:8180/WFJPA2EL-1.0/");
}

public void testJPARunAsClient(String URL) throws InterruptedException
{
String methodName = "testJPARunAsClient()";
System.out.println("Inside: " + methodName + "- URL: " + URL );
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get(URL);
String pageTitle = driver.getTitle();
System.out.println(" URL " + contextPath +  " - " +methodName + " - Found Page Title:  " + pageTitle);
Assert.assertEquals( "Testing RAC - J2EE JPA2 API!", pageTitle);
// Press the Check RAC instance Button
driver.findElement(By.id("j_idt8:cBtn32")).click();
String rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
if ( rtInfo != null )
{
System.out.println(rtInfo);
Assert.assertTrue(rtInfo.contains("DB Name:  BANKA"));
}
// Close brower window after 5 seconds
Thread.sleep(5000);
driver.quit();
System.out.println("Leaving: " + methodName);
}
}

Note our tested URL should return
Inside: testJPARunAsClient()- URL: http://localhost:8081/WFJPA2EL-1.0/
URL http://127.0.0.1:8180/testJPABeanUsingWebdriver/ - testJPARunAsClient() - Found Page Title:  Testing RAC - J2EE JPA2 API!
10:34:11.045 Calling  getRacInfo() in progress ...
10:34:11.046 EclipseLink Version: 2.5.2 - [ EclipseLink 2.5.2 == JPA 2.1]
10:34:11.047 Driver Name             : Oracle JDBC driver
10:34:11.047 Driver Version          : 12.1.0.2.0
10:34:11.048 Database Product Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Advanced Analytics and Real Application Testing options
10:34:11.056 DB Name:  BANKA
10:34:11.057 1. Instance Name: bankA_3 - Host: hract21.example.com
10:34:11.057 Leaving getRacInfo() without Exceptions !
Leaving: testJPARunAsClient()

Use View Page Source from firefox to find out our GUI IDs
<td><input id="j_idt8:cBtn32" type="submit" name="j_idt8:cBtn32" value="Check running RAC Instances and JPA Version " /></td>

Starting the test using Maven
$ mvn test

This tests should do the following
- Start 2 firfox browser session and execute the JSF function invoked by j_idt8:cBtn32 button
- After each test the browser should be  closed automatically

The above maven command should return
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 51.583 sec
Results :
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1:06.197s
[INFO] Finished at: Thu Jun 18 15:23:00 CEST 2015
[INFO] Final Memory: 19M/55M
[INFO] ------------------------------------------------------------------------

 

Testing a quite complex JTA transaction application by using multiple Browsers


For running test3() and test4() we use a SessionScoped Web application.
This application runs  the following 5 HTTP request :
 - HTTP Request1: Request the initial page via HTTP GET request
 - HTTP Request2: Cleanup table records
 - HTTP Request3: Uses  a HTTP post request to START and SUSPEND a Transaction 
     - Start a JTA transaction
     - Run JPA flush [ == Insert a new db record )
     - Suspend the JTA transaction using the JEE TransactionManager API
     - Add JTA transaction object, Entity Manager object to our HTTPSession Object 
  - HTTP Request4: Uses  a HTTP post request to RESUME and COMMIT the Transaction      
     - retrieve JTA transaction object and Entity Manager object from our HTTPSession Object
     - Resume the Transaction and update the record
     - Commit the record -  in case of any errors rollback the transaction
     - Cleanup HTTP session object , clear the Entity Manager 
  - HTTP Request5: Uses  a HTTP post request to invalidate the HTTP session          
     - Invalidate the HTTP session 

-> This is a quite complex Transaction sample and we will see whether WebDriver 
   can handle this ! 

The main purpose of these tests [ test3() and test4() ]  are 
- Test a SessionScoped JEE application with different Browser [ Firefox and GUIless HtmlUnitDriver ]
- Track the JSESSIONID cookie 
- test3() uses Firefox Driver  
   - start a Firfox session
   - Display the HTML page 
   - Use wait times to display the HTTP pages 
 
- test4()  uses the GUIless HtmlUnitDriver 
   - don't start any browser and display any HTLM page  ( useful for GUI test )
   - Don't use any wait times between the HTTP requests ( useful for performance test ) 

JAVA Code 
  @Test 
     public void test3() throws InterruptedException
      {
         testJPARunAsClientTestSession("http://localhost:8180/WFJPA2EL-1.0/", true);
      }  
    
     @Test 
     public void test4() throws InterruptedException
      {
         testJPARunAsClientTestSession("http://localhost:8180/WFJPA2EL-1.0/", false);
      }  
      public void testJPARunAsClientTestSession(String URL , boolean useGUI) throws InterruptedException
      {
        WebDriver driver = null; 
        String methodName = "testJPARunAsClient()";
        System.out.println("Inside: " + methodName + "- URL: " + URL );
        if (useGUI)
            driver = new FirefoxDriver();
        else 
            driver = new HtmlUnitDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 
        driver.get(URL);  
            //driver.get("http://localhost:8081/WFJPA2EL-1.0/");
            // browser.get("http://localhost:8180/WFJPA2EL-1.0/");
        String pageTitle = driver.getTitle();        
        System.out.println(" URL " + contextPath +  " - " +methodName + " - Found Page Title:  " + pageTitle);
        Assert.assertEquals( "Testing RAC - J2EE JPA2 API!", pageTitle);  
       
            // Press Clean Table Button
        driver.findElement(By.id("j_idt8:cBtn15")).click();       
        String rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            if (useGUI)
                System.out.println(rtInfo);
            Assert.assertTrue(rtInfo.contains("Leaving cleanTable() without Exceptions - Data commited"));
         }
        checkCookie(driver, "Action: Clean Table");
        if (useGUI)
            Thread.sleep(2000);
        
            // click Start and Resume Button
        driver.findElement(By.id("j_idt8:cBtn13")).click();       
        rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            if (useGUI)
                System.out.println(rtInfo);
            Assert.assertTrue(rtInfo.contains("-> Suspend Transaction - Status: SUSPEND - Salary:1500"));
         }
        checkCookie(driver, "Action: Start and Suspend Transaction");
        if (useGUI)
            Thread.sleep(5000);
        
            // Click Resumee and Commit button
        driver.findElement(By.id("j_idt8:cBtn14")).click();       
        rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            if (useGUI)
                    System.out.println(rtInfo);
            Assert.assertTrue(rtInfo.contains("-> Transaction Commited  -  Salary after update:1599"));
         }
        checkCookie(driver, "Action: Resume and Commit Transaction");
        if (useGUI)
            Thread.sleep(10000);
        
               // Click Session Invalidation button
        driver.findElement(By.id("j_idt8:cBtn31")).click();       
        rtInfo = driver.findElement(By.id("j_idt8:optxt1")).getText();
        if ( rtInfo != null )
         {
            System.out.println(rtInfo);          
         }
        checkCookie(driver, "Action: Invalidate JSF session");
        if (useGUI)
            Thread.sleep(1000);
        driver.quit();
      }
     
    private void checkCookie(WebDriver driver, String info)
      {
        Cookie cookie= driver.manage().getCookieNamed("JSESSIONID");
        System.out.println(info + " - JSESSIONID cookie: " + cookie.getValue());
      }
    

Let's verify the Output :  
Action: Clean Table - JSESSIONID cookie: 1ThmlTaJ_TQAqIeltEuixN23.wls1
Action: Start and Suspend Transaction - JSESSIONID cookie: 1ThmlTaJ_TQAqIeltEuixN23.wls1
Action: Resume and Commit Transaction - JSESSIONID cookie: 1ThmlTaJ_TQAqIeltEuixN23.wls1
Action: Invalidate JSF session - JSESSIONID cookie: E9uqbcDsgyCr5aTxu6bQxX26.wls1
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 42.93 sec

-> After invalidation of our JSF session we get a new JSESSIONID cookie - Perfect !

Summary:

  • WebDriver is an easy API for GUI testing and functional testing
  • WebDriver can be used with JMETER ( used for Multithreading testing )
  • WebDriver is able the run even complex JEE application
  • WebDriver perfect deals with the  JSESSIONID cookie

Reference

Using ExecutorService, Callable API to run Multi-threaded JUNIT tests

Overview

  • In this tutorial we use ExecutorService, Callable API  and JUNIT to test your program for thread safty
  • Callable vs Runable
    • Runnable interface is older than Callable, there from JDK 1.0, while Callable is added on Java 5.0.
    • Runnable interface has run() method to define task while Callable interface uses call() method for task definition.
    • run() method does not return any value, it’s return type is void while call method returns value. Callable interface is a generic parameterized interface and Type of value is provided, when instance of Callable implementation is created.
    • Another difference on run and call method is that run method can not throw checked exception, while call method can throw checked exception in Java.

Test case details

  • Assume on of your developer has created the following ThreadCounter class.
  • This class works fine in single threaded Apps but fails if more than 1 Thread is using this Counter

JAVA code : JUnitTest/src/main/java/com/hhu/junittest/ThreadCounter.java

package com.hhu.junittest;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class ThreadCounter
    {
    private  int count = 0;
    public final VolatileInt vi = new VolatileInt();    
    
    public ThreadCounter()
      {
      }    
    public ThreadCounter( int count)
      {
        this.count = count;
      }        
    public void setCounter( int count)
      {
        this.count = count;
      }
    public static void main(String[] args)
      {
        System.out.println("Hallo from ThreadCounter Class");
          // TODO code application logic here
        // final VolatileInt vi = new VolatileInt();
        ThreadCounter tc = new ThreadCounter();
        tc.setCounter(100*1000*1000);
        for (int j = 0; j < tc.count; j++)
            tc.testIncrement();
        tc. counterStatus();
      }
    
    public void testIncrement()
      {
        vi.num++;
      }
    
    public int getCounter()
      {
        return vi.num;
      }
    static class VolatileInt 
      {
        volatile int num = 0;
      }
    
    public void counterStatus()
      {
         System.out.printf("Total %,d but was %,d", count, getCounter() );
          if ( count == vi.num   )
                System.out.printf(" - Test : OK \n");
            else
               System.out.printf(" - Test : FAILED \n");
      }   
    }

The single Thread test works fine and returns : 
  Hallo from ThreadCounter Class
  Total 100,000,000 but was 100,000,000 - Test : OK 

Test Code for testing thread-safty : JUnitTest/src/test/java/ThreadTest.java

JAVA Code :
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import com.hhu.junittest.ThreadCounter;

import org.junit.Assert;
import org.junit.Test;
 
public class ThreadTest
  {
    
    /*
     static class VolatileInt 
      {
        volatile int num = 0;
      }
    */
    private void test(final int threadCount, boolean atomicTest ) throws InterruptedException, ExecutionException 
      {
        final boolean atomicTestf = atomicTest;        
       // final VolatileInt vi = new VolatileInt();          // This test fails for threadCount > 1
        final AtomicInteger num = new AtomicInteger();     // This test works for any threadCount value
        
        final int count = 100 *1000*1000;
        
        final ThreadCounter tc = new ThreadCounter(100*1000*1000);
            // Create an Anonymous Innner Class with a Callable Object
            // Use Callable  object so we get some results back from our thread test
        Callable<String> task = new Callable<String>() 
          {
            @Override
            public String call() 
              {
                for (int j = 0; j < count; j += threadCount)
                  {
                    if (atomicTestf)
                        num.incrementAndGet();
                    else 
                      //  vi.num++;
                      tc.testIncrement();
                  }       
                return "atomicTest: " + atomicTestf + " - Leaving Thread:  " + Thread.currentThread().getName() +
                   " - nThreads: "  + threadCount; 
              }                
          };
           // As we want to run the same Callable Objects on all threads use:  Collections.nCopies   
           // Collections.nCopies returns an immutable list consisting of n copies of the specified object. 
           // Note the newly allocated data object contains only a single reference to the data object.
        List<Callable<String>> tasks = Collections.nCopies(threadCount, task);
           //Get ExecutorService from Executors utility class, thread pool size is threadCount 
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
           // The invokeAll() method invokes all of the Callable objects you pass to it in the collection passed as parameter. 
           // The invokeAll() returns a list of Future objects via which you can obtain the results of the executions of each Callable.
        List<Future<String>> futures = executorService.invokeAll(tasks);
           // create new and empty String ArrayList
        List<String> resultList = new ArrayList<String>(futures.size());
        // Check for exceptions - our Futures are returning  String Objects
        for (Future<String> future : futures) 
          {
            // Throws an exception if an exception was thrown by the task.
            resultList.add(future.get());
          }
        // Note the future.get() blocks until we get some return value
        // At this stage all tasks are finished - either with an Exception or be a regular method return
        // Validate the final Thread Counter status        
        if (atomicTest)
          {
            System.out.printf("With %,d threads should total %,d but was %,d",
                threadCount , count, num.intValue() ); 
             if ( count == num.intValue()   )
                System.out.printf(" - Test : OK \n");
            else
               System.out.printf(" - Test : FAILED \n");
            Assert.assertEquals(count,num.intValue());
          }
        else
          {
            System.out.printf("With %,d threads should total %,d but was %,d",
                threadCount , count,  tc.getCounter()  ); 
            if ( count == tc.getCounter()  )
                System.out.printf(" - Test : OK \n");
            else
               System.out.printf(" - Test : FAILED \n"); 
            Assert.assertEquals(count,  tc.getCounter());
          }
           // Display the results 
        for ( int i = 0; i<resultList.size(); i++)
            System.out.println(resultList.get(i) );
      }
 
    @Test
    public void test01() throws InterruptedException, ExecutionException 
      {
        test(1,false);
      }
 
    @Test
    public void test02() throws InterruptedException, ExecutionException 
      {
        test(2,false);
      } 
 
    @Test
    public void test04() throws InterruptedException, ExecutionException 
      {
        test(4,false);
      }
 
    @Test
    public void test08() throws InterruptedException, ExecutionException 
      {
        test(8,false);
      }
 
    @Test
    public void test16() throws InterruptedException, ExecutionException 
      {
        test(8,true);    
   } 
 }

Test results

[oracle@wls1 JUnitTest]$ mvn test
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running ThreadTest
With 1 threads should total 100,000,000 but was 100,000,000 - Test : OK 
atomicTest: false - Leaving Thread:  pool-1-thread-1 - nThreads: 1
With 2 threads should total 100,000,000 but was 74,553,473 - Test : FAILED 
With 4 threads should total 100,000,000 but was 40,718,556 - Test : FAILED 
With 8 threads should total 100,000,000 but was 23,405,246 - Test : FAILED 
With 8 threads should total 100,000,000 but was 100,000,000 - Test : OK 
atomicTest: true - Leaving Thread:  pool-5-thread-1 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-2 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-3 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-4 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-5 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-6 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-7 - nThreads: 8
atomicTest: true - Leaving Thread:  pool-5-thread-8 - nThreads: 8
Tests run: 5, Failures: 3, Errors: 0, Skipped: 0, Time elapsed: 2.253 sec <<< FAILURE!

Results :
Failed tests:   
  test02(ThreadTest): expected:<100000000> but was:<74553473>
  test04(ThreadTest): expected:<100000000> but was:<40718556>
  test08(ThreadTest): expected:<100000000> but was:<23405246>
Tests run: 5, Failures: 3, Errors: 0, Skipped: 0

Some comments on above test results

  • test01 works as we use only a single Thread
  • test02, test04, test08 fails if using 2,4 or 8 Threads and if using volatile int as ThreadCounter
  • test08 works even for 8 Threads if using AtomicInteger() instead of volatile int as ThreadCounter
  • test08 with AtomicInteger() returns a String object for each Thread by using our Future objects

 

Reference

What is the best way to implement a thread-safe Integer Counter ?

Overview and Key Facts

  • You may take into account the following JAVA features
    • Using a static volatile int like  :  volatile int num = 0;            –>  NOT WORKING
    • Use a synchronized method  
    • Using AtomicInteger         like  :  final AtomicInteger num = new AtomicInteger();
  • The Java volatile keyword guarantees visibility of changes to variables across threads
  • Using volatile is not enough to create thread safe code
   Lets assume we have 2 threads incrementing a global volatile int as our Thread Counter
     Thread 1 could read a shared counter variable with the value 20 into its CPU cache, increment it to 21
     Thread 2 could read a shared counter variable with the value 20 into its CPU cache, increment it to 21
     Thread 1 writes Thread Counter value [ which is 21 ] to main memory
     Thread 2 writes Thread Counter value [ which is 21 ] to main memory
   Despite we have incremented our Counter 2x the counter value increases only by 1 !
   This problem can occur as the ++ operator is not thread safe !
  • AtomicInteger uses combination of volatile & CAS for thread-safe implementation of Integer Counter.
  • AtomicInteger class stores its value field in a volatile variable, thus it is a decorator over the traditional volatile variable
  • AtomicInteger provides unique non-blocking mechanism for updating the value after requiring the hardware level support for CAS (compare and set).
  • Syncronized access is using locks and therefore slower than CAS method used by AtomicInteger

 

JAVA test case : IncrementNotThreadSafeMain.java

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class IncrementNotThreadSafeMain {
  public static void main(String... args) throws InterruptedException {
    for (int nThreads = 1; nThreads <= 64; nThreads *= 2)
      doThreadSafeTest(nThreads);
  }

  static class VolatileInt {
    volatile int num = 0;
  }

  private static void doThreadSafeTest(final int nThreads) throws InterruptedException {
    final int count = 100 * 1000 * 1000;

    ExecutorService es = Executors.newFixedThreadPool(nThreads);
    final VolatileInt vi = new VolatileInt();
    System.out.printf("--- Testing with Volatile --- ");
    for (int i = 0; i < nThreads; i++)
      es.submit(new Runnable() {
        public void run() {
          for (int j = 0; j < count; j += nThreads)
             vi.num++;
        }
      });
    es.shutdown();
    es.awaitTermination(1, TimeUnit.MINUTES);
    assert es.isTerminated();
    System.out.printf("With %,d threads should total %,d but was %,d%n", nThreads, count, vi.num /*num.longValue()*/);
    
    System.out.printf("--- Testing AtomicInteger --- ");
    es = Executors.newFixedThreadPool(nThreads);
    final AtomicInteger num = new AtomicInteger();
    for (int i = 0; i < nThreads; i++)
      es.submit(new Runnable() {
        public void run() {
          for (int j = 0; j < count; j += nThreads)
              num.incrementAndGet();
        }
      });
    es.shutdown();
    es.awaitTermination(1, TimeUnit.MINUTES);
    assert es.isTerminated();
    System.out.printf("With %,d threads should total %,d but was %,d%n", nThreads, count, num.longValue() );   
  }
}

Running above Code
$  java  IncrementNotThreadSafeMain
--- Testing with Volatile --- With 1 threads should total 100,000,000 but was 100,000,000
--- Testing AtomicInteger --- With 1 threads should total 100,000,000 but was 100,000,000
--- Testing with Volatile --- With 2 threads should total 100,000,000 but was 54,089,900
--- Testing AtomicInteger --- With 2 threads should total 100,000,000 but was 100,000,000
--- Testing with Volatile --- With 4 threads should total 100,000,000 but was 44,019,787
--- Testing AtomicInteger --- With 4 threads should total 100,000,000 but was 100,000,000
--- Testing with Volatile --- With 8 threads should total 100,000,000 but was 24,731,449
--- Testing AtomicInteger --- With 8 threads should total 100,000,000 but was 100,000,000
--- Testing with Volatile --- With 16 threads should total 100,000,000 but was 28,908,662
--- Testing AtomicInteger --- With 16 threads should total 100,000,000 but was 100,000,000
--- Testing with Volatile --- With 32 threads should total 100,000,000 but was 37,063,611
--- Testing AtomicInteger --- With 32 threads should total 100,000,000 but was 100,000,000
--- Testing with Volatile --- With 64 threads should total 100,000,000 but was 79,022,174
--- Testing AtomicInteger --- With 64 threads should total 100,000,000 but was 100,000,000

--> All Volatile tests with more then 2 Threads are failing !

Reference

Using Eclipselink as a Persistence Provider in a Netbeans/Wildfly project for JTA transaction

Project Versions

 EclipseLink Version: 2.5.2 - [ EclipseLink 2.5.2 == JPA 2.1] 
 JBDC Driver Name             : Oracle JDBC driver
 JDBC Driver Version          : 12.1.0.2.0
 Database Version             : Database Product Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
                                With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
                                Advanced Analytics and Real Application Testing options
 Database Name and Instances  : DB Name:  BANKA
                                1. Instance Name: bankA_2 - Host: hract21.example.com
                                2. Instance Name: bankA_1 - Host: hract22.example.com
 Netbeans Version             : 8.0.2
 Wildfly Version              : 8.2
 Entity Manger Type           : Application Managed
 Transaction Type             : JTA

Setup EclipseLink as a Wildfly Module

Check modules/system/layers/base/org/eclipse/persistence/main directory
oracle@wls1 main]$ pwd
/usr/local/wildfly-8.2.0.Final/modules/system/layers/base/org/eclipse/persistence/main

Copy eclipselink-2.5.2.jar from MAVEN repository  to modules/system/layers/base/org/eclipse/persistence/main
[oracle@wls1 main]$ ls
eclipselink-2.5.2.jar  jipijapa-eclipselink-1.0.1.Final.jar  module.xml
 
Add  eclipselink-2.5.2.jar to module.xml in  modules/system/layers/base/org/eclipse/persistence/main
[oracle@wls1 main]$ cat  module.xml
<module xmlns="urn:jboss:module:1.3" name="org.eclipse.persistence">
    <resources>
        <resource-root path="jipijapa-eclipselink-1.0.1.Final.jar"/>
        <resource-root path="eclipselink-2.5.2.jar"/>
    </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.javassist"/>
        <module name="org.jboss.as.jpa.spi"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.vfs"/>
    </dependencies>

Configure  your pom.xml

  • Remove the hibernate reference and add the EclipseLink reference
As we provided the EclipseLink Jar as a Wildlfly module add : <scope>provided</scope>

        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.5.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId>
            <version>2.5.2</version>
            <scope>provided</scope>
        </dependency>

Create a new Netbeans project

Create new Maven project : Maven -> Web Application 
Add JSF support          : Properties -> Add Framework -> JSF 2.2 
Source Package -> New  -> Entity Class from Database 
Add New File -> Persistence -> Entity Class from Database 
-> Select Datasource:
 Host : ract2-scan.grid12c.example.com 
 Port : 1521/banka
 URL  : jdbc:oracle:thin:@ract2-scan.grid12c.example.com:1521/banka

-> Select table : EMP2
Select ; 
x Generate Named Query Annotations for Persistent Fields
x Generate JAXB Annotations
x Create Persistence Unit

Create persistence.xml 
New File -> Persistence -> Create new Persistence Unit 
-> Select Datasource: ..
x Use Java Transaction API


A working persistence.xml sample may look like :

<?xml version="1.0" encoding="UTF-8"?>
<!-- <persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0"> -->
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="jpaPU" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>java:/jboss/datasources/myRacDS</jta-data-source>
    <jar-file>MyFirstRACPU.jar</jar-file>
    <class>com.hhu.wfjpa2el.Emp2</class>
    <class>com.hhu.wfjpa2el.Logemp2</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="eclipselink.logging.level" value="FINEST"/>
      <property name="eclipselink.cache.shared.default" value="false"/>
    </properties>
  </persistence-unit>
</persistence>

  • JTA is used and the datasoruce name is : java:/jboss/datasources/myRacDS
  • org.eclipse.persistence.jpa.PersistenceProvider is the Persistence Provider
  • The perstistence Unit name is jpaPU [ this is used by our JAVA code ]

JAVA Code to create a thread safe access to the Entity Manager

  •   Persistence.createEntityManagerFactory(“jpaPU“) must match  <persistence-unit name=”jpaPU” transaction-type=”JTA“>
  •  <class>com.hhu.wfjpa2el.Logemp2</class>  must match the  Classes we have  created by using Netbeans menu option : Create Entity Class from Database
  • For the Entity Manger access we use the “ThreadLocal Pattern”
 

 static 
      {
        emf = Persistence.createEntityManagerFactory("jpaPU");
        threadLocal = new ThreadLocal<EntityManager>();        
      }
    
    
    public static EntityManager getEntityManager() 
      {
        EntityManager em = threadLocal.get();

        if (em == null) 
          {
          // setRunTimeInfo(getRunTimeInfo() + Tools.add_hmtl_pre_tag("Creating Entity Manager ! "  ));
            logger.info("Creating Entity Manager Factory ..." );
            em = emf.createEntityManager();
            // set your flush mode here
            threadLocal.set(em);
          }
        return em;
      }
    
    
    public static void closeEntityManager() 
      {
        EntityManager em = threadLocal.get();
        if (em != null) 
          {
            logger.info("Closing Entity Manager" );
            em.close();
            threadLocal.set(null);
           }
     }
    
Note for each request you have to open and close the Entity Manager 
   ..
   em=getEntityManager();
   ..
   closeEntityManager();
   ..

A more Complete Code fragment

public String addEntity()  
      {
        EntityManager em;
        String methodName = "addEntity()";
        short eno= getEmpno();
        cleanall();
        try
          {    
            setRunTimeInfo("Calling "  + methodName + "in progress - ID: " + eno + " - useJoinTransaction : " + isUseJoinTransaction() );          
            Emp2 e =  new Emp2(eno);
            e.setEname("Helmut");
            e.setJob("Progr.");
            e.setSal(new BigDecimal(1000.0));
            setRunTimeInfo("Requesting Entity Manager.. ");
            em=getEntityManager();
            ut.begin();
            em.joinTransaction();
            setRunTimeInfo("Running em.persists() ... ");           
            em.persist(e);
            setRunTimeInfo("Running em.flush() ... ");
            em.flush();
            setRunTimeInfo("Running ut.commit() ... ");
            ut.commit();
            setRunTimeInfo("Closing  Entity Manager.. !");
            setRunTimeInfo("Leaving " + methodName + " without Exceptions !");                   
            }            
          catch ( Throwable t1)
          {            
            jpa_exception(t1, methodName);
          }            
        closeEntityManager();
        setRunTimeInfo("Leaving "  +  methodName + " - Entity manager  closed !\n");
        return "index";
      }

The related Server.log File shoud look like :

2015-05-20 18:38:23,361 INFO  [org.eclipse.persistence] (default task-5) EclipseLink, version: Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd
2015-05-20 18:38:23,496 INFO  [org.eclipse.persistence.connection] (default task-5) connecting(DatabaseLogin(
2015-05-20 18:38:23,497 INFO  [org.eclipse.persistence.connection] (default task-5) Connected: jdbc:oracle:thin:@ract2-scan.grid12c.example.com:1521/banka
2015-05-20 18:38:23,497 INFO  [org.eclipse.persistence.connection] (default task-5) connecting(DatabaseLogin(
2015-05-20 18:38:23,497 INFO  [org.eclipse.persistence.connection] (default task-5) Connected: jdbc:oracle:thin:@ract2-scan.grid12c.example.com:1521/banka
2015-05-20 18:38:23,653 INFO  [org.eclipse.persistence.connection] (default task-5) vfs:/usr/local/wildfly-8.2.0.Final/standalone/deployments/t-1.0.war/WEB-INF/classes/_jpaPU login successful

Using ServletContextListener and JNDI to run a clean Web Application shutdown

Key Facts and Overview

  • ServletContextListener runs contextInitialized() during a deployment operation
  • ServletContextListener runs contextDestroyed() during a un-deployment operation
  • This allows to cleanup or initialize certain objects factories, loggers, ..
  • Without a clean shutdown you may encounter following Exception during redeployment of a WEB applications
     12:54:21.020 Object: com.hhu.wfjpa2el.Emp2[ empno=9997 ] is not a known entity type.
     12:54:21.020 java.lang.IllegalArgumentException: Object: com.hhu.wfjpa2el.Emp2[ empno=9997 ] is not a known entity type.
         at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:4228)
         at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persist(EntityManagerImpl.java:496)
         at com.hhu.wfjpa2el.JPATestBean.runJPA(JPATestBean.java:137)
         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  • To solve this reboot your Webserver or shutdown() the Entity Manager Factory

JAVA Code

  • JPATestBean() constructor stores/binds a object reference of the current  JPATestBean() reference via JNDI
  • shutdown() is invoked by  ServletContextListener function contextDestroyed() and stops the Entity Manager Factory.
  • ServletContextListener is using JNDI lookup to get the object reference
JPATestBean.java  
public JPATestBean() throws Exception
      {
        ctx = new InitialContext();
        ctx.rebind(jndiName, this);  
        logger.info("Constructor JPATestBean()  called and bound to JNDI !");
      }
 
 static 
      {
        emf = Persistence.createEntityManagerFactory("jpaELPU");
        threadLocal = new ThreadLocal<EntityManager>();       
      }
 public void shutdown()
      {
        logger.info("\nWeb Application shutdown ..." );
        closeEntityManager();
        logger.info("Closing Entitiy Manager Factory ..." );
        emf.close();
        emf=null; 
        System.gc();
        logger.info("Leaving Web Application shutdown" );
      }
...

Implementing ServletContextListener 
  -  contextDestroyed() uses JNDI lookup to read an object reference from our  JPATestBean() instance
  -  contextDestroyed() invokes shutdown methode to run a clean application shutdown

web.xml entry
./src/main/webapp/WEB-INF/web.xml
..
  <listener>
        <listener-class>com.hhu.wfjpa2el.ServletContextListenerImpl</listener-class>
    </listener>


Java Code for ServletContextListener
package com.hhu.wfjpa2el;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.slf4j.LoggerFactory;

public class ServletContextListenerImpl implements ServletContextListener 
  {
    final static org.slf4j.Logger logger = LoggerFactory.getLogger(ServletContextListenerImpl.class);
    private JPATestBean jtb;    
    private final String jndiName = "java:global/myJPATestBean";
    private InitialContext ctx;
    
    @Override
    public void contextInitialized(ServletContextEvent arg) {
        logger.info("+++ ServletContextListener : contextInitialized - no action \n");
 
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg) 
     {
        System.out.println("+++ ServletContextListener: running contextDestroyed()....");
        try
          {
            ctx = new InitialContext();
            jtb = (JPATestBean)ctx.lookup(jndiName);
            jtb.shutdown();
            logger.info("+++ ServletContextListener:  Leaving contextDestroyed() without Exception\n");
          } catch (NamingException ex)
          {
            //Logger.getLogger(ServletContextListenerImpl.class.getName()).log(Level.SEVERE, null, ex);
            logger.error("+++ Error in contextDestroyed()\n" + ex);
          }
     }
}

Reference

 

Using logback with Logfile Separation for your Wildfly project

Overview

Logback is intended as a successor to the popular log4j project.
In this sample we will configure Logback to write logging info to an application specific logfile 
and to the Wildlfy server.log file. For a first check we many read the application loggin file. 
If you are interested in timing considerations for generic Wildfly errors and your application 
errors you may review Wildflys server.log file

Logging Separation 
Assuming your container supports child-first class loading, separation of logging can be 
accomplished by embedding a copy of slf4j and logback jar files in each of your applications. 
For web-applications, placing slf4j and logback jar files under the WEB-INF/lib directory of 
the web-application is sufficient to endow each web-application with a separate logging 
environment. A copy of the logback.xml configuration file placed under WEB-INF/classes will 
be picked up when logback is loaded into memory.

By virtue of class loader separation provided by the container, each web-application will 
load its own copy of LoggerContext which will pickup its own copy of logback.xml.

XML configuration files

pom.xml 
     <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.7</version> 
        </dependency>
        
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.3</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.3</version>
        </dependency>

Disable server logging features: ./src/main/webapp/WEB-INF/jboss-deployment-structure.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
  <deployment>
    <exclusions>
      <module name="org.apache.commons.logging" />
      <module name="org.apache.log4j" />
      <module name="org.jboss.logging" />
      <module name="org.jboss.logging.jul-to-slf4j-stub" />
      <module name="org.jboss.logmanager" />
      <module name="org.jboss.logmanager.log4j" />
      <module name="org.slf4j" />
      <module name="org.slf4j.impl" />
    </exclusions>
  </deployment>

Logback configuration file:  ./src/main/resources/logback.xml

-> Writes logging Info to /tmp/JPATestBean.log and Wildfly server.log 
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                   %d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
            </Pattern>
        </layout>
    </appender>
        <appender name="FILE" class="ch.qos.logback.core.FileAppender">  
            <file>/tmp/JPATestBean.log</file>  
            <layout class="ch.qos.logback.classic.PatternLayout">    
                <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>  
            </layout>
        </appender>
  
    <root level="debug">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>
</configuration>

Java Code

Initialize logger :
public class JPATestBean implements Serializable
  {
    // private static final org.slf4j.Logger logger = LoggerFactory.getLogger(JPATestBean.class);
    final static Logger logger = LoggerFactory.getLogger(JPATestBean.class);
......     
        logger.info("\nWeb Application shutdown ..." );
....
        logger.error("FATAL ERROR: Closing Entitiy Manager Factory ..." );

 

Reference

Remove a Wildfly Transaction from LOG-STORE

Overview

You may need to run these commands under following circumstances:

  • you are running a test system and testing UserTransaction API
  •  you have dropped some objects ( database , table ) and you don’t care about this XA transactions
  • your DBA has manually committed or rolled back a XA transaction  be running : COMMIT FORCE ‘Local_TranID’ or ROLLBACK FORCE  ‘Local_TranID’ via sqlplus
  • In any case be careful when running this commands as this could logically corrupt your production system very easily  !

 

Setup and Commands

List PREPARED transactions: 
[oracle@wls1 XA]$ cat xa.cli
/subsystem=transactions/log-store=log-store/:probe()
ls /subsystem=transactions/log-store=log-store/transactions

[oracle@wls1 XA]$  $WILDFLY_HOME/bin/jboss-cli.sh --connect --file=xa.cli
 {"outcome" => "success"}
0:ffffc0a805c9:682bf87e:55433e74:127

Try to List JNDI resources 
[standalone@localhost:9990 /]  /subsystem=transactions/log-store=log-store/transactions=0\:ffffc0a805c9\:682bf87e\:55433e74\:127:read_resource
{
    "outcome" => "failed",
    "failure-description" => "JBAS014884: No operation named 'read_resource' exists at address [
    (\"subsystem\" => \"transactions\"),
    (\"log-store\" => \"log-store\"),
    (\"transactions\" => \"0:ffffc0a805c9:682bf87e:55433e74:127\")
]",
    "rolled-back" => true
}

Finally delete the transaction and verify transaction status  
[standalone@localhost:9990 /]  /subsystem=transactions/log-store=log-store/transactions=0\:ffffc0a805c9\:682bf87e\:55433e74\:127:delete
{"outcome" => "success"}

[oracle@wls1 XA]$ $WILDFLY_HOME/bin/jboss-cli.sh --connect --file=xa.cli
{"outcome" => "success"}

Reference:

Integrate Oracle JDBC driver, UCP Pool, ONS and JSF with Maven

Add Oracle JDBC driver in your Maven local repository

[oracle@wls1 Driver]$ mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc7 \
 -Dversion=12.1.0.2 -Dpackaging=jar -Dfile=ojdbc7.jar -DgeneratePom=true
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-install-plugin:2.3.1:install-file (default-cli) @ standalone-pom ---
[INFO] Installing /home/oracle/JDBC/Driver/ojdbc7.jar to /home/oracle/.m2/repository/com/oracle/ojdbc7/12.1.0.2/ojdbc7-12.1.0.2.jar
[INFO] Installing /tmp/mvninstall5544900966056750978.pom to /home/oracle/.m2/repository/com/oracle/ojdbc7/12.1.0.2/ojdbc7-12.1.0.2.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.552s
[INFO] Finished at: Wed Apr 15 08:45:56 CEST 2015
[INFO] Final Memory: 5M/42M
[INFO] ------------------------------------------------------------------------

 
Create a new Netbeans project -> Maven -> Web Application 
  Add            : Wildfly Server & JEE7 support 
  Add JSF Support:  Properties -> Framework -> Add -> JavaServer Faces 

This will create index.xhtml under Web Pages directory. Change it to  
    <h:body>
        Hello from Maven JSF and JDBC test
    </h:body>
Run it and verify that above string was printed 
  http://localhost:8180/WFMavenJDBC-1.0-SNAPSHOT/


Note As our JDBC driver is installed as a module add: <scope>runtime</scope>
pom.xml: 
   <dependency>
      <groupId>com.oracle</groupId>
      <artifactId>ojdbc7</artifactId>
      <version>12.1.0.2</version>
      <scope>runtime</scope>
    </dependency>
  
runtime:
This scope indicates that the dependency is not required for compilation, but is for execution. 
It is in the runtime and test classpaths, but not the compile classpath.
Note  <scope>runtime</scope> does not work 

For Details how to install Oracle JDBC driver please read following article: 
How to integrate the Oracle JDBC driver as a Wildfly module ?

Integrate ONS and UCP in your local Maven repository

[oracle@wls1 lib]$ pwd
/home/oracle/UCP/lib
[oracle@wls1 lib]$ ls
ojdbc7.jar  ons.jar  ucp.jar
[oracle@wls1 lib]$ mvn install:install-file -DgroupId=com.oracle -DartifactId=ucp \
  -Dversion=12.1.0.2 -Dpackaging=jar -Dfile=ucp.jar -DgeneratePom=true
[INFO] Scanning for projects...
--------------------------------------------------------------------
...
[INFO] --- maven-install-plugin:2.3.1:install-file (default-cli) @ standalone-pom ---
[INFO] Installing /home/oracle/UCP/lib/ucp.jar to /home/oracle/.m2/repository/com/oracle/ucp/12.1.0.2/ucp-12.1.0.2.jar
[INFO] Installing /tmp/mvninstall8385397296650809803.pom to /home/oracle/.m2/repository/com/oracle/ucp/12.1.0.2/ucp-12.1.0.2.pom
Add to pom.xml in your Maven project: 
   <dependency>
     <groupId>com.oracle</groupId>
     <artifactId>ucp</artifactId>
     <version>12.1.0.2</version>
   </dependency> 

[oracle@wls1 lib]$ mvn install:install-file -DgroupId=com.oracle -DartifactId=ons \
  -Dversion=12.1.0.2 -Dpackaging=jar -Dfile=ons.jar -DgeneratePom=true
[INFO] --- maven-install-plugin:2.3.1:install-file (default-cli) @ standalone-pom ---
[INFO] Installing /home/oracle/UCP/lib/ons.jar to /home/oracle/.m2/repository/com/oracle/ons/12.1.0.2/ons-12.1.0.2.jar
[INFO] Installing /tmp/mvninstall1244421194501868057.pom to /home/oracle/.m2/repository/com/oracle/ons/12.1.0.2/ons-12.1.0.2.pom

Add to pom.xml in your Maven project: 
   <dependency>
     <groupId>com.oracle</groupId>
     <artifactId>ons</artifactId>
     <version>12.1.0.2</version>
   </dependency> 

Manually compile and deploy the WAR file

[oracle@wls1 Desktop]$ cd  /home/oracle/NetBeansProjects/GIT/WFMavenJDBC
[oretacle@wls1 WFMavenJDBC]$ ls *.xml
nb-configuration.xml  pom.xml  
[oracle@wls1 WFMavenJDBC]$ mvn clean
[oracle@wls1 WFMavenJDBC]$ mvn package
[oracle@wls1 WFMavenJDBC]$ $WILDFLY_HOME/bin/jboss-cli.sh --connect --command="deploy --force target/WFMavenJDBC-1.0-SNAPSHOT.war"
[oracle@wls1 WFMavenJDBC]$ firefox http://localhost:8180/WFMavenJDBC-1.0-SNAPSHOT/

Testing the application

 
Invoke:  CheckJDBC
  JDBC Driver Check - Loading Driver class ok : oracle.jdbc.OracleDriver
  JDK Version: 1.7.0_71
  ClassPath  : /usr/local/wildfly-8.2.0.Final/jboss-modules.jar
  Driver Name             : Oracle JDBC driver
  Driver Version          : 12.1.0.2.0
  Database Product Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
    With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
    Advanced Analytics and Real Application Testing options

Invoke: IinitUCP
  Initializing UCP Pool in progress ...
  UCP Pool initialized !
  RAC DB: BANKA
  Instance Name:bankA_2 - Host: hract22.example.com
  Instance Name:bankA_3 - Host: hract21.example.com
  Instance Name:bankA_2 - Session Count 10
  Instance Name:bankA_3 - Session Count 9

 

Source and Configuration Files

Reference

Create an object factory to return a Singleton Java Object Instance

Purpose  of this tutorial

  • Create and deploy your custom Wildfly module
  • Create an Object Factory class which instantiates a Singleton Instance of our TestBean class
  • Build a Test client [ pure java SE program ] using remote JNDI to lookup our Remote Object Factory MyObjectFactory

Requirements

  • Set classpath :  $ export CLASSPATH=/usr/local/wildfly-8.2.0.Final/bin/client/jboss-client.jar:.
  • Tested with   Wildfly 8.0.2

JAVA Code [ Server Side ]

 
MyObjectFactory.java:

package hhu.object_factory;
/**
 * @author Helmut Hutzler
 */
import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;import javax.naming.spi.ObjectFactory;
import hhu.object_factory.TestBean;
public class MyObjectFactory implements ObjectFactory
 {
    /*
       Note we need to restart the Wilfdly server when we change the  MyObjectFactory object !
       Making constructor  MyObjectFactory() as private to prevent access to outsiders
       The instance of  TestBean()  is created at the startup of the class and remains valid
         until someone shutdown the  JVM.
       Since TestBean is a static, it gets loaded and created during loading of the MyObjectFactory class.
       Calling getObjectInstance does not instantiate the TestBean class a 2.nd time
    */
    private static volatile TestBean bean =  new TestBean("City","Sattelmannsburg - ( believe me - this is not  in India)");
    
       public MyObjectFactory()
       {
            System.out.println(" NEW: [MyCustomObjectFactory] MyCustomObjectFactory initialized.");
       }

       public Object getObjectInstance(Object obj, Name name, Context nameCtx,Hashtable environment) throws Exception
       {
            // TestBean bean = new TestBean("City","Pune (India)");
            return bean;
       }
   }

TestBean.java:
package hhu.object_factory;
/**
 *
 * @author Helmut Hutzler 
 */
public class TestBean implements java.io.Serializable
  {
      private String name;
      private String value;
      private long itime;

    public long getItime()
      {
        return itime;
      }
      
      public TestBean(String name,String value)
       {
         this.name=name;
         this.value=value;
         this.itime=System.currentTimeMillis();
         System.out.println("[TestBean] TestBean initialized - itime: " + this.itime);
       }

      public String getName()
       {
          return name;
       }
      public String getValue()
       {
          return value;
       }
      
  }

Deploy our JAR file as a Wildfly Module

Assemble jar file WF_Object_Factory.jar  with following files 

[oracle@wls1 dist]$ pwd 
/home/oracle/NetBeansProjects/GIT/WF_Object_Factory/dist
[oracle@wls1 dist]$  jar tvf WF_Object_Factory.jar
     0 Fri Mar 13 17:50:52 CET 2015 META-INF/
   177 Fri Mar 13 17:50:50 CET 2015 META-INF/MANIFEST.MF
     0 Fri Mar 13 17:50:50 CET 2015 hhu/
     0 Fri Mar 13 17:50:50 CET 2015 hhu/object_factory/
  1135 Fri Mar 13 17:50:50 CET 2015 hhu/object_factory/MyObjectFactory.class
   818 Fri Mar 13 17:50:50 CET 2015 hhu/object_factory/TestBean.class

Deploy JAR file 
[oracle@wls1 dist]$ cd /home/oracle/NetBeansProjects/GIT/WF_Object_Factory/dist
[oracle@wls1 dist]$ mkdir -p $WILDFLY_HOME/modules/object_factory/main
[oracle@wls1 dist]$ cp /home/oracle/NetBeansProjects/GIT/WF_Object_Factory/dist/WF_Object_Factory.jar  
                       $WILDFLY_HOME/modules/object_factory/main 
[oracle@wls1 dist]$ cd    $WILDFLY_HOME/modules/object_factory/main 
[oracle@wls1 dist]$ pwd 
/usr/local/wildfly-8.2.0.Final/modules/object_factory_wf/main
[oracle@wls1 main]$ ls -l
total 8
-rw-rw-r-- 1 oracle oracle  265 Mar 12 16:03 module.xml
-rw-rw-r-- 1 oracle oracle 2819 Mar 12 15:52 Object_Factory_WF.jar

Create a module.xml with following content
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.4" name="object_factory">
   <resources>
       <resource-root path="WF_Object_Factory.jar"/>
   </resources>
  <dependencies>
       <module name="javax.api"/>
  </dependencies>
</module>
Verify module.xml entries
[oracle@wls1 main]$ ls ../../object_factory
main
[oracle@wls1 main]$ ls WF_Object_Factory.jar
WF_Object_Factory.jar

Module Management - Load the module a first time 

[oracle@wls1 JNDI]$   $WILDFLY_HOME/bin/jboss-cli.sh --connect --file=obj_factory_jndi.cli
obj_factory_jndi.cli : 
/subsystem=naming/binding=java\:jboss\/exported\/object_factory/:add(binding-type=object-factory,module=object_factory,class=hhu.object_factory.MyObjectFactory

Server log should report: 
17:41:13,286 INFO  [stdout] (management-handler-thread - 4) [TestBean] TestBean initialized - itime: 1426351273285
17:41:13,286 INFO  [stdout] (management-handler-thread - 4)  NEW: [MyCustomObjectFactory] MyCustomObjectFactory initialized.
2015-03-14 17:41:13,286 INFO  [stdout] (management-handler-thread - 4) [TestBean] TestBean initialized - itime: 1426351273285
2015-03-14 17:41:13,286 INFO  [stdout] (management-handler-thread - 4)  NEW: [MyCustomObjectFactory] MyCustomObjectFactory initialized.

Note if you need to change the MyObjectFactory.class or TestBean.class you need to restart your Wildfly server 

In case you need to remove the module run :
[oracle@wls1 JNDI]$ cat rm_obj_factory_jndi.cli
/subsystem=naming/binding=java\:jboss\/exported\/object_factory/:remove

[oracle@wls1 JNDI]$   $WILDFLY_HOME/bin/jboss-cli.sh --connect --file=rm_obj_factory_jndi.cli
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
--> restart Wildfly

Build and run Remote JNDI test program

BindJndiDemo.java:

import java.io.*;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class BindJndiDemo
{
public final static String JNDI_FACTORY="org.jboss.naming.remote.client.InitialContextFactory";

public static void main(String[] args) throws Exception
  {
     if (args.length != 1) {
         System.out.println("Usage: java BindJndiDemo URL");
         System.out.println("Example:  java BindJndiDemo  http-remoting://127.0.0.1:8180");
         return;
     } 

     InitialContext ic = getInitialContext(args[0]);
     BindJndiDemo demo = new BindJndiDemo();
     String jnid_lookup = "java:object_factory";
     hhu.object_factory.TestBean testBean=(hhu.object_factory.TestBean)ic.lookup(jnid_lookup);
     System.out.println("\t(hhu.object_factory.TestBean)ic.lookup(jnid_lookup) testBean = "+testBean);
     System.out.println("\tname="+testBean.getName()+"\tvalue="+testBean.getValue()+" - Object Inst. Time: " + testBean.getItime());
     System.out.println("");
  }

private static InitialContext getInitialContext(String url) throws NamingException
     {
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
        env.put(Context.PROVIDER_URL, url);

        env.put(Context.SECURITY_PRINCIPAL, "oracle");
        env.put(Context.SECURITY_CREDENTIALS, "helmut11");
        InitialContext ic=new InitialContext(env);
        System.out.println("\t Got InitialContext ic: "+ic);
         return ic;
      }
}

Test Client: 
[oracle@wls1 JNDI]$  java BindJndiDemo  http-remoting://127.0.0.1:8180
Mar 14, 2015 5:47:17 PM org.xnio.Xnio <clinit>
INFO: XNIO version 3.3.0.Final
Mar 14, 2015 5:47:17 PM org.xnio.nio.NioXnio <clinit>
INFO: XNIO NIO Implementation Version 3.3.0.Final
Mar 14, 2015 5:47:17 PM org.jboss.remoting3.EndpointImpl <clinit>
INFO: JBoss Remoting version 4.0.6.Final
     Got InitialContext ic: javax.naming.InitialContext@5cef8a56
    (hhu.object_factory.TestBean)ic.lookup(jnid_lookup) testBean = hhu.object_factory.TestBean@7c91f442
    name=City    value=Sattelmannsburg - ( believe me - this is not  in India) - Object Inst. Time: 1426351273285

Rerunning Test client: 
[oracle@wls1 JNDI]$  java BindJndiDemo  http-remoting://127.0.0.1:8180
Mar 14, 2015 5:47:19 PM org.xnio.Xnio <clinit>
...
    (hhu.object_factory.TestBean)ic.lookup(jnid_lookup) testBean = hhu.object_factory.TestBean@7c91f442
    name=City    value=Sattelmannsburg - ( believe me - this is not  in India) - Object Inst. Time: 1426351273285

--> The Object Instantiation time is always 1426351273285 so we can sure it is the same object!

Reference