Skip Headers
Oracle® SOA Suite Developer's Guide
10g (10.1.3.1.0)

Part Number B28764-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

9.6 Collecting Data for Use by a Web Service

In an SOA system, you may need to collect data that will be used by an external application. For example, in the Order Booking system, the SOADEMO-CLIENT application collects customer information, which is then passed to the external customer service application, which, in turn, creates a new customer.

Applications and components within an SOA system must expose public service interfaces, typically using WSDL. The web client may therefore either interact with the application components (via RMI) or with the web service interfaces. When interacting through a web service, you can determine the data that a page may need to collect (for example, the attribute names and types) by using the provided WSDL to create a service proxy to the web service.

If methods on the service take simple data types as parameters, then you can create forms that collect data using ADF data binding, similar to the forms created to display data. First, you create a data control based on the provided WSDL. For the procedure, see Section 5.3.3, "How to Create a Data Control From a Web Service". Then, you drop the method itself (as opposed to the return of a method), to create the input form, as described in the following section.

If a method takes a complex object as a parameter, instead of using ADF data binding, you must create the logic to collect the data and pass it to the service. You add this logic to the page's backing bean. For the procedure, see Section 9.6.3, "How to Invoke a Service Using a Backing Bean".

9.6.1 How to Create an Input Form Using a Web Service Data Control

Instead of dragging a return from a method, as you do to display existing data, you drag the method itself to create a parameterized form.


Note:

You cannot successfully use a data control to create complex objects. For example, to create a Customer object for the Order Booking application, you must also create an Address object. To do this, you must manually invoke the service from a backing bean. For more information, see Section 9.6.3, "How to Invoke a Service Using a Backing Bean".

To create an ADF input form:

  1. Open a JSF page in the visual editor.

  2. From the Data Control Palette, drag the appropriate operation onto the JSF page.

  3. From the context menu, choose Parameters > ADF Parameter Form.

    The Edit Form Fields dialog opens, which allows you to customize the labels, bindings, and UI components before creating the form. JDeveloper automatically adds a command button bound to the method, which will invoke the web service and send the data captured in the form.

9.6.2 What Happens When You Create an ADF Input Form

When you drop an operation as a parameter form, JDeveloper:

  • Defines variables to hold the data values, a method binding for the operation, and the attribute bindings for the associated attributes in the page definition file.

  • Inserts code in the JSF page for the form using ADF Faces inputText components and an ADF Faces command button component. This code is the same as code for any other input form or command button.

When you create a parameter form, JDeveloper creates NamedData elements for each parameter. Because the user will provide the parameter values, each NamedData element is bound to the attribute binding for the corresponding attribute. This binding allows the operation to access the attribute's value for the parameter on execution.

Note that like the attributes for a collection, attributes for a method also reference an iterator. However, instead of referencing a method iterator that accesses and iterates over the collection that the associated method returns, attributes for a creation-type method access and iterate over variables. Because this type of method has not returned an object, there is nothing to hold the values entered on the page. Variables act as the data holders.

JDeveloper creates a variable for each parameter the method takes. The variables are declared as children to the variable iterator, and are local, meaning they "live" only as long as the associated binding context. Example 9-9 shows the variable iterator and variables created when you use the addNewCustomer operation from a data control created from the CustomerSvc WSDL. Note that for the purposes of demonstration, not all attributes were used to create the form.

Example 9-9 Variables and the Variable Iterator

<executables>
  <variableIterator id="variables">
    <variable Type="java.lang.String" Name="addNewCustomer_customer_fname"
              IsQueriable="false"/>
    <variable Type="java.lang.String" Name="addNewCustomer_customer_lname"
              IsQueriable="false"/>
    <variable Type="java.lang.String" Name="addNewCustomer_customer_email"
              IsQueriable="false"/>
  </variableIterator>
</executables>

When the user enters data and submits the form, the variables are populated and the attribute binding can then provide the value for the method's parameters. Note in Example 9-10 that the method parameters are the NamedData elements, which use an EL expression that evaluates to the attribute binding. The attribute bindings refer to the variables for their value.

Example 9-10 Method Parameters Use NamedData Elements to Provide Values

<bindings>
  <methodAction id="addNewCustomer" MethodName="addNewCustomer"
                RequiresUpdateModel="true" Action="999"
                IsViewObjectMethod="false" DataControl="CustomerSvc"
                InstanceName="CustomerSvc"
         ReturnName="CustomerSvc.methodResults.CustomerSvc_addNewCustomer_result">
    <NamedData NDName="customer_lname" NDType="java.lang.String"
               NDValue="${bindings.addNewCustomer_customer_lname}"/>
    <NamedData NDName="customer_fname" NDType="java.lang.String"
               NDValue="${bindings.addNewCustomer_customer_fname}"/>
    <NamedData NDName="customer_email" NDType="java.lang.String"
               NDValue="${bindings.addNewCustomer_customer_email}"/>
  </methodAction>
  <attributeValues id="customer_fname" IterBinding="variables">
    <AttrNames>
      <Item Value="addNewCustomer_customer_fname"/>
    </AttrNames>
  </attributeValues>
  <attributeValues id="customer_lname" IterBinding="variables">
    <AttrNames>
      <Item Value="addNewCustomer_customer_lname"/>
    </AttrNames>
  </attributeValues>
  <attributeValues id="customer_email" IterBinding="variables">
    <AttrNames>
      <Item Value="addNewCustomer_customer_email"/>
    </AttrNames>
  </attributeValues>
</bindings>

For more information about using ADF Parameter forms, refer to the Oracle Application Development Framework Developer's Guide.

9.6.3 How to Invoke a Service Using a Backing Bean

There may be cases when you will need to directly invoke a web service, and you cannot use a data control. You create the logic to do this in the page's backing bean. For example, in the SOADEMO-CLIENT application, all the logic to collect the data and then send it to the service is on the Register.java backing bean.

In order to easily bind the components on a page, you can use the Automatic Component Binding feature when creating the JSF page. This will automatically bind each component to a property in the backing bean. You'll then add logic to the method bound to the command component, which will send the data to the web service.

To invoke a service without using ADF Data Binding:

  1. Create a JSF page, as described in Section 9.3.1, "How to Create a JSF Web Page". However, for step 7 of that procedure, be sure to select the Automatically Expose UI Components in a New Managed Bean option. Click Help for more information on this step of the wizard.

  2. Use the Component Palette's dropdown menu to choose ADF Faces Core, as shown in Figure 9-19. This will allow you to drag ADF Faces components onto the JSF page.

    Figure 9-19 Selecting a Tag Library in the Component Palette

    Tag libraries in Component Palette.
  3. From the Component Palette, drag an InputText component onto the page.

    Because you chose to use automatic component binding, each component dropped on the page will automatically be bound to a property on the backing bean.

    Component properties, such as Label, AutoSubmit, and Disabled, are set for you. You can change these as needed. Refer to the JDeveloper online help for more information about ADF Faces properties.

  4. By default, the component will have an ID based on the component type, such as inputText1. Change this ID to be the same as the corresponding element name from the associated WSDL.

    For example, Example 9-11 shows the elements for a customer in the CustomerService WSDL:

    Example 9-11 Element Definitions in the WSDL

    <complexType name="Customer"> 
      <sequence> 
        <element name="password" type="string" nillable="true" /> 
        <element name="lname" type="string" nillable="true" /> 
        <element name="phonenumber" type="string" nillable="true" /> 
        <element name="fname" type="string" nillable="true" /> 
        <element name="addressList" type="ns1:list" nillable="true" /> 
        <element name="creditcardtype" type="string" nillable="true" /> 
        <element name="email" type="string" nillable="true" /> 
        <element name="status" type="string" nillable="true" /> 
        <element name="creditcardnumber" type="string" nillable="true" /> 
        <element name="custid" type="string" nillable="true" /> 
      </sequence> 
    </complexType>
    
    

    To create an inputText component for the lname element, you would change the ID of that component to lname.

  5. Add code to the corresponding backing bean to collect the data and invoke the web service.

    Since there are already getter and setter methods for the input components on the page, you only need to write code that creates a new object using that data. Example 9-12 shows the code to create customer and address objects.

    The web service is accessed using the client generated when creating the proxy (see Section 5.3.1, "How to Create a Web Service Proxy"). Note that this method first sets the user as an authorized user, then checks to make sure that the data entered in the password and password check components is the same, and then creates a customer by accessing the web service.


    Tip:

    You will need to import any classes used from the proxy. For example, in Example 9-12, you would need to import the Customer and Address classes.

    Example 9-12 Code to Create a Customer and Invoke the CustomerService Web Service

    public void register_action(ActionEvent ae) {
      String AUTH_USER = "Authorized_User";
      FacesContext ctx = FacesContext.getCurrentInstance();
      Customer newCust = new Customer();
      if (password.getValue().toString().equals(password
                                          _chk.getValue().toString())) {
           
        // Call Web service to register new customer
         try {
               oracle.soademo.view.services.CustomerServiceClient myPort = new
                       oracle.soademo.view.services.CustomerServiceClient();
               System.out.println("calling " + myPort.getEndpoint());
                 
                 // Adding new customer info
                    Address addr = new Address();
                    
                    newCust.setFname(fname.getValue().toString());
                    newCust.setLname(lname.getValue().toString());
                    newCust.setEmail(email.getValue().toString());
                    newCust.setPhonenumber(phone.getValue().toString());
                    newCust.setPassword(password.getValue().toString());
     
                    addr.setStreet(street.getValue().toString());
                    addr.setCity(city.getValue().toString());
                    addr.setState(state.getValue().toString());
                    addr.setZip(zip.getValue().toString());
                      
                    List addrList = new ArrayList();                  
                    addrList.add(addr);                              
                    newCust.setAddressList(addrList);                   
              
                    // Call Customer WS to add customer - 
                              returns customer id of new customer (newCustId)                newCustId = myPort.addNewCustomer(newCust);                                  // Retrieve complete customer object using WS                  
                           newCust = myPort.findCustomerById(newCustId);                             
                      
                 // Generate successful registration message..        
                    FacesContext.getCurrentInstance().addMessage(null, new
                           FacesMessage("Registration Successful!"));
                          
           } catch (Exception ex) {
              FacesMessage msg = new FacesMessage("Registration Failed!");
              msg.setSeverity(msg.SEVERITY_ERROR);
              FacesContext.getCurrentInstance().addMessage(null, msg);
              FacesContext.getCurrentInstance().addMessage(null, new
                        FacesMessage(ex.getMessage()));
               ex.printStackTrace();
                 
       }
    
    
  6. Drag a command button from the Component Palette.

    This button will be used to invoke the method just created.

  7. With the command button selected, in the Property Inspector, use the dropdown menu to select the method just created.

    This binds the command button to that method. When the user clicks the button, that method will be invoked, and the entered data will be sent to the web service.

9.6.4 What Happens When You Invoke a Service From a Web Page

When you drop components onto a JSF page and choose to use automatic component binding, JDeveloper does the following:

  • If you elect to have JDeveloper create a backing bean, creates a JavaBean using the same name as the JSP, and places it in the view.backing package.

  • Creates a managed bean entry in the faces-config.xml file for the backing bean. By default, the managed bean name is backing_<page_name> and the bean uses the request scope.

  • On the newly created or selected bean, adds a property and accessor methods for each component tag you place on the JSP.

  • Binds the component tag to that property using an EL expression as the value for its binding attribute.

Example 9-13 shows the code created on a backing bean when you add two input components, one for first name and one for last name.

Example 9-13 Register Backing Bean

public class Register {
 
    private HtmlHtml html1;
    private HtmlHead head1;
    private HtmlBody body1;
    private HtmlForm form1;
    private CoreInputText fname;
    private CoreInputText lname;
 
    public void setHtml1(HtmlHtml html1) {
        this.html1 = html1;
    }
 
    public HtmlHtml getHtml1() {
        return html1;
    }
 
    public void setHead1(HtmlHead head1) {
        this.head1 = head1;
    }
 
    public HtmlHead getHead1() {
        return head1;
    }
 
    public void setBody1(HtmlBody body1) {
        this.body1 = body1;
    }
 
    public HtmlBody getBody1() {
        return body1;
    }
 
    public void setForm1(HtmlForm form1) {
        this.form1 = form1;
    }
 
    public HtmlForm getForm1() {
        return form1;
    }
 
    public void setFname(CoreInputText inputText1) {
        this.fname = inputText1;
    }
 
    public CoreInputText getFname() {
        return fname;
    }
 
    public void setLname(CoreInputText inputText1) {
        this.lname = inputText1;
    }
 
    public CoreInputText getLname() {
        return lname;
    }
}

Example 9-14 shows the code on the JSF page binding the components to the Register backing bean properties.

Example 9-14 JSF Code Using Automatic Component Binding

<afh:body binding="#{backing_Register.body1}" id="body1">
  <h:form binding="#{backing_Register.form1}" id="form1">
    <af:inputText label="First Name" binding="#{backing_Register.fname}"
                     id="fname"/>
    <af:inputText label="Label 2" binding="#{backing_Register.lname}"
                     id="lname"/>
  </h:form>
</afh:body>

A command button can use either its Action or ActionListener attribute to bind to a method. The actionListener attribute was used instead of the action attribute in this case, because the navigation capabilities provided by the action attribute are not needed, the user remains on the registration page. When you bind the command component to the method on the backing bean, the method is invoked when the user clicks the button.

When creating a method to invoke a web service, you can invoke the web service using the client class automatically generated when creating the proxy. You first call the service, then call the needed operations on the service.

For example, the register_action method on the Register.java backing bean first calls the web service using the client class, as shown in Example 9-15.

Example 9-15 Calling the CustomerService Web Service Using the Client Class

oracle.soademo.view.services.CustomerServiceClient myPort = new
                      oracle.soademo.view.services.CustomerServiceClient();

The method then creates the customer by taking the value of each component, converting it to a String, and setting that as the value for the corresponding property on the Customer object, as shown in Example 9-16.

Example 9-16 Creating the Customer

Customer newCust = new Customer();. . .       
     newCust.setFname(fname.getValue().toString());
     newCust.setLname(lname.getValue().toString());
. . .

Once the customer is created, the method calls the addNewCustomer operation on the web service, passing in the created customer, as shown in Example 9-17.

Example 9-17 Calling an Operation on the Web Service

myPort.addNewCustomer(newCust)