Write an InfoProvider

Warning: this tutorial is definitively out of date !! Refactoring is in progress …

An InfoProvider is a special orchestration of Web Services inside jSeduite. This orchestration collects all expected informations from the jSeduite services pool, and then return it to the client in a standardized way.

Inside a jSeduite bundle, the InfoProvider is the keystone of the information broadcasting process. Each bundle defines its own InfoProvider, as the broadcasting process is different for each targeted academic institution.

This page is a cookbook to make your life easier when you want to define your own InfoProvider (and so, your own jSeduite bundle). Follow the guidelines and build your own information broadcasting system in a really short time !

Retrieving the Skeleton

The InfoProvider process follows a well-known pattern. We implement this pattern as a BPEL process in the InfoProviderSkel project.

This project is architectured as the following:

  • InfoProvider.xsd: Information Data Model, Request & Response Message definition
  • InfoProvider.wsdl: Public contract to exchange message with the real world
  • InfoProvider.bpel: the BPEL process skeleton (sou you 'just' fill in the blank as when you were in junior school…)
  • TechPartners: Contains public WSDL contracts, data models & wrappers for technical partners (account management, preferences & error logging)
  • Sources: This empty folder will contain information sources WSDL contracts, datamodels & wrappers for the source you're going to compose.

The BPEL process skeleton also defines the following variables:

  • user: the given login (xsd:string) read from the input message
  • password: the given password (xsd:string, plain text) read from the input message
  • authorized: a xsd:boolean variable, received from the AccountManager service.
    • ⇒ output of the isAuthorized operation.
  • result: a tns:ArrayOfInformation which is returned by the process when sending response.

To retrieve the skeleton, copy/paste the InfoProviderSkel Process Files content. Do not forget to retrieve the catalog.xml file content (a premature end of file exception will be throw if you've forgot to copy it).

Skeleton Namespace Customization

In order to avoid namespace conflicts and other XML stuff, you'll need to customize the InfoProvider.* file to define your own process.

If you skip this step, you'll define an Infoprovider using the skel namespace (by the way, it's not a good idea to skip this step …)

  • InfoProvider.xsd:
    • Change the xmlns:tns and the targetNamespace xsd:schema attributes, replacing skel with your institution name for example (eg epu):
      <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
          targetNamespace="http://modalis.polytech.unice.fr/jSeduite/schema/InfoProvider/epu"
          xmlns:tns="http://modalis.polytech.unice.fr/jSeduite/schema/InfoProvider/epu"
          elementFormDefault="qualified">
  • InfoProvider.wsdl:
    • Edit the definitions node by changing the following attributes (replace skel by your institution name): targetNamespace, xmlns:tns & xmlns:ns
      <definitions name="InfoProvider"
          targetNamespace="http://modalis.polytech.unice.fr/jSeduite/wsdl/InfoProvider/epu" 
          xmlns:tns="http://modalis.polytech.unice.fr/jSeduite/wsdl/InfoProvider/epu"
          xmlns:ns="http://modalis.polytech.unice.fr/jSeduite/schema/InfoProvider/epu" >
    • Edit the xsd:schema node and perform the same change on the targetNamespace. Do not forget to change the namespace of the xsd:import node defined inside:
      <xsd:schema targetNamespace="http://modalis.polytech.unice.fr/jSeduite/wsdl/InfoProvider/epu">
        <xsd:import namespace="http://modalis.polytech.unice.fr/jSeduite/schema/InfoProvider/epu"
                    schemaLocation="InfoProvider.xsd"/>
      </xsd:schema>
    • Click on the Validate XML Button, you must have the following output inside your Netbeans XML check window:
      XML validation started.
      0 Error(s),  0 Warning(s).
      XML validation finished.
      
  • InfoProvider.bpel:
    • Edit the following attributes of the process node, replacing skel with your institution name: targetNamespace, tns & xmlns:ns0.
      <process
          targetNamespace="http://modalis.polytech.unice.fr/jSeduite/bpel/InfoProvider/epu"
          xmlns:tns="http://modalis.polytech.unice.fr/jSeduite/bpel/InfoProvider/epu"
          xmlns:ns0="http://modalis.polytech.unice.fr/jSeduite/schema/InfoProvider/epu">
    • Edit the import node for the WSDL & XSD files, and replace skel by your institution name:
      <import namespace="http://modalis.polytech.unice.fr/jSeduite/wsdl/InfoProvider/epu" 
              location="InfoProvider.wsdl" importType="http://schemas.xmlsoap.org/wsdl/" />
      <import namespace="http://modalis.polytech.unice.fr/jSeduite/schema/InfoProvider/epu" 
              location="InfoProvider.xsd" importType="http://www.w3.org/2001/XMLSchema" />
    • Edit the partnerLink named external and replace skel by … guess what … your institution name:
      <partnerLink name="external" 
                   xmlns:tns="http://modalis.polytech.unice.fr/jSeduite/wsdl/InfoProvider/epu"
                   partnerLinkType="tns:InfoProvider" myRole="InfoProviderPortTypeRole"/>
    • Edit the GetInformationIn & GetInformationOut variable node to replace skel value:
      <variable name="GetInformationOut" 
                xmlns:tns="http://modalis.polytech.unice.fr/jSeduite/wsdl/InfoProvider/epu" 
                messageType="tns:GetInformationResponse"/>
      <variable name="GetInformationIn" 
                xmlns:tns="http://modalis.polytech.unice.fr/jSeduite/wsdl/InfoProvider/epu" 
                messageType="tns:GetInformationRequest"/>
    • Edit the receive activity (in the sequence named reception) and change the xmlns:tns attribute:
      <receive name="receive" createInstance="yes" partnerLink="external" operation="GetInformation" 
               xmlns:tns="http://modalis.polytech.unice.fr/jSeduite/wsdl/InfoProvider/epu"
               portType="tns:InfoProviderPortType" variable="GetInformationIn"/>
    • Do exactly the same with the reply activity in the response sequence:
      <reply name="reply" partnerLink="external" operation="GetInformation" 
             xmlns:tns="http://modalis.polytech.unice.fr/jSeduite/wsdl/InfoProvider/epu" 
             portType="tns:InfoProviderPortType" variable="GetInformationOut"/>
  • At the end of this step, the XML check validation should return 2 warnings (it's normal):
    XML validation started.
    $JESDUITE_HOME/providers/InfoProviderSkel/src/InfoProvider.bpel:26,8
    WARNING: The variable "globalIndex" is initialized and not used.
    $JSEDUITE_HOME/providers/InfoProviderEPU/src/InfoProvider.bpel:28,8
    WARNING: The variable "authorized" is initialized and not used.
    $JSEDUITE_HOME/providers/InfoProviderEPU/src/InfoProvider.bpel:74,16
    WARNING: The types of "From" and "To" activities are different: "string" and "InformationSet".
    0 Error(s),  2 Warning(s).
    XML validation finished.
    
    • The first warning indicates that we're not using the globalIndex integer variable
      • This variable is used when feeding the result with information, and as we haven't any information for now … it's quite normal not to use it.
    • The second warning means that we're never using the authorized variable
      • (which is normal, as the process basically do almost nothing for now)
    • The third means that we're not assigning a good value inside the result variable.
      • It's normal too, as Netbeans BPEL Engine doesn't support properly the xml literal assignment. so we're using an ugly hack to perform the initialization (forcing the empty string as node content will enforce the node initialization).

If your process validate with these two warnings, you're done with the namespace customization !

Source of Informations

Import WSDL contract

First of all, and even if it sounds like a good idea, you must NEVER used the remote WSDL importation mechanism. It create a (bloody) mess inside the Sources folders, and you'll loose your marbles in a very short time. Always use the local WSDL importation mechanism.

  • First of all, download on your hard drive the wanted WSDL & XSD files from the jSeduite registry: wsdl
  • Right click on the Sources folder, and choose the New / External WSDL Document(s) menu item
  • Tick the From Local File System radio button (cf previous warning), and choose the WSDL file you've just downloaded
    • Warning: XML import mechanism is case sensitive, and this website isn't … be sure that your file uses the right camelCase name (rssreaderservice.wsdl != RssReaderService.wsdl).
  • Click on the finish button.
  • Drag'n drop the wsdl file on the right side of the BPEL Process, under the others orchestration partners
    • Choose a partnerLinkName (and role if asked to) related to the source of information you're adding (for the CacheRssReader partner, use feedreader instead of PartnerLink1).
  • Save your BPEL process ! LOL

If you've made a mistake and want to delete those file, you'll have to also delete entries in the catalog.xml files as the refactoring process in Netbeans 6.5 doesn't handle it properly.

Customizing the data model

You need to enhance the InfoProvider.xsd data model to handle properly the new source of information:

  • Import the XSD file which defines the business object data type (eg RssReaderService.xsd for the CachedFeedReader source):
    <xsd:import schemaLocation="Sources/RssReaderService.xsd" 
                namespace="http://feeds.technical.jSeduite.modalis.i3s.unice.fr/"/>
  • Enhance the Information choice to handle this kind of data as business object:
    <xsd:complexType name="Information">
      <xsd:choice>
        <!-- others available kinds of information -->
        <xsd:element name="feedContent" type="ns2:feedContent"/>
      </xsd:choice>
      <xsd:attribute name="kind" type="xsd:string"/>
    </xsd:complexType>
  • Define a DataTypeSet complex type to handle collections of informations:
    <xsd:complexType name="FeedContentSet">
      <xsd:sequence>
        <xsd:element name="item" type="ns2:feedContent" maxOccurs="unbounded" minOccurs="0"/>
      </xsd:sequence>
    </xsd:complexType>

BPEL global variable

We need to add a global variable in the BPEL Process InfoProvider.bpel to collect all informations from this new source:

<variable name="feed_reader_result" type="ns0:FeedContentSet"/>

Enhancing the call database

If the source of information use input parameters, you'll have to enrich the database with the adequate call informations.

  • First of all, add the source inside the sources relation:
    INSERT INTO `sources` VALUES (Source_Id, WebService_Name, Operation_Name);
  • Define a link between a login and a source in the preferences relation (ie this login wants to subscribe to this source):
    INSERT INTO `preferences` VALUES (Preference_Id, Login, Source_Id);
  • Define in the messages relation the parameters values this login will use to perform a call:
    INSERT INTO `messages` VALUES (NULL, Preference_Id, Call_Id, Parameter_Name, Value);

Example: We consider here that we're adding the CachedFeedReader source. The user with login hall subscribes to this source, and expects to retrieve the content of two feeds (TV5_une & Antibes_tout) with a validity period of 30 minutes.

INSERT INTO `sources` VALUES (1, 'CachedFeedReader', 'read');
INSERT INTO `preferences` VALUES (1, 'hall', 1);
INSERT INTO `messages` VALUES (NULL, 1, 1, 'validity', '30');
INSERT INTO `messages` VALUES (NULL, 1, 1, 'name', 'TV5_une');
INSERT INTO `messages` VALUES (NULL, 1, 2, 'validity', '30');
INSERT INTO `messages` VALUES (NULL, 1, 2, 'name', 'Antibes_tout');

Building the invocation pattern

Take a look at the commented first scope (named SourceName) inside the InfoProvider.bpel skeleton code. It implements the pattern of information retrieval for a given source.

  • Change SourceOperationOut & SourceOperationIn variables
  • Activity log_pre: change the SourceName value in the message assignment
  • Activity silentIgnore: change the to part of the assignment to fit with you global variable
  • Activity getCalls_pre: change the service and operation values to fit with your source.
  • For each parameter of your source, add a getParameter_ParamName sequence:
    • Activity getParameter_ParamName_pre: change service, operation and ParamName values.
    • Activity getParameter_ParamName_post: change $SourceOperationIn.in/ns:ParamName value.
  • Activity perform_call: change the attributes to fit with your data source
  • Activity feedLocalResult: change global_variable_name value.

Do not hesitate to look the source code of existing providers ( like InfoProviderEpu, …) and inspire your development from those validated process.

Adding information to final result

Take a look at the second commented scope (named SourceName_Feed). This code will feed the global result with the source ones.

  • Activity feed_loop: change the global_variable_name value in the condition
  • Activity feed_result: change the global_variable_name and the dataType value.

Source Policies

  • FIXME
cookbook/build-infoprovider.txt · Last modified: 2009/05/11 11:48 by mosser
CC Attribution-Noncommercial-Share Alike 3.0 Unported www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0