April 9, 2009

Using WLST with the WebLogic Server Job Scheduler

I recently wrote about a simple example using the WebLogic Server Job Scheduler.  This describes how to cancel the jobs and get visibility into job execution status.

jmx [2]

Cancelling a task

One of the things to note about the JobScheduler is that you cannot call certain CommonJ API calls, particularly around cancelling tasks.  The way to do that is via the JobSchedulerRuntimeMBean, exposed with console functionality or via JMX.  Obviously the console is great for on-demand access, but what if you want to script things to make automated decisions?

Here is some sample output from a WLST session that shows me browsing to the JobSchedulerRuntimeMBean, finding an active task and cancelling it.

wls:/offline> connect('weblogic','weblogic','t3://localhost:7011')
Connecting to t3://localhost:7011 with userid weblogic ...
Successfully connected to managed Server 'managedServer1' that belongs to domain 'wldf_domain'.
Warning: An insecure protocol was used to connect to the
server. To ensure on-the-wire security, the SSL port or
Admin port should be used instead.
wls:/wldf_domain/serverConfig> domainRuntime()
DomainRuntime MBeanServer is not enabled on a Managed Server.
wls:/wldf_domain/serverConfig> ls()
dr--   AdminConsole
dr--   AppDeployments
dr--   BridgeDestinations
dr--   Clusters
dr--   CustomResources
dr--   DeploymentConfiguration
dr--   Deployments
dr--   EmbeddedLDAP
dr--   ErrorHandlings
dr--   FileStores
dr--   InternalAppDeployments
dr--   InternalLibraries
dr--   JDBCDataSourceFactories
dr--   JDBCStores
dr--   JDBCSystemResources
dr--   JMSBridgeDestinations
dr--   JMSInteropModules
dr--   JMSServers
dr--   JMSSystemResources
dr--   JMX
dr--   JTA
dr--   JoltConnectionPools
dr--   Libraries
dr--   Log
dr--   LogFilters
dr--   Machines
dr--   MailSessions
dr--   MessagingBridges
dr--   MigratableTargets
dr--   RemoteSAFContexts
dr--   SAFAgents
dr--   SNMPAgent
dr--   SNMPAgentDeployments
dr--   Security
dr--   SecurityConfiguration
dr--   SelfTuning
dr--   Servers
dr--   ShutdownClasses
dr--   SingletonServices
dr--   StartupClasses
dr--   SystemResources
dr--   Targets
dr--   VirtualHosts
dr--   WLDFSystemResources
dr--   WLECConnectionPools
dr--   WSReliableDeliveryPolicies
dr--   WTCServers
dr--   WebAppContainer
dr--   WebserviceSecurities
dr--   XMLEntityCaches
dr--   XMLRegistries
-r--   AdminServerName                              AdminServer
-r--   AdministrationMBeanAuditingEnabled           false
-r--   AdministrationPort                           9002
-r--   AdministrationPortEnabled                    false
-r--   AdministrationProtocol                       t3s
-r--   ArchiveConfigurationCount                    0
-r--   ClusterConstraintsEnabled                    false
-r--   ConfigBackupEnabled                          false
-r--   ConfigurationAuditType                       none
-r--   ConfigurationVersion                         10.3.0.0
-r--   ConsoleContextPath                           console
-r--   ConsoleEnabled                               true
-r--   ConsoleExtensionDirectory                    console-ext
-r--   DomainVersion                                10.3.0.0
-r--   GuardianEnabled                              false
-r--   InternalAppsDeployOnDemandEnabled            true
-r--   LastModificationTime                         0
-r--   Name                                         wldf_domain
-r--   Notes                                        null
-r--   Parent                                       null
-r--   ProductionModeEnabled                        false
-r--   RootDirectory                                C:\Oracle\wls10gR3\user_projects\domains\wldf_domain
-r--   Type                                         Domain
-r-x   freezeCurrentValue                           Void : String(attributeName)
-r-x   isSet                                        Boolean : String(propertyName)
-r-x   unSet                                        Void : String(propertyName)
wls:/wldf_domain/serverConfig> serverRuntime()
wls:/wldf_domain/serverRuntime> ls()
dr--   ApplicationRuntimes
dr--   AsyncReplicationRuntime
dr--   ClusterRuntime
dr--   ConnectorServiceRuntime
dr--   DefaultExecuteQueueRuntime
dr--   EntityCacheCumulativeRuntime
dr--   EntityCacheCurrentStateRuntime
dr--   EntityCacheHistoricalRuntime
dr--   ExecuteQueueRuntimes
dr--   JDBCServiceRuntime
dr--   JMSRuntime
dr--   JTARuntime
dr--   JVMRuntime
dr--   JoltRuntime
dr--   LibraryRuntimes
dr--   LogBroadcasterRuntime
dr--   LogRuntime
dr--   MANAsyncReplicationRuntime
dr--   MANReplicationRuntime
dr--   MailSessionRuntimes
dr--   MaxThreadsConstraintRuntimes
dr--   MinThreadsConstraintRuntimes
dr--   PathServiceRuntime
dr--   PersistentStoreRuntimes
dr--   RequestClassRuntimes
dr--   SAFRuntime
dr--   SNMPAgentRuntime
dr--   ServerChannelRuntimes
dr--   ServerSecurityRuntime
dr--   ServerServices
dr--   SingleSignOnServicesRuntime
dr--   ThreadPoolRuntime
dr--   TimerRuntime
dr--   WANReplicationRuntime
dr--   WLDFRuntime
dr--   WTCRuntime
dr--   WebServerRuntimes
dr--   WorkManagerRuntimes
-r--   ActivationTime                               1237559025844
-r--   AdminServer                                  false
-r--   AdminServerHost                              192.168.2.1
-r--   AdminServerListenPort                        7001
-r--   AdminServerListenPortSecure                  false
-r--   AdministrationPort                           9002
-r--   AdministrationPortEnabled                    false
-r--   AdministrationURL                            t3://192.168.2.1:7011
-r--   CurrentDirectory                             C:\Oracle\wls10gR3\user_projects\domains\wldf_domain\.
-r--   CurrentMachine
-r--   DefaultExecuteQueueRuntime                   null
-r--   DefaultURL                                   t3://192.168.2.1:7011
-r--   EntityCacheCumulativeRuntime                 null
-r--   EntityCacheCurrentStateRuntime               null
-r--   EntityCacheHistoricalRuntime                 null
-r--   HealthState                                  Component:ServerRuntime,State:HEALTH_OK,MBean:managedServer1,ReasonCode:[]
-r--   JoltRuntime                                  null
-r--   ListenAddress                                JBAYER-LAP/192.168.2.1
-r--   ListenPort                                   7011
-r--   ListenPortEnabled                            true
-r--   MANAsyncReplicationRuntime                   null
-r--   MANReplicationRuntime                        null
-r--   Name                                         managedServer1
-r--   OpenSocketsCurrentCount                      3
-r--   Parent                                       null
-r--   PathServiceRuntime                           null
-r--   RestartRequired                              false
-r--   RestartsTotalCount                           0
-r--   SSLListenAddress                             null
-r--   SSLListenPort                                7002
-r--   SSLListenPortEnabled                         false
-r--   ServerClasspath                              C:\Oracle\wls10gR3\JROCKI~1\jre\bin\jrockit\jrockit1.6.0.jar;C:\Oracle\wls10gR3\JROCKI~1\jre\bin\jrockit\jmapi.jar;C:\Oracle\wls10gR3\JROCKI~1\
3\JROCKI~1\jre\bin\jrockit\rmp.jar;C:\Oracle\wls10gR3\JROCKI~1\jre\bin\jrockit\latency.jar;C:\Oracle\wls10gR3\JROCKI~1\jre\lib\resources.jar;C:\Oracle\wls10gR3\JROCKI~1\jre\lib\rt.jar;C:\Oracle\w
acle\wls10gR3\JROCKI~1\jre\lib\jsse.jar;C:\Oracle\wls10gR3\JROCKI~1\jre\lib\jce.jar;C:\Oracle\wls10gR3\JROCKI~1\jre\lib\charsets.jar;C:\Oracle\wls10gR3\JROCKI~1\jre\classes;C:\JDeveloper\mywork\J
ener.jar;C:\Oracle\wls10gR3\patch_wlw1030\profiles\default\sys_manifest_classpath\weblogic_patch.jar;C:\Oracle\wls10gR3\patch_wls1030\profiles\default\sys_manifest_classpath\weblogic_patch.jar;C:
ult\sys_manifest_classpath\weblogic_patch.jar;C:\Oracle\wls10gR3\patch_cie670\profiles\default\sys_manifest_classpath\weblogic_patch.jar;C:\Oracle\wls10gR3\patch_cie660\profiles\default\sys_manif
s10gR3\patch_alsb1030\profiles\default\sys_manifest_classpath\weblogic_patch.jar;C:\Oracle\wls10gR3\JROCKI~1\lib\tools.jar;C:\Oracle\wls10gR3\WLSERV~1.3\server\lib\weblogic_sp.jar;C:\Oracle\wls10
cle\wls10gR3\modules\features\weblogic.server.modules_10.3.0.0.jar;C:\Oracle\wls10gR3\WLSERV~1.3\server\lib\webservices.jar;C:\Oracle\wls10gR3\modules\ORGAPA~1.5/lib/ant-all.jar;C:\Oracle\wls10gR
\Oracle\wls10gR3\jdeveloper\modules\features\adf.share_11.1.1.jar;;C:\Oracle\wls10gR3\WLSERV~1.3\common\eval\pointbase\lib\pbclient57.jar;C:\Oracle\wls10gR3\WLSERV~1.3\server\lib\xqrl.jar;;;C:\Or
sysext_manifest_classpath\weblogic_ext_patch.jar
-r--   SocketsOpenedTotalCount                      3
-r--   State                                        RUNNING
-r--   StateVal                                     2
-r--   Type                                         ServerRuntime
-r--   WANReplicationRuntime                        null
-r--   WLECConnectionServiceRuntime                 null
-r--   WeblogicVersion                              WebLogic Server Temporary Patch for CR380042 Thu Sep 11 13:33:40 PDT 2008
WebLogic Server Temporary Patch for 7372756 Fri Sep 12 17:05:44 EDT 2008
WebLogic Server Temporary Patch for CR380913 Wed Oct 15 13:24:22 PDT 2008
WebLogic Server Temporary Patch for CR381739 Tue Oct 21 14:06:14 IST 2008
WebLogic Server Temporary Patch for CR381056 Mon Oct 06 10:48:50 EDT 2008
WebLogic Server Temporary Patch for CR374413, CR378680 Tue Sep 02 09:55:36 PDT 2008
WebLogic Server Temporary Patch for CR378102 Wed Sep 10 23:28:48 PDT 2008
WebLogic Server Temporary Patch for CR378741 Tue Sep 09 13:08:51 PDT 2008
WebLogic Server Temporary Patch for CR378781, CR380313 Fri Sep 19 13:34:16 PDT 2008
WebLogic Server 10.3  Fri Jul 25 16:30:05 EDT 2008 1137967
-r-x   addRequestClassRuntime                       Boolean : WebLogicMBean(weblogic.management.runtime.RequestClassRuntimeMBean)
-r-x   forceShutdown                                Void :
-r-x   forceSuspend                                 Void :
-r-x   getServerChannel                             java.net.InetSocketAddress : String(protocol)
-r-x   getURL                                       String : String(protocol)
-r-x   preDeregister                                Void :
-r-x   restartSSLChannels                           Void :
-r-x   resume                                       Void :
-r-x   shutdown                                     Void :
-r-x   shutdown                                     Void : Integer(timeout),Boolean(ignoreSessions)
-r-x   start                                        Void :
-r-x   suspend                                      Void :
-r-x   suspend                                      Void : Integer(timeout),Boolean(ignoreSessions)
wls:/wldf_domain/serverRuntime> cd('ClusterRuntime')
wls:/wldf_domain/serverRuntime/ClusterRuntime> ls()
dr--   myCluster
wls:/wldf_domain/serverRuntime/ClusterRuntime> cd('myCluster')
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster> ls()
dr--   JobSchedulerRuntime
dr--   ServerMigrationRuntime
dr--   UnicastMessaging
-r--   ActiveSingletonServices                      java.lang.String[TimerMaster]
-r--   AliveServerCount                             1
-r--   CurrentMachine                               null
-r--   CurrentSecondaryServer
-r--   DetailedSecondariesDistribution              null
-r--   ForeignFragmentsDroppedCount                 0
-r--   FragmentsReceivedCount                       581
-r--   FragmentsSentCount                           581
-r--   HealthState                                  Component:null,State:HEALTH_OK,MBean:null,ReasonCode:[]
-r--   MulticastMessagesLostCount                   0
-r--   Name                                         myCluster
-r--   PrimaryCount                                 0
-r--   ResendRequestsCount                          0
-r--   SecondaryCount                               0
-r--   SecondaryDistributionNames                   null
-r--   SecondaryServerDetails
-r--   ServerNames                                  java.lang.String[managedServer1]
-r--   Type                                         ClusterRuntime
-r--   UnicastMessaging                             null
-r-x   preDeregister                                Void :
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster> cd('JobSchedulerRuntime')
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime> ls()
dr--   JobSchedulerRuntime
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime> cd('JobSchedulerRuntime')
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime/JobSchedulerRuntime> ls()
dr--   ExecutedJobs
-r--   Name                                         JobSchedulerRuntime
-r--   Type                                         JobSchedulerRuntime
-r-x   getJob                                       WebLogicMBean : String(id)
-r-x   preDeregister                                Void :
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime/JobSchedulerRuntime> cd('ExecutedJobs')
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime/JobSchedulerRuntime/ExecutedJobs> ls()
dr--   JobRuntime-managedServer1_1237564053328
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime/JobSchedulerRuntime/ExecutedJobs> cd('JobRuntime-managedServer1_1237564053328')
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime/JobSchedulerRuntime/ExecutedJobs/JobRuntime-managedServer1_1237564053328> ls()
-r--   Description                                  jamesbayer.client.SystemOutTimerListener@2ed941
-r--   ID                                           managedServer1_1237564053328
-r--   LastLocalExecutionTime                       1237564580328
-r--   LocalExecutionCount                          18
-r--   Name                                         JobRuntime-managedServer1_1237564053328
-r--   Period                                       30000
-r--   State                                        Running
-r--   Timeout                                      6719
-r--   TimerListener                                jamesbayer.client.SystemOutTimerListener@333c5d
-r--   Type                                         JobRuntime
-r-x   cancel                                       Void :
-r-x   preDeregister                                Void :
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime/JobSchedulerRuntime/ExecutedJobs/JobRuntime-managedServer1_1237564053328> ls()
-r--   Description                                  jamesbayer.client.SystemOutTimerListener@2ed941
-r--   ID                                           managedServer1_1237564053328
-r--   LastLocalExecutionTime                       1237564850547
-r--   LocalExecutionCount                          27
-r--   Name                                         JobRuntime-managedServer1_1237564053328
-r--   Period                                       30000
-r--   State                                        Running
-r--   Timeout                                      18812
-r--   TimerListener                                jamesbayer.client.SystemOutTimerListener@349b7f
-r--   Type                                         JobRuntime
-r-x   cancel                                       Void :
-r-x   preDeregister                                Void :
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime/JobSchedulerRuntime/ExecutedJobs/JobRuntime-managedServer1_1237564053328> cmo.cancel()
wls:/wldf_domain/serverRuntime/ClusterRuntime/myCluster/JobSchedulerRuntime/JobSchedulerRuntime/ExecutedJobs/JobRuntime-managedServer1_1237564053328> ls()
-r--   Description                                  jamesbayer.client.SystemOutTimerListener@2ed941
-r--   ID                                           managedServer1_1237564053328
-r--   LastLocalExecutionTime                       1237564850547
-r--   LocalExecutionCount                          27
-r--   Name                                         JobRuntime-managedServer1_1237564053328
-r--   Period                                       30000
-r--   State                                        Cancelled
-r--   Timeout                                      -1
-r--   TimerListener                                null
-r--   Type                                         JobRuntime
-r-x   cancel                                       Void :
-r-x   preDeregister                                Void :

Automating JobScheduler status checking

One of my customers asked me about how they could periodically check if a task was running in the cluster, and if it is not then send someone an email, etc.  Basically, the sky is the limit with scripting.  A more advanced use of this would be to connect this to alerts in WebLogic Diagnsotic Framework or SNMP traps in Oracle Enterprise Manager, but this is a start.  Here is a python script that you can invoke with WLST that will do several things:

  • Connect to the Admin Server
  • Get a list of all managed servers in the cluster
  • Check each managed server for a particular running timer task
  • If no running tasks are found exit with a non-zero exit code, otherwise exit a zero exit code

isJobRunning.py

user='weblogic'
pw='weblogic'
adminServer='localhost'
adminPort='7001'
clusterName='myCluster'
timerRunning=false
timerClass='jamesbayer.client.SystemOutTimerListener'
## Standard Connection
try:
  connect(user,pw,'t3://'+adminServer+':'+adminPort)
except:
  print 'Error connecting to Admin Server'
## Get the list of managed servers in the cluster
try:
  domainConfig()
  cd('Clusters/'+clusterName)
  managedServers=cmo.getServers()
  print 'Found ' + `len(managedServers)` + ' managed servers'
except:
  print 'Error navigating DomainConfig MBean tree for the list of managed servers'
## Loop through managed servers and look for the job
domainRuntime()
for managedServer in managedServers:
  try:
    managedServerName=managedServer.getName()
    print 'Trying ' + managedServerName
    cd('/ServerRuntimes/'+managedServerName)
    if cmo.getState() == 'RUNNING':
      cd( '/ServerRuntimes/'+managedServerName+'/ClusterRuntime/'+clusterName+'/JobSchedulerRuntime/JobSchedulerRuntime')
      try:
        jobs=cmo.getExecutedJobs()
        for job in jobs:
          if job.getDescription().find(timerClass) > -1 and job.getState() == 'Running':
            timerRunning=true
            print timerClass + ' is running on ' +  managedServerName
      except:
        print 'Error checking ' + managedServerName + ' ExecutedJobs'
    else:
      print managedServerName + ' is not RUNNING'
  except:
    print 'Error checking JobScheduler on ' + managedServerName
  if timerRunning:
    break
disconnect()
if timerRunning:
  print 'The Job is Running'
  exit(exitcode=0)
else:
  print 'The Job is NOT Running'
  exit(exitcode=1)

Script output

C:\Oracle\wls10gR3\user_projects\domains\wldf_domain>bin\setDomainEnv.cmd
C:\Oracle\wls10gR3\user_projects\domains\wldf_domain>java weblogic.WLST C:\MyData\Accounts\PepsiAmericas\JobScheduler\isJobRunning.py
Initializing WebLogic Scripting Tool (WLST) ...
Welcome to WebLogic Server Administration Scripting Shell
Type help() for help on available commands
Connecting to t3://localhost:7001 with userid weblogic ...
Successfully connected to Admin Server 'AdminServer' that belongs to domain 'wldf_domain'.
Warning: An insecure protocol was used to connect to the
server. To ensure on-the-wire security, the SSL port or
Admin port should be used instead.
Location changed to serverRuntime tree. This is a read-only tree with DomainMBean as the root.
For more help, use help(domainConfig)
Found 1 managed servers
Location changed to domainRuntime tree. This is a read-only tree with DomainMBean as the root.
For more help, use help(domainRuntime)
Trying managedServer1
Disconnected from weblogic server: AdminServer
The Job is Running
Exiting WebLogic Scripting Tool.
C:\Oracle\wls10gR3\user_projects\domains\wldf_domain>

April 8, 2009

A Simple Job Scheduler Example - WebLogic Server Clustered Timer

Did you know WebLogic Server can schedule future tasks similar to a cron job?  This even works in a WebLogic cluster.  Using a cluster ensures that as long as one of the managed servers in the cluster is available, your task has a high-availability characteristic and the task will execute.  This has come up for at least 3 of my local customers.  Every once in awhile I see questions about WebLogic timers from my peers, so I thought I’d share a simple example for how this works and some extra tidbits based on personal experience that might not be in the standard documentation.  Read on if you want to see how to schedule a simple println() task to execute every 30 seconds in a cluster that can survive server failures in both the WebLogic tier and the database tier (provided you use Oracle RAC).

HA

Background

Oracle (then BEA Systems) and IBM collaborated on a common API for Timers and Work Managers (think multi-threading) that would be portable across application servers.  They aptly named this API CommonJ.  This API has been supported in WebLogic Server since 9.x and apparently in WebSphere since 6.x.  When combined with WebLogic clustering support, the CommonJ Timer API is known as the Job Scheduler.  It requires some configuration as described in the docs, but essentially the way it works under the covers is by serializing the class that will execute the task and some related metadata to a database.  Using the leasing feature of WebLogic Server, exactly one cluster member will be responsible for JobScheduler (singleton service) which executes the Timer Tasks.  The server responsible for this service will check the database every 30 seconds to see if there are new tasks to execute.

Instructions for the System Out Example Timer

These instructions assume starting from scratch with nothing but a basic WebLogic Server installation and a database like Oracle XE.  I run all of this easily on my 2+ yr old laptop (I do have 3+ gig of ram).  The documentation is more detailed now, so definitely refer to that as well.

  1. Create a new domain with 1 Admin Server and at least one Managed Server that will be a part of a cluster.  Refer to the Oracle By Example page for WLS if you need help with this, but you should be able to do all of this from the Configuration Wizard.  I named my cluster “myCluster” and my managed servers “managedServer1” and “managedServer2”.
  2. Set up the database – Basically run the DDL for your DB, which will create a table called WEBLOGIC_TIMERS. If you don’t set up database often, here is my simple POC sequence with Oracle XE.  In production, I would recommend Oracle RAC with a Multi Data Source, but you can POC this with an XE database or a single database node if you can live with a single point of failure.  Open the XE database web console and create a new database user, of course I use weblogic/weblogic for the user name password and give them admin rights.  Start sqlplus and login as that user.  Navigate to the directory that contains the DDL you want to run and use the @ syntax to execute the DDL like this.  You can of course ignore the messages about the comments not being valid commands: scheduler.ddl
  3. Keep the sql prompt open, we’ll use it again in a minute.  Notice that the script is in the oracle\920 directory, that simply means for 9.2+ of Oracle DB, it works totally fine for me on XE 10g.
  4. Configure the data source – Create a new data source for this and target it at all the servers in your domain (or at least the ones in your cluster) and specify it as the cluster’s JobScheduler Data Source.  I recommend that you test your data source when you are creating it.
  5. Set up leasing – You can use consensus or database leasing, but since we already using the DB for the Job Scheduler, just do database leasing which creates a table called ACTIVE (at least in the recent releases of WLS, it used to be something like WEBLOGIC_ACTIVE in earlier releases).  This means running the appropriate WL_HOME/server/db/dbname/leasing.ddl as well as configuring the data source, which can be the same one you used before, and configuring the cluster to use that data source for leasing.  Make sure you note database based leasing requires a highly-available database.  If the connection goes away, the managed servers will fail.  For this reason you can use multi data sources with Oracle RAC to get an even more HA architecture, but Oracle XE works fine for a POC.  I got consensus leasing to work at one time in the past using WLS 9.2, but if I remember correctly I had to install Node Manager and configure “machines” for my servers for it to work.  So DB-based leasing is what I’m using in this example because it’s simpler and I have not had issues with it before. leasing.ddl
  6. Write some code – There is a sample in the docs showing how to look up the job scheduler and schedule a task.  I’ll take care of that for you, here is a WAR (Servlet 2.5 based) that has code to register the task via a servlet and a JAR file that contains the class that implements the TimerListener interface.  The source code is at the way bottom of this post.
  7. Deploy the WAR file, target it at the cluster, and make sure the application is started.
  8. Edit your server classpath to contain the timer implementation class which is in the JAR referenced earlier.  You might be asking yourself, why the heck does the timer listener class need to be placed on the system classpath?!!  Well if you think about how the classloaders work, the singleton service running the tasks does not have access to the classes from the JEE module that registered the timer.  It is running as a WebLogic system thread.  This class will be deserialized from the database, potentially on another server.  So I recommend not doing anything too sophisticated in the timer listener.  If you have lots of logic with multiple classes, just consider having the timer listener drop a message on a distributed JMS queue, which can have an MDB from another application that does all of your heavy lifting.  Back to putting the TimerListener implementation on the classpath, I accomplished this by added the following line to my domain’s setDomainEnv.cmd script.  There is also the option to use an EJB Timer, which apparently does not have the system classpath requirement, but I haven’t tried that before.
    set PRE_CLASSPATH=C:\JDeveloper\mywork\JobSchedulerApp\TimerListener\deploy\TimerListener.jar
    
  9. Optional – Enable verbose logging for the related sub-systems, I find this helpful when troubleshooting. 
    set JAVA_OPTIONS=%JAVA_OPTIONS% -Dweblogic.debug.DebugSingletonServices=true -Dweblogic.JobScheduler=true

  10. Restart your Admin Server and Managed Server.  Make sure you see the JAR in the classpath settings in the log file.  args
  11. If your enabled the additional logging, you should see that leasing and job scheduler are creating log entries like the following in the managed server log file (not in standard out!). 
  12. ####<Apr 8, 2009 3:10:01 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '1' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221401078> <BEA-000000> <SingletonMonitor: Checking Failed Leases> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: Now checking lease statuses.> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: Checking for registered Migratable Targets and Singleton Services without a lease> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: TimerMaster - Found an owner - -7090657857495109585/managedServer1> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: Checking existant, but expired leases> 
    ####<Apr 8, 2009 3:10:11 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221411078> <BEA-000000> <SingletonMonitor: Checking Failed Leases> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: Now checking lease statuses.> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: Checking for registered Migratable Targets and Singleton Services without a lease> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: TimerMaster - Found an owner - -7090657857495109585/managedServer1> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: Checking existant, but expired leases> 
    ####<Apr 8, 2009 3:10:21 PM CDT> <Debug> <SingletonServices> <jbayer-lap> <managedServer1> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1239221421078> <BEA-000000> <SingletonMonitor: Checking Failed Leases> 

  13. Register the timer by hitting the URL or invoking the web service of one of the managed servers.  In my case that is http://localhost:7011/TimerWeb/timerservlet.  Note that each time you invoke the URL successfully a new timer listener will be registered with the cluster, so you probably only want to do this once.
  14. Notice the messages in standard out if this is working correctly.
  15. timerExpired() called at 4/8/09 3:12 PM
    timerExpired() called at 4/8/09 3:13 PM

  16. Shut down the managed server that has the messages printing to standard out.  You should see the messages show up on another managed server in the cluster in standard out.
  17. Now shut down all of the managed servers and restart at least one.
  18. You should see the timer task start printing to standard out when one of the managed servers in the cluster is available.

Summary

So you should have a working timer example in WebLogic Server that survives failures.  The debug messages in the managed server log files can be helpful in trouble-shooting in case anything goes wrong.  A couple other things to note, you cannot cancel timer tasks via CommonJ API calls when running in the JobScheduler.  You have to use the JobRuntimeMBean for that.  I’ll show an example of using this bean with WLST in another entry.  Here is the source code for the servlet and the timer listener classes.  Hopefully this will help you utilize this powerful capability built-in to WebLogic.

package view.jamesbayer;
import commonj.timers.TimerManager;
import jamesbayer.client.SystemOutTimerListener;
import java.io.IOException;
import java.io.PrintWriter;
import javax.naming.InitialContext;
import javax.servlet.*;
import javax.servlet.http.*;
public class TimerServlet extends HttpServlet {
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }
    public void service(HttpServletRequest request,
                        HttpServletResponse response) throws ServletException,
                                                             IOException {
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head><title>TimerServlet</title></head>");
        try {
            System.out.println("service() entering try block to intialize the timer from JNDI");
            InitialContext ic = new InitialContext();
            TimerManager jobScheduler =
                (TimerManager)ic.lookup("weblogic.JobScheduler");
            System.out.println("jobScheduler reference " + jobScheduler);
            commonj.timers.TimerListener timerListener =
                new SystemOutTimerListener();
            System.out.println("timerListener reference " + timerListener);
            jobScheduler.schedule(timerListener, 0, 30 * 1000);
            //execute this job every 30 seconds
            System.out.println("service() started the timer");
            out.write("Started the timer - status:");
        } catch (Throwable t) {
            System.out.println("service() error initializing timer manager with JNDI name weblogic.JobScheduler " +                               t);
        }
        out.println("</body></html>");
        out.close();
    }
}

package jamesbayer.client;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import commonj.timers.Timer;
import commonj.timers.TimerListener;
public class SystemOutTimerListener implements Serializable, TimerListener 
{
	private static final long serialVersionUID = 8313912206357147939L;
	public void timerExpired(Timer timer) 
	{
		SimpleDateFormat sdf = new SimpleDateFormat();
		System.out.println( "timerExpired() called at " + sdf.format( new Date() ) );
	}
}

March 25, 2009

Oracle Enterprise Pack for Eclipse 11g – WebLogic Interop Tip

OEPE 11g is out I had to rush out and try it.  I used the full install from OTN.  I assume most users of OEPE 11g will also be WebLogic users.  Out of the box, Workspaces are not pre-configured with a WTP Server Runtime or WebLogic Shared Libraries because OEPE doesn’t know where WebLogic is installed or which version you want to use if you have multiple installations.  There is a simple way to enable this by specifying your WebLogic home in the eclipse.ini file.  I added the following line (substitute your path to WLS):

-Dweblogic.home=C:/Oracle/wls10gR3/wlserver_10.3

Now your Workspaces (existing and new) should become populated with a WebLogic Server Runtime of the version you specified with WebLogic Shared Libraries.  Ah, but there is another gotcha!  In order for this to work with WLS 10gR3 Eclipse needs to be started with a JDK6 JVM.  In my case,  my system’s default JVM was JDK5, so I had to explicitly tell OEPE 11g to start with JDK 6 by specifying the JVM in eclipse.ini.  If you use JRockit instead of Sun you may want to make other adjustments such as making the min/max memory the same and not configuring PermSize at all, but those are just extra tweaks. Again, specify your specific path, but here is mine:

-vm
C:/Oracle/wls10gR3/jrockit_160_05/jre/bin/javaw.exe

Using Windows->Preferences you should be able to see the end result when you launch Eclipse.  Be sure to check out the OEPE 11g tutorials for some great examples.

runtime

libs

March 24, 2009

Eclipse2JDev Series – An Eclipse user tries JDeveloper

Since I’ve joined Oracle via the BEA acquisition I have had the opportunity to start learning JDevleoper and I like it a lot, but I’ve had some bumps in the road since I’m so used to Eclipse.  Much of the IDE tooling for the Oracle’s SOA, BPM, and Application Server products is migrating to JDeveloper, which is Oracle’s comprehensive IDE.  This gives developers using Oracle products a very easy-to-use and highly integrated development environment.  Oracle is still strongly committed to the Eclipse community as evidenced by the contributions to many Eclipse detailed on the Oracle Enterprise Pack for Eclipse page and just announced 11g.  There are some differences for accomplishing certain tasks in JDeveloper and Eclipse and I thought I’d write about my transition from the perspective of a long-time Eclipse user.  Some members of the JDeveloper team have agreed to vet these entries and I hope others will contribute some knowledge as well.  I’ll use Workshop 10gR3 and JDeveloper 11g as my points of comparison.

Application and Project Archive Packaging

This use case was part of the inspiration for this series, simply to have an Enterprise Application with a Web Module that has a dependency on a Java project that is also included in the exported EAR.  In Eclipse WTP, this is accomplished by creating 3 separate projects and linking them together:

  1. Enterprise Application Project – named LibraryTestApp
  2. Utility Project – named LibraryUtility
  3. Dynamic Web Project – named LibraryWeb

As you can see in the J2EE Module Dependencies section of the LibraryTestApp project, I have placed dependencies on the other 2 projects, which results in the LibraryUtility.jar being placed in the EAR’s APP-INF/lib and the WAR being included in the EAR as well.

EclipseDependencies 

EclipseEAR

JDeveloper has the concept of an Application, which is a container for Projects.  So first create a new Generic Application named LibraryTestApp.  The wizard guides you through the creation of a project for this application, and selected JSP and Servlet technologies and name the project LibraryWeb.  Then add a new Java Project to this Application and call it LibraryUtility.  Both of these projects are initially empty, so create a new JSP file in the Web project.  Looking at the structure for the web module, you can see that it has a WEB-INF directory, but no lib directory underneath it.

JDev

How To Create a Directory

I’m going to side-track this a bit and talk about a variation to this use case.  The first time I tried this I already had a pre-built jar file on the file system and my very first intuition was to create a lib directory underneath of WEB-INF and copy the file over.  JDeveloper does not allow you to create folders with a right-click on WEB-INF.  In fact, creating a folder is not directly supported in JDeveloper.  You can indirectly accomplish it by launching the “New…” wizard and generic file, and put the folder name in the Wizard. 

file

lib

This was not exactly intuitive to me as I was used to the Resource Perspective in Eclipse that gives you a pretty good idea of what all the files look like on the file system and lets you manipulate them.  I heard from the product team that this is an often requested feature and is being considered for future JDeveloper releases.  It turns out that you can also just add something to the file system and JDeveloper will pick it up, but there is a better way.  More on that later, but first a little more background on the Application and Project settings.

Deployment Profiles and Dependencies in JDeveloper

The concept of Applications and Projects will be new to Eclipse users where everything is a Project, but this helps group projects together instead of having a cluttered workspace full of potentially unrelated projects.  It turns out that you can right-click on the Application name in the Application Navigator and select Application Properties.  Similarly, you can right click on the Project name and select Project Properties.  Alt-Enter also works as a short-cut exactly as in Eclipse.  Inside of Project Properties there is a menu option for Deployments.  From an Eclipse perspective, if you want to create a jar file from a java project you can right-click on the project and select “Export->Export…->Java->Jar”.  JDeveloper does not have an “Export” option, but this is covered by a Deployment Profile.  By default there is no Deployment Profile for the project, so create a new one and name it what you want the jar to be named.  You can see that this will jar up this project and place it in the project’s deploy directory.

jar [2]

You can explore this even further by looking at the File Groups->Project Output->Contributors and see that the Build Output and Project Dependencies both make up the contents of this jar.  Now that we have a jar, let’s turn to the LibraryWeb project that we want to use the LibraryUtility.jar.  Remember earlier when I tried to manually add the jar to the WEB-INF/lib directory?  I should have just used the “Project Properties->Libraries and Classpath” for the ViewController web module project and added the jar file to the classpath.  Notice that the “Export” checkbox is selected which means this jar will be packaged as part of the WAR under WEB-INF/lib.  So similar to the LibraryUtiilty project, you can create a Deployment Profile for the LibraryWeb project.  This time select WAR as the archive type.  You can see that the jar will be included in the WAR under the WEB-INF/lib contributors.

classpath

Contributors

zip

Notice that the Deployment Profile also has a menu option for Profile Dependencies.  There you can indicate that this Deployment Profile depends on the Deployment Profile that builds the jar for the LibraryUtility project.

libutility

You can follow similar steps to create a Deployment Profile for the Application via the Application Properties, this time selecting an EAR archive type.  Now we have a similar experience to Eclipse where I can right click on the project select Deploy->LibraryTestApp-> to EAR file.  In fact, I can get fancy in the Application’s Deployment Profile and specify the path to the LibraryUtility.jar file in the EAR to be in APP-INF/lib.  You can set up multiple deployment profiles per project or application, so it’s actually more flexible than the Eclipse structure.

deploy

If you notice the Deploy->LibraryTestApp-> as has a “to” option as well as “to EAR file”.  Using this option I can deploy this archive to a running WLS server, more detail on that in another entry.

An Alternative Approach – Project Dependencies

There is alternative to the Libraries and Classpath linked to Deployment Profile approach that JDeveloper actually uses by default for Fusion Web Applications.  When you create a new Fusion Web Application, a Model project and a ViewController project are created by default.  In ViewController->Project Properties->Dependencies you will see a dependency on the Model project. 

fusion

Now look at the auto-generated Deployment Profile for the ViewController project and you will see this causes the build output of the Model project to be added to the build output of the ViewController project because of the checkbox for “Project Dependencies” in the WEB-INF/classes contributors section.  This results in only one combined module inside the EAR, instead of two separate ones.  So which method is better – Project Dependencies or linking the Libraries and Classpath to another project’s Deployment Profile?  It is really a matter of taste, but since I had a preconceived notion for the structure of the EAR in the original use case, the Libraries and Classpath linked to the LibraryUtility project’s Deployment Profile worked best for me.

fusionDeploymentProfile

Summary

So the key take-aways are:

  • JDeveloper organizes Projects inside of Applications
  • Applications and Projects have the concept of Deployment Profiles and Dependencies, which can be used to structure the archives as we like them
  • Deployment Profiles can then deploy the archives directly to running servers as well as the file system

Hopefully this gives a good introduction to some of the distinctions for developing and packaging Enterprise Applications and Modules in Eclipse and JDeveloper.

Potential Future Topics

Here is a list of potential topics that I think are interesting for comparison’s sake, let me know if there are others you’d like to hear about.

  • IDE meta-data
  • IDE shortcuts
  • Monitoring network traffic
  • Deploying to a server
  • Facets versus Technology Scope

March 21, 2009

Workaround for Using JConsole with WLS 10gR3 JMX

4-24-2009 Update – Please see the comments of this entry for a solution that only requires setting the classpath and does not require a custom RMI/IIOP proxy.  Thanks to Kai and Mic for commenting with an easier solution.  James

I came across a surprising interoperability issue the other day using JConsole to browse WLS 10gR3 JMX MBeans.  Read on to see how to I got around it.  One of my customers wanted to monitor some WLS services running in a cluster recently, so in doing a little research I decided to pull up JConsole to see what the JMX Beans looked like.  Of course WLST works well for this, but I didn’t quite know where the MBean was located so I wanted something visual that I could navigate in a tree fashion without typing commands.

In order to bring up JConsole, you need to follow some basic steps in the documentation to enable RMI on the server you want to connect to: http://edocs.bea.com/wls/docs103/jmxinst/accesscust.html#wp1107229  Be sure to set the default RMI user and password and you will also need to restart the servers after you perform this configuration so it takes effect.

So normally you could just launch JConsole from the JDK’s bin directory and plug-in your connection info.  In my case I am using JDK 6 from the WLS Example server which is running on port 7001.  This is the URI I put into JConsole:

service:jmx:iiop:///jndi/iiop://localhost:7001/weblogic.management.mbeanservers.runtime

My RMI default user and password is “weblogic”

Well, to my surprise I got a JConsole Output window that kept scrolling with errors.  Here is the beginning of the stack:

com.sun.corba.se.impl.encoding.CDRInputStream_1_0_read_value
WARNING: "IOP00810257: (MARSHAL) Could not find class"
 at com.sun.corba.se.imple.logging.ORBUtilSystemException.couldNotFindClass(ORBUtilSystemException:7756)
 ....

I looked around a bit on Google and found that since JDK 5 there has been a bug in the IIOP RMI stack in the JDK.  Thankfully there is a work-around that involves creating a simple poor-man’s proxy.  So I compiled and ran the RMIIIOPProxy.java file from that link (I removed the package name for brevity) and tried again to connect again while the proxy was running.  This time it worked.

C:\temp>java RMIIIOPProxy 7011 weblogic.management.mbeanservers.runtime localhost 7001 weblogic.management.mbeanservers.runtime
Connection established with south server at: service:jmx:iiop:///jndi/iiop://localhost:7001/weblogic.management.mbeanservers.runtime
Proxy server listening at: service:jmx:rmi:///jndi/rmi://localhost:7011/weblogic.management.mbeanservers.runtime
Strike <Enter> to exit

So now there is a simple proxy that listens on port 7011 which then connects to port 7001 on my behalf and gets around the bug.  I simply take the JMX URI from the proxy console output and plug that back in to JConsole, this time with a successful connection.  Notice that this URI does not include IIOP.  Now I get browse the MBeans, see the attributes, and execute operations like I expect.  I also tried this with JDK 5’s JConsole and the same issue was present and solved by the work-around.

cropper

February 18, 2009

Hermes JMS – Revisited for WebLogic Server JMS 10gR3

Hermes JMS is an open source JMS Browser created by Colin Crist and hosted on Sourgeforge that works with numerous JMS implementations including WebLogic JMS and Oracle Application Server JMS.  I have written about using Hermes and WebLogic together before so see that entry for an overview.  I have found that this tool works great for me to quickly view/move/delete JMS messages in queues and topics.  This entry is simply an update for the recent version of Hermes 1.13 and WebLogic Server 10gR3.  Here’s a screenshot that highlights just some of the capabilities, click to enlarge.

hermesFeatures 

  • I like using the off-line installation from Sourceforge for reasons that will probably become apparent below, but there is also a Web Start version on the project home page.
  • I found an old comment that I had written that claimed using the same JVM as the WLS server with Hermes helps, so I modify the %HERMES_INSTALL%\bin\hermes.bat file to use JRockit from WLS 10gR3:
SET JAVA_HOME=C:\Oracle\wls10gR3\jrockit_160_05
set PATH=C:\Oracle\wls10gR3\jrockit_160_05\bin
  • Launch Hermes and go to Options->Preferences to add the weblogic.jar to the providers tab, this is nice because presumably I could use multiple WLS versions (I haven’t tried that)

ClasspathGroup

  • Configure a new Session in the GUI.

session 

  • Then right click on the session and select “Discover” and you should have all the destinations available to browse.
  • The Session gets saved in hermes-config.xml (C:\.hermes\hermes-config.xml on my machine) and the relevant snippet looks like this:
        <factory classpathId="weblogic10.3">
            <provider className="hermes.JNDIConnectionFactory">
                <properties>
                    <property name="initialContextFactory" value="weblogic.jndi.WLInitialContextFactory"/>
                    <property name="providerURL" value="t3://localhost:7001"/>
                    <property name="securityCredentials" value="weblogic"/>
                    <property name="binding" value="javax/jms/QueueConnectionFactory"/>
                    <property name="securityPrincipal" value="weblogic"/>
                </properties>
            </provider>
            <connection clientID="" connectionPerThread="false">
                <session audit="false" id="examplesQCF" reconnects="0" transacted="true" useConsumerForQueueBrowse="false"/>
            </connection>
            <destination domain="1" name="weblogic/wsee/DefaultQueue"/>
            <destination domain="1" name="weblogic/examples/ejb30/ExampleQueue"/>
            <destination domain="2" name="weblogic/examples/jms/exampleTopic"/>
            <destination domain="1" name="weblogic/examples/jms/exampleQueue"/>
            <destination domain="1" name="jms/MULTIDATASOURCE_MDB_QUEUE"/>
            <destination domain="2" name="quotes"/>
            <destination domain="2" name="stockTopic"/>
            <extension className="hermes.ext.weblogic.WebLogicJMSAdminFactory">
                <properties/>
            </extension>
        </factory>


    Now you should be ready to browse.  You could also take the alternative route of binding to the Initial Context of the server, which then makes it easy to create multiple Sessions from the Connection Factory objects.  However, I had trouble doing this without editing the hermes-config.xml due to what might be a fluke in the GUI for changing the class-loader provider from System to the WebLogic10.3 one that has the weblogic.jar.  If you have trouble with this you can either edit the hermes-config.xml file to have the correct provider or just add the weblogic.jar to the classpath (so System inherits it).  Good luck with Hermes.

    December 29, 2008

    WebLogic Server Resources – My Comprehensive List

    Overview

    Prior to joining BEA over 3 years ago, I never used WebLogic Server and had to come up to speed very quickly.  I have assembled my list of favorite resources for acquiring WebLogic knowledge.  Now that Oracle has declared WebLogic Server as the strategic application server platform I expect that many Oracle employees, customers and partners will be in a similar situation as I was when I joined BEA.  The good news is that there are many excellent ways to come up to speed in many different media formats.

    The Basics – Terminology and Concepts

    Step zero is to understand some of the concepts and terminology that are specific to WebLogic Server.  There is a very short and easy presentation that does this that has been posted on slideshare.  If you need the very high-level, then start here.  Of course you can get all of this from the documentation in a more verbose way; however I have not found a better concise introduction than this presentation.

    Baby Steps – Oracle By Example

    swing Oracle has a very nice concept called “Oracle By Example” where they explain in detail with screenshots how to perform specific tasks.  Now there is a complete Oracle By Example section on WebLogic Server with lessons for Installing and Configuring Oracle WebLogic Server Instance , Create a Basic Cluster, Using the WebLogic Server Administration Console and many others.  You have to crawl before you walk and run, so be sure to check these out as they are great for getting started.

    Samples and Examples Ship With the Productlightinstall

    It surprises me how often people do not know that WebLogic Server has example source code and an sample domain that can be installed with the product.  In the past this was part of the default installation, but I believe with 10gR3 that you now have to specify the option to install the samples as part of a custom installation.  If you did the default installation you should be able to add the examples by running the installer again and selecting the custom installation to add only the examples to an existing installation.  You can see detail about the samples by opening the file <WEBLOGIC_INSTALLATION>\wlserver_10.3\samples\server\wls_samples_overview.html

    Check out the complete index of the 10gR3 examples on the image below and see how many specific examples are included.  For example, there web services examples for several of the WS-* specifications, in some cases mixed and matched together.  A simple rule of thumb is to always check the examples whenever you are getting started with a feature for the first time or you need a refresher on a feature you have not used in a while.  Many of the examples also can be used as a template to build on for your scripts and code.

    The examples instructions also include instructions on how to start the Examples Server also known as the samples domain, so be sure to check those instructions out as most examples will get deployed to the samples domain located at <WEBLOGIC_INSTALLATION>\wlserver_10.3\samples\domains\wl_server

    examplesIndex

    Required Reading - Documentation

    sitemap Although it is not as fun as watching a screencast or as quick as a topic tailored presentation, you absolutely must become familiar with the standard documentation when you get in to any level of detail on WebLogic features.  Here are a couple non-obvious items from the docs table of contents that I have circled on the left that you should note.

    What’s New – Provides a breakdown by subsystem of what has changed between releases, sometimes there are new features that do not get featured on the front-page, but that are very nice to know about.

    Known and Resolved Issues – These can come in very handy when you trying to discover if an issue you’ve run into is currently known about and potentially resolved.  It has the specific bug number (known as a CR in WebLogic speak) that can come in handy when interfacing with support.

    Supported Configurations – I cannot stress enough how important it is that you review the documentation for the specific OS / Chipset / JVM combination that you are using in various environments.  When using proprietary OS’s like HP-UX or AIX for example, only very specific JVM versions are supported and there may be specific patches required for the OS, the JVM, and WebLogic Server.  I have seen issues come up many times in the field when these pre-tested and certified versions are not adhered to strictly.  Take a look at this page for AIX 5.3 for example which gives precise version information and special installation instructions and patch information for this combination.

    Documentation Search Tip - One short-cut that I use often when searching the documentation is the google “site:” syntax.  So for example, to constrain my search the WebLogic Server 10gR3 documentation for the words “deployment descriptor” you can specify the path to restrict the results to.  I type this in the google search bar: 

    site:http://edocs.bea.com/wls/docs103/ deployment descriptor
    You can take specify a deeper path as well, so if I only wanted to search a portion of the JMS documentation, I could have used the path http://edocs.bea.com/wls/docs103/jms

    In fact, I have another short-cut that simplifies this further, I use a tool called SlickRun where I can create my own short-cuts by keyword.  I have created a “wls” keyword so I can type the following command into a prompt that is always keyboard accessible:

    wls deployment descriptor

    and SlickRun will open my browser, put in the google site syntax for me, and substitue the “deployment descriptor” phrase to be my search terms.  But I digress…

    The final thing I will mention about the documentation is that it is a living set of documents.  If you find a gap that needs to be filled, an area that needs improvement or more detail, or a mistake then please participate in making the documentation better by sending feedback via the link at the bottom of each page or emailing it to docsupport at bea dot com.

    Oracle Technology Network (OTN)

    Many of the resources mentioned here are part of the Oracle Technology Network which has tons of information.  Here are some of my favorites for WebLogic:

    WebLogic Server Product Page – This is the center of the universe for WebLogic.  Do not miss the recorded demos (a list is below).

    WebLogic Server Product Blog – Many great posts by the product team.

    RSS feed for all WebLogic related articles and news

     demos

    Forums

    There are many product specific forums on the Oracle Technology Network that are monitored by experts to answer informed questions.  In WebLogic Server’s case there are even sub-forums for specific sub-systems of WebLogic Server that are often monitored by developers and experts in those subject areas.  In addition to the Generic WebLogic Server forum that I like to read, there are currently forums specific to JDBC, Security, Web Services, etc.  This is not a comprehensive list and they are adding more all the time, so check the Application Server category to see if there is a specific WebLogic forum for your question.  One of the most important things to remember is that the detailed, well-researched, and well-explained questions are most likely to get a helpful response.  If you are lazy and have not used some of the resources above or if you do not provide enough detail so that someone with no context can figure out what you are asking, then you end up wasting people’s time.  There is also a read-only archive of the former BEA dev2dev forums that is especially helpful for researching questions on older releases.

    I really like using the RSS feeds from the forums to find out about new postings in my RSS Reader.  You can also do other handy things like watch a specific thread so you receive emails about any updates to that thread only instead of for the entire forum.

    Oracle provides a formal support process for their customers with defined Service Level Agreements and the forums are not a substitute for that.  They are a community-based volunteer mechanism to help both the questioners and the responders further their knowledge.  So if you use the forums to post questions, give back and help answer some of the questions too.  Even if you only start by redirecting people to previous answers or a better forum to post their question in, you can help build the community and learn yourself.

    Support

    Whenever an issue or question comes up that has urgency, I urge my customers to open a support case.  I use this simple support quick reference guide with my customers that has all contact information and describes how to open a support case, escalate an issue, etc on only one page.  It’s easy to print out and post somewhere where management, developers and administrators can see it.  WebLogic support is still handled by the http://support.bea.com website as of this post, but over time it will migrate to the My Oracle Support website formerly known as Metalink.

    Support Patterns - The WebLogic support patterns are a fantastic way to try self-service support on common issues.  These are used by the support engineers and are common enough to be published for anyone to use.  They are broken down by topic area and I often find myself pointing customers to this information.  For example, if you need to troubleshoot multicast issues in a cluster there is a page dedicated to that topic.

    Oracle University

    Formal training courses from Oracle University and certifications are a great way to build knowledge.  WebLogic courses are currently listed under the BEA section.

    Summary

    I’m sure that I have omitted some excellent resources by accident.  There are published books on these topics and many WebLogic blogs out there, not all of which are hosted on blogs.oracle.com.

    Once you participate in the community awhile you make connections with experts in many subject areas.  The relationships that I have built up over time with the product team and specialists are helpful, but it did not happen over night.  So my advice is to participate in the community and take advantage of the many resources out there.  Leave a comment if you have any favorites resources that I left out.

    December 5, 2008

    Comet Workshop Recording

    Google recently posted a video recording of a Comet Workshop delivered by Kevin Nilson, who has also authored an article and a podcast about his experiences with Comet, Bayeux and Dojo.  He also has a website that has links to hosted presentations.  Definitely give his material a look if you want to learn more about the Comet examples I posted previously and if you want an objective vendor-neutral perspective.

    October 21, 2008

    Real-time Updates on WebPages - Part 3 - Dojo 1.2.0 tip and Bayeux Handshake

    Yesterday I published my sample Comet application for WLS 10.3 and described how to get it to work with Dojo 1.1.1.  I mentioned that I had an issue with Dojo's brand new 1.2.0 release.  Well I figured out the issue and the work-around to using Dojo 1.2.0 with WLS 10.3.  All that is required is to call the dojox.cometd.connectionTypes.unregister() function before you use dojox.cometd.init().

    dojox.cometd.connectionTypes.unregister("long-polling-json-encoded");

    Now that I ruined the punch-line, read-on if you're interested in how the Bayeux protocol handshake happens and how I trouble-shot this.  When the client initializes there is a handshake message exchanged with the server so they can agree on which method of communicating to use.  Apparently WLS 10.3 as it ships does not like a new supported connection type that is available in Dojo 1.2.0.

    The client normally uses code like this to initialize a connection:

    <!-- Import Dojo -->
    <script type="text/javascript" src="dojo-release-1.2.0/dojo/dojo.js"
        djConfig="parseOnLoad:true, isDebug:true"></script>
    
    

    <script type="text/javascript">
    dojo.require("dojox.cometd");
    dojox.cometd.init("cometd");
    </script>


    Using Firebug and a simple URL decoder we can see that it sends the following with a POST to the server:

    message=[{"version":"1.0","minimumVersion":"0.9","channel":"/meta /handshake","id":"0","supportedConnectionTypes":["long-polling","long-polling-json-encoded ","callback-polling"]}]

    The response looks like this:

    [{"channel": "/meta/handshake", "successful": false, "error": "402:long-polling-json-encoded:Invalid
     supportedConnectionTypes attribute.", "supportedConnectionTypes": ["long-polling","callback-polling"
    ], "version": "1.0", "minimumVersion": "0.1", "advice": {"reconnect": "none", "interval": 500, "multiple-clients"
    : false}}]

    Uh oh, notice how there is an error in the handshake indicating that WLS does not like the long-polling-json-encoded connection type?  So after posting in the Dojox support forum, I got a response suggesting specifying a property as an argument to the init() call so as not to send the extra connection type.  That did not work for me, but it put me on the path of using Firebug, the js source, and the Dojo API docs.  I discovered that the connection types are stored in an dojo.AdapterRegistry and that there is an unregister function for the connection types.  That's it.  So now my client code looks like this with the new unregister invocation:

    <!-- Import Dojo -->
    <script type="text/javascript" src="dojo-release-1.2.0/dojo/dojo.js"
        djConfig="parseOnLoad:true, isDebug:true"></script>
    
    

    <script type="text/javascript">
    dojo.require("dojox.cometd");
    dojox.cometd.connectionTypes.unregister("long-polling-json-encoded");
    dojox.cometd.init("cometd");
    </script>


    Which results in a POST like this:

    message=[{"version":"1.0","minimumVersion":"0.9","channel":"/meta /handshake","id":"0","supportedConnectionTypes":["long-polling","callback-polling "]}]

    And a successful response like this:

    [{"channel": "/meta/handshake", "version": "1.0", "supportedConnectionTypes": ["long-polling","callback-polling"
    ], "clientId": "NNR2BOeRyCVKjLN", "successful": true, "minimumVersion": "0.1", "authSuccessful": true
    , "advice": {"interval": 500, "multiple-clients": false}}]

    Which causes the Dojo cometd framework to send another request specifying that it prefers long-polling:

    [{"channel":"/meta/connect","clientId":"NNR2BOeRyCVKjLN","connectionType":"long-polling","id":"1"}]

    And a confirmation response that long-polling should be initiated:

    [{"channel": "/meta/connect", "successful": true, "clientId": "NNR2BOeRyCVKjLN", "error": "", "timestamp"
    : "2008-10-22 01:59:27", "connectionId": "null", "advice": {"interval": 500, "multiple-clients": false
    }}]

    Which results in an immediate call to the server:

    [{"channel":"/meta/connect","connectionType":"long-polling","clientId":"lMRDFU5fBxnE5kg","id":"3"}]

    The response either times out on the server after about 80 seconds or returns if there is an event that the client has subscribed to sooner.  Then the process simply repeats.  Here is the response after a timeout.

    [{"channel": "/meta/connect", "successful": true, "clientId": "lMRDFU5fBxnE5kg", "error": "", "timestamp"
    : "2008-10-22 02:15:57", "connectionId": "null", "advice": {"reconnect": "retry", "interval": 500, "multiple-clients"
    : false}}]

    This causes the connect message to be sent again.  Firebug shows me the spinning request (see the last POST) indicating that it is waiting for the server response, and I know that it's working.  And the world is right again.  A helpful diagram showing how some of the various delivery methods work for this is on Carol McDonald's blog.

    spin

    October 20, 2008

    Real-time Updates on WebPages - Part 2 - Hello World Comet Application

    Overview

    *10/21/2008 Update* I mention in this post that I had an issue with Dojo 1.2.0, well I figured it out, read Part 3 for details.

    Last week I wrote about the introduction of a HTTP Publish-Subscribe Server in WebLogic Server 10gR3.  The new feature is based on the concept of Comet and implements the Bayeux protocol and is very useful for publishing events immediately to subscribed clients over HTTP.  There are many uses for a feature like this, essentially any time where stale information should be updated on a web page as soon as possible.  This entry will showcase a basic Hello World example application that will demonstrate the basic mechanics for using this feature.  Click the image to enlarge and get a better look at the application.

    helloJames

    Pre-reqs

    Dev Tools - I built this example with Oracle Enterprise Pack for Eclipse 1.0.0, the Eclipse 3.4 version, which you can download here.  If you just want to deploy the WAR file, then you can skip this.

    Application Server - You will need WebLogic Server 10gR3.

    Browser Debugging  - You must have Firebug for Firefox if you spend any time doing web development.  I insist.

    Javascript Framework - It's also probably not a good idea for me to include Dojo Toolkit source with my example without getting approval, so grab a copy of that too.  I used version 1.1.1 because 1.2.0 was not out last week and more importantly when I tried 1.2.0 tonight, I got the error message below which leads me to believe there is a compatibility issue with 1.2.0 and the Bayeux implementation on WLS.  More to come when I figure this out.  I see that Dojo 1.2.0 version supports an additional connection type that WLS's pubsub server doesn't accept currently.  The bottom line is use Dojo 1.1.1 for now.

    *10/21/2008 Update* I mention in this post that I had an issue with Dojo 1.2.0, well I figured it out, read Part 3 for details.

    [{"channel": "/meta/handshake", "successful": false, "error": "402:long-polling-json-encoded:Invalid
    
    

    supportedConnectionTypes attribute.", "supportedConnectionTypes": ["long-polling","callback-polling"

    ], "version": "1.0", "minimumVersion": "0.1", "advice": {"reconnect": "none", "interval": 500, "multiple-clients"

    : false}}]


    Server-side

    The example consists of server-side components that simply requires editing two deployment descriptor files in your web application's WEB-INF folder.  The typical steps section of the documentation are pretty clear.  In your weblogic.xml file, add a reference to the pubsub library, which will cause WLS to merge the files in the pubsub library with your application at runtime.  Here is the simplest that file could look:

    <?xml version="1.0" encoding="UTF-8"?>
    <weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/90"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <library-ref>
            <library-name>pubsub</library-name>
            <specification-version>1.0</specification-version>   
        </library-ref>        
    </weblogic-web-app>

    Secondly, you will need a weblogic-pubsub.xml file.  Below is the simple one for my sample application.  Notice the channel pattern definition, which is concept very similar to a Topic in JMS, except that there is also pattern matching.  There are also some configuration constraints for the channel pattern.

    <?xml version="1.0" encoding="UTF-8"?>
    <wlps:weblogic-pubsub
        xmlns:wlps="http://www.bea.com/ns/weblogic/weblogic-pubsub">
     
      <wlps:channel>
        <wlps:channel-pattern>/hello/**</wlps:channel-pattern>
        <!--since no handler defined, the default handler will be used -->
      </wlps:channel>  
      
      <wlps:channel-constraint>
        <wlps:channel-resource-collection>
          <wlps:channel-resource-name>subscribe</wlps:channel-resource-name>
          <wlps:description>subscribe channel constraint</wlps:description>
          <wlps:channel-pattern>/hello/*</wlps:channel-pattern>
          <wlps:channel-operation>subscribe</wlps:channel-operation>
          <wlps:channel-operation>create</wlps:channel-operation>
          <wlps:channel-operation>publish</wlps:channel-operation>
        </wlps:channel-resource-collection>
      <!-- Open this up for all users, if this section is enabled, web users will need to authenticate
        <wlps:auth-constraint>
          <!- allow only user with "subscriber" role to subscribe to above channels ->
          <wlps:role-name>subscriber</wlps:role-name>
        </wlps:auth-constraint>
       -->
      </wlps:channel-constraint>

    Client-side

    The simple.jsp that is included with my project showcases the most basic example of Dojo client API.  For additional functionality, look at the source of index.jsp.  Both of these files just as easily could be html files instead of jsp.

    <html>
      <head>
        <!-- Import Dojo -->
        <script type="text/javascript" src="dojo-release-1.1.1/dojo/dojo.js"
            djConfig="parseOnLoad:true, isDebug:true"></script>
    
    

    <script type="text/javascript">
    dojo.require("dojox.cometd");
    dojox.cometd.init("cometd");
    dojox.cometd.subscribe('/hello/world', function(msg) { alert(msg.data.test); } );

    </script>
    </head>
    <body>
    <input type="button"
    onclick="dojox.cometd.publish('/hello/world', { test: 'hello world' } )"
    value="Click Me!">
    </body>
    </html>


    Run it

    Below are the steps for OEPE/Eclipse, if you just would rather work with the war file, download CometWEB.war, add Dojo 1.1.1 as described in step 3, and deploy to the server.

    1. Download my CometWEB project archive
    2. Import the archive into OEPE as an existing project.
    3. Put Dojo 1.1.1 in the web application so that the path to dojo looks like CometWEB\WebContent\dojo-release-1.1.1\dojo\dojo.js
    4. Deploy to WLS 10.3, I used the samples domain <WEBLOGIC_INSTALLATION>\wlserver_10.3\samples\domains\wl_server
    5. Go to your URL, on my configuraiton it is: http://localhost:7001/CometWEB/index.jsp

    Try it in multiple browsers at the same time and publish messages to one another.  Use Firebug to see what is going on in the network traffic between the server and the client.  In future posts I plan on showing some of the protocol and discussing more advanced enterprise features like JMS integration and security.