====== 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 [[:arch:bundles|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 [[:arch:infoprovider|well-known pattern]]. We implement this pattern as a BPEL process in the [[http://code.google.com/p/jseduite/source/browse/#svn/trunk/providers/InfoProviderSkel/src|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 [[http://anubis.polytech.unice.fr/jSeduite/doku/services/ws/userprofile#accountmanager|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''):
* **''InfoProvider.wsdl''**:
* Edit the ''definitions'' node by changing the following attributes (replace ''skel'' by your institution name): ''targetNamespace'', ''xmlns:tns'' & ''xmlns:ns''
* 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:
* 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''.
* Edit the ''import'' node for the WSDL & XSD files, and replace ''skel'' by your institution name:
* Edit the ''partnerLink'' named ''external'' and replace ''skel'' by ... guess what ... your institution name:
* Edit the ''GetInformationIn'' & ''GetInformationOut'' ''variable'' node to replace skel value:
* Edit the ''receive'' activity (in the ''sequence'' named ''reception'') and change the ''xmlns:tns'' attribute:
* Do exactly the same with the ''reply'' activity in the ''response'' sequence:
* 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: [[:apps: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):
* Enhance the ''Information'' choice to handle this kind of data as business object:
* Define a ''DataTypeSet'' complex type to handle collections of informations:
==== BPEL global variable ====
We need to add a global variable in the BPEL Process **''InfoProvider.bpel''** to collect all informations from this new source:
==== 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 ...