Worklist moving to java.net

A quick update for those who are interested in the custom BPM worklist sample.  As our previous Subversion host is not going to be able to continue to provide that service, we have moved the sample to java.net.  All download links and Subversion details have been updated in the main worklist page.

Posted in Uncategorized | Tagged | Leave a comment

Setting up Process Portal

My colleague George posted an article on configuring the BPM Process Portal on WebCenter 11.1.1.5 here.

Posted in Uncategorized | Tagged , , | Leave a comment

BPM 10g Performance Tuning Whitepaper published

My colleague Sushil Shukla and I have just published our BPM 10g Performance Tuning whitepaper on the Oracle BPM website, you can access the PDF directly here.

The whitepaper covers topics like:

  • Environment considerations
  • Application design considerations
  • Tuning the BPM Engine
  • Tuning the Directory Service
  • Tuning the PAPI Instance Cache
  • Testing
  • JVM Tuning
  • WebLogic Server Considerations
  • Database Tuning

We would like to acknowledge the assistance of many people from the BPM development team, and from a number of our customers who reviewed this document and gave valuable feedback.  Thank you all, you know who you are.

P.S.:  We have an 11g version under development for our 11g readers.

Posted in Uncategorized | Tagged , , , , | Leave a comment

Mobile worklist

Inspired by a comment from Flávio Fonseca, I decided to experiment with making the worklist render for a mobile device using JQuery Mobile.

Turns out it is pretty easy to do.  All I did was change the style sheets and the head.jspf and tail.jspf files to slightly alter the HTML around the pages.  I introduced a new variable to remember whether we are in mobile mode or not, and a couple of menu items to switch between the two.  The new MobileController is responsible for the flip/flop.

All the code is in Subversion if you want to take a look.  Here are a few screen shots from a 7″ Samsung Galaxy Tablet (Android 2.1) emulator.  I did not do anything to make it look nicer – note that the buttons/drop down select boxes are not really well formatted.  JQuery Mobile will make this look nice on a whole range of mobile devices including Android and iOS devices.

The Task List:

Task Details page:

Choosing an action to take on a task:

Comments on a task:

The ‘loading’ animation between pages:

The process instance details page:

The process audit image:

Enjoy!

Posted in Uncategorized | Tagged , , | 9 Comments

Introduction to the Sales Order Entry application

This post is part of a series on building a modern web-based interface for E-Business Suite using Oracle ADF with Oracle Service Bus providing services between EBS and the front end.

Our (imaginary) client wants a new, modern, web-based Sales Order Entry application.  It needs to integrate with Oracle E-Business Suite R12.  It also needs to have good performance.  It will be used in many branches, spread right across the country.  Some of these branches have fast dedicated connections, but some are using slower connection speeds.

The majority of customers who come to branches are account customers, who place an order against their account and will be invoiced after the time of sale.

The application will allow the creation and entry of Sales Orders.  All lookup fields, e.g. Customer Name, Address, Product Details, etc., are fetched from Oracle E-Business Suite and presented to the user in a “auto-suggest” drop down when they start typing in the fields.

User Interface

When a user connects to the Sales Order Entry system, they will be presented with the main screen (see below).

From this screen, the user can select to:

  • Create a new Sales Order,
  • Search for (and modify) an existing Sales Order, or
  • Lookup Product Details.

If the user selects Create a new Sales Order, they are sent to the Sales Order Entry screen (see below).  This screen is the heart of the application.  It is where the user will enter details of the Sales Order.

The top half of the screen is to do with the Sales Order Header.  It includes details about the customer, ship to and bill to addresses, the sales person, freight charges, delivery dates and so on.

The lower half of the screen contains the Lines that make up the Sales Order.  Users can add additional lines, or remove lines if they wish to.  Each line contains details about the product, quantity, pricing, requested and promised shipping details and so on.

Many of the fields on this screen will have “auto suggest” behaviour.  This means that suitable values will be suggested to the user in a drop down box as they type data into the field, as shown below.  As more data is typed into the field, the list of suggestions is dynamically adjusted.  This kind of behaviour is commonly seen on web sites today, for example Google use it on their main search page.

The user should complete the top half of the page, then select Save from the Order menu.  At this point, a Sales Order Header should be created in Oracle E-Business Suite.  The user will then add lines to the Sales Order.  When they are done, they will select Book from the Order menu.  At this point, the Sales Order Lines should be created in Oracle E-Business Suite and the Sales Order should be booked.

Integration with Oracle E-Business Suite

There are several points of integration with Oracle E-Business Suite required for this application.  These are listed below.   As part of the example, you will be figuring out how to go about doing this integration.

E-Business Suite Integration Requirements

Reference E-Business Suite object How used

1

Customer Account The customer field in the Sales Order Header is populated from the Customer Accounts.

2

Site The Ship To and Bill To fields in the Sales Order Header are populated from the Sites.

3

Sales Person The Sales Person field in the Sales Order Header is populated from the Sales People.

4

Item The Part Number, Unit of Measure and other fields are populated from the Item Master.

5

Price The Price is obtained from E-Business Suite to ensure all of the pricing rules, discounts, agreements, etc. are applied.   Note that the Price for an Item depends on the Customer and the Order Date.

6

Sales Order Header The details entered in the User Interface are used to create the Sales Order Header in E-Business Suite.  The order will be created and booked based on various actions in the User Interface.

7

Sales Order Line The details entered in the User Interface are used to create Sales Order Lines in E-Business Suite.

8

Organisation The Branch is populated from the Organisations.

Oracle Service Bus Requirements

There are two key requirements to be addressed by the Oracle Service Bus in this project:

  1. Hide the complexity of the E-Business Suite interfaces.
    Many of the interfaces that you will need to use are complex, have many input and output parameters, several layers of structure, and in some cases you may need to call more than one interface to get the data you need.  You should use the Oracle Service Bus to hide all of this complexity from the User Interface developer, and present nice, clean services to them for use in building the User Interface.
  2. Improve performance by caching frequently used data.
    Oracle Service Bus 11g introduced a feature called Service Result Caching which allows you to easily cache the results of a service call for later use.  You should use this feature to improve the performance of your services and therefore the User Interface as well.

What you will need to build the example

To build the example, you will need the following:

  • Oracle E-Business Suite R12.1 with the 12.1.3 patch installed and Integrated SOA Gateway enabled, plus some data.  We used and recommend the ‘Vision’ database that comes with the Rapid Install Wizard.
  • Oracle Service Bus 11.1.1.3 or later – we used 11.1.1.5.  This installation will include Oracle WebLogic Server and ADF.
  • Oracle JDeveloper 11.1.1.3 or later – we used 11.1.1.5 – for building the ADF application.

We ran all of this in a VM running Oracle Linux 5.5.  Everything is 64-bit.

The next post in this series (coming soon) will discuss how we find and expose the necessary functionality in E-Business Suite.

Acknowledgements

This example builds on work done by many people over a period of time.  I woudl like to acknowledge the contribution of the following people (in alphabetical order): Jasper Chu, John Graves, Victor Luo, Pieter Malan, Tanya Williams, Devon Winkworth, Joey Wong, Brenda Yin, Raymond Zhang and Rade Zheng.

Posted in Uncategorized | Tagged , , | Leave a comment

Introductory presentation on custom worklist

Last week, I did a presentation at the InSync11 conference which is organised by Oracle User Groups that provided an overview of the custom worklist sample.  I am sharing the presentation material here for those who may be interested but were not able to attend the conference.

Posted in Uncategorized | Tagged | 2 Comments

Installer cannot access the oraInventory

Ran into another interesting little challenge today.  While installing SOA Suite onto a machine which already had another, completely separate Oracle product installation on it (albeit under a different userid), the installer helpfully reported that it could not access /home/oracle/oraInventory.

To get around this, I went and copied the /etc/oraInst.loc file to /etc/fmwInst.loc and updated the contents to point to a new directory in my ‘fmw’ user’s home directory, and then ran the installer with the option to point to this new file:

runInstaller -invPtrLoc /etc/fmwInst.loc
Posted in Uncategorized | Tagged , , | Leave a comment

RCU cannot connect to database with SYS user

Today I found an interesting little issue when trying to use RCU to create schemas for a middleware installation.  RCU could not connect to the database with the SYS user.  I could connect with other users, like SYSTEM for example, and I had the password correct.

Turns out the database in question did not have an Oracle password file.  You can check this by using the following query, which should return a row for SYS:

SQL> select * FROM v$pwfile_users;

no rows selected

As it did not, the solution was the create the password file, as follows:

[oracle@ebs ~]$ orapwd file=/oracle/VIS/db/tech_st/11.1.0/dbs/orapwVIS
Posted in Uncategorized | Tagged | Leave a comment

Getting started with Continuous Integration for OSB

As a first step towards including Oracle Service Bus projects into our Continuous Integration environment, let’s look at how to script exporting some project(s) from Oracle Enterprise Pack for Eclipse (the IDE for OSB) and deploying those project(s) to an OSB server.  Later, we will include this into the Maven/Hudson environment we have been constructing in this series of posts on continuous integration.

Here is our script, right up front, then we will discuss it:

@echo Export project from eclipse
java ^
  -Dweblogic.home=c:\oracle\middleware\wlserver_10.3 ^
  -Dosb.home=c:\oracle\middleware\Oracle_OSB1 ^
  -Dosgi.bundlefile.limit=500 ^
  -Dharvester.home=c:\oracle\middleware\Oracle_OSB1\harvester ^
  -Dosgi.nl=en_US ^
  -Dsun.lang.ClassLoader.allowArraySyntax=true ^
  -jar c:\Oracle\OEPE\oepe_11gR1PS4\plugins\org.eclipse.equinox.launcher_1.1.1.R36x_v20101122_1400.jar ^
  -data c:\src\osb\notsvn ^
  -application com.bea.alsb.core.ConfigExport ^
  -configProject "OSB Configuration 1" ^
  -configJar c:\src\osb\test_sbconfig.jar ^
  -configSubProjects "OSB Project 1" ^
  -includeDependencies true

@echo Deploy 'import' to Service Bus
c:\oracle\middleware\oracle_common\common\bin\wlst import.py import.properties

First of all, if you have not seen them before, the ‘^’ is a continuation character in Windows CMD files, such as this one, so that we can spread a command over many lines in our script, but it is executed as if it were all typed in on a single line.

This script has not been made generic yet – it has a bunch of stuff hardcoded.  Let’s take a look.

First, we run java with a bunch of properties.  You will need to set weblogic.home, osb.home and harvester.home to suit your environment.  You can just include the others as they are.

Following the properties, you see we point to a JAR file, this allows us to run eclipse in headless mode.  The remainder of the parameters are passed to eclipse.  You can see we need to specify the location of the workspace to use (in data) – this can also be the Subversion trunk (or similar).  The application tells it to run the OSB exporter.

The other important parameters are configProject which names the OSB Configuration project in the workspace you want to use, configSubProjects which is a comma separated list of the OSB projects you want to export, and configJar which is the name of the JAR file you want to create.

If you want to know more about this command, take a look in the online help in your OSB IDE.  Look under the OSB help topic, then ‘Tasks,’ ‘Working with projects, folders, resources & configurations,’ ‘exporting resources,’ ‘using command line,’ and then the ANT topic.

When this command has run, we will have an OSB configuration JAR file (test_sbconfig.jar in this case) which is ready to import into (deploy to) an OSB server.

The second part is to perform the deployment (import).  We will do this using a WLST script from Oracle, import.py (see below).  This script also expects a properties file.  We need to set up some details in the properties file so the script knows what to do.

Let’s take a look at the properties file:

##################################################################
# OSB Admin Security Configuration                              #
##################################################################
adminUrl=t3://localhost:7001
importUser=weblogic
importPassword=welcome1

##################################################################
# OSB Jar to be exported, optional customization file           #
##################################################################
importJar=test_sbconfig.jar
#customizationFile=OSBCustomizationFile.xml

##################################################################
# Optional passphrase and project name                           #
##################################################################
#passphrase=osb
#project=default

You can see we have provided the URL for the Administration Server, and also the name of the OSB configuration JAR file (that we just created in the previous step).

Here is the import.py sciript that WLST will run:

from java.util import HashMap
from java.util import HashSet
from java.util import ArrayList
from java.io import FileInputStream

from com.bea.wli.sb.util import Refs
from com.bea.wli.config.customization import Customization
from com.bea.wli.sb.management.importexport import ALSBImportOperation

import sys

#=======================================================================================
# Entry function to deploy project configuration and resources
#        into a ALSB domain
#=======================================================================================

def importToALSBDomain(importConfigFile):
    try:
        SessionMBean = None
        print 'Loading Deployment config from :', importConfigFile
        exportConfigProp = loadProps(importConfigFile)
        adminUrl = exportConfigProp.get("adminUrl")
        importUser = exportConfigProp.get("importUser")
        importPassword = exportConfigProp.get("importPassword")

        importJar = exportConfigProp.get("importJar")
        customFile = exportConfigProp.get("customizationFile")

        passphrase = exportConfigProp.get("passphrase")
        project = exportConfigProp.get("project")

        connectToServer(importUser, importPassword, adminUrl)

        print 'Attempting to import :', importJar, "on ALSB Admin Server listening on :", adminUrl

        theBytes = readBinaryFile(importJar)
        print 'Read file', importJar
        sessionName = createSessionName()
        print 'Created session', sessionName
        SessionMBean = getSessionManagementMBean(sessionName)
        print 'SessionMBean started session'
        ALSBConfigurationMBean = findService(String("ALSBConfiguration.").concat(sessionName), "com.bea.wli.sb.management.configuration.ALSBConfigurationMBean")
        print "ALSBConfiguration MBean found", ALSBConfigurationMBean
        ALSBConfigurationMBean.uploadJarFile(theBytes)
        print 'Jar Uploaded'

        if project == None:
            print 'No project specified, additive deployment performed'
            alsbJarInfo = ALSBConfigurationMBean.getImportJarInfo()
            alsbImportPlan = alsbJarInfo.getDefaultImportPlan()
            alsbImportPlan.setPassphrase(passphrase)
            alsbImportPlan.setPreserveExistingEnvValues(true)
            importResult = ALSBConfigurationMBean.importUploaded(alsbImportPlan)
            SessionMBean.activateSession(sessionName, "Complete test import with customization using wlst")
        else:
            print 'ALSB project', project, 'will get overlaid'
            alsbJarInfo = ALSBConfigurationMBean.getImportJarInfo()
            alsbImportPlan = alsbJarInfo.getDefaultImportPlan()
            alsbImportPlan.setPassphrase(passphrase)
            operationMap=HashMap()
            operationMap = alsbImportPlan.getOperations()
            print
            print 'Default importPlan'
            printOpMap(operationMap)
            set = operationMap.entrySet()

            alsbImportPlan.setPreserveExistingEnvValues(true)

            #boolean
            abort = false
            #list of created ref
            createdRef = ArrayList()

            for entry in set:
                ref = entry.getKey()
                op = entry.getValue()
                #set different logic based on the resource type
                type = ref.getTypeId
                if type == Refs.SERVICE_ACCOUNT_TYPE or type == Refs.SERVICE_PROVIDER_TYPE:
                    if op.getOperation() == ALSBImportOperation.Operation.Create:
                        print 'Unable to import a service account or a service provider on a target system', ref
                        abort = true
                elif op.getOperation() == ALSBImportOperation.Operation.Create:
                    #keep the list of created resources
                    createdRef.add(ref)

            if abort == true :
                print 'This jar must be imported manually to resolve the service account and service provider dependencies'
                SessionMBean.discardSession(sessionName)
                raise

            print
            print 'Modified importPlan'
            printOpMap(operationMap)
            importResult = ALSBConfigurationMBean.importUploaded(alsbImportPlan)

            printDiagMap(importResult.getImportDiagnostics())

            if importResult.getFailed().isEmpty() == false:
                print 'One or more resources could not be imported properly'
                raise

            #customize if a customization file is specified
            #affects only the created resources
            if customFile != None :
                print 'Loading customization File', customFile
                print 'Customization applied to the created resources only', createdRef
                iStream = FileInputStream(customFile)
                customizationList = Customization.fromXML(iStream)
                filteredCustomizationList = ArrayList()
                setRef = HashSet(createdRef)

                # apply a filter to all the customizations to narrow the target to the created resources
                for customization in customizationList:
                    print customization
                    newcustomization = customization.clone(setRef)
                    filteredCustomizationList.add(newcustomization)

                ALSBConfigurationMBean.customize(filteredCustomizationList)

            SessionMBean.activateSession(sessionName, "Complete test import with customization using wlst")

        print "Deployment of : " + importJar + " successful"
    except:
        print "Unexpected error:", sys.exc_info()[0]
        if SessionMBean != None:
            SessionMBean.discardSession(sessionName)
        raise

#=======================================================================================
# Utility function to print the list of operations
#=======================================================================================
def printOpMap(map):
    set = map.entrySet()
    for entry in set:
        op = entry.getValue()
        print op.getOperation(),
        ref = entry.getKey()
        print ref
    print

#=======================================================================================
# Utility function to print the diagnostics
#=======================================================================================
def printDiagMap(map):
    set = map.entrySet()
    for entry in set:
        diag = entry.getValue().toString()
        print diag
    print

#=======================================================================================
# Utility function to load properties from a config file
#=======================================================================================

def loadProps(configPropFile):
    propInputStream = FileInputStream(configPropFile)
    configProps = Properties()
    configProps.load(propInputStream)
    return configProps

#=======================================================================================
# Connect to the Admin Server
#=======================================================================================

def connectToServer(username, password, url):
    connect(username, password, url)
    domainRuntime()

#=======================================================================================
# Utility function to read a binary file
#=======================================================================================
def readBinaryFile(fileName):
    file = open(fileName, 'rb')
    bytes = file.read()
    return bytes

#=======================================================================================
# Utility function to create an arbitrary session name
#=======================================================================================
def createSessionName():
    sessionName = String("SessionScript"+Long(System.currentTimeMillis()).toString())
    return sessionName

#=======================================================================================
# Utility function to load a session MBeans
#=======================================================================================
def getSessionManagementMBean(sessionName):
    SessionMBean = findService("SessionManagement", "com.bea.wli.sb.management.configuration.SessionManagementMBean")
    SessionMBean.createSession(sessionName)
    return SessionMBean

# IMPORT script init
try:
    # import the service bus configuration
    # argv[1] is the export config properties file
    importToALSBDomain(sys.argv[1])

except:
    print "Unexpected error: ", sys.exc_info()[0]
    dumpStack()
    raise

You need to put the original script, import.py and import.properties all in to the same directory.  Now you can run our original script and it will perform the export from eclipse and the deployment to OSB.

In a future post, we will be parameterizing this and folding it into our Hudson/Maven oriented continuous integration environment.

Posted in Uncategorized | Tagged , | 5 Comments

SOA Quickstart Guide

Our Product Management team have released an updated verison of the SOA Quickstart Guide, which is available here.

Posted in Uncategorized | Tagged | Leave a comment