Visual Web Pack Tip: Using Data Providers with (Open ESB) Web Services

Following on from a previous article I decided it would be time to expand on the concept of linking Data Providers to Web Services and how / when they are called within your Visual Web Pack (VWP) pages. In addition to this I have upgraded the backend project from the previous Java CAPS eInsight implementation to an Open ESB implementation  and will also described how this has been built.

Resources
Open ESB Backend Project

The aim of the backend Open ESB project is to simply wrap a series of database queries and present them as Web Services. The backend database that will be used is the TRAVEL database shipped with the standard NetBeans installation. To facilitate this we will need to create the following projects:
  1. SQL Application
  2. BPEL Module
  3. Composite Application
The SQL Application and the BPEL Module are available for download but they can be created as follows.

SQL Application
  1. Create a New Project->SOA->SQL Module (or New Project->CAPS->ESB->SQL Module) and name it BlogTravelSQLApp.
  2. Edit the connectivityinfo.xml to match the following:

        <connection>
          <database-url value='jdbc:derby://localhost:1527/travel'/>
          <jndi-name value='jdbc/BlogDerbyTravel'/>   
          <transaction-required value=''/>   
        </connection>

  3. Create a new SQL File (New->Other->SOA->SQL File) and add the following query:

    select \* from TRAVEL.TRIP WHERE PERSONID = ?

  4. Create a second SQL File and add the following query:

    select \* from TRAVEL.PERSON WHERE PERSONID > ?

  5. Right Click on the project and choose Generate WSDL. This will generate a WSDL based on the queries and that can then be used within the BPEL Module.
    Note: In the version of the SQL SE that is available at the time of publishing this blog entry you will need to modify the generated WSDL because it will generate two global definitions for an element called record and the return for each of the queries will reference the global record. The net result of this is that one of the response definitions is incorrect. The resolution to this is to convert the definitions to the in-line style as follows:

                <xsd:element name="PersonSelectResponse">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="record" maxOccurs="unbounded">
                                <xsd:complexType>
                                    <xsd:sequence>
                                        <xsd:element name="PERSONID" type="xsd:int"/>
                                        <xsd:element name="NAME" type="xsd:string"/>
                                        <xsd:element name="JOBTITLE" type="xsd:string"/>
                                        <xsd:element name="FREQUENTFLYER" type="xsd:short"/>
                                        <xsd:element name="LASTUPDATED" type="xsd:string"/>
                                    </xsd:sequence>
                                </xsd:complexType>
                            </xsd:element>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>

                <xsd:element name="TripSelectByPersonIdResponse">
                    <xsd:complexType>
                        <xsd:sequence>
                            <xsd:element name="record" maxOccurs="unbounded">
                                <xsd:complexType>
                                    <xsd:sequence>
                                        <xsd:element name="TRIPID" type="xsd:int"/>
                                        <xsd:element name="PERSONID" type="xsd:int"/>
                                        <xsd:element name="DEPDATE" type="xsd:string"/>
                                        <xsd:element name="DEPCITY" type="xsd:string"/>
                                        <xsd:element name="DESTCITY" type="xsd:string"/>
                                        <xsd:element name="TRIPTYPEID" type="xsd:int"/>
                                        <xsd:element name="LASTUPDATED" type="xsd:string"/>
                                    </xsd:sequence>
                                </xsd:complexType>
                            </xsd:element>
                        </xsd:sequence>
                    </xsd:complexType>
                </xsd:element>


  6. Clean and Build the project.
BPEL Module
  1. Create a new BPEL Module (New->SOA->BPEL Module) and name it BlogTripBpelModule.
  2. Import the attached WSDL.
  3. Create a new BPEL Process (TripService.bpel) below.

    Trip Service BPEL

    1. This process can be created by Dragging the imported TripService.wsdl onto the left hand inbound service part of the canvas and creating the appropriate Wrapper WSDL. This will be prompted for just change the Wrapper so that this BPEL process provides the service.
    2. Drag the Generated WSDL from the BlogTravelSQLApp onto the right portion of the canvas to create the called services. This will create a project link to the BlogTravelSQLApp.wsdl in the BlogTravelSQLApp project rather than copying the file.
    3. Drag a pick onto the canvas and set the Create Instance property to true.
    4. Link the On Message to the Inbound List Trips Operation and create the default Variable.
    5. Add and Assign, Invoke, ForEach and reply to the On Message Sequence.
    6. Link the Invoke to the TripSelect Operation and create the default variables.
    7. Link the Reply to the Inbound List Trips Operation and create the default Variable.
    8. The ForEach should be configured as follows:

      List Trip ForEach

    9. Drag and Assign within the ForEach and create Predicates for the TripSelectByPersonIdOut-TripSelectByPersonIdResponse-record based on the ForEach Counter.Repeat for the ListTripOut-result-trip.

      ForEach

    10. Add a new On Message and repeat the process for the ListPerson operation. On the Assign we will pass 0 into the PersonSelectIn parameter.
  4. Save, Clean and Build.
Composite Application
  1. Create a new Composite Application (New->SOA->Composite Application) and name it BlogTravelCompositeApp.
  2. Add the JBi Modules BlogTravelSQLApp and BlogTripBpelModule.
  3. Clean and Build
  4. Edit the Service Assembly and connect the SQLPartnerLink to the SQL Application

    Service Assembly

  5. Clean and Build / Deploy
  6. Create some Test cases for the List Trips and List Person Operations within the BlogTripBPELModule and execute.
We now have a working backend process that will supply Trip and person data from the JavaDB TRAVEL database using Web Services. We will now create a VWP Project and link it to these web services.

Visual Web Pack Project

Before we start to build the VWP Pages we need to import the Web Service(s) that we created into Visual Web Pack and this is done as follows:
  1. Select Sevices Tab
  2. Select Web Services
  3. Right-Click on the Web Services Tree Node and create a new Group called Blog (this is only for grouping and keeping you tree structure tidy).
  4. Right-Click on Blog and select Add Web Service
  5. Select the TripService.wsdl File and import.

    Add Web Service

  6. This will build a local jar associated with the Web Service and you will notice that the all the operations are defined and available  although we will not use all of them. Because the initial WSDL contained all the definitions we do not need to import both sets of WSDL we previously created.

    Imported WSDL
Now that we have import the WSDL we can create the VWP Project that will use the previously created Web Service. This implementation / usage is the crux of this blog and I intend to go into detail on some of the processing functionality behind the VWP page.
  1. Create a new Web Application (use Visual Web Java Server Faces) called BlogTravelWeb Application
  2. Rename the default Page1 to TripListPage
    1. Add a Label, Drop Down (personDD) and Table (tripTable) to the Page

      Basic Page

  3. Drag the ListPersons Operation onto the Person Drop-Down (personDD).
  4. Right-Click Person Drop-Down and select Bind to Data and configure as below.

    Person Drop-Down

  5. Right-Click on the Person Drop Down and select "Add Binding Attribute"
  6. Right-Click on the Person Drop Down and select "Auto Submit on Change"
  7. Drag the ListTrips onto Trip Table
  8. Drag the TripPort onto the canvas and then change the tripPortListTrips1 tripPortClient to match the newly created tripPortClient2
  9. Right-Click on the Table and select Table Layout.
  10. Edit to match the following adding a new column for the details button.

    Table Layout

  11. Add the following Properties to the SessionBean
    1. String personName
    2. String depDate
    3. String depCity
    4. String destCity
  12. Double Click the Details Button to open the Java Source and create the action method and Add the following code.

        public String button1_action() {
            getSessionBean1().setDepDate((String) getValue("#{currentRow.value['depdate']}"));
            getSessionBean1().setDepCity((String) getValue("#{currentRow.value['depcity']}"));
            getSessionBean1().setDestCity((String) getValue("#{currentRow.value['destcity']}"));
            getSessionBean1().setPersonName(personDD.getSelected().toString());
            return null;
        }

  13. Create a Second Page (TripDetailsPage) as below.

    Trip Details

  14. For each of the Static Text Fields (abc) Right Click and Bind to the appropriate SessionBean Property.
  15. Right-Click on the Canvas and select Page Navigation. Link the Pages as below:

    Page Navigation

  16. Add comment similar to those below to the init(), prerender() and preprocess() methods.
            log ("\*\*\* APH-I1 : preprocess() START");
            log ("\*\*\* APH-I1 : preprocess() END");

We will now attempt to run the Web Application (tailing the log file will help). When we do this you will notice that the resulting Web Page does not display the Table and this is due to the associated DataProvider failing to retrieve the information from the Web Service because it failed. What you will see is something similar to the following in the server.log.

[#|2008-07-03T13:28:59.750+0100|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=59;_ThreadName=httpSSLWorkerThread-8080-0;|PWC1412: WebModule[/BlogTravelWebApplication] ServletContext.log():\*\*\* APH-I1 : init() START|#]
[#|2008-07-03T13:28:59.765+0100|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=59;_ThreadName=httpSSLWorkerThread-8080-0;|PWC1412: WebModule[/BlogTravelWebApplication] ServletContext.log():\*\*\* APH-I1 : init() END|#]
[#|2008-07-03T13:28:59.765+0100|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=59;_ThreadName=httpSSLWorkerThread-8080-0;|PWC1412: WebModule[/BlogTravelWebApplication] ServletContext.log():\*\*\* APH-I1 : prerender() START|#]
[#|2008-07-03T13:28:59.765+0100|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=59;_ThreadName=httpSSLWorkerThread-8080-0;|PWC1412: WebModule[/BlogTravelWebApplication] ServletContext.log():\*\*\* APH-I1 : prerender() END|#]
[#|2008-07-03T13:28:59.796+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundReceiver|_ThreadID=25;_ThreadName=Thread-66;|Accepted the message in JDBC Binding. 105590275865051-59129-134343809397960110|#]
[#|2008-07-03T13:28:59.796+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundMessageProcessor|_ThreadID=60;_ThreadName=Thread-1806;105590275865051-59129-134343809397960110;|Accepted message with exchange ID 105590275865051-59129-134343809397960110 in JDBC outbound message processor.|#]
[#|2008-07-03T13:28:59.796+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundMessageProcessor|_ThreadID=60;_ThreadName=Thread-1806;105590275865051-59129-134343809397960110;|Accepted message with exchange ID 105590275865051-59129-134343809397960110 in JDBC outbound message processor.|#]
[#|2008-07-03T13:28:59.796+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundMessageProcessor|_ThreadID=60;_ThreadName=Thread-1806;105590275865051-59129-134343809397960110;http://www.w3.org/2004/08/wsdl/in-out;|Pattern for exchange Id 105590275865051-59129-134343809397960110 is http://www.w3.org/2004/08/wsdl/in-out.|#]
[#|2008-07-03T13:28:59.796+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundMessageProcessor|_ThreadID=60;_ThreadName=Thread-1806;105590275865051-59129-134343809397960110;|Received in-out message 105590275865051-59129-134343809397960110.|#]
[#|2008-07-03T13:28:59.796+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundMessageProcessor|_ThreadID=60;_ThreadName=Thread-1806;Context=context;|Executing SQL....select \* from TRAVEL.PERSON WHERE PERSONID > ?|#]
[#|2008-07-03T13:28:59.812+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.JDBCNormalizer|_ThreadID=60;_ThreadName=Thread-1806;[#document: null];Context=context;|normalized message|#]
[#|2008-07-03T13:28:59.812+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundReceiver|_ThreadID=25;_ThreadName=Thread-66;|Accepted the message in JDBC Binding. 105590275865051-59129-134343809397960110|#]
[#|2008-07-03T13:28:59.812+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundMessageProcessor|_ThreadID=61;_ThreadName=Thread-1807;105590275865051-59129-134343809397960110;|Accepted message with exchange ID 105590275865051-59129-134343809397960110 in JDBC outbound message processor.|#]
[#|2008-07-03T13:28:59.812+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundMessageProcessor|_ThreadID=61;_ThreadName=Thread-1807;105590275865051-59129-134343809397960110;|Accepted message with exchange ID 105590275865051-59129-134343809397960110 in JDBC outbound message processor.|#]
[#|2008-07-03T13:28:59.812+0100|INFO|sun-appserver9.1|sun-sql-engine.com.sun.jbi.jdbcbc.OutboundMessageProcessor|_ThreadID=61;_ThreadName=Thread-1807;105590275865051-59129-134343809397960110;http://www.w3.org/2004/08/wsdl/in-out;|Pattern for exchange Id 105590275865051-59129-134343809397960110 is http://www.w3.org/2004/08/wsdl/in-out.|#]
.......

[#|2008-07-03T13:28:59.843+0100|SEVERE|sun-appserver9.1|com.sun.jbi.engine.bpel.core.bpel.util.Utility|_ThreadID=46;_ThreadName=BPELSEInOutThread8;Process Instance Id=192.168.1.11:-458be17d:11ae8978e70:-7ed2;Service Assembly Name=BlogTravelCompositeApp;BPEL Process Name=TripServices;_RequestID=1af7b431-81bb-4dab-8293-58956546bcf4;|I18N: BPCOR-3068: attempt to access the value of an uninitialized variable "ListTripsOut"|#]
[#|2008-07-03T13:28:59.843+0100|WARNING|sun-appserver9.1|com.sun.jbi.engine.bpel.BPELSEHelper|_ThreadID=46;_ThreadName=BPELSEInOutThread8;Process Instance Id=192.168.1.11:-458be17d:11ae8978e70:-7ed2;Service Assembly Name=BlogTravelCompositeApp;BPEL Process Name=TripServices;_RequestID=1af7b431-81bb-4dab-8293-58956546bcf4;|BPJBI-6001:Sending ERROR status (Service Name = {http://enterprise.netbeans.org/bpel/BlogTripBpelModule/TripServices}TripPartnerLink, Endpoint Name = TripManagerRole_myRole, Operation Name = {urn:wsdl:blog:examples.evision:services}ListTrips, Message Exchange Id = 105590275865051-59129-134343809398280111)
 Error properties
  com.sun.jbi.crl.faultcode = Server
  com.sun.jbi.crl.faultstring = BPCOR-6135:A fault was not handled in the process scope; Fault Name is {http://docs.oasis-open.org/wsbpel/2.0/process/executable}uninitializedVariable; Fault Data is null. Sending errors for the pending requests in the process scope before terminating the process instance
  com.sun.jbi.crl.faultactor = sun-bpel-engine
  com.sun.jbi.crl.faultdetail =
   BPCOR-6135:A fault was not handled in the process scope; Fault Name is {http://docs.oasis-open.org/wsbpel/2.0/process/executable}uninitializedVariable; Fault Data is null. Sending errors for the pending requests in the process scope before terminating the process instance
   Caused by: I18N: BPCOR-3068: attempt to access the value of an uninitialized variable "ListTripsOut"
BPCOR-6129:Line Number is 72
BPCOR-6130:Activity Name is ListServicesReply
java.lang.Exception: BPCOR-6135:A fault was not handled in the process scope; Fault Name is {http://docs.oasis-open.org/wsbpel/2.0/process/executable}uninitializedVariable; Fault Data is null. Sending errors for the pending requests in the process scope before terminating the process instance
    at com.sun.jbi.engine.bpel.core.bpel.model.runtime.impl.BPELProcessInstanceImpl.doProcesCompletionTasks(BPELProcessInstanceImpl.java:1174)
    at com.sun.jbi.engine.bpel.core.bpel.model.runtime.impl.BPELProcessInstanceImpl.doResumeAction(BPELProcessInstanceImpl.java:757)
    at com.sun.jbi.engine.bpel.core.bpel.model.runtime.impl.VirtualCatchAllUnit.doResumeAction(VirtualCatchAllUnit.java:112)


This caused because the DataProvider associated with the ListTrips operation has not had its inbound parameter (personId) set and hence the call to the Web Service is invalid. You will notice, from the log comments, that the execution of the DataProvider is done after the completion of the prerender() method so we can assume that if we initialise the Web Service Data Provider within this method it will display correctly. To resolve this issue we will write a new method to set the query parameters and then call this from the prerender() method as follows.

    public void prerender() {
        log ("\*\*\* APH-I1 : prerender() START");
        setQueryParameters();
        log ("\*\*\* APH-I1 : prerender() END");
    }
   
    private void setQueryParameters() {
        String personId = null;
        if (personDD.getSelected() == null) {
            if (tripPortListPersons1.cursorFirst()) {
                personId = tripPortListPersons1.getValue(tripPortListPersons1.getFieldKey("personId")).toString();
            }
        } else {
            personId = personDD.getSelected().toString();
        }
       
        tripPortListTrips1.setPersonId(personId);
    }

Now when re run application we see that the trip data for the first entry in the drop down is displayed.

Trip List

If we now change the Person within the Drop Down you will notice that the Page throws and exception and does not display. If we no return to the log file we can see that this is essentially the same exception thrown earlier although this time the service.log indicates that the prerender() method was not executed.

[#|2008-07-03T14:06:30.203+0100|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=59;_ThreadName=httpSSLWorkerThread-8080-0;|PWC1412: WebModule[/BlogTravelWebApplication] ServletContext.log():\*\*\* APH-I1 : init() START|#]
[#|2008-07-03T14:06:30.203+0100|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=59;_ThreadName=httpSSLWorkerThread-8080-0;|PWC1412: WebModule[/BlogTravelWebApplication] ServletContext.log():\*\*\* APH-I1 : init() END|#]
[#|2008-07-03T14:06:30.203+0100|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=59;_ThreadName=httpSSLWorkerThread-8080-0;|PWC1412: WebModule[/BlogTravelWebApplication] ServletContext.log():\*\*\* APH-I1 : preprocess() START|#]
[#|2008-07-03T14:06:30.203+0100|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=59;_ThreadName=httpSSLWorkerThread-8080-0;|PWC1412: WebModule[/BlogTravelWebApplication] ServletContext.log():\*\*\* APH-I1 : preprocess() END|#]


Instead we see that the preprocess() is executed. We can resolve this by modifying the preprocess() to call the setQueryParameters() method in the same way as the prerender() method. It is therefore important that we understand the call stack based on the actions we take within a page and thus initialise Web Service information s appropriate. To explain this I will use the two following scenarios and hopefully throw some light onto this.
  1. Navigate to the page and then select a new person.
  2. Navigate to the page and select Details.
The methods discussed are by no means all those called behind the scenes but do list those you can edit. Before I do that Double Click on the Person Drop Down to create an action method and add the following code:

    public void personDD_processValueChange(ValueChangeEvent event) {
        log ("\*\*\* APH-I1 : personDD_processValueChange() START");
        setQueryParameters();
        tripPortListTrips1.refresh();
        log ("\*\*\* APH-I1 : personDD_processValueChange() END");
    }


Navigate to Page and Select a Person
  1. http://localhost:8080/BlogTravelWebApplication
    1. init()
    2. prerender()
    3. DataProvider Refreshed.
    4. Page Displayed
  2. New Person Selected From Drop Down.
    1. init()
    2. preprocess()
    3. DataProvider Refreshed.
    4. personDD_processValueChanged()
    5. prerender() - Called because the page is being displayed.
Navigate to Page and Select Details
  1. http://localhost:8080/BlogTravelWebApplication
    1. init()
    2. prerender()
    3. DataProvider Refreshed.
    4. Page Displayed
  2. Details Button
    1. init()
    2. preprocess()
    3. DataProvider Refreshed.
    4. TripDetails Page Displayed
From the above step you may have identified that the init() method is always called and we you may add the call to setQueryParameters() to this method but you can not add the call anywhere within this method. To facilitate the same functionality the code can only be added after the application initialisation is complete (that is to say at the end of this method) as follows:

        // Perform application initialization that must complete
        // \*after\* managed components are initialized
        // TODO - add your own initialization code here
        setQueryParameters();
        log ("\*\*\* APH-I1 : init() END");
    }

Hopefully this short article will give you some insight into how to connect DataProviders with Web Services.


Resources



Comments:

Also I am keep getting ListTripsOut variable uninitialized, but at same time test cases run without any issues. Can you help in debugging the issue.?

Thanks
Raghu

Posted by Raghu on January 16, 2009 at 01:20 PM GMT #

Hello,

I am trying to follow your steps, I did not understand couple of steps

Why do we need to perform step8 and can you elaborate
In step 14 you mentioned to bind the data to respective session property. But when I click to bind I do not see any session data or object to bind.

Thanks
Raghu

Posted by Raghu on January 16, 2009 at 01:21 PM GMT #

Post a Comment:
Comments are closed for this entry.
About

As a member of the Oracle A-Team we specialise in enabling and supporting the Oracle Fusion Middleware communities.

Search

Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today