Search This Blog

Thursday, 17 February 2011

JRuby Script to Monitor a Oracle WebLogic GridLink Data Source Remotely

In WebLogic 10.3.4 release, a single data source implementation has been introduced to support Oracle RAC cluster. To simplify and consolidate its support for Oracle RAC, WebLogic Server has provided a single data source that is enhanced to support the capabilities of Oracle RAC.  It provides a single connection pool/data source within Oracle WebLogic Server that supports the consumption of database services in an unrestricted manner. For more information on this see the URL below.

http://download.oracle.com/docs/cd/E17904_01/web.1111/e13737/gridlink_datasources.htm

In the example below we show how we can monitor this new Active GridLink Data Source from a JRuby script to get runtime information as the Data Source is in use from the MBean. In this example we are assuming our Data Source has a name "jdbc/gridlinkDS" which was created in the console of WebLogic itself.

1. Determine the remote connection URL to connect to WebLogic 10.3.4. The URL will be something as follows which shows are are connecting to the runtime MBean server of the managed server itself. In short this will be where you have targeted your GridLink Data Source to, it's not the ADMIN SERVER it's the managed server itself.

Format:

service:jmx:iiop://{hostname}:{managed-server-port}/jndi/weblogic.management.mbeanservers.runtime

Example:

service:jmx:iiop://wayne-p2.au.oracle.com:7003/jndi/weblogic.management.mbeanservers.runtime

2. At this point it's worth connecting using JConsole remotely to the WebLogic server using the URL above as this will help you see how the MBeans are structured and what you then need to alter the JRuby script with. Start jconsole ensuring your using wlfullclient.jar in the classpath from $WLS_HOME/server/lib directory.

Windows Example: (Connecting to a remote linux x86 server)

> jconsole -J-Djava.class.path=C:\jdev\weblogic-client\1034\wlfullclient.jar;C:\jdev\jdk\jdk1.6.0_21\lib\jconsole.jar -J-Djmx.remote.protocol.provider.pkgs=weblogic.management.remote

3. Connect using the service url from #1 above and with your username/password for the managed server where the GridLink Data Source is targeted for.



4. Click on the "MBeans" tab

5. At this point we want to determine what the MBean for the GridLink Data Source is but also what the MBean names are for the instances within the RAC cluster. To do that click on "com.bea" using the + symbol to expand the tree.

6. Scroll down and locate your GridLink Data Source in this case it's "jdbc/gridlinkDS" , use the + symbol to expand the tree

7. Click on the + symbol next to "JDBCOracleDataSourceRuntime"

8. Now actually click on "JDBCOracleDataSourceRuntime" to reveal the MBean name for the actual GidLink Data Source. Make a note of it which is displayed in the field "Object Name" in the right hand side of the dialog.

com.bea:ServerRuntime=apple,Name=jdbc/gridlinkDS,Type=JDBCOracleDataSourceRuntime

9. Select the "Attributes" node in the tree to view the GridLink Data Source runtime attributes.

10. Double click on the "Instances" Value field to reveal the MBean names for the individual instances within your cluster. Make a note of them as we will need them shortly. For my example there as follows.

com.bea:ServerRuntime=apple,Name=A11,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS
com.bea:ServerRuntime=apple,Name=A12,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS

11. Create a test client as follows
require 'java'
require 'rubygems'
require 'jmx4r'
require 'C:/jdev/weblogic-client/1034/wlfullclient.jar'

java_import 'javax.management.ObjectName'
java_import java.lang.System

class MonitorGridLinkDataSource
  def initialize(user, passwd, url)
    System.setProperty("jmx.remote.protocol.provider.pkgs", "weblogic.management.remote")
    @user, @passwd, @url = user, passwd, url
       
    @conn = JMX::MBean.establish_connection :url => @url, :username => @user, :password => @passwd 
  end

  # add getters and setters for all attrributes we wish to expose    
  attr_reader :user, :passwd, :url, :conn
  
  def display_array (value)
    data = "" 
    value.each do |x|
      data += "\n\t" + x.to_s
    end
    return data
  end

  def display_attribute_data(conn, object_name, attribute)  
    s = conn.get_attribute object_name, attribute
    search_str = s.to_s
    if (/^\[Ljava.lang.String/.match(search_str)) or 
       (/^\[I/.match(search_str)) or
       (/^\[Ljavax.management.ObjectName/.match(search_str))
      # we have a array with data
      return display_array s
    else
      return search_str
    end 
  end
  
  def to_s    
    "MonitorGridLinkDataSource [user=#{@user}, passwd=#{@passwd}, " +    
    "url=#{@url}]"    
  end  
  
  def run(parent_ds_runtime_mbean_name, child_ds_instances)

    mbean = JMX::MBean.find_by_name parent_ds_runtime_mbean_name
    object_name = ObjectName.new parent_ds_runtime_mbean_name

    #
    # Display main JDBC grindlink Data Source MBean info
    # 
    printf "\n** JDBC GridLink Data Source mbean \"jdbc/gridlinkDS\" ** \n\n"

    # display attributes key/values
    mbean.attributes.each do |key, value|  
     puts "Name: #{value}, Value: #{display_attribute_data conn, object_name, value}\n"
    end

    #
    # Now display info about each RAC instances within the gridlink DS
    #
    # Note: there will be as many instances as your RAC cluster contains here, in my case 
    # just a 2 node RAC cluster here

    child_ds_instances.each {|mbean_name| 
      ds1_mbean = JMX::MBean.find_by_name mbean_name
      object_name1 = ObjectName.new mbean_name
      
      printf "\n** Instance MBean \n\t[#{mbean_name}] \n\n"
      ds1_mbean.attributes.each do |key, value|  
       puts "Name: #{value}, Value: #{display_attribute_data conn, object_name1, value}\n"
      end
    }
    
  end

end

print "Run at ", Time.now , "\n"

#Connection details to MBeanServer within Weblogic 10.3.4 
url = "service:jmx:iiop://wayne-p2.au.oracle.com:7003/jndi/weblogic.management.mbeanservers.runtime"
username = "weblogic"
password = "welcome1"

# parent GridLink Data Source MBean name
parent_ds_runtime_mbean_name = 
      "com.bea:ServerRuntime=apple,Name=jdbc/gridlinkDS,Type=JDBCOracleDataSourceRuntime"
      
# child instance MBean array, add for each instance in the RAC cluster
child_ds_instances = 
  ["com.bea:ServerRuntime=apple,Name=A11,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS", 
   "com.bea:ServerRuntime=apple,Name=A12,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS"]

begin
  mon_grid_link_ds = MonitorGridLinkDataSource.new username, password, url
  puts mon_grid_link_ds
  while (true)
    mon_grid_link_ds.run parent_ds_runtime_mbean_name, child_ds_instances
    # sleep for 20 seconds
    puts "\nSleeping for 20 seconds....\n"   
    sleep 20
  end
rescue 
  print "\n** Error occured **\n"
 print "Failed executing GridLink Data Source Monitoring from JRuby ", $!, "\n"  
end

print "\nEnded at ", Time.now , "\n" 

12. Edit the following lines as per the information we collected above.

require 'C:/jdev/weblogic-client/1034/wlfullclient.jar'
...

#Connection details to MBeanServer within Weblogic 10.3.4 
url = "service:jmx:iiop://wayne-p2.au.oracle.com:7003/jndi/weblogic.management.mbeanservers.runtime"
username = "weblogic"
password = "welcome1"

# parent GridLink Data Source MBean name
parent_ds_runtime_mbean_name = 
      "com.bea:ServerRuntime=apple,Name=jdbc/gridlinkDS,Type=JDBCOracleDataSourceRuntime"
      
# child instance MBean array, add for each instance in the RAC cluster
child_ds_instances = 
["com.bea:ServerRuntime=apple,Name=A11,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS", 
 "com.bea:ServerRuntime=apple,Name=A12,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS"]

...



Note: We previously installed "jmx4r" ruby gem to allow us to use JMX API to communicate with the WebLogic server as follows


> jruby -S gem install jmx4r

13. Run the JRuby script as follows it will continually run sleeping every 20 seconds to display runtime information regarding your GridLink Data Source. To end it simply use CNRL-C to stop it running.

> jruby gridlink-monitor.rb

Output

Run at Thu Feb 17 21:55:32 +1100 2011
MonitorGridLinkDataSource [user=weblogic, passwd=welcome1, url=service:jmx:iiop://wayne-p2.au.oracle.com:7003/jndi/weblogic.management.mbean
servers.runtime]


** JDBC GridLink Data Source mbean "jdbc/gridlinkDS" **


Name: ActiveConnectionsCurrentCount, Value: 0
Name: WaitingForConnectionFailureTotal, Value: 0
Name: Instances, Value:
        com.bea:ServerRuntime=apple,Name=A11,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS
        com.bea:ServerRuntime=apple,Name=A12,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS
Name: FailedRCLBBasedBorrowCount, Value: 0
Name: WaitingForConnectionTotal, Value: 0
Name: ConnectionsTotalCount, Value: 28
Name: SuccessfulRCLBBasedBorrowCount, Value: 0
Name: DriverVersion, Value: 11.2.0.2.0
Name: WaitingForConnectionCurrentCount, Value: 0
Name: LeakedConnectionCount, Value: 0
Name: HighestNumUnavailable, Value: 20
Name: PrepStmtCacheAccessCount, Value: 0
Name: LastTask, Value:
Name: Parent, Value: com.bea:Name=apple,Type=ServerRuntime
Name: WaitSecondsHighCount, Value: 0
Name: ActiveConnectionsHighCount, Value: 20
Name: FailedAffinityBasedBorrowCount, Value: 0
Name: PrepStmtCacheHitCount, Value: 0
Name: ActiveConnectionsAverageCount, Value: 0
Name: VersionJDBCDriver, Value: oracle.jdbc.OracleDriver
Name: DatabaseProductVersion, Value: Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options
Name: SuccessfulAffinityBasedBorrowCount, Value: 0
Name: PrepStmtCacheDeleteCount, Value: 0
Name: ReserveRequestCount, Value: 36
Name: FailuresToReconnectCount, Value: 0
Name: WaitingForConnectionHighCount, Value: 0
Name: PrepStmtCacheMissCount, Value: 0
Name: Enabled, Value: true
Name: FailedReserveRequestCount, Value: 0
Name: Type, Value: JDBCOracleDataSourceRuntime
Name: HighestNumAvailable, Value: 20
Name: WorkManagerRuntimes, Value:
Name: DatabaseProductName, Value: Oracle
Name: ONSClientRuntime, Value: com.bea:ServerRuntime=apple,Name=jdbc/gridlinkDS,Type=ONSClientRuntime,JDBCOracleDataSourceRuntime=jdbc/gridl
inkDS
Name: Properties, Value: {user=scott}
Name: CurrCapacityHighCount, Value: 20
Name: PrepStmtCacheCurrentSize, Value: 0
Name: ServiceName, Value:
Name: JDBCDriverRuntime, Value:
Name: WaitingForConnectionSuccessTotal, Value: 0
Name: NumUnavailable, Value: 0
Name: PrepStmtCacheAddCount, Value: 0
Name: DriverName, Value: Oracle JDBC driver
Name: NumAvailable, Value: 20
Name: ModuleId, Value: jdbc/gridlinkDS
Name: Name, Value: jdbc/gridlinkDS
Name: State, Value: Running
Name: ConnectionDelayTime, Value: 133
Name: DeploymentState, Value: 2
Name: CurrCapacity, Value: 20


** Instance MBean
        [com.bea:ServerRuntime=apple,Name=A11,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS]


Name: Parent, Value: com.bea:ServerRuntime=apple,Name=jdbc/gridlinkDS,Type=JDBCOracleDataSourceRuntime
Name: Enabled, Value: true
Name: ActiveConnectionsCurrentCount, Value: 0
Name: Type, Value: JDBCOracleDataSourceInstanceRuntime
Name: NumAvailable, Value: 10
Name: Signature, Value: instance=A11,service=pas_srv,database=A1,host=auw2k3
Name: CurrentWeight, Value: 1
Name: Name, Value: A11
Name: ConnectionsTotalCount, Value: 14
Name: ReserveRequestCount, Value: 19
Name: State, Value: Enabled
Name: NumUnavailable, Value: 0
Name: CurrCapacity, Value: 10
Name: InstanceName, Value: A11


** Instance MBean
        [com.bea:ServerRuntime=apple,Name=A12,Type=JDBCOracleDataSourceInstanceRuntime,JDBCOracleDataSourceRuntime=jdbc/gridlinkDS]


Name: Parent, Value: com.bea:ServerRuntime=apple,Name=jdbc/gridlinkDS,Type=JDBCOracleDataSourceRuntime
Name: Enabled, Value: true
Name: ActiveConnectionsCurrentCount, Value: 0
Name: Type, Value: JDBCOracleDataSourceInstanceRuntime
Name: NumAvailable, Value: 10
Name: Signature, Value: instance=A12,service=pas_srv,database=A1,host=auw2k4
Name: CurrentWeight, Value: 1
Name: Name, Value: A12
Name: ConnectionsTotalCount, Value: 14
Name: ReserveRequestCount, Value: 17
Name: State, Value: Enabled
Name: NumUnavailable, Value: 0
Name: CurrCapacity, Value: 10
Name: InstanceName, Value: A12


Sleeping for 20 seconds....

Thursday, 10 February 2011

JRuby script to access Oracle Coherence MBean attributes

I found a ruby gem known as "jmx4r" to use JMX from JRuby. The aim here was to use that to display details of an MBean's attributes but found it not as easy as I thought it would be. Here are 2 ways I did that, to be honest using option 2 seemed the better way to do this.

Option 1

In this example here I have using Ruby to make dynamic method calls based on the attribute value.
require 'java'
require 'rubygems'
require 'jmx4r'

def display_array (meth)
  data = ""
  
  meth.call.send("each") do |x|
    data += "\n\t" + x.to_s
  end
  
  return data
end

def display_attribute_data(key, mbean)
  meth = mbean.method(key)
  data = ""
  s = meth.call.to_s
  if (/^\[Ljava.lang.String/.match(s))
    # we have a String[] array with data
    return display_array meth
  elsif (/^\[I/.match(s))
    return display_array meth
  else
    return s
  end

end

url = "service:jmx:rmi://localhost:3000/jndi/rmi://localhost:9000/server"
conn = JMX::MBean.establish_connection :url => url
    
mbean = JMX::MBean.find_by_name "Coherence:type=Cluster"

# display attributes key/values
mbean.attributes.each do |key, value|  
 puts "Name: #{key}, Value: #{display_attribute_data key, mbean}\n"
end

# puts "\n\n** PRETTY PRINT DISPLAY attributes/method descriptions ** \n"
#JMX::MBean.pretty_print "Coherence:type=Cluster", :url => url
Output

Name: local_member_id, Value: 2
Name: cluster_size, Value: 2
Name: license_mode, Value: Development
Name: members_departed, Value:
Name: refresh_time, Value: Thu Feb 10 14:40:21 EST 2011
Name: cluster_name, Value: cluster:0xC4DB
Name: running, Value: true
Name: oldest_member_id, Value: 1
Name: members, Value:
        Member(Id=1, Timestamp=2011-02-10 14:38:05.783, Address=10.187.114.243:8088, MachineId=50163, Location=machine:paslap-au,process:662
0, Role=CoherenceServer)
        Member(Id=2, Timestamp=2011-02-10 14:38:15.57, Address=10.187.114.243:8090, MachineId=50163, Location=machine:paslap-au,process:2992
, Role=TangosolNetMBeanConnector)
Name: version, Value: 3.6.0.0
Name: members_departure_count, Value: 0
Name: member_ids, Value:
        1
        2


Option 2

In this example I get a JAVA javax.management.ObjectName so I can easily obtain attribute values by name. In this example I don't make any effort to format the value for the attribute should it be an array type. I could easily just use the code I did in option 1 above.
require 'java'
require 'rubygems'
require 'jmx4r'

java_import 'javax.management.ObjectName'

def display_attribute_data(conn, object_name, attribute)  
  return conn.get_attribute object_name, attribute
end

url = "service:jmx:rmi://localhost:3000/jndi/rmi://localhost:9000/server"
conn = JMX::MBean.establish_connection :url => url
    
mbean = JMX::MBean.find_by_name "Coherence:type=Cluster"
object_name = ObjectName.new "Coherence:type=Cluster"

# display attributes key/values
mbean.attributes.each do |key, value|  
 puts "Name: #{value}, Value: #{display_attribute_data conn, object_name, value}\n"
end 
Output

Name: LocalMemberId, Value: 2
Name: ClusterSize, Value: 2
Name: LicenseMode, Value: Development
Name: MembersDeparted, Value: [Ljava.lang.String;@725967
Name: RefreshTime, Value: Thu Feb 10 14:41:25 EST 2011
Name: ClusterName, Value: cluster:0xC4DB
Name: Running, Value: true
Name: OldestMemberId, Value: 1
Name: Members, Value: [Ljava.lang.String;@6e3e5e
Name: Version, Value: 3.6.0.0
Name: MembersDepartureCount, Value: 0
Name: MemberIds, Value: [I@9b87f6

Friday, 4 February 2011

JRuby Script to Verify Your 11g R2 RAC Setup using SCAN

The following demo can be used to verify failover using an 11g R2 (11.2.0.2) RAC cluster from a JRuby script. For this example we are using an Oracle UCP Pool setup to use FCF to receive FAN events / notifications.

1. Download ucp.jar and ojdbc6.jar from the links below.

ojdbc6.jar (11.2.0.2)
ucp.jar (11.2.0.1)

2. In a "lib" sub directory create a JRuby script called "ucppool-singleton.rb" with content as follows
require 'java'
require 'C:/jdev/jdcbdrivers/11.2/11202/ojdbc6.jar'
require 'C:/jdev/jdcbdrivers/11.2/11202/ons.jar'
require 'C:/jdev/jdcbdrivers/11.2/ucp/ucp.jar'

java_import 'oracle.ucp.jdbc.PoolDataSource'
java_import 'oracle.ucp.jdbc.PoolDataSourceFactory'

API_VERSION = 1.0

class MyOracleUcpPool
   
   def load_properties(properties_filename)
    properties = {}
    File.open(properties_filename, 'r') do |properties_file|
      properties_file.read.each_line do |line|
        line.strip!
        if (line[0] != ?# and line[0] != ?=)
          i = line.index('=')
          if (i)
            properties[line[0..i - 1].strip] = line[i + 1..-1].strip
          else
            properties[line] = ''
          end
        end
      end      
    end
    return properties
  end
  
  def initialize()
    props = load_properties(File.dirname(__FILE__) + "/ucp.properties")

    @user = props["user"]
    @passwd = props["password"]
    @url = props["url"]
    @minsize = props["minpoolsize"].to_i
    @maxsize = props["maxpoolsize"].to_i
    @initialsize = props["initialpoolsize"].to_i
    @factoryclassname = props["connectionfactory"]
    @onsconfig = props["onsconfig"]
    
    #create pool for use here
    @pds = PoolDataSourceFactory.getPoolDataSource
    @pds.set_user user
    @pds.set_password passwd
    @pds.set_url url
    @pds.set_connection_factory_class_name factoryclassname
    @pds.set_connection_pool_name "ruby-fcfucppool"
    @pds.set_initial_pool_size initialsize
    @pds.set_min_pool_size minsize
    @pds.set_max_pool_size maxsize
    @pds.setONSConfiguration(onsconfig)
    @pds.set_fast_connection_failover_enabled true
    
  end

  #add getters and setters for all attrributes
  attr_reader :user, :passwd, :url, :minsize, :maxsize, :initialsize, :factoryclassname, :onsconfig
  
  @@instance = MyOracleUcpPool.new
  @pds = nil
  
  def self.instance()
    return @@instance
  end
  
  def get_connection()
    return @pds.get_connection
  end
  
  def return_connection(conn)
    conn.close
  end

  def to_s
    "MyOracleUcpPool [user=#{@user}, passwd=#{@passwd}, " +
    "url=#{@url}, minsize=#{@minsize}, maxsize=#{@maxsize}, " +
    "initialsize=#{@initialsize}], factoryclassname=#{factoryclassname}"
  end
  alias_method :to_string, :to_s
    
  def display_pool_details()
    return "\n** FCF Enabled UCP Pool Details **\n" + 
            "NumberOfAvailableConnections: #{@pds.getAvailableConnectionsCount()}\n" +
            "BorrowedConnectionsCount: #{@pds.getBorrowedConnectionsCount()}\n";
  end
  
  private_class_method :new

 end    

3. In the same "lib" directory create a properties file called "ucp.properties" with content as follows. Ensure you set the correct details for your 11g RAC Cluster.


user=scott
password=tiger
url=jdbc:oracle:thin:@apctcsol1.au.oracle.com:1521/pas_srv
connectionfactory=oracle.jdbc.pool.OracleDataSource
initialpoolsize=5
minpoolsize=5
maxpoolsize=20
onsconfig=nodes=auw2k3.au.oracle.com:6200,auw2k4.au.oracle.com:6200

4. Edit the 3 lines below in the file "lib/ucppool-singleton.rb" to indicate the PATH to the 2 JAR files downloaded at step #1. For ons.jar you would obtain that from your CRS_HOME or RAC node at "$ORACLE_HOME/opmn/lib/ons.jar".

require 'C:/jdev/jdcbdrivers/11.2/11202/ojdbc6.jar'
require 'C:/jdev/jdcbdrivers/11.2/11202/ons.jar'
require 'C:/jdev/jdcbdrivers/11.2/ucp/ucp.jar'

5. Create a JRuby script called "ucp_fcf_test.rb" with content as follows.
require 'lib/ucppool-singleton'

INSTANCE_SQL = <<EOF  
select sys_context('userenv', 'instance_name'),  
sys_context('userenv', 'server_host'),   
sys_context('userenv', 'service_name')  
from dual  
EOF

def get_instance_details (conn, index)
  stmt = nil
  rset = nil
  
  begin
    stmt = conn.create_statement  
    rset = stmt.execute_query INSTANCE_SQL  
    rset.next  
    result = "\n--> Connection #{index} : instance [#{rset.get_string 1}], " +   
         "host[#{rset.get_string 2}], service[#{rset.get_string 3}]"  
    
    rset.close
    stmt.close
    
    return result
  rescue
    if (!rset.nil?)
      rset.close
    end
    if (!stmt.nil?)
      stmt.close
    end
    raise
  end
end

print "Run at ", Time.now , "\n"

conn = nil
ucppool = nil
i = 0

begin

  #use as a singleton class enusuring only one instance can exist
  ucppool = MyOracleUcpPool.instance()
  print ucppool , "\n"
  
  while (true)
    #get 5 connections from pool and insert into ruby hash
    conn = []
    for y in 0..4
      conn[y] = ucppool.get_connection
    end
    
    #  print instance details for each connection
    x = 0
    conn.each {|connection| print get_instance_details connection, x += 1}
    
    #print pool details
    puts
    print ucppool.display_pool_details

    #return connections
    conn.each {|connection| ucppool.return_connection connection}
    
    # sleep for 20 seconds
    puts "\nSleeping for 20 seconds....\n"
    sleep 20
  end
  
rescue 
  print "\n** Error occured **\n"
 print "Failed executing FCF UCP Pool demo from JRuby ", $!, "\n"
  
end

print "\nEnded at ", Time.now , "\n"
6. Connect to one of your RAC node instances in preparation to perform a ungraceful instance crash.
[oradb1@auw2k3 ~]$ sqlplus / as sysdba

SQL*Plus: Release 11.2.0.2.0 Production on Thu Feb 3 21:27:13 2011

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


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options

SQL>

7.  Run the JRuby script "ucp_fcf_test.rb" as shown below.

This script will create a UCP Pool setup for use with FCF,  obtain 5 connections and then sleep for 20 seconds and continue the process of obtaining another 5 connections and so on until the program is ended using CNTRL-C.

> jruby ucp_fcf_test.rb
Run at Thu Feb 03 21:30:58 +1100 2011
MyOracleUcpPool [user=scott, passwd=tiger, url=jdbc:oracle:thin:@apctcsol1.au.oracle.com:1521/pas_srv, minsize=5, maxsize=20, initialsize=5]
, factoryclassname=oracle.jdbc.pool.OracleDataSource

--> Connection 1 : instance [A11], host[auw2k3], service[pas_srv]
--> Connection 2 : instance [A11], host[auw2k3], service[pas_srv]
--> Connection 3 : instance [A12], host[auw2k4], service[pas_srv]
--> Connection 4 : instance [A12], host[auw2k4], service[pas_srv]
--> Connection 5 : instance [A11], host[auw2k3], service[pas_srv]

** FCF Enabled UCP Pool Details **
NumberOfAvailableConnections: 0
BorrowedConnectionsCount: 5

Sleeping for 20 seconds....

8. Now once the program output shows it has obtained 5 connections and is currently sleeping return to your SQL*Plus session at step #6 and perform an ungraceful shutdown using "shutdown abort" as shown below.
SQL> shutdown abort;
ORACLE instance shut down. 

9. Return to the JRuby script and wait for it to wake up and verify that the node which has crashed is no longer in the list of connected instances.

Run at Thu Feb 03 21:30:58 +1100 2011
MyOracleUcpPool [user=scott, passwd=tiger, url=jdbc:oracle:thin:@apctcsol1.au.oracle.com:1521/pas_srv, minsize=5, maxsize=20, initialsize=5]
, factoryclassname=oracle.jdbc.pool.OracleDataSource

--> Connection 1 : instance [A11], host[auw2k3], service[pas_srv]
--> Connection 2 : instance [A11], host[auw2k3], service[pas_srv]
--> Connection 3 : instance [A12], host[auw2k4], service[pas_srv]
--> Connection 4 : instance [A12], host[auw2k4], service[pas_srv]
--> Connection 5 : instance [A11], host[auw2k3], service[pas_srv]

** FCF Enabled UCP Pool Details **
NumberOfAvailableConnections: 0
BorrowedConnectionsCount: 5

Sleeping for 20 seconds....

*** RAC instance on auw2k3 shutdown at this point **

--> Connection 1 : instance [A12], host[auw2k4], service[pas_srv]
--> Connection 2 : instance [A12], host[auw2k4], service[pas_srv]
--> Connection 3 : instance [A12], host[auw2k4], service[pas_srv]
--> Connection 4 : instance [A12], host[auw2k4], service[pas_srv]
--> Connection 5 : instance [A12], host[auw2k4], service[pas_srv]

** FCF Enabled UCP Pool Details **
NumberOfAvailableConnections: 0
BorrowedConnectionsCount: 5

Sleeping for 20 seconds....

10. Return to your SQL*Plus session at step #6 and start the instance back up using "startup".
SQL> startup;
ORACLE instance started.

Total System Global Area  790941696 bytes
Fixed Size                  1347084 bytes
Variable Size             587203060 bytes
Database Buffers          197132288 bytes
Redo Buffers                5259264 bytes
Database mounted.
Database opened. 
11. Verify from the running JRuby script that connections from the recently returned instance are coming up in the list as shown below.

.....


Sleeping for 20 seconds....

*** RAC instance on auw2k3 started at this point **

--> Connection 1 : instance [A12], host[auw2k4], service[pas_srv]
--> Connection 2 : instance [A11], host[auw2k3], service[pas_srv]
--> Connection 3 : instance [A11], host[auw2k3], service[pas_srv]
--> Connection 4 : instance [A11], host[auw2k3], service[pas_srv]
--> Connection 5 : instance [A12], host[auw2k4], service[pas_srv]

** FCF Enabled UCP Pool Details **
NumberOfAvailableConnections: 5
BorrowedConnectionsCount: 5

Sleeping for 20 seconds....

For more information on using SCAN with 11g R2 RAC see the white paper below.

http://www.oracle.com/technetwork/database/clustering/overview/scan-129069.pdf

Monday, 31 January 2011

JRuby Oracle RAC 11g R2 SCAN Client Demo

Previously I created a JDBC client against an 11g R2 RAC client using SCAN as shown here. That example simply ensures we are load balancing between the RAC nodes in the cluster because from the JDBC URL we would not even know we are connecting to a RAC cluster.

jdbc:oracle:thin:@apctcsol1.au.oracle.com:1521/pas_srv

In the example below we use some JRuby code to do the exact same thing. We are using the 11.2.0.2 Oracle JDBC Driver and an 11.2.0.2 RAC cluster as well.

JRuby Code
require 'java'  
require 'C:/jdev/jdcbdrivers/11.2/11202/ojdbc6.jar'  
  
java_import java.sql.Statement
java_import java.sql.Connection
java_import java.sql.SQLException
java_import java.sql.DatabaseMetaData

java_import 'oracle.jdbc.OracleDriver'
java_import 'oracle.jdbc.pool.OracleDataSource'

INSTANCE_SQL = <<EOF
select sys_context('userenv', 'instance_name'),
sys_context('userenv', 'server_host'), 
sys_context('userenv', 'service_name')
from dual
EOF

class MyOracleDataSource   
  def initialize(user, passwd, url)  
    @user, @passwd, @url = user, passwd, url
      
    @ods = OracleDataSource.new
    @ods.set_user user
    @ods.set_password passwd
    @ods.set_url url
  end  
   
  # add getters and setters for all attrributes we wish to expose  
  attr_reader :user, :passwd, :url

  def get_connection()
    @ods.get_connection
  end
  
  def create_statement()
    @connection.create_statement
  end
  
  def to_s  
    "OracleDataSource  [user=#{@user}, passwd=#{@passwd}, " +  
    "url=#{@url}]"  
  end  

  def self.create(user, passwd, url)
    ods = new(user, passwd, url)
  rescue
    puts "\n** Error occured **\n"  
    puts "Failed executing SCAN Load Blance test from JRuby ", $!, "\n"
  end
end


user = "scott"
passwd = "tiger"
url = "jdbc:oracle:thin:@apctcsol1.au.oracle.com:1521/pas_srv"

print "Run at #{Time.now} using JRuby #{RUBY_VERSION}\n\n"  

mods = MyOracleDataSource.create(user, passwd, url)

# empty array
conns = []

# obtain 5 connections
for i in 1..5 
  conns[i] = mods.get_connection
end

# determine instance details
for i in 1..5
  if (i == 1)
    meta = conns[i].get_meta_data
    puts "=============\nDatabase Product Name is ... #{meta.getDatabaseProductName()}"  
    puts "Database Product Version is  #{meta.getDatabaseProductVersion()}"  
    puts "=============\nJDBC Driver Name is ........ #{meta.getDriverName()}" 
    puts "JDBC Driver Version is ..... #{meta.getDriverVersion()}"
    puts "JDBC Driver Major Version is #{meta.getDriverMajorVersion()}"  
    puts "JDBC Driver Minor Version is #{meta.getDriverMinorVersion()}" 
    puts "============="    
  end
  
  stmt = conns[i].create_statement
  rset = stmt.execute_query INSTANCE_SQL
  rset.next
  puts "Connection #{i} : instance [#{rset.get_string 1}], " + 
       "host[#{rset.get_string 2}], service[#{rset.get_string 3}] "
  
  rset.close
  stmt.close
end

#close the 5 connections
for i in 1..5
  conns[i].close
end

print "\nEnded at #{Time.now}"

Output

C:\jdev\scripting\demos\jruby\jdbc\scan-load-balance-test>jruby scan-lbt.rb
Run at Mon Jan 31 14:28:11 +1100 2011 using JRuby 1.8.7


=============
Database Product Name is ... Oracle
Database Product Version is  Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options
=============
JDBC Driver Name is ........ Oracle JDBC driver
JDBC Driver Version is ..... 11.2.0.2.0
JDBC Driver Major Version is 11
JDBC Driver Minor Version is 2
=============
Connection 1 : instance [A12], host[auw2k4], service[pas_srv]
Connection 2 : instance [A11], host[auw2k3], service[pas_srv]
Connection 3 : instance [A12], host[auw2k4], service[pas_srv]
Connection 4 : instance [A11], host[auw2k3], service[pas_srv]
Connection 5 : instance [A12], host[auw2k4], service[pas_srv]


Ended at Mon Jan 31 14:28:12 +1100 2011

Friday, 21 January 2011

Invoking a JAX-WS Oracle Weblogic 11g (10.3.4) Web Service from JRuby

The following demo show how to call a JAX-WS from Oracle Weblogic Server 11g (10.3.4) from a JRuby script. The real work is done by JDeveloper 11g (11.1.1.4) which creates the Web Service, generates a proxy client JAR which JRuby then uses to invoke the Web Service.

So in JDeveloper we have 2 projects one for the Web Service and one for the Proxy.



The Web Service is deployed to Weblogic 10.3.4 as shown below.



1. Create a JRuby script named "jaxws11g.rb" as follows
require 'java'

# the web service client JAR file generated from JDeveloper 11g Proxy wizard
require 'SimpleWSService-Client.jar'

java_import 'pas.au.wsclient.SimpleWSPortClient'

class TestWLSWebService

  def initialize
    @wsclient = SimpleWSPortClient.new  
  end
  
  def invoke_method
    return @wsclient.invoke_method
  end
  
end


print "Run at #{Time.now} using JRuby #{RUBY_VERSION}\n\n"

print "** FMW Weblogic 10.3.4 Web Service Invoke Test **\n\n"

test = TestWLSWebService.new
print test.invoke_method

print "\n\nEnded at #{Time.now} \n"

2. The JAR file referenced below is the Web Service proxy JAR file which is generated by JDeveloper once a proxy project is created from the WSDL file for the Web Service.


# the web service client JAR file generated from JDeveloper 11g Proxy wizard
require 'SimpleWSService-Client.jar'


3. Run shown below which simply identified the Weblogic managed server name it's running in and the date it was invoked.

> jruby jaxws11g.rb


Run at Fri Jan 21 11:10:37 +1100 2011 using JRuby 1.8.7
** FMW Weblogic 10.3.4 Web Service Invoke Test **
SimpleWS invoked at Thu Jan 20 11:05:13 EST 2011 from Weblogic Managed Server named apple
Ended at Fri Jan 21 11:10:38 +1100 2011

The Web Service is a simple class as follows

package pas.au.ws;

import java.util.Date;

import javax.jws.WebService;

@WebService
public class SimpleWS 
{
  public SimpleWS() 
  {
  }
    
  public String getManagedServerName () 
  {
    String retData = 
      String.format("SimpleWS invoked at %s from Weblogic Managed Server named %s", 
                    new Date(),
                    System.getProperty("weblogic.Name"));
    
    return retData;
    
  }
}

Thursday, 13 January 2011

Retrieving DBMS_OUTPUT from PLSQL in a JRuby script

This demo shows how to get DBMS OUTPUT form PLSQL blocks and PLSQL program units using JRuby. In this example we obtain a JDBC connection which we then use to invoke a PLSQL block and get the DBMS OUTPUT back to the JRuby script.

1. Download ojdbc6.jar from the links below.

ojdbc6.jar (11.2.0.2)

2. Create a JRuby script for the JDBC connection named "jdbc_connection.rb" as follows
require 'java'
require 'C:/jdev/jdcbdrivers/11.2/ojdbc6.jar'

import 'oracle.jdbc.OracleDriver'
import 'java.sql.DriverManager'

class OracleConnection 

  @conn = nil
  
  def initialize (user, passwd, url)
    @user = user
    @passwd = passwd
    @url = url
    
    # load driver class
    oradriver = OracleDriver.new
    
    DriverManager.registerDriver(oradriver)
    @conn = DriverManager.getConnection(url,user,passwd);
    @conn.setAutoCommit(false);
    
  end
 
  #add getters and setters for all attrributes we wish to expose
  attr_reader :user, :passwd, :url
 
  def getConnection()
    return @conn
  end

  def closeConnection()
    @conn.close()
  end

  def to_s
    "OracleConnection [user=#{@user}, passwd=#{@passwd}, " +
    "url=#{@url}]"
  end
  alias_method :to_string, :to_s
  
end


- Edit the line below to indicate the PATH to the Oracle JDBC driver downloaded at step #1

require 'C:/jdev/jdcbdrivers/11.2/ojdbc6.jar'


3. Create a JRuby script for the DBMS OUTPUT class named "dbms_output.rb" as follows.
require 'java'

require 'C:/jdev/jdcbdrivers/11.2/ojdbc6.jar'

import 'java.sql.CallableStatement'
import 'java.sql.Connection'
import 'java.sql.SQLException'
import 'java.sql.Types'

class DbmsOutput

  def initialize (conn)
    @enable_stmt  = conn.getConnection.prepareCall( "begin dbms_output.enable(:1); end;" );
    @disable_stmt = conn.getConnection.prepareCall( "begin dbms_output.disable; end;" );
    
    @show_stmt = conn.getConnection.prepareCall( 
          "declare " +
          "    l_line varchar2(255); " +
          "    l_done number; " +
          "    l_buffer long; " +
          "begin " +
          "  loop " +
          "    exit when length(l_buffer)+255 > :maxbytes OR l_done = 1; " +
          "    dbms_output.get_line( l_line, l_done ); " +
          "    l_buffer := l_buffer || l_line || chr(10); " +
          "  end loop; " +
          " :done := l_done; " +
          " :buffer := l_buffer; " +
          "end;" );
  end
  
  def enable (size)
    @enable_stmt.setInt( 1, size );
    @enable_stmt.executeUpdate();
  end
  
  def disable
    @disable_stmt.executeUpdate();
  end
  
  def show
      output = ""
      done = 0;
  
      @show_stmt.registerOutParameter( 2, 4);
      @show_stmt.registerOutParameter( 3, 12 );
  
      while (done == 0)   
          @show_stmt.setInt( 1, 32000 );
          @show_stmt.executeUpdate();
          output = output , "" , @show_stmt.getString(3), "\n"
          if ( (done = @show_stmt.getInt(2)).to_i == 1 ) 
            break
          end
      end
      
      return output
  end
  
  def closeAll
    @enable_stmt.close();
    @disable_stmt.close();
    @show_stmt.close();
  end
  
end 

- Edit the line below to indicate the PATH to the Oracle JDBC driver downloaded at step #1

require 'C:/jdev/jdcbdrivers/11.2/ojdbc6.jar'


4. Create a JRuby test script named "test_dbms_output.rb" as follows
# test DBMS_OUTPUT from JRuby
#

require 'lib/jdbc_connection'
require 'lib/dbms_output'

print "Run at ", Time.now , " using JRuby ", RUBY_VERSION, "\n"
puts 

conn = nil

begin

  conn = OracleConnection.new("scott", "tiger", "jdbc:oracle:thin:@beast.au.oracle.com:1524/linux11gr2")
  puts conn
  dbms_output = DbmsOutput.new(conn)
  dbms_output.enable( 1000000 );
  
  plsql_block = 
    "begin " + 
    " for i in 1..10 loop " +
    "  dbms_output.put_line('Hello JRuby at position '||i); " + 
    " end loop; " +
    "end;"
 
  stmt = conn.getConnection.createStatement();
  stmt.execute(plsql_block);   
  
  print "** Output from PLSQL Block as follows **"
  puts dbms_output.show()
  dbms_output.closeAll()
  
rescue 
  print "\n** Error occured **\n"
 print "Failed executing Oracle JDBC DBMS_OUTPUT demo from JRuby ", $!, "\n"
  if (!conn.nil?)
    conn.closeConnection()
  end
  
end

print "\nEnded at ", Time.now , "\n"

- Edit the 2 lines above to refer to the files created at step #2 and step #3. In this example they exist of a lib directory from the current directory.

require 'lib/jdbc_connection'
require 'lib/dbms_output'

Note: Ensure you specify a connection to your database as follows

conn = OracleConnection.new("scott", "tiger", "jdbc:oracle:thin:@beast.au.oracle.com:1524/linux11gr2")

5. Run test_dbms_output.rb

Run at Thu Jan 13 07:45:21 +1100 2011 using JRuby 1.8.7

OracleConnection [user=scott, passwd=tiger, url=jdbc:oracle:thin:@beast.au.oracle.com:1524/linux11gr2]
** Output from PLSQL Block as follows **


Hello JRuby at position 1
Hello JRuby at position 2
Hello JRuby at position 3
Hello JRuby at position 4
Hello JRuby at position 5
Hello JRuby at position 6
Hello JRuby at position 7
Hello JRuby at position 8
Hello JRuby at position 9
Hello JRuby at position 10


Ended at Thu Jan 13 07:45:21 +1100 2011

Friday, 7 January 2011

JRuby example using Oracle UCP (Universal Connection Pool)

The Oracle Universal Connection Pool (UCP) for JDBC is a full-featured connection pool for managing database connections not only for Oracle but also for other non Oracle databases. The advantage with using UCP with Oracle is that UCP JDBC connection pools provide a tight integration with various Oracle Real Application Clusters (RAC) Database features . The features include Fast Connection Failover (FCF), Run-Time Connection Load Balancing, and Connection Affinity.

In this example below we show how to use UCP with an Oracle Database from a JRuby client BUT just a single instance database rather then RAC back end.

Note: We are using the HR schema for this demo

1. Download ucp.jar and ojdbc6.jar from the links below.

ojdbc6.jar (11.2.0.2)
ucp.jar (11.2.0.1)

2. Create a pool class as follows in a JRuby script called "ucppool.rb" in a directory called "lib". Client would then create an instance of this pool class and use it to retrieve / return connections from it.

require 'java'
require 'C:/jdev/jdcbdrivers/11.2/ojdbc6.jar'
require 'C:/jdev/jdcbdrivers/11.2/ucp/ucp.jar'

import 'oracle.ucp.jdbc.PoolDataSource'
import 'oracle.ucp.jdbc.PoolDataSourceFactory'

API_VERSION = 1.0

class MyOracleUcpPool

  #pool data source object
  @pds
  
  def initialize(user, passwd, url, minsize=0, maxsize=10, initialsize=2)
    @user = user
    @passwd = passwd
    @url = url
    @minsize = minsize
    @maxsize = maxsize
    @initialsize = initialsize
    
    #create pool for use here
    @pds = PoolDataSourceFactory.getPoolDataSource()
    @pds.setUser(user)
    @pds.setPassword(passwd)
    @pds.setURL(url)
    @pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource")
    @pds.setConnectionPoolName("ruby-ucppool")
    @pds.setInitialPoolSize(initialsize)
    @pds.setMinPoolSize(minsize)
    @pds.setMaxPoolSize(maxsize)
    
  end
  
  #add getters and setters for all attrributes
  attr_reader :user, :passwd, :url, :minsize, :maxsize, :initialsize
  
  def getConnection()
    return @pds.getConnection()
  end
  
  def returnConnection(conn)
    conn.close()
  end
  
  def displayPoolDetails()
    return "\n** UCP Pool Details **\n" + 
            "NumberOfAvailableConnections: ", @pds.getAvailableConnectionsCount(), "\n" +
            "BorrowedConnectionsCount: ", @pds.getBorrowedConnectionsCount(), " \n";
  end
  
  def to_s
    "MyOracleUcpPool [user=#{@user}, passwd=#{@passwd}, " +
    "url=#{@url}, minsize=#{@minsize}, maxsize=#{@maxsize}, " +
    "initialsize=#{@initialsize}]"
  end
  alias_method :to_string, :to_s
  
 end

- Edit the 2 lines below to indicate the PATH to the 2 JAR files downloaded at step #1


require 'C:/jdev/jdcbdrivers/11.2/ojdbc6.jar'
require 'C:/jdev/jdcbdrivers/11.2/ucp/ucp.jar'


3. In your current directory create a test client to verify the UCP called "testucp.rb" as follows to test your UCP Pool.

require 'lib/ucppool'

print "Run at ", Time.now , "\n"

conn = nil
ucppool = nil

begin

  ucppool = MyOracleUcpPool.new("hr", "hr", "jdbc:oracle:thin:@beast.au.oracle.com:1524/linux11gr2", 0, 5, 2)
  print ucppool , "\n"

  #get connection from pool
  conn = ucppool.getConnection()

  #print pool details
  print ucppool.displayPoolDetails()
  puts

  #execute query
  stmt = conn.createStatement()
  rset = stmt.executeQuery("select * from departments")
  while rset.next()
    print "DepartmentId=", rset.getInt(1), 
          ", DepartmentName=" + rset.getString(2), "\n"
  end

  rset.close()
  stmt.close()

  #return connection
  ucppool.returnConnection(conn)
  print "\nConnection returned to pool\n"

  #print pool details
  print ucppool.displayPoolDetails()

rescue 
  print "\n** Error occured **\n"
 print "Failed executing UCP Pool demo from JRuby ", $!, "\n"
  if (!conn.nil?)
    if (!ucppool.nil?)
      ucppool.returnConnection(conn)  
      print "\nConnection returned to pool\n"
    end
  end
  
end

print "\nEnded at ", Time.now , "\n"

4. Your file system would look as follows
C:\jdev\scripting\demos\jruby\jdbc\ucp>dir
 Volume in drive C is OS
 Volume Serial Number is 7C37-0C64

 Directory of C:\jdev\scripting\demos\jruby\jdbc\ucp

06/01/2011  10:21 PM    <DIR>          .
06/01/2011  10:21 PM    <DIR>          ..
06/01/2011  10:30 PM    <DIR>          lib
07/01/2011  08:47 AM             1,112 testucp.rb
               1 File(s)          1,112 bytes
               3 Dir(s)  248,428,380,160 bytes free

5. Edit the following line of code to ensure you provide the correct connect details for your database.

ucppool = MyOracleUcpPool.new("hr", "hr", "jdbc:oracle:thin:@beast.au.oracle.com:1524/linux11gr2", 0, 5, 2)

6. Run the test client using jruby testucp.rb. In this example we do the following.

  • create a UCP Pool
  • obtain a JDBC Connection from the Pool
  • Query a table
  • Return the JDBC connection to the pool


OUTPUT

Run at Fri Jan 07 09:25:16 +1100 2011
MyOracleUcpPool [user=hr, passwd=hr, url=jdbc:oracle:thin:@beast.au.oracle.com:1524/linux11gr2, minsize=0, maxsize=5, initialsize=2]


** UCP Pool Details **
NumberOfAvailableConnections: 1
BorrowedConnectionsCount: 1


DepartmentId=10, DepartmentName=Administration
DepartmentId=20, DepartmentName=Marketing
DepartmentId=30, DepartmentName=Purchasing
DepartmentId=40, DepartmentName=Human Resources
DepartmentId=50, DepartmentName=Shipping
DepartmentId=60, DepartmentName=IT
DepartmentId=70, DepartmentName=Public Relations
DepartmentId=80, DepartmentName=Sales
DepartmentId=90, DepartmentName=Executive
DepartmentId=100, DepartmentName=Finance
DepartmentId=110, DepartmentName=Accounting
DepartmentId=120, DepartmentName=Treasury
DepartmentId=130, DepartmentName=Corporate Tax
DepartmentId=140, DepartmentName=Control And Credit
DepartmentId=150, DepartmentName=Shareholder Services
DepartmentId=160, DepartmentName=Benefits
DepartmentId=170, DepartmentName=Manufacturing
DepartmentId=180, DepartmentName=Construction
DepartmentId=190, DepartmentName=Contracting
DepartmentId=200, DepartmentName=Operations
DepartmentId=210, DepartmentName=IT Support
DepartmentId=220, DepartmentName=NOC
DepartmentId=230, DepartmentName=IT Helpdesk
DepartmentId=240, DepartmentName=Government Sales
DepartmentId=250, DepartmentName=Retail Sales
DepartmentId=260, DepartmentName=Recruiting
DepartmentId=270, DepartmentName=Payroll


Connection returned to pool


** UCP Pool Details **
NumberOfAvailableConnections: 2
BorrowedConnectionsCount: 0


Ended at Fri Jan 07 09:25:16 +1100 2011


More Information

Oracle Universal Connection Pool for JDBC Developer's Guide
11g Release 2 (11.2)
http://download.oracle.com/docs/cd/E11882_01/java.112/e12265/toc.htm

Monday, 20 December 2010

Querying Coherence Cache from JRuby

To complete the Coherence/JRuby demos this final demo shows how we can query the cache using filters to show the data we are interested in. From this demo you can see our cache has the oracle data dictionary view ALL_DB_OBJECTS data which was loaded from an 11.2.0.2 RDBMS. The output will make that obvious.

JRuby script is as follows - coh-extend-client-query.rb
require 'java'
require 'C:/jdev/scripting/demos/jruby/extendclient-coherence/extenddemo.jar'
require 'C:/jdev/coherence/36/coherence/lib/coherence.jar'

include_class "pas.au.coherence.extend.server.AllDBObject"
import com.tangosol.net.CacheFactory
import com.tangosol.net.NamedCache
import java.util.Date
import java.lang.System
import java.math.BigDecimal
import java.util.Set

puts "***********************************************"
puts "Coherence 3.6 Extend Client Example from JRUBY"
puts "***********************************************"

print "Started at ", Date.new.toString, "\n"

begin

  # setup required properties to connect to proxy server as extend client
  System.setProperty("tangosol.pof.enabled", "true")
  System.setProperty("tangosol.pof.config", "extend-pof-config.xml")
  System.setProperty("tangosol.coherence.cacheconfig", "client-cache-config.xml")
  System.setProperty("proxy.host", "papicell-au2.au.oracle.com")

  # get named cache alldbobjs
  alldbobjs = CacheFactory.getCache("alldbobjs")

  #retrieve size of cache
  print "\nCache [alldbobjs] size  = " + alldbobjs.size().to_s + "\n\n"
  
  #retrieve all SCOTT schema entries
  filter = com.tangosol.util.filter.EqualsFilter.new("getOwner", "SCOTT")
  scottObjects = alldbobjs.entrySet(filter)
  
  #iterate through SCOTT's objects 
  print "\nTotal of " + scottObjects.size().to_s + " cache entries found \n"

  print "Is scottObjects empty : ", scottObjects.empty?, "\n"
  puts
  
  iterator = scottObjects.iterator()
  while iterator.hasNext()
    entry = iterator.next()
    print "Key : [" + entry.getKey().to_s + "] "
    print "Value : [Owner=" + entry.getValue().getOwner() + 
          ", objectName=" + entry.getValue().getObjectName() +
          ", objectType=" + entry.getValue().getObjectType() + "]"
    puts
  end
  
rescue 
  print "\n** Error occured **\n"
 print "Failed to access Coherence Cluster from proxy server -> \n", $!, "\n\n"
  
end

puts
print "Ended at ", Date.new.toString, "\n"

The output when run shows the SCOTT schema objects being queried from the cache


C:\jdev\scripting\demos\jruby\extendclient-coherence>vi coh-extend-client-query.rb


C:\jdev\scripting\demos\jruby\extendclient-coherence>jrb coh-extend-client-query.rb
***********************************************
Coherence 3.6 Extend Client Example from JRUBY
***********************************************
Started at Mon Dec 20 07:36:52 EST 2010
2010-12-20 07:36:52.752/0.869 Oracle Coherence 3.6.0.0 (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:
/jdev/coherence/36/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2010-12-20 07:36:52.756/0.873 Oracle Coherence 3.6.0.0 (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/jde
v/coherence/36/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2010-12-20 07:36:52.756/0.873 Oracle Coherence 3.6.0.0 (thread=main, member=n/a): Optional configuration override "/tangosol-coherence-
override.xml" is not specified
2010-12-20 07:36:52.759/0.876 Oracle Coherence 3.6.0.0 (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml"
is not specified


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


2010-12-20 07:36:52.945/1.062 Oracle Coherence GE 3.6.0.0 (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/jd
ev/scripting/demos/jruby/extendclient-coherence/extenddemo.jar!/client-cache-config.xml"
2010-12-20 07:36:53.107/1.224 Oracle Coherence GE 3.6.0.0 (thread=RemoteCache:TcpInitiator, member=n/a): Loaded POF configuration fro
m "jar:file:/C:/jdev/scripting/demos/jruby/extendclient-coherence/extenddemo.jar!/extend-pof-config.xml"
2010-12-20 07:36:53.111/1.228 Oracle Coherence GE 3.6.0.0 (thread=RemoteCache:TcpInitiator, member=n/a): Loaded included POF configur
ation from "jar:file:/C:/jdev/coherence/36/coherence/lib/coherence.jar!/coherence-pof-config.xml"
2010-12-20 07:36:53.214/1.331 Oracle Coherence GE 3.6.0.0 (thread=RemoteCache:TcpInitiator, member=n/a): Started: TcpInitiator{Name=Rem
oteCache:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), PingInterval=0, PingTimeout=0, RequestTimeout=0, Con
nectTimeout=0, SocketProvider=SystemSocketProvider, RemoteAddresses=[papicell-au2.au.oracle.com/10.187.80.136:9099]}
2010-12-20 07:36:53.218/1.335 Oracle Coherence GE 3.6.0.0 (thread=main, member=n/a): Opening Socket connection to 10.187.80.136:9099
2010-12-20 07:36:53.220/1.337 Oracle Coherence GE 3.6.0.0 (thread=main, member=n/a): Connected to 10.187.80.136:9099


Cache [alldbobjs] size  = 99927




Total of 55 cache entries found
Is scottObjects empty : false


Key : [82967] Value : [Owner=SCOTT, objectName=TEST_STRING, objectType=TABLE]
Key : [126758] Value : [Owner=SCOTT, objectName=Host2, objectType=JAVA CLASS]
Key : [128400] Value : [Owner=SCOTT, objectName=DISPLAYPROPERTIES, objectType=FUNCTION]
Key : [173453] Value : [Owner=SCOTT, objectName=SYS_LOB0000173452C00002$$, objectType=LOB]
Key : [128399] Value : [Owner=SCOTT, objectName=CheckProperties, objectType=JAVA CLASS]
Key : [85457] Value : [Owner=SCOTT, objectName=JUNKPR, objectType=PROCEDURE]
Key : [150089] Value : [Owner=SCOTT, objectName=HELLOWORLDPKG, objectType=PACKAGE]
Key : [155471] Value : [Owner=SCOTT, objectName=CELCIUSTOFAHRENHEIT, objectType=FUNCTION]
Key : [91848] Value : [Owner=SCOTT, objectName=SYS_C0019928, objectType=INDEX]
Key : [82964] Value : [Owner=SCOTT, objectName=TEST_TYP, objectType=TYPE]
Key : [150088] Value : [Owner=SCOTT, objectName=pas/au/jsp/DemoJSP, objectType=JAVA CLASS]
Key : [82966] Value : [Owner=SCOTT, objectName=TEST_PROC1, objectType=PROCEDURE]
Key : [91846] Value : [Owner=SCOTT, objectName=SYS_LOB0000091845C00002$$, objectType=LOB]
Key : [73200] Value : [Owner=SCOTT, objectName=PK_DEPT, objectType=INDEX]
Key : [91849] Value : [Owner=SCOTT, objectName=xp_cmdshell, objectType=JAVA CLASS]
Key : [91855] Value : [Owner=SCOTT, objectName=xp_cmdshell, objectType=JAVA SOURCE]
Key : [126760] Value : [Owner=SCOTT, objectName=HOST_API, objectType=PACKAGE BODY]
Key : [173456] Value : [Owner=SCOTT, objectName=FORMMODEL_INS_TRG, objectType=TRIGGER]
Key : [73199] Value : [Owner=SCOTT, objectName=DEPT, objectType=TABLE]
Key : [155571] Value : [Owner=SCOTT, objectName=SAYHELLONAME, objectType=FUNCTION]
Key : [169925] Value : [Owner=SCOTT, objectName=DEPT_LIST_TABLE, objectType=TYPE]
Key : [173144] Value : [Owner=SCOTT, objectName=CUSTOMER, objectType=TABLE]
Key : [91850] Value : [Owner=SCOTT, objectName=DOIT, objectType=PROCEDURE]
Key : [160445] Value : [Owner=SCOTT, objectName=runhttprequest, objectType=JAVA SOURCE]
Key : [169926] Value : [Owner=SCOTT, objectName=WS_PACKAGE, objectType=PACKAGE]
Key : [73204] Value : [Owner=SCOTT, objectName=SALGRADE, objectType=TABLE]
Key : [160648] Value : [Owner=SCOTT, objectName=SYS_C0046421, objectType=INDEX]
Key : [140715] Value : [Owner=SCOTT, objectName=DRIVERVERSION, objectType=PROCEDURE]
Key : [160446] Value : [Owner=SCOTT, objectName=RunHttpRequest, objectType=JAVA CLASS]
Key : [173455] Value : [Owner=SCOTT, objectName=FORMMODEL_PK, objectType=INDEX]
Key : [73202] Value : [Owner=SCOTT, objectName=PK_EMP, objectType=INDEX]
Key : [169927] Value : [Owner=SCOTT, objectName=WS_PACKAGE, objectType=PACKAGE BODY]
Key : [173452] Value : [Owner=SCOTT, objectName=FORMMODEL, objectType=TABLE]
Key : [79037] Value : [Owner=SCOTT, objectName=XML_PACKAGE, objectType=PACKAGE]
Key : [91845] Value : [Owner=SCOTT, objectName=CREATE$JAVA$LOB$TABLE, objectType=TABLE]
Key : [160890] Value : [Owner=SCOTT, objectName=MYTEST3, objectType=TABLE]
Key : [160647] Value : [Owner=SCOTT, objectName=CAL, objectType=TABLE]
Key : [155581] Value : [Owner=SCOTT, objectName=SAYHELLONAME_SYS, objectType=FUNCTION]
Key : [79038] Value : [Owner=SCOTT, objectName=XML_PACKAGE, objectType=PACKAGE BODY]
Key : [169924] Value : [Owner=SCOTT, objectName=DEPT_TYPE, objectType=TYPE]
Key : [85455] Value : [Owner=SCOTT, objectName=Junk, objectType=JAVA SOURCE]
Key : [155472] Value : [Owner=SCOTT, objectName=CELCIUSTOFAHRENHEIT1, objectType=FUNCTION]
Key : [155473] Value : [Owner=SCOTT, objectName=CELCIUSTOFAHRENHEIT2, objectType=FUNCTION]
Key : [173457] Value : [Owner=SCOTT, objectName=FORMMODEL_UPD_TRG, objectType=TRIGGER]
Key : [180988] Value : [Owner=SCOTT, objectName=ALL_DB_OBJECTS, objectType=TABLE]
Key : [160447] Value : [Owner=SCOTT, objectName=FN_RUN_HTTP_REQUEST, objectType=FUNCTION]
Key : [150090] Value : [Owner=SCOTT, objectName=HELLOWORLDPKG, objectType=PACKAGE BODY]
Key : [91851] Value : [Owner=SCOTT, objectName=JAVA$OPTIONS, objectType=TABLE]
Key : [173458] Value : [Owner=SCOTT, objectName=FORMMODEL_ID_SEQ, objectType=SEQUENCE]
Key : [85456] Value : [Owner=SCOTT, objectName=Junk, objectType=JAVA CLASS]
Key : [162619] Value : [Owner=SCOTT, objectName=TMP_JD_TEST, objectType=TABLE]
Key : [126759] Value : [Owner=SCOTT, objectName=HOST_API, objectType=PACKAGE]
Key : [73201] Value : [Owner=SCOTT, objectName=EMP, objectType=TABLE]
Key : [73203] Value : [Owner=SCOTT, objectName=BONUS, objectType=TABLE]
Key : [126757] Value : [Owner=SCOTT, objectName=HOST2, objectType=JAVA SOURCE]


Ended at Mon Dec 20 07:36:54 EST 2010

Thursday, 16 December 2010

Access Coherence Cache from JRuby as an Extend client

In my previous example below I wanted to quickly join a coherence cluster from JRuby and basically did it the easiest way possible by simply becoming a member in the cluster.

Access Coherence Cache from JRuby/Jython scripts

In the example below we will we use JRuby as a Coherence*Extend client using POF (Portable Object Format) and we do this for the following reasons.

1. Being a console application we want to connect/disconnect many times a day and even though we are a storage disabled member it results in overhead which an extend client avoids.
2. Being an extend client we are storage disabled by default.
3. Using POF has many advantages ranging from performance benefits to language independence, although in this example we are using it from a Java enabled client.

So our JRuby code is now as follows.
require 'java'
require 'C:/jdev/scripting/demos/jruby/extendclient-coherence/extenddemo.jar'
require 'C:/jdev/coherence/36/coherence/lib/coherence.jar'

include_class "pas.au.coherence.extend.server.AllDBObject"
import com.tangosol.net.CacheFactory
import com.tangosol.net.NamedCache
import java.util.Date
import java.lang.System
import java.math.BigDecimal

puts "***********************************************"
puts "Coherence 3.6 Extend Client Example from JRUBY"
puts "***********************************************"

print "Started at ", Date.new.toString, "\n"

begin

  # setup required properties to connect to proxy server as extend client
  System.setProperty("tangosol.coherence.cacheconfig", "client-cache-config.xml")
  System.setProperty("tangosol.pof.enabled", "true")
  System.setProperty("tangosol.pof.config", "extend-pof-config.xml")
  System.setProperty("proxy.host", "papicell-au2.au.oracle.com")

  # get named cache alldbobjs
  alldbobjs = CacheFactory.getCache("alldbobjs")

  #retrieve size of cache
  print "\nCache [alldbobjs] size  = " + alldbobjs.size().to_s + "\n\n"

  #retrieve one record
  objectid = BigDecimal.new(54)

  objectrecord = AllDBObject.new
  objectrecord = alldbobjs.get(objectid)

  puts "Record 54 = " + objectrecord.to_s
  puts

rescue
  print "\n** Error occured **\n"
        print "Failed to access Coherence Cluster from proxy server ", $!, "\n\n"

end

print "Ended at ", Date.new.toString, "\n"
From the code we have done the following.

1. Used a client cache config file to connect as an extend client, basically connect to an extend proxy which is a cluster member.

2. We provide a client JAR file which contains our domain objects and config files that being extenddemo.jar

3. The client cache config is defined as follows.
<!DOCTYPE cache-config SYSTEM "cache-config.dtd">

<cache-config>
  <caching-scheme-mapping>
    <cache-mapping>
      <cache-name>alldbobjs</cache-name>
      <scheme-name>remote</scheme-name>
    </cache-mapping>
  </caching-scheme-mapping>
  <caching-schemes>
    <remote-cache-scheme>
      <scheme-name>remote</scheme-name>
      <initiator-config>
        <tcp-initiator>
          <remote-addresses>
            <socket-address>
              <address system-property="proxy.host">
  papicell-au2.au.oracle.com
       </address>
              <port system-property="proxy.port">
                9099
              </port>
              <reusable>true</reusable>
            </socket-address>
          </remote-addresses>
        </tcp-initiator>
      </initiator-config>
    </remote-cache-scheme>
  </caching-schemes>
</cache-config>

So when we run this we get output as follows.

C:\jdev\scripting\demos\jruby\extendclient-coherence>jrb coh-extend-client.rb
***********************************************
Coherence 3.6 Extend Client Example from JRUBY
***********************************************
Started at Thu Dec 16 14:08:06 EST 2010
2010-12-16 14:08:06.114/1.033 Oracle Coherence 3.6.0.0 (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:
/jdev/coherence/36/coherence/lib/coherence.jar!/tangosol-coherence.xml"
2010-12-16 14:08:06.118/1.037 Oracle Coherence 3.6.0.0 (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/jde
v/coherence/36/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
2010-12-16 14:08:06.118/1.037 Oracle Coherence 3.6.0.0 (thread=main, member=n/a): Optional configuration override "/tangosol-coherence-
override.xml" is not specified
2010-12-16 14:08:06.121/1.040 Oracle Coherence 3.6.0.0 (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml"
is not specified


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


2010-12-16 14:08:06.304/1.223 Oracle Coherence GE 3.6.0.0 (thread=main, member=n/a): Loaded cache configuration from "jar:file:/C:/jd
ev/scripting/demos/jruby/extendclient-coherence/extenddemo.jar!/client-cache-config.xml"
2010-12-16 14:08:06.472/1.391 Oracle Coherence GE 3.6.0.0 (thread=RemoteCache:TcpInitiator, member=n/a): Loaded POF configuration fro
m "jar:file:/C:/jdev/scripting/demos/jruby/extendclient-coherence/extenddemo.jar!/extend-pof-config.xml"
2010-12-16 14:08:06.475/1.394 Oracle Coherence GE 3.6.0.0 (thread=RemoteCache:TcpInitiator, member=n/a): Loaded included POF configur
ation from "jar:file:/C:/jdev/coherence/36/coherence/lib/coherence.jar!/coherence-pof-config.xml"
2010-12-16 14:08:06.567/1.486 Oracle Coherence GE 3.6.0.0 (thread=RemoteCache:TcpInitiator, member=n/a): Started: TcpInitiator{Name=Rem
oteCache:TcpInitiator, State=(SERVICE_STARTED), ThreadCount=0, Codec=Codec(Format=POF), PingInterval=0, PingTimeout=0, RequestTimeout=0, Con
nectTimeout=0, SocketProvider=SystemSocketProvider, RemoteAddresses=[papicell-au2.au.oracle.com/10.187.80.136:9099]}
2010-12-16 14:08:06.572/1.491 Oracle Coherence GE 3.6.0.0 (thread=main, member=n/a): Opening Socket connection to 10.187.80.136:9099
2010-12-16 14:08:06.580/1.499 Oracle Coherence GE 3.6.0.0 (thread=main, member=n/a): Connected to 10.187.80.136:9099


Cache [alldbobjs] size  = 99927


Record 54 = AllDbObject - owner: SYS ,objectName: I_CDEF2 ,subObjectName: null ,objectId: 54 ,dataObjectId: 54 ,objectType: INDEX ,created:
2009-08-15 ,lastDDLTime: 2009-08-15 ,timestamp: 2009-08-15:00:16:51 ,status: VALID ,temporrary: N ,generated: N ,secondary: N ,namespace: 4
,editionName: null


Ended at Thu Dec 16 14:08:06 EST 2010