====== 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 ...