Automating creation of JDBC Data Sources and DbAdapter plan updates and redeployment

That’s a long title… anyway, as part of the desire to have a fully automated continuous integration environment for SOA and BPM, there is another bridge that we need to cross.

SOA/BPM Composites can contain dependencies on resources in the runtime environment, like JDBC Data Sources and JMS Queues for example.  This poses a challenge for us, as we need to ensure that these resources exist, are properly configured, and are available before we attempt to run our SCA Tests in our composite.

So this means we need a way to automate the creation of these resources, so that we can do this as part of our build process.

This post presents a first step in that direction – a WLST script that can automate the process for JDBC.  I say ‘first step’ for a couple of reasons:

  • It only handles JDBC, nothing else yet,
  • It is a bit delicate – I am not really happy with the error handling (which is almost non-existent, but you have to excuse me on that point, this is my very first Python program ever), and
  • I have not made it handle parameters yet, or integrated it into Maven, although this should just be ‘a small matter of programming’ as the saying goes.

It also implements a restart of the managed server, and I am not 100% sure we actually need to do that.

Anyway, here it is in all its glory – also available from Subversion on java.net (may be newer):

# Copyright 2012 Oracle Corporation.
# All Rights Reserved.
#
# Provided on an 'as is' basis, without warranties or conditions of any kind,
# either express or implied, including, without limitation, any warranties or
# conditions of title, non-infringement, merchantability, or fitness for a
# particular purpose. You are solely responsible for determining the
# appropriateness of using and assume any risks. You may not redistribute.
#
# Please refer to https://redstack.wordpress.com/continous-integration for details.
#
# This WLST script can be used as part of a continuous integration build process
# before deploying a SCA composite, to create any necessary Java EE data sources
# on the WebLogic Server.
#
# In addition to creating the data source, this script will also update the
# resource adapter and redeploy it.
#
# Parts of this script were adapted from Richard van den Berg's post at
# https://forums.oracle.com/forums/message.jspa?messageID=10131949#10131949

import time

#
# These are the parameters that you need to edit before running this script
#

# admin server url
url                  = 't3://localhost:7001'
# username to connect to the admin server
username             = 'weblogic'
# password to connect to the admin server
password             = 'welcome1'
# the name for the EIS - as defined in the DB Adapter wizard in JDEV
eisName              = 'eis/db/myDS'
# the admin or managed server to target where the DbAdapter is deployed
serverName           = 'soa_server1'
nmServerName         = 'soa_server1'
# the name for the data source
dsName               = 'myDS'
# the JNDI name for the data source
jndiName             = 'jbdc/myDS'
# the database url for the data source
dbUrl                = 'jdbc:oracle:thin:@localhost:1521:orcl'
# the database user
dbUser               = 'mark'
# the database password
dbPassword           = 'welcome1'
# the database driver to use
dbDriver             = 'oracle.jdbc.xa.client.OracleXADataSource'
# the host where node manager is running
nmHost               = 'localhost'
# the port to connect to node manager (5556 is default for plain mode)
nmPort               = '5556'
# the user to connect to node manager
nmUser               = 'weblogic'
# the password to connection to node manager
nmPassword           = 'welcome1'
# the name of the weblogic domain
domain               = 'base_domain'

# don't change these ones
uniqueString         = ''
appName              = 'DbAdapter'
moduleOverrideName   = appName+'.rar'
moduleDescriptorName = 'META-INF/weblogic-ra.xml'

#
# method definitions
#

def makeDeploymentPlanVariable(wlstPlan, name, value, xpath, origin='planbased'):
  """Create a varaible in the Plan.
  This method is used to create the variables that are needed in the Plan in order
  to add an entry for the outbound connection pool for the new data source.
  """

  try:
    variableAssignment = wlstPlan.createVariableAssignment(name, moduleOverrideName, moduleDescriptorName)
    variableAssignment.setXpath(xpath)
    variableAssignment.setOrigin(origin)
    wlstPlan.createVariable(name, value)

  except:
    print('--> was not able to create deployment plan variables successfully')

def main():

  print ' Copyright 2012 Oracle Corporation. '
  print ' All Rights Reserved. '
  print ''
  print ' Provided on an ''as is'' basis, without warranties or conditions of any kind, '
  print ' either express or implied, including, without limitation, any warranties or '
  print ' conditions of title, non-infringement, merchantability, or fitness for a '
  print ' particular purpose. You are solely responsible for determining the '
  print ' appropriateness of using and assume any risks. You may not redistribute.'
  print ''
  print ' Please refer to https://redstack.wordpress.com/continous-integration for details.'
  print ''
  print ' This WLST script can be used as part of a continuous integration build process'
  print ' before deploying a SCA composite, to create any necessary Java EE data sources'
  print ' on the WebLogic Server.'
  print ''
  print ' In addition to creating the data source, this script will also update the '
  print ' resource adapter and redeploy it.'
  print ''
  print ' !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!!'
  print ''
  print ' This script will make changes to your WebLogic domain.  Make sure you know '
  print ' what you are doing.  There is no support for this script.  If something bad '
  print ' happens, you are on your own!  You have been warned.'

  #
  # generate a unique string to use in the names
  #

  uniqueString = str(int(time.time()))

  #
  # Create a JDBC Data Source.
  #

  try:
    print('--> about to connect to weblogic')
    connect(username, password, url)
    print('--> about to create a data source ' + dsName)
    edit()
    startEdit()
    cmo.createJDBCSystemResource(dsName)
    cd('/JDBCSystemResources/' + dsName + '/JDBCResource/' + dsName)
    cmo.setName(dsName)
    cd('/JDBCSystemResources/' + dsName + '/JDBCResource/' + dsName + '/JDBCDataSourceParams/' + dsName)
    set('JNDINames',jarray.array([String(jndiName)], String))
    cd('/JDBCSystemResources/' + dsName + '/JDBCResource/' + dsName + '/JDBCDriverParams/' + dsName)
    cmo.setUrl(dbUrl)
    cmo.setDriverName(dbDriver)
    cmo.setPassword(dbPassword)
    cd('/JDBCSystemResources/' + dsName + '/JDBCResource/' + dsName + '/JDBCConnectionPoolParams/' + dsName)
    cmo.setTestTableName('DUAL')
    cd('/JDBCSystemResources/' + dsName + '/JDBCResource/' + dsName + '/JDBCDriverParams/' + dsName + '/Properties/' + dsName)
    cmo.createProperty('user')
    cd('/JDBCSystemResources/' + dsName + '/JDBCResource/' + dsName + '/JDBCDriverParams/' + dsName + '/Properties/' + dsName + '/Properties/user')
    cmo.setValue(dbUser)
    cd('/JDBCSystemResources/' + dsName + '/JDBCResource/' + dsName + '/JDBCDataSourceParams/' + dsName)
    cmo.setGlobalTransactionsProtocol('TwoPhaseCommit')
    cd('/JDBCSystemResources/' + dsName)
    set('Targets',jarray.array([ObjectName('com.bea:Name=' + serverName + ',Type=Server')], ObjectName))
    save()
    print('--> activating changes')
    activate()
    print('--> done')

#
# update the deployment plan
#
    print('--> about to update the deployment plan for the DbAdapter')
    startEdit()
    planPath = get('/AppDeployments/DbAdapter/PlanPath')
    appPath = get('/AppDeployments/DbAdapter/SourcePath')
    print('--> Using plan ' + planPath)
    plan = loadApplication(appPath, planPath)
    print('--> adding variables to plan')
    makeDeploymentPlanVariable(plan, 'ConnectionInstance_eis/DB/' + dsName + '_JNDIName_' + uniqueString, eisName, '/weblogic-connector/outbound-resource-adapter/connection-definition-group/[connection-factory-interface="javax.resource.cci.ConnectionFactory"]/connection-instance/[jndi-name="' + eisName + '"]/jndi-name')
    makeDeploymentPlanVariable(plan, 'ConfigProperty_xADataSourceName_Value_' + uniqueString, eisName, '/weblogic-connector/outbound-resource-adapter/connection-definition-group/[connection-factory-interface="javax.resource.cci.ConnectionFactory"]/connection-instance/[jndi-name="' + eisName + '"]/connection-properties/properties/property/[name="xADataSourceName"]/value')
    print('--> saving plan')
    plan.save();
    save();
    print('--> activating changes')
    activate(block='true');
    cd('/AppDeployments/DbAdapter/Targets');
    print('--> redeploying the DbAdapter')
    redeploy(appName, planPath, targets=cmo.getTargets());
    print('--> done')

  except:
    print('--> something went wrong, bailing out')
    stopEdit('y')
    raise SystemExit

  #
  # disconnect from the admin server
  #

  print('--> disconnecting from admin server now')
  disconnect()

  #
  # Restart the managed server using the node manager.
  #

  try:
    print('--> about to restart server ' + nmServerName)
    nmConnect(nmUser, nmPassword, nmHost, nmPort, domain)
    print('--> stopping server...')
    nmKill(nmServerName)
    print('--> starting server')
    nmStart(nmServerName)
    print('--> done')
    nmDisconnect()

  except:
    print('--> was not able to restart server successfully')

#
#  this is the main entry point
#

main()

To use this script, you need to go edit those parameters at the top of the program, save it somewhere, e.g. createDS.py, and then run it with WLST, for example:

cd /your/fmwhome/wlserver_10.3/common/bin/
wlst.sh /path/to/createDS.py

Please let me know if you have any success, or comments, I would love to hear them.

I must also acknowledge the following folks from whom I borrowed code and ideas: Richard van den Berg and Michel Schildmeijer and in turn those who they borrowed from, and so on.

About Mark Nelson

Mark Nelson is an Architect (an "IC6") in the Fusion Middleware Central Development Team at Oracle. Mark's job is to make Fusion Middleware easy to use in the cloud and at home, for developers and operations folks, with special focus on continuous delivery, configuration management and provisioning - making it simple to manage the configuration of complex environments and applications built with Oracle Database, Fusion Middleware and Fusion Applications, on-premise and in the cloud. Before joining this team, Mark was a senior member of the A-Team since 2010, and worked in Sales Consulting at Oracle since 2006 and various roles at IBM since 1994.
This entry was posted in Uncategorized and tagged , , , , , . Bookmark the permalink.

3 Responses to Automating creation of JDBC Data Sources and DbAdapter plan updates and redeployment

  1. Pingback: Automating creation of JMS Queues and JmsAdapter plan updates and redeployment | RedStack

  2. HI Mark – Your this post really saved a lot of my time. Thank you for that. Yesterday, I sat with the code and then thought that it will be nice to have three info on this page.

    1. This code will not work remotely. The following line doesn’t work remotely. It needs to be on server box.
    plan = loadApplication(appPath, planPath)

    2. Restart is not required, and code it not restarting as well due to some reason.

    3. Line no 164, there is a bug. We need to pass jndi name instead.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s