Search This Blog

Tuesday, 20 July 2010

How to Set v$session.program From a Universal Connection Pool (UCP)

The follow shows how you can ensure connections created from your Oracle Universal Connection Pool (UCP) clients can be uniquely identified using the Oracle JDBC driver property v$session.program. The property is an Oracle JDBC driver property so what we do here is the following.

1. Set the factory class to "oracle.jdbc.OracleDriver" using the method PoolDataSource.setConnectionFactoryClassName()
2. Use the PoolDataSource.setConnectionFactoryProperties() method to specify the driver properties that each Connection will use.

So here is a basic class showing how to set v$session.program and verify it did this correctly from SQL*Plus.


TestUCPJDBCProps.java

package demo;

import java.io.IOException;

import java.sql.Connection;
import java.sql.SQLException;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import oracle.ucp.UniversalConnectionPoolAdapter;
import oracle.ucp.UniversalConnectionPoolException;
import oracle.ucp.admin.UniversalConnectionPoolManager;
import oracle.ucp.admin.UniversalConnectionPoolManagerImpl;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;


public class TestUCPJDBCProps
{
  private PoolDataSource pds = null;
  private Properties props = new Properties();
  private UniversalConnectionPoolManager mgr = null;
  private String poolName = "PasUCPTest";
  
  public TestUCPJDBCProps() throws SQLException, UniversalConnectionPoolException
  {  
    mgr = UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager();
    
   // Create pool-enabled data source instance.
    pds = PoolDataSourceFactory.getPoolDataSource();
    // PoolDataSource and UCP configuration
    
    //set the connection properties on the data source and pool properties
    pds.setUser("scott");
    pds.setPassword("tiger");
    pds.setURL("jdbc:oracle:thin:@//beast.au.oracle.com:1523/linux11gr2");
    pds.setConnectionFactoryClassName("oracle.jdbc.OracleDriver");
    pds.setInitialPoolSize(2);
    pds.setMinPoolSize(2);
    pds.setMaxPoolSize(20);
    pds.setConnectionPoolName(poolName);
    props.put("v$session.program", "scott-ucp-j2seclient");
    pds.setConnectionFactoryProperties(props);
    
    mgr.createConnectionPool((UniversalConnectionPoolAdapter)pds);
    
    mgr.startConnectionPool(poolName);

  }

  public void run () throws SQLException, IOException
  {
    List connList = new ArrayList();
    
    for (int i = 0; i < 5 ;i++ ) 
    {
      //Get a database connection from the datasource. 
      Connection conn = pds.getConnection();
      System.out.println("Retrieved a connection from pool");
      connList.add(conn);
    }

    System.out.println("Press Enter to finish the demo -> ");
    System.in.read();
      
    // close all connections
    for (int j = 0; j < connList.size() ; j++) 
    {
      ((Connection)connList.get(j)).close();
    }
    
  }
  
  public void stopPool () throws UniversalConnectionPoolException
  {
    mgr.stopConnectionPool(poolName);  
  }
  
  public static void main(String[] args) throws IOException
  {
    System.out.println("Started UCP JDBC Property Test at " + new Date());
    TestUCPJDBCProps test;

    try
    {
      test = new TestUCPJDBCProps();
      test.run();
      test.stopPool();
    }
    catch (Exception e)
    {
      e.printStackTrace();
      System.exit(-1);
    }
    
    System.out.println("Ended UCP JDBC Property Test at " + new Date());
  }
} 

SQL*PLus Output

SCOTT@linux11gr2> @query-scott.sql

SCOTT sessions

USERNAME PROGRAM                   STATUS
-------- ------------------------- --------
SCOTT    sqlplus.exe               ACTIVE
SCOTT    scott-ucp-j2seclient      INACTIVE
SCOTT    scott-ucp-j2seclient      INACTIVE
SCOTT    scott-ucp-j2seclient      INACTIVE
SCOTT    scott-ucp-j2seclient      INACTIVE
SCOTT    scott-ucp-j2seclient      INACTIVE

6 rows selected.

SCOTT@linux11gr2>

The SQL for the query above was as follows.

set head on feedback on

set pages 999
set linesize 120

prompt
prompt SCOTT sessions

col machine format a25
col username format a15
col username format a8
col program format a25

select
username,
program,
status,
last_call_et seconds_since_active,
to_char(logon_time, 'dd-MON-yyyy HH24:MI:SS') "Logon"
from v$session
where username = 'SCOTT'
/

Thursday, 15 July 2010

SQL Worksheet using JSF 2 / JSTL Result

Having used JSTL / JSP often enough I thought I would quickly try and get a Facelet page to use a JSTL Result object to provide a VERY basic SQL Worksheet demo which allowed the user to query the database and display the data regardless of what the query data was. Found a few gotchas on the Facelet / JSF 2.0 side which were handy to solve.

Problems

1. Using c:if for conditional output seemed to always result in FALSE when clearly that wasn't the case. There are a few options in JSF 2.0 world but the easiest was to now use ui:fragment as shown below.
<ui:fragment rendered="#{queryBean.rowcount > 0}">

2. As was the case with c:if , c:forEach didn't work for me either. I believe it had something to do with it being run when the component tree is being built. So now I will be using ui:repeat instead, which is close to identical but now use the attribute value instead of items.
<ui:repeat var="columnName" value="#{queryBean.queryData.columnNames}"> 

So here is the Facelet page, Managed bean and a quick HTML screen show of how it worked.

Query.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<ui:composition
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      template="/pages/templates/EmpTemplate.xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:c="http://java.sun.com/jsp/jstl/core">

    <f:metadata>
        <f:viewParam name="refresh" value="#{employeeBean.refresh}" />
        <f:viewParam name="deptno" value="#{employeeBean.deptno}" />
        <f:viewParam name="empno" value="#{employeeBean.empno}" />
    </f:metadata>

    <ui:define name="title">
        #{msg.browserheading}
    </ui:define>

    <ui:define name="header">
        <ui:include src="/pages/employees/header.xhtml" />
    </ui:define>

    <ui:define name="body">
        <b>Enter SQL query below without semi colon</b>
        <p />
        <h:message for="query" style="color: #336699"/>
        <h:form>
            <h:inputTextarea rows="8"
                             cols="100"
                             value="#{queryBean.query}"
                             required="true"
                             requiredMessage="You must an SQL select statement to execute"
                             validator="#{queryBean.validateQuery}"
                             id="query"/>
            <br />
            <h:commandButton value="Submit Query" action="#{queryBean.executeQuery}"/>
            <h:commandButton value="Clear" action="#{queryBean.clearScreen}"/>
            <p />
        </h:form>
        <p />
        <ui:fragment rendered="#{queryBean.rowcount > 0}">
            <i>Total of #{queryBean.rowcount} record(s) found</i>
            <p />
            <table border="1">
                <thead>
                  <tr>
                    <ui:repeat var="columnName" value="#{queryBean.queryData.columnNames}">
                        <th class="heading">#{columnName}</th>
                    </ui:repeat>
                  </tr>
                </thead>
                <tbody>
                    <ui:repeat var="row" value="#{queryBean.queryData.rows}" varStatus="loop">
                        <tr class="${((loop.index % 2) == 0) ? 'even' : 'odd'}">
                          <ui:repeat var="columnName" value="#{queryBean.queryData.columnNames}">
                            <td>#{row[columnName]}</td>
                          </ui:repeat>
                        </tr>
                    </ui:repeat>
                </tbody>
            </table>
            <p />
        </ui:fragment>
    </ui:define>
    
    <ui:define name="footer">
        <ui:include src="/pages/employees/footer.xhtml" />
    </ui:define>

</ui:composition>

QueryBean.java
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package oracle.jsf.demo.managedbeans;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
import javax.servlet.jsp.jstl.sql.Result;
import oracle.jsf.demo.dao.emp.EmployeeService;

/**
 *
 * @author papicell
 */
@ManagedBean
public class QueryBean
{
    private Result queryData;
    private String query;
    private int rowcount;

    @ManagedProperty(value="#{employeeServiceImpl}")
    private EmployeeService service;

    public QueryBean()
    {
      rowcount = 0;
    }

    public String getQuery()
    {
        return query;
    }

    public void setQuery(String query)
    {
        this.query = query;
    }

    public Result getQueryData()
    {
        return queryData;
    }

    public void setQueryData(Result queryData)
    {
        this.queryData = queryData;
    }

    public EmployeeService getService()
    {
        return service;
    }

    public void setService(EmployeeService service)
    {
        this.service = service;
    }

    public int getRowcount()
    {
        return rowcount;
    }

    public void setRowcount(int rowcount)
    {
        this.rowcount = rowcount;
    }

    /*
     * Custom Validation method for query field
     */
    public void validateQuery(FacesContext context,
                                     UIComponent componentToValidate,
                                     Object value) throws ValidatorException
    {
        String statementSQL = ((String)value);
        if (!statementSQL.toLowerCase().startsWith("select"))
        {
            FacesMessage message =
                new FacesMessage("Not a valid SQL Select statement entered");
            throw new ValidatorException(message);
        }
    }

    public void executeQuery ()
    {
       queryData = service.executeQuery(getQuery());
       setRowcount(queryData.getRowCount());
    }

    public void clearScreen ()
    {
       queryData = null;
       setRowcount(0);
    }
} 

Browser Ouput

Wednesday, 14 July 2010

JSF 2 Handling Unexpected Runtime Errors

Note for myself:

1. Create a managed bean as follows.
 
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package oracle.jsf.demo.managedbeans;

import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;

/**
*
* @author papicell
*/
@ManagedBean
public class ErrorBean
{
private static final String BR = "n";

public String getStackTrace()
{
FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestMap();
Throwable throwable = (Throwable) map.get("javax.servlet.error.exception");
StringBuilder builder = new StringBuilder();
builder.append(throwable.getMessage()).append(BR);

for (StackTraceElement element : throwable.getStackTrace())
{
builder.append(element).append(BR);
}

return builder.toString();
}

}
2. Define error page in web.xml which will catch all unknown exceptions.
 
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/pages/main/error.jsf</location>
</error-page>

3. Define error page Facelet error.xhtml as follows
 
<?xml version="1.0" encoding="UTF-8"?>
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="/pages/templates/EmpTemplate.xhtml"
xmlns:f="http://java.sun.com/jsf/core">

<ui:define name="title">
#{msg.browserheading}
</ui:define>

<ui:define name="header">
<h3 style="font-family: arial; font-variant: small-caps; color: #336699">
You have encountered a system error!!
</h3>
</ui:define>

<ui:define name="body">
The error message is:
<b>
#{requestScope['javax.servlet.error.message']}
</b>
<p />
<font color="RED">
Please show the system administator the error below.
</font>
<p />
<textarea rows="30" cols="100">
<h:outputText escape="false" value="#{errorBean.stackTrace}"/>
</textarea>
<p />
</ui:define>

<ui:define name="footer">
<ui:include src="/pages/employees/footer.xhtml" />
</ui:define>

</ui:composition>

Tuesday, 6 July 2010

Simple JSF 2 h:dataTable example using Result for the value attribute

With JSF 2 we can now use a JSTL Result (javax.servlet.jsp.jstl.sql.Result) , well perhaps you could with JSF 1.2 but seemed to be a JSF 2 new feature from what I could see. His a basic example on it. What I like about it is it completely takes the data off the JDBC ResultSet object and lets you work with it independently. Kinda like storing a JDBC ResultSet in an array of Objects but saves you having to define an object and populate it yourself. JSTL Result is easy and only a few lines of code required to use it.

1. Firstly create a basic class which returns a JSTL Result object from a query. In this example the Connection is retrieved from a data source within the container itself.

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package pas.jsf2.fun.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.jsp.jstl.sql.Result;
import javax.servlet.jsp.jstl.sql.ResultSupport;
import javax.sql.DataSource;

/**
*
* @author papicell
*/
public class JdbcUtil
{
private static Connection getJNDIConnection ()
{
Context ctx;
Connection conn = null;

try
{
ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("jdbc/scottDS");
conn = ds.getConnection();

}
catch (Exception ex)
{
Logger.getLogger(JdbcUtil.class.getName()).log(Level.SEVERE, null, ex);
}

return conn;
}

public static Result runQuery (String query, int maxrows) throws SQLException
{
Statement stmt = null;
ResultSet rset = null;
Result res = null;
Connection conn = null;

try
{
conn = getJNDIConnection();
stmt = conn.createStatement();
rset = stmt.executeQuery(query);

/*
* Convert the ResultSet to a
* Result object that can be used with JSTL/JSF tags
*/
if (maxrows == -1)
{
res = ResultSupport.toResult(rset);
}
else
{
res = ResultSupport.toResult(rset, maxrows);
}
}
finally
{
if (rset != null)
{
rset.close();
}

if (stmt != null)
{
stmt.close();
}

if (conn != null)
{
conn.close();
}
}

return res;
}

}

2. Create a Managed Bean as follows.
 
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package pas.jsf2.fun;

import java.sql.ResultSet;
import java.sql.SQLException;
import javax.faces.bean.ManagedBean;
import javax.servlet.jsp.jstl.sql.Result;
import pas.jsf2.fun.jdbc.JdbcUtil;
/**
*
* @author papicell
*/
@ManagedBean(name="JDBCEmpTable")
public class JDBCEmpTable
{
private Result empResultData;

public Result getEmpResultData() throws SQLException
{
populateEmpResultData();
return empResultData;
}

private void populateEmpResultData () throws SQLException
{
empResultData =
JdbcUtil.runQuery("select empno, ename, job from emp", -1);
}

}

3. Finally create the view Facelet page which will display the Result in a h:dataTable component.


<?xml version="1.0" encoding="UTF-8"?>
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>JSTL Result Emp Map Table Demo</title>
</h:head>
<h:body>
<h3 style="font-family: arial; font-variant: small-caps; color: #336699">
JSTL Result Emp Map Table Demo
</h3>
<h:dataTable var="row" value="#{JDBCEmpTable.empResultData}" border="1">
<h:column>
<f:facet name="header">#Empno</f:facet>
#{row.empno}
</h:column>
<h:column>
<f:facet name="header">Name</f:facet>
#{row.ename}
</h:column>
<h:column>
<f:facet name="header">Job</f:facet>
#{row.job}
</h:column>
</h:dataTable>
<p />
<h:link
outcome="index.jsp"
value="Return To Home" />
</h:body>
</html>

Monday, 5 July 2010

Oracle UCP with Java DB (Derby)

Creating some JSF 2.0 demos and was told if I could use Sun Java DB (derby) rather then Oracle for the back end database. Thought it would be a chance to use some other DB and was surprised with how easy it was to install, setup and create a database with. Here is how I ended up settting up a UCP Connection Pool against a Java Db (Derby) database.

1. Create the database itself

> java -jar %DERBY_HOME%\lib\derbyrun.jar ij
> connect 'jdbc:derby:firstdb;create=true';

2. Create an SQL file to use the classic DEPT/EMP tables.

SQL File to create classic DEPT/EMP Tables
 
drop table emp;
drop table dept;

AUTOCOMMIT OFF;

CREATE TABLE DEPT (
DEPTNO INTEGER NOT NULL,
DNAME VARCHAR(14),
LOC VARCHAR(13));

ALTER TABLE DEPT
ADD CONSTRAINT DEPT_PK Primary Key (DEPTNO);

INSERT INTO DEPT VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO DEPT VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO DEPT VALUES (40, 'OPERATIONS', 'BOSTON');

CREATE TABLE EMP (
EMPNO INTEGER NOT NULL,
ENAME VARCHAR(10),
JOB VARCHAR(9),
MGR INTEGER,
HIREDATE DATE,
SAL INTEGER,
COMM INTEGER,
DEPTNO INTEGER);

ALTER TABLE EMP
ADD CONSTRAINT EMP_PK Primary Key (EMPNO);

INSERT INTO EMP VALUES
(7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800, NULL, 20);
INSERT INTO EMP VALUES
(7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-21', 1600, 300, 30);
INSERT INTO EMP VALUES
(7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250, 500, 30);
INSERT INTO EMP VALUES
(7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975, NULL, 20);
INSERT INTO EMP VALUES
(7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250, 1400, 30);
INSERT INTO EMP VALUES
(7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850, NULL, 30);
INSERT INTO EMP VALUES
(7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450, NULL, 10);
INSERT INTO EMP VALUES
(7788, 'SCOTT', 'ANALYST', 7566, '1982-12-09', 3000, NULL, 20);
INSERT INTO EMP VALUES
(7839, 'KING', 'PRESIDENT', NULL, '1981-11-17', 5000, NULL, 10);
INSERT INTO EMP VALUES
(7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 1500, 0, 30);
INSERT INTO EMP VALUES
(7876, 'ADAMS', 'CLERK', 7788, '1983-01-12', 1100, NULL, 20);
INSERT INTO EMP VALUES
(7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950, NULL, 30);
INSERT INTO EMP VALUES
(7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000, NULL, 20);
INSERT INTO EMP VALUES
(7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300, NULL, 10);

COMMIT;

ALTER TABLE EMP
ADD CONSTRAINT EMP_FK Foreign Key (DEPTNO)
REFERENCES DEPT (DEPTNO);

COMMIT;

Ant Build File Used to Load the Data

<?xml version="1.0"?>

<project default="buildschema" name="deptemp" basedir=".">

<!-- Set Properties -->
<property file="build.properties"/>

<!-- Targets -->

<target name="init">
<tstamp/>
<delete file="deptemp.out"/>
</target>

<target name="buildschema" depends="init">
<java classname="org.apache.derby.tools.ij"
output="deptemp.out"
failonerror="true"
dir="."
fork="true">
<classpath>
<pathelement path="${derby.home}/lib/derby.jar"/>
<pathelement path="${derby.home}/lib/derbytools.jar"/>
<pathelement path="${derby.home}/lib/derbyclient.jar"/>
</classpath>
<sysproperty key="ij.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<sysproperty key="ij.database" value="${jdbcurl}"/>
<arg value="deptemp.sql"/>
</java>
</target>

</project>

Ant Properties File

# derby.home
#
# This property is only required if using ANT to run this demo. It will
# use the property to build a classpath required to run the utilities

derby.home=C:\\pas\\software\\derby\\10530\\JavaDB

# jdbcurl , assumes server network connection

jdbcurl=jdbc:derby://localhost:1527/firstdb;create=true

3. Start a network server which my clients will connect to to access the database

D:\jdev\derby\pas\databases>java -jar D:\jdev\derby\10530\JavaDB\lib\derbyrun.jar server start
2010-07-04 22:14:37.187 GMT : Security manager installed using the Basic server security policy.
2010-07-04 22:14:38.109 GMT : Apache Derby Network Server - 10.5.3.0 - (802917) started and ready to accept connections on port 15
27

4. Create a quick client to verify UCP using Java Db (Derby).

Note: Need to add ucp.jar and derbyclient.jar to the classpath
 
package pas.au.ucp.standalone;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;

import java.sql.Statement;

import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;

public class DerbyUCPTest
{
private PoolDataSource pds = null;

public DerbyUCPTest() throws SQLException
{
pds = PoolDataSourceFactory.getPoolDataSource();
pds.setURL("jdbc:derby://localhost:1527/firstdb");
pds.setConnectionFactoryClassName("org.apache.derby.jdbc.ClientDriver");
}

public void run () throws SQLException
{

Connection conn = null;
Statement stmt = null;
ResultSet rset = null;

try
{
conn = pds.getConnection();

System.out.println("Got Connection to DERBY database server from UCP Pool");

stmt = conn.createStatement();
rset = stmt.executeQuery("SELECT empno, ename from EMP");

while (rset.next())
{
System.out.println
(String.format("Empno#: %s, Ename: %s",
rset.getInt(1),
rset.getString(2)));
}
}
catch (SQLException se)
{
se.printStackTrace();
}
finally
{
if (rset != null)
{
rset.close();
}

if (stmt != null)
{
stmt.close();
}

if (conn != null)
{
conn.close();
}
}

}

public static void main(String[] args) throws SQLException
{
DerbyUCPTest derbyUCPTest = new DerbyUCPTest();
derbyUCPTest.run();

}
}

Output
-------

Got Connection to DERBY database server from UCP Pool
Empno#: 7369, Ename: SMITH
Empno#: 7499, Ename: ALLEN
Empno#: 7521, Ename: WARD
Empno#: 7566, Ename: JONES
Empno#: 7654, Ename: MARTIN
Empno#: 7698, Ename: BLAKE
Empno#: 7782, Ename: CLARK
Empno#: 7788, Ename: SCOTT
Empno#: 7839, Ename: KING
Empno#: 7844, Ename: TURNER
Empno#: 7876, Ename: ADAMS
Empno#: 7900, Ename: JAMES
Empno#: 7902, Ename: FORD
Empno#: 7934, Ename: MILLER

Thursday, 24 June 2010

JSF 2.0 My First Look

Heard enough about JSF 2.0 to look into it today. Step 1was to find an IDE which supported it but unfortunately JDeveloper 11g didn't, so for the first time in a long time I had to move into another IDE and NetBeans IDE seemed the way to go here.

Although I just created some very basic demos it didn't take long to get into building tables from collections and other more useful demos. Few things really impressed me about JSF 2.0.

1. Finally I can add references to my model attributes as follows without the need to use a h:outputText component

#{TaskBean.info}

2. You can simply use a default bean name for backing beans without the need to declare beans with managed-bean in faces-config.xml. You simple put @ManagedBean above the class definition.

@ManagedBean(eager=true)
@SessionScoped
public class CalculatorManagedBean implements Serializable {
public static char[] operands = { '+', '-', '*', '/' };

3. The use of Facelets, not JSP, as the standard technology for all your JSF pages. So you name your page pas.xhtml and can reference it as pas.jsf as long as your web.xml contains the following.


<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>


4. No real need to define explicit navigation rules. If your bean methods return a a string as follows then the resulting page pas.xhtml will be called.

return "pas";

Hope to spend more time on JSF 2.0 and of course there is more to it then just this but thats a good enough start for me.

Monday, 21 June 2010

Query a RAC Cluster to get Connected users

While testing FCF with JDBC it's often useful to know how many connections I have on each instance within the cluster. Sure it's easy enough to get the instance I am connected to from the JDBC side , but if you run a query as follows using the GV$ tables on the RAC cluster you can get the info as follows for all the connections within your pool.

SQL Query

col username format a10
col service_name format a20
col host_name format a30
col instance_name format a15

select s.username, s.service_name, i.INSTANCE_NAME, i.HOST_NAME
from gv$session s, gv$instance i
where i.INST_ID = s.INST_ID
and s.username = 'SCOTT'
and s.service_name = 'HASERVICE'
/

Note: You will need to replace the username / service name with your details.

Results
  
SQL> @users

USERNAME SERVICE_NAME INSTANCE_NAME HOST_NAME
---------- -------------------- --------------- ------------------------------
SCOTT HASERVICE orcl1 apemrac1.au.oracle.com
SCOTT HASERVICE orcl1 apemrac1.au.oracle.com
SCOTT HASERVICE orcl1 apemrac1.au.oracle.com
SCOTT HASERVICE orcl1 apemrac1.au.oracle.com
SCOTT HASERVICE orcl2 apemrac2.au.oracle.com
SCOTT HASERVICE orcl2 apemrac2.au.oracle.com
SCOTT HASERVICE orcl2 apemrac2.au.oracle.com
SCOTT HASERVICE orcl2 apemrac2.au.oracle.com
SCOTT HASERVICE orcl2 apemrac2.au.oracle.com
SCOTT HASERVICE orcl2 apemrac2.au.oracle.com

10 rows selected.

Wednesday, 16 June 2010

trimDirectiveWhitespaces with JSTL

While using JSP I always use JSTL to avoid any use of java on the JSP itself. To get a quick world cup 2010 tipping competition up and running I found that my response pages using JSTL contained just way to much white space. Luckily in the JSP 2.1 world we can use the page directive trimDirectiveWhitespaces to easily remove that unwanted white spaces. Basically it's done as follows

<%@ page
contentType="text/html;charset=windows-1252"
trimDirectiveWhitespaces="true" %>

So to see how well this works simply use the code below in JDeveloper 10.1.3 (JSP 2.0) and then in JDeveloper 11g (JSP 2.1) and view the source of the page after running it.

Note: When running this code in JDeveloper 10.1.3 you will have to remove trimDirectiveWhitespaces="true" as it does not support that.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=windows-1252" trimDirectiveWhitespaces="true" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"/>
<title>JSP 2.1 - trimDirectiveWhitespaces JSTL demo</title>
</head>
<body>
<h2>JSP 2.1 - trimDirectiveWhitespaces JSTL demo</h2>

<c:forEach var="row" begin="1" end="5">
<c:choose>
<c:when test="${row == 1}">
<font color="green">
<c:out value="At row 1"/>
</font>
<br />
</c:when>
<c:otherwise>
<c:choose>
<c:when test="${row != 1}">
<font color="Red">
<c:out value="Not at row 1"/>
</font>
</c:when>
<c:otherwise>
<c:out value="Should never get here"/>
</c:otherwise>
</c:choose>
<br />
</c:otherwise>
</c:choose>
</c:forEach>

</body>
</html>

Thursday, 3 June 2010

Tam and her DBA Blog

Tam has entered the world of blogging and someone who I would frequently go to whenever I had RAC/DBA issues. In fact she would sit right next to me for a year or so. She is now leaving Oracle in a few days but her blog will continue and has some very useful RAC/RDBMS/EM information. Worth a read that's for sure.

http://sosdba.wordpress.com/

Thanks Tam.

Monday, 31 May 2010

Tomcat 6.0 / UCP Data Source Setup

To setup tomcat to use UCP as it's data source implementation here are the steps. I used 11.2 JDBC driver and UCP jar files to connect to a 11.2.0.1 RDBMS.

1. Copy ojdbc6.jar and ucp.jar into $TOMCAT_HOME/lib directory. You can download those JAR files from here.

http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/index.html

2. Add your Data Source setup in $TOMCAT_HOME/conf/server.xml as follows.

<!-- Define the default virtual host
Note: XML Schema validation will not work with Xerces 2.2.
-->

<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true"
xmlValidation="false" xmlNamespaceAware="false">

<Context docBase="demods" path="/demods" reloadable="true">
<Resource name="jdbc/UCPPool"
auth="Container"
factory="oracle.ucp.jdbc.PoolDataSourceImpl"
type="oracle.ucp.jdbc.PoolDataSource"
description="Pas testing UCP Pool in Tomcat"
connectionFactoryClassName="oracle.jdbc.pool.OracleDataSource"
minPoolSize="2"
maxPoolSize="5"
inactiveConnectionTimeout="20"
user="scott"
password="tiger"
url="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)
(HOST=beast.au.oracle.com)(PORT=1523))(CONNECT_DATA=
(SERVICE_NAME=linux11gr2)))"

connectionPoolName="UCPPool"
validateConnectionOnBorrow="true"
sqlForValidateConnection="select 1 from DUAL" />
</Context>
</Host>

3. In your web projects you deploy to tomcat add the following to web.xml

<resource-ref>
<res-ref-name>jdbc/UCPPool</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>

4. Your code to lookup the data source would be as follows.

private DataSource getDataSource (String dataSourceLocation) throws NamingException
{
// Get a context for the JNDI look up
Context ctx = new InitialContext();
Context envContext = (Context) ctx.lookup("java:/comp/env");

// Look up a data source
javax.sql.DataSource ds
= (javax.sql.DataSource) envContext.lookup (dataSourceLocation);


return ds;
}

private Connection getConnection (DataSource ds) throws SQLException
{
Connection conn = null;
// Get a connection object
conn = ds.getConnection();

return conn;
}

Note: The dataSouceLocation would be "jdbc/UCPPool"

5. Finally verify using jconsole that indeed your using UCP. In the example below we are verifying that the pool named "UCPPool" is indeed created.

SQL*Plus Direct Connection URL

Note for myself, avoiding the use of a tnsnames.ora file to connect with.

sqlplus {username}/{password}@{hostname}:{port}/{service-name}
 
d:\temp>sqlplus scott/tiger@beast.au.oracle.com:1523/linux11gr2

SQL*Plus: Release 11.2.0.1.0 Production on Mon May 31 08:04:56 2010

Copyright (c) 1982, 2010, Oracle. All rights reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SCOTT@beast.au.oracle.com:1523/linux11gr2>

Monday, 24 May 2010

DBMS_MONITOR for Tracing Current Session from Oracle JDBC

Note for myself.

Turn On

begin DBMS_MONITOR.SESSION_TRACE_ENABLE (session_id => ?, serial_num => ?, waits => TRUE, binds => TRUE); end;

Turn Off

begin DBMS_MONITOR.SESSION_TRACE_DISABLE (session_id => ?, serial_num => ?); end;

In order to get the session_id and serial_num use a query as follows to dynamically determine that. This query can be used from Oracle 9i onwards


SCOTT@linux11gr2> SELECT dbms_debug_jdwp.current_session_id sid,
2 dbms_debug_jdwp.current_session_serial serial#
3 from dual;

SID SERIAL#
---------- ----------
411 5395

SCOTT@linux11gr2>

JDBC Code as follows


  
// hold session info for connected user
private int serialNum;
private int sessionId;

private void turnOnSessionTrace (Connection conn) throws SQLException
{
String sql =
"SELECT dbms_debug_jdwp.current_session_id sid, " +
"dbms_debug_jdwp.current_session_serial serial# " +
"from dual";
String turnOnSQL =
"begin DBMS_MONITOR.SESSION_TRACE_ENABLE (session_id => ?, " +
"serial_num => ?, waits => TRUE, binds => TRUE); end;";

Statement stmt = conn.createStatement();
ResultSet rset = stmt.executeQuery(sql);
rset.next();

if (rset != null)
{
sessionId = rset.getInt(1);
serialNum = rset.getInt(2);
}

System.out.println(
String.format("Session Details : session_id=%s, serial_num=%s",
sessionId, serialNum));

OracleCallableStatement csmt = (OracleCallableStatement) conn.prepareCall(turnOnSQL);
csmt.setInt(1, sessionId);
csmt.setInt(2, serialNum);
csmt.execute();

stmt.close();
rset.close();
csmt.close();
}

private void turnOffSessionTrace (Connection conn) throws SQLException
{
String turnOffSQL =
"begin DBMS_MONITOR.SESSION_TRACE_DISABLE (session_id => ?, serial_num => ?); end;";

OracleCallableStatement csmt = (OracleCallableStatement) conn.prepareCall(turnOffSQL);
csmt.setInt(1, sessionId);
csmt.setInt(2, serialNum);
csmt.execute();
}

Wednesday, 12 May 2010

Using Coherence*Web With the Monolithic Session Model

With the release of WLS 10.3.3 we now get the Coherence*Web Library deployed by default in our domains when we add configured them to use Oracle Enterprise Manger as described here. With that here are the steps to ensure your WAR projects use C*Web. In this demo we switch to the Monolithic model which is not the default Session model.

Note: This is a WAR based demo.

1. Create a weblogic.xml file in the WEB-INF directory of your web based project which references the C*web library

<?xml version = '1.0' encoding = 'windows-1252'?>
<weblogic-web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-web-app http://www.bea.com/ns/weblogic/weblogic-web-app/1.0/weblogic-web-app.xsd"
xmlns="http://www.bea.com/ns/weblogic/weblogic-web-app">
<library-ref>
<library-name>coherence-web-spi</library-name>
<specification-version>1.0.0.0</specification-version>
<implementation-version>1.0.0.0</implementation-version>
<exact-match>false</exact-match>
</library-ref>
</weblogic-web-app>

2. Edit the web.xml of your web based project to switch to Monolithic model.

<context-param>
<param-name>coherence-sessioncollection-class</param-name>
<param-value>com.tangosol.coherence.servlet.MonolithicHttpSessionCollection</param-value>
</context-param>

3. Finally ensure you place coherence.jar into your WEB-INF/lib directory

The following show what your project would look like in JDeveloper 11.1.1.3





















4. Once deployed we will see that we have swicthed to the new Session Model which is shown in the managed server log file at startup of the container or at the point when the application is started.


2010-05-13 07:11:37.680/37.754 Oracle Coherence 3.5.3/465 (thread=[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Loaded operational configuration from resource "zip:/home/oracle/product/11gR3/user_projects/domains/cweb_dom/servers/lemon/tmp/_WL_user/cohwebmonolithicmodel/5z88cr/war/WEB-INF/lib/coherence.jar!/tangosol-coherence.xml"
2010-05-13 07:11:37.687/37.761 Oracle Coherence 3.5.3/465 (thread=[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Loaded operational overrides from resource "zip:/home/oracle/product/11gR3/user_projects/domains/cweb_dom/servers/lemon/tmp/_WL_user/cohwebmonolithicmodel/5z88cr/war/WEB-INF/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2010-05-13 07:11:37.689/37.763 Oracle Coherence 3.5.3/465 (thread=[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Optional configuration override "/tangosol-coherence-override.xml" is not specified
2010-05-13 07:11:37.695/37.769 Oracle Coherence 3.5.3/465 (thread=[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified

Oracle Coherence Version 3.5.3/465
Grid Edition: Development mode
Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.

2010-05-13 07:11:37.853/37.927 Oracle Coherence GE 3.5.3/465 (thread=[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): Loaded cache configuration from "file:/home/oracle/product/11gR3/user_projects/domains/cweb_dom/servers/lemon/tmp/_WL_user/coherence-web-spi/bky8eh/WEB-INF/classes/session-cache-config.xml"
2010-05-13 07:11:38.607/38.681 Oracle Coherence GE 3.5.3/465 (thread=[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)', member=n/a): UnicastUdpSocket failed to set receive buffer size to 1428 packets (2096304 bytes); actual size is 92 packets (135168 bytes). Consult your OS documentation regarding increasing the maximum socket buffer size. Proceeding with the actual value may cause sub-optimal performance.
2010-05-13 07:11:38.925/38.999 Oracle Coherence GE 3.5.3/465 (thread=Cluster, member=n/a): Service Cluster joined the cluster with senior service member n/a
2010-05-13 07:11:42.158/42.232 Oracle Coherence GE 3.5.3/465 (thread=Cluster, member=n/a): Created a new cluster "cluster:0xDDEB" with Member(Id=1, Timestamp=2010-05-13 07:11:38.628, Address=10.187.81.36:8088, MachineId=57380, Location=site:au.oracle.com,machine:wayne-p2,process:16376, Role=WeblogicServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=2) UID=0x0ABB5124000001288E5BC584E0241F98
2010-05-13 07:11:42.204/42.278 Oracle Coherence GE 3.5.3/465 (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
2010-05-13 07:11:43.622/43.696 Oracle Coherence GE 3.5.3/465 (thread=DistributedCache:DistributedSessions, member=1): Service DistributedSessions joined the cluster with senior service member 1
2010-05-13 07:11:43.683/43.757 Oracle Coherence GE 3.5.3/465 (thread=Invocation:SessionOwnership, member=1): Service SessionOwnership joined the cluster with senior service member 1
2010-05-13 07:11:43.709/43.783 Oracle Coherence GE 3.5.3/465 (thread=[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)', member=1): Configured session model "MonolithicHttpSessionCollection":
Clustered Session Cache Name=session-storage
Local Session Cache Name=local-session-storage
Local Session Attribute Cache Name=local-attribute-storage
Death Certificate Cache Name=session-death-certificates
SessionDistributionController Class Name=
AttributeScopeController Class Name=com.tangosol.coherence.servlet.AbstractHttpSessionCollection$ApplicationScopeController
Maximum Session Inactive Seconds=3600
Session ID Character Length=52
Member Session Locking Enforced=true
Application Session Locking Enforced=true
Thread Session Locking Enforced=false
Assume Session Locality for Reaping=false
Strict "Servlet Specification" Exception Handling=true
Sticky Session Ownership=true
Sticky Session Ownership Service Name=SessionOwnership
2010-05-13 07:11:43.725/43.799 Oracle Coherence GE 3.5.3/465 (thread=[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)', member=1): Registering HttpSessionManager(ServetContext=ServletContextWrapper (2.5)
SessionHelper!=null
MajorVersion=2
MinorVersion=5
Clustered=false
ServletContext (wrapped)=weblogic.servlet.internal.session.CoherenceWebServletContextWrapper@1f4d4bd
AttributeMap=null
Oracle Coherence 3.5.3/465) using object name "type=HttpSessionManager,nodeId=1,appId=cohwebmonolithicmodel!cohwebmonolithicmodel.war"



Also to start a coherence server which is storage enabled for the session management you would do it as follows. By default the WLS Coherence node is storage disabled. This is a unix script example.

export JAVA_HOME=/home/oracle/product/11gR3/jdk160_18
export COHERENCE_HOME=/home/oracle/product/coherence/353/coherence
export COH_OPTS="-server -classpath $COHERENCE_HOME/lib/coherence.jar:$COHERENCE_HOME/lib/coherence-web-spi.war"
export COH_OPTS="$COH_OPTS -Dtangosol.coherence.cacheconfig=/WEB-INF/classes/session-cache-config.xml
-Dtangosol.coherence.distributed.localstorage=true -Dtangosol.coherence.management.remote=true
-Dtangosol.coherence.session.localstorage=true"

java $COH_OPTS -Xms512m -Xmx512m com.tangosol.net.DefaultCacheServer

Thursday, 6 May 2010

JDeveloper 11g - ADF Deployment using a Data Source defined in WLS itself

Typically when deploying ADF applications I will use a data source config defined at the WLS level and targeted to my managed server or cluster. I then deploy my ADF application from JDeveloper to that managed server or cluster however there are a few things to be aware of prior to deployment to ensure your using the correct Data Source. By default you won't be using the WLS defined Data Source if you not aware of a few things.

Note: For those who prefer to use a separate Data Source per application then out of the box you don't need to follow the steps below as it will do that for you by default. Also for our model ADFBC project we are assuming that it's configurtion is set to use "JDBC DataSource".

When your ready to deploy

1. Select "Applications -> Application Properties"
2. Click on "Deployment"

By default the "Auto generate and synchronize weblogic-jdbc.xml Descriptors during deployemnt" will be checked.

3. Uncheck that option we don't want to do that here as we already have a Data Source created in WLS.

4. Verify indeed that the weblogic-jdbc.xml is not part of the archive by selecting "Application -> Deploy -> .. to ear file"

Note: This show we no longer will bundle a weblogic-jdbc.xml file.

 
D:\jdev\jdevprod\11gr3\jdeveloper\jdev\mywork\ADFDemo\deploy>jar -tvf ADFDemo_application1.ear
4305851 Thu May 06 09:45:32 EST 2010 ADFDemo_ViewController_webapp1.war
221 Thu May 06 09:45:34 EST 2010 META-INF/adfm.xml
495 Thu May 06 09:45:34 EST 2010 META-INF/application.xml
3933 Thu May 06 09:04:04 EST 2010 META-INF/cwallet.sso
949 Thu May 06 09:04:02 EST 2010 META-INF/jps-config.xml
1559 Thu May 06 09:03:20 EST 2010 META-INF/weblogic-application.xml
745 Thu May 06 09:04:02 EST 2010 adf/META-INF/adf-config.xml
1253 Thu May 06 09:04:04 EST 2010 adf/META-INF/connections.xml
831 Thu May 06 09:05:10 EST 2010 adf/model/common/bc4j.xcfg
273 Thu May 06 09:45:34 EST 2010 lib/adf-loc.jar

D:\jdev\jdevprod\11gr3\jdeveloper\jdev\mywork\ADFDemo\deploy>


5. Finally it's worth checking that indeed you not using a bundled data source so that you are actually defining the required properties for your data source in WLS console for the correct one.

Wednesday, 5 May 2010

Installing ADF runtime into FMW 11gR1 patchset 2

If you wish to use ADF with FMW 11gR1 pathset 2 (11.1.1.3) you will need to install it as follows into your stand alone FMW home.

Note: Assuming you already have Weblogic 10.3.3 installed.

1. Navigate to this web page which is where we need to download some files from.

http://www.oracle.com/technology/software/products/middleware/htdocs/fmw_11_download.html

2. Download and install "Application Development Runtime (11.1.1.2.0)" into your stand alone Weblogic 10.3.3

3. Now download and install "Application Development Runtime (11.1.1.3.0)" into your stand alone Weblogic 10.3.3.

4. Now run config.sh to create a new domain for ADF applications. I normally select "Oracle Enterprise Manager" which will then include the JRF required for ADF, as shown below.
















5. Then in EM itself apply the JRF template to the managed servers which will host ADF applications developed in JDeveloper 11.1.1.3.

- http://{server}:{port}/em
- Click the + symbol for "Weblogic Domain".
- Click on the + symbol for your domain.
- Select the managed server you wish to enable ADF applications for.
- Click on the button "Apply JRF Template".

6. Finally deploy an ADF app from JDeveloper 11.1.1.3 to verify the setup.

[09:22:08 AM] ---- Deployment started. ----
[09:22:08 AM] Target platform is (Weblogic 10.3).
[09:22:08 AM] Retrieving existing application information
[09:22:09 AM] Running dependency analysis...
[09:22:09 AM] Building...
[09:22:19 AM] Deploying 2 profiles...
[09:22:23 AM] Wrote Web Application Module to D:\jdev\jdevprod\11gr3\jdeveloper\jdev\mywork\ADFDemo\ViewController\deploy\ADFDemo_ViewController_webapp1.war
[09:22:25 AM] Wrote Enterprise Application Module to D:\jdev\jdevprod\11gr3\jdeveloper\jdev\mywork\ADFDemo\deploy\ADFDemo_application1.ear
[09:22:26 AM] Deploying Application...
[09:22:29 AM] [Deployer:149191]Operation 'deploy' on application 'ADFDemo_application1' is initializing on 'apple'
[09:22:36 AM] [Deployer:149192]Operation 'deploy' on application 'ADFDemo_application1' is in progress on 'apple'
[09:22:47 AM] [Deployer:149194]Operation 'deploy' on application 'ADFDemo_application1' has succeeded on 'apple'
[09:22:47 AM] Application Deployed Successfully.
[09:22:47 AM] The following URL context root(s) were defined and can be used as a starting point to test your application:
[09:22:47 AM] http://10.187.81.36:7003/adfdemo
[09:22:47 AM] Elapsed time for deployment: 39 seconds
[09:22:47 AM] ---- Deployment finished. ----