Professional Documents
Culture Documents
Introduction......................................................................................................................................... 2 Overview ........................................................................................................................................ 2 Definitions, Acronyms and Abbreviations ........................................................................................ 2 Purpose .......................................................................................................................................... 2 The ServiceCenter Web Services features ............................................................................................... 3 Introduction to Web Services in ServiceCenter..................................................................................... 3 Consuming an external Web Service from ServiceCenter...................................................................... 4 Example: Calling a Web Service sample from the ScriptLibrary ........................................................ 5 Example: Getting up-to-date currency data from a Web Service......................................................... 5 Publishing ServiceCenter data ........................................................................................................... 9 Understanding the ServiceCenter Web Service .............................................................................. 10 Things to consider prior to publishing data .................................................................................... 14 Example: Publishing data from the currency and curconvert files ..................................................... 16 Consuming a ServiceCenter Web Service ......................................................................................... 24 Retrieving data from ServiceCenter............................................................................................... 25 Example: Retrieving ServiceCenter price lists into a text file using Connect-It ..................................... 26 Example: Getting currency information and pricelist information from another ServiceCenter system .... 29 Using the ServiceCenter Web Services examples in the RUN directory ................................................. 31 Troubleshooting ................................................................................................................................. 32 What to do if the WSDL2JS utility fails.............................................................................................. 32 What happens if an exposed table is tailored?.................................................................................. 33 Debugging .................................................................................................................................... 33 debughttp.................................................................................................................................. 33 RTM:3 and debugdbquery:999 ................................................................................................... 34 Testing your WSDL using .NET Web Service Studio ........................................................................... 34 Advanced Troubleshooting.............................................................................................................. 36 How to troubleshoot a Web Service that is behind a closed firewall ................................................. 36 Special considerations for using Keep-Alive with ServiceCenter servlet mode ........................................ 40 Is it possible to consume Web Services in ServiceCenter through a proxy server? .................................. 41 Error Messages.............................................................................................................................. 41 Appendix ......................................................................................................................................... 46 Understanding the return codes provided by the ServiceCenter Web Service ........................................ 46 Using SSL connections to connect to an external Web Service ............................................................. 49 Steps to take when modifying an existing extaccess record ............................................................. 50 Syntax for Entity References in XML .................................................................................................. 50 What does a nillable field designate and what is its purpose? ......................................................... 51 Best Practices................................................................................................................................. 51 Writing a JavaScript for consuming a Web Service ........................................................................ 51 Date/Time handling in the self-written JavaScript............................................................................ 51 Writing expressions in extaccess .............................................................................................. 52 References ........................................................................................................................................ 52 For more information.......................................................................................................................... 53
Introduction
Overview
Information that is available on standalone systems would be much more useful to a company if it were shared with other applications. In the past, sharing valuable information required complicated, customized, and expensive integrations between the applications. With the introduction of Web Services, application integration is made easier because it allows applications to use any Web Service independently of the platform or programming language in which it was developed. In addition, integrations based on Web Services are less expensive to maintain and very flexible, which makes them an ideal solution for integrations between different systems. With a Web Service, data is exchanged using XML and the Simple Object Access Protocol (SOAP). Web Services are applications that are generally available via the World Wide Web. They are specified with a URL that programmatically returns requested information to a client. Web Services can integrate with other applications or Web sites, either on the same server or on servers located all over the world. For example, a travel Web Site could process a users request for weather and flight information at any destination by making behind the scenes calls to Web Services that provide this information. Then the travel site displays the results to the user. This eliminates the need for the user to go to various sites to get this information.
Purpose
This document provides guidance for users who wish to publish or consume Web Services using ServiceCenter. It includes examples that can be used as templates.
Web Services and their clients can be written in any programming language and for any platform. ServiceCenter Web Services ships with examples using both the Java and Visual C# programming languages. In addition, the examples are all based on ServiceCenter 6.1. Although the ServiceCenter 6.0 Web Services APIs are still available, changes and improvements to the Web Services features in ServiceCenter 6.1 makes it the recommended release to use.
In ServiceCenter 6.1, the Web Services features were greatly improved to be able to both publish and consume Web Services and to allow publishing Web Services using the default ServiceCenter listener port. This change made communications less complicated and improved performance. Also, an abstraction layer was introduced which allowed ServiceCenter to expose its Web Services using much more user-friendly names. (For example, to create an Incident, one would issue a CreateIncidentRequest rather than a probsummaryAdd request.) In addition, several ITIL-based services were published as part of the out-of-the-box ServiceCenter 6.1 system. These WSDLs expose several data elements from different tables in order to provide basic ITIL workflows via the Web Services API. The following ITIL based WSDLs are provided out of the box: IncidentManagement ConfigurationManagement ServiceManagement ProblemManagement
Note: Table-based WSDLs are still available in ServiceCenter 6.1 for users who have previous Web Service applications for ServiceCenter 6.0. To publish a ServiceCenter Web Service, you create one extaccess record per table that you want to publish in that Service, and modify the data policy record for this table. The extaccess and data policy records for a table are displayed as a joined file when displayed from the Web Services
Utilities. Though configuration changes can be made directly to data policy, HP recommends that you make them using the WSDL Configuration Utility. To use the utility, click Toolkit -> WSDL Configuration Utility. Important: Changes to the WSDL Configuration Utility affect any client that is currently consuming them. If you modify this configuration, make sure to test all other applications that consume the Web Service and address possible issues immediately. The ServiceCenter server requires that each Web Service request provide a valid operator name and password combination. These must be supplied via a standard HTTP Basic Authorization header. SOAP toolkits universally support this authentication mechanism. Use SSL if you are concerned about the possibility of someone using a network monitoring tool to discover passwords. Basic Authorization by itself does not encrypt the password; it simply encodes it using Base 64. In addition to having a valid login, the operator must have the SOAP API capability word to access the Web Services API. If the Web Service request does not contain valid authorization information, then the server sends a response message containing ResponseCode: 401 (Unauthorized). If the request is valid, then the server sends a response message containing the results of your Web Services operation. The response message contains only the information that the operator is allowed to see. Both Document Engine and Mandanten security group settings are maintained through the Web Services API.
determine what functions, inputs, and formats the Web Service expects. Some third-party Web Services tools allow you to experiment interactively with Web Services. HP recommends that you familiarize yourself with the Web Service using such a tool before beginning any ServiceCenter JavaScript work. 3. Execute the Run WSDL to JS wizard to obtain and convert the Web Service's WSDL into JavaScript. 4. Write custom JavaScript to call the JavaScript functions generated by the WSDL to JS wizard. These functions will enable you to create and send the SOAP messages required to interact with the Web Service. HP recommends that you write a short standalone script and invoke it from the Script Library utility to test it prior to implementing the JavaScript call from format control, triggers, or display options. After you have determined and debugged the JavaScript code required to invoke the service, you can then integrate the script with your ServiceCenter application. 5. Tailor your ServiceCenter application to invoke your custom JavaScript when you want to connect to a remote Web Service. Usually Web Services are invoked from the Document Engine, Format Control, Links, Display application, or from similar tailoring tools. For testing purposes, the JavaScript code can be called from within the ScriptLibrary record itself before being called from any of the other tailoring tools.
Note: With any free provider, it is possible that the Web Service is available only for a short period. This example shows how to integrate any Web Service into ServiceCenter. For an example of a for-fee currency conversion tool that can be used instead of the following example,
http://www.<anywebserviceproviderhere>.com/CurrencyConvertor.wsdl
4. Click Proceed. 5. Click Add to add the new ScriptLibrary record called CurrencyConvertor. 6. Write an interfacing JavaScript record in the ScriptLibrary called CurrencyConvertorRUN, as
follows:
function GetCurrencies(From, To) var Currencies = new system.library.CurrencyConvertor.CurrencyConvertor(); // first, initialize the Service Object for this JavaScript var Curr=Currencies; // put the result of that call into a differently named variable // (not always necessary) var validCurrencies=new Array("AED","AFA","ALL","ANG","ARS","AUD", "AWG","BBD","BDT","BHD","BIF","BMD","BND","BOB","BRL","BSD","BTN","BWP"," BZD","CAD","CHF","CLP","CNY","COP","CRC","CUP","CVE","CYP","CZK","DJF","D KK","DOP","DZD","EEK","EGP","ETB","EUR","FKP","GBP","GHC","GIP","GMD","GN F","GTQ","GYD","HKD","HNL","HRK","HTG","HUF","IDR","ILS","INR","IQD","ISK ","JMD","JOD","JPY","KES","KHR","KMF","KPW","KRW","KWD","KYD","KZT","LAK" ,"LBP","LKR","LRD","LSL","LTL","LVL","LYD","MAD","MDL","MGF","MKD","MMK", "MNT","MOP","MRO","MTL","MUR","MVR","MWK","MXN","MYR","MZM","NAD","NGN"," NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","Q AR","ROL","RUB","SAR","SBD","SCR","SDD","SEK","SGD","SHP","SIT","SKK","SL L","SOS","SRG","STD","SVC","SYP","SZL","THB","TND","TOP","TRL","TTD","TWD ","TZS","UAH","UGX","USD","UYU","VEB","VND","VUV","WST","XAF","XAG","XAU" ,"XCD","XOF","XPD","XPF","XPT","YER","YUM","ZAR","ZMK","ZWD") var currenciesTemp=validCurrencies.toString(); if (currenciesTemp.indexOf(From)>0) { var myRate = new system.library.CurrencyConvertor.ConversionRate(); // Create the Request Object myRate.FromCurrency.setValue(From); myRate.ToCurrency.setValue(To); // Fill the required input values that specify the query / request into // the Request Object(see below on how to find them) var ConversionRateResponse = Curr.invoke(myRate); invoke / call the web service and pass in the Request Object var result = ConversionRateResponse.ConversionRateResult; Request the result instance of the previous call var conversionRate=result.getValue(); get the value that was returned in the result instance for further use } else { print( From + " is not a valid Currency for this rate converter. Proceeding to next currency.") return 0; } }
Retrieving relevant data from the generated JavaScript to create the calling JavaScript Check these sections in the master JavaScript to write your calling JavaScript: The first line in the master code gives the name of the main function or Service Object to call first in the calling JavaScript: function CurrencyConvertor()
1. Find the function that does what is needed; in this case, performs a currency conversion:
function ConversionRate() { this.$$attributes = new Array(); this.$$xmlNames = new Array(); this.$$objNames = new Array(); this.getName = getName; this.getXmlName = getXmlName; this.setContent = setContent; this.addContent = addContent; this.getContent = getContent; this.isFault = isFault; this.$$elementChildren = new Array(); this.$$name = "ConversionRate"; this.$$xmlNames[ "ConversionRate" ] = "ConversionRate"; this.xmlns = new String("http://www.webserviceX.NET/"); this.$$attributes.push( "xmlns" ); this.FromCurrency = new Currency(); this.$$elementChildren.push( "FromCurrency" ); this.ToCurrency = new Currency(); this.$$elementChildren.push( "ToCurrency" ); } The bold $$elementChildren.push sections give the parameters that have to be filled in the calling JavaScript using setValue or a similarly defined function. function setValue( value ) { this.$$value = value; }
2. Check which parameters the invoke() function expects:
function invoke( requestObj, headerObj ) In this case, the headerObj was optional (was nullsubed in the JavaScript code), so the requestObj is the only required argument.
3. Check the syntax for the Response function:
function ConversionRateResponse( ) { this.$$attributes = new Array(); this.$$xmlNames = new Array(); this.$$objNames = new Array(); this.getName = getName; this.getXmlName = getXmlName; this.setContent = setContent; this.addContent = addContent; this.getContent = getContent; this.isFault = isFault; this.$$elementChildren = new Array(); this.$$name = "ConversionRateResponse";
bold). 5. Use getValue (or a similarly defined function) to read the result of the request. function getValue( ) { return this.$$value; }
6. Use the calling JavaScript to update values in ServiceCenter. Rewrite the calling JavaScript to be
a callable function such as: function GetCurrencyFromSC() { var CurrCode=""; var CurrencyRecord=new SCFile("currency"); var CurrConvRecord=new SCFile("curconvert") var foundCurrency = CurrencyRecord.doSelect( "true" ); while ( foundCurrency == RC_SUCCESS ) { USDConversionRate = system.library.CurrencyConvertorRUN.GetCurrencies(CurrencyRecord.cu rrency_code, "USD") if (USDConversionRate > 0) { CurrConvRecord.currency_code=CurrencyRecord.currency_code; CurrConvRecord.rate=parseFloat(USDConversionRate); CurrConvRecord.root_code="USD"; CurrConvRecord.date=system.functions.tod(); var rc = CurrConvRecord.doInsert(); if (rc != RC_SUCCESS) { print( "Could not insert currency conversion record. " + RCtoString( rc ) ); } } else { print(" Invalid Conversion Rate returned." + USDConversionRate) } foundCurrency = CurrencyRecord.getNext(); } }
7. Call the JavaScript from the schedule file to regularly update the currency values. Add a
schedule record as shown below to weekly update the curconvert file: Note: Invoking a Web Service can be very resource and time intensive. Carefully consider batch processing as shown below, and do not use it to invoke a Web Service multiple times during the day, since this would negatively influence system performance. Batch processing should only be done off-hours if overall calls to the Web Service can be minimized this way.
With this example, we are now able to receive real-time currency conversion rates into ServiceCenter that can be used in the procurement and service chargeback processes.
10
Example: Retrieving data from ServiceCenter via a Web Service The simplest way to perform retrieval operations is via Query-by-example (QBE). This is done by creating an instance of a particular kind of object (such as an Incident) and populating one or more fields with values to determine the result set. This instance is then used in a RetrieveXXXKeysList operation. In a program, such as the sample programs provided with ServiceCenter, you would be assigning values to properties or calling setter methods on various Java or C# or other objects. In the following example, we submit a RetrieveIncidentKeysList object, supplying only a value for "Category". We get back a RetrieveIncidentKeysListResponse object listing the primary keys of the matching Incident objects. Note that we only have to supply values for the fields on which we wish to select. The request: <?xml version="1.0" encoding="UTF-8" ?> <SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <RetrieveIncidentKeysListRequest filename="probsummary" xmlns="http://servicecenter.peregrine.com/PWS/2005-05-02/"> <model> <keys> <IncidentID/> </keys> <instance> <Category>telecoms</Category> </instance> </model> </RetrieveIncidentKeysListRequest> </SOAP-ENV:Body> </SOAP-ENV:Envelope> ResponseCode: 200 (OK) Pragma:thinktime="0" Connection:Close Content-Length:1102 Cache-Control:no-cache Content-Type:text/xml; charset=utf-8 Set-Cookie:SessionId=127.0.0.1:4139;Version=1 Server:gSOAP/2.2 The response: <?xml version="1.0" encoding="utf-16"?> <SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAPENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://servicecenter.peregrine.com/PWS"> <SOAP-ENV:Body> <RetrieveIncidentKeysListResponse message="Success" query="category#"telecoms"" returnCode="0" schemaRevisionDate="2006-09-15" schemaRevisionLevel="14" status="SUCCESS" xmlns="http://servicecenter.peregrine.com/PWS" xmlns:cmn="http://servicecenter.peregrine.com/PWS/Common" xsi:schemaLocation="http://servicecenter.peregrine.com/PWS http://server:12670/PWS/Incident.xsd"> <keys> <IncidentID type="String">IM1049</IncidentID> </keys> <keys> <IncidentID type="String">IM1001</IncidentID> </keys> <keys>
11
<IncidentID type="String">IM1059</IncidentID> </keys> <keys> <IncidentID type="String">IM10002</IncidentID> </keys> <keys> <IncidentID type="String">IM1070</IncidentID> </keys> </RetrieveIncidentKeysListResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Having retrieved a list of <keys> elements we can now retrieve these Incidents using a RetrieveIncidentList request, by supplying the collection of keys elements in that request. You can submit a variable number of <keys> elements in a RetrieveXXXList request, subject only to your programs ability to handle large XML responses. Java client programs can sometimes run out of memory if the server returns very large responses. If we resubmit the request and supply an <OpenedBy> element with the value of "falcon" in addition to the Category value of "telecoms", the list of returned keys now contains only 1 IncidentId because the two query terms are connected with AND. Using this query mechanism there is no way to use OR to connect query terms. To do that, you must supply an expert query as a string. The request: <?xml version="1.0" encoding="UTF-8" ?> <SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <RetrieveIncidentKeysListRequest filename="probsummary" xmlns="http://servicecenter.peregrine.com/PWS/2005-05-02/"> <model> <keys> </keys> <instance> <Category>telecoms</Category> <OpenedBy>falcon</OpenedBy> </instance> </model> </RetrieveIncidentKeysListRequest> </SOAP-ENV:Body> </SOAP-ENV:Envelope> ResponseCode: 200 (OK) Pragma:thinktime="0" Connection:Close Content-Length:903 Cache-Control:no-cache Content-Type:text/xml; charset=utf-8 Set-Cookie:SessionId=127.0.0.1:4162;Version=1 Server:gSOAP/2.2 The response: <?xml version="1.0" encoding="utf-16"?> <SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAPENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://servicecenter.peregrine.com/PWS"> <SOAP-ENV:Body> <RetrieveIncidentKeysListResponse message="Success" query="category#"telecoms" and opened.by#"falcon"" returnCode="0" schemaRevisionDate="2006-09-15" schemaRevisionLevel="14"
12
status="SUCCESS" xmlns="http://servicecenter.peregrine.com/PWS" xmlns:cmn="http://servicecenter.peregrine.com/PWS/Common" xsi:schemaLocation="http://servicecenter.peregrine.com/PWS http://server:12670/PWS/Incident.xsd"> <keys> <IncidentID type="String">IM10002</IncidentID> </keys> </RetrieveIncidentKeysListResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> The ServiceCenter GUI clients support queries using a special QBE query syntax which involves special characters such as # ("starts with"), or relational operators such as > or < preceding an actual data value in the form. This kind of syntax is also supported via Web Services, although if the field is of a type other than string (for example an integer or dateTime type) and you are using a strongly typed programming language such as Java or C# to write your client code, you will not be able to leverage this feature. You cannot do so because the automatically generated proxy code will not let you set a field on type integer to a string value containing a non-numeric character. In the following example, we place #f in the OpenedBy element, which would work in Java because OpenedBy is a string. This should retrieve all Incidents opened by operators whose IDs start with the letter f. The request: <?xml version="1.0" encoding="UTF-8" ?> <SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <RetrieveIncidentKeysListRequest xmlns="http://servicecenter.peregrine.com/PWS/2005-05-02/"> <model> <keys> </keys> <instance> <OpenedBy>#f</OpenedBy> </instance> </model> </RetrieveIncidentKeysListRequest> </SOAP-ENV:Body> </SOAP-ENV:Envelope> ResponseCode: 200 (OK) Pragma:thinktime="0" Connection:Close Content-Length:864 Cache-Control:no-cache Content-Type:text/xml; charset=utf-8 Set-Cookie:SessionId=127.0.0.1:4208;Version=1 Server:gSOAP/2.2 The response: <?xml version="1.0" encoding="utf-16"?> <SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAPENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://servicecenter.peregrine.com/PWS"> <SOAP-ENV:Body> <RetrieveIncidentKeysListResponse message="Success" query="opened.by#"f"" returnCode="0" schemaRevisionDate="200609-15" schemaRevisionLevel="14" status="SUCCESS" xmlns="http://servicecenter.peregrine.com/PWS" xmlns:cmn="http://servicecenter.peregrine.com/PWS/Common"
13
xsi:schemaLocation="http://servicecenter.peregrine.com/PWS http://server:12670/PWS/Incident.xsd"> <keys> <IncidentID type="String">IM10002</IncidentID> </keys> </RetrieveIncidentKeysListResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Note: In the response above, the server has populated a "query" attribute on the RetrieveIncidentKeysListResponse element with the actual query string that was generated from the input. The field names in such server-generated query strings reflect the actual field names (such as opened.by instead of OpenedBy). Clients who want to submit an expert/advanced query should use either the query attribute on the <keys> element or the query attribute on the <instance> element. Both are provided because some requests do not define any <instance> element. During SOAP API request processing, the server will look first at the <keys> element and, if there is no query attribute there, will look at the <instance> element if it exists. Query attributes defined on any other element are never consulted during inbound SOAP request processing. The XML document which describes a particular record (such as a Change or Incident) is "wrapped" in an outer document called a "model", which is nothing more than a container for separating the actual data (the instance part) from the "keys" part, which is metadata about the fields which make up the primary key of the object.
14
ServiceCenter server automatically converts the XML schema data to the ServiceCenter field's listed data type format. The services, objects, and fields published in the ServiceCenter out-of-box Web Services API already have the proper XML schema data mappings listed in the data policy record. If the data policy does not list a data type mapping, then the Web Services API treats the field data as a string. Typically, you need to add or change a Web Services API data type mapping only to publish custom fields that you have added to ServiceCenter as Web Services objects. The following table lists the available SOAP API data types and their ServiceCenter equivalents:
SOAP API Data Type Base64Type BooleanType ByteType DateTimeType DateType TimeType DurationType DecimalType DoubleType IntType LongType ShortType FloatType StringType ServiceCenter Data Type used for binary data Boolean Decimal Date/Time Date/Time Date/Time Date/Time Decimal Decimal Decimal Decimal Decimal Decimal Text
Important: Always map ServiceCenter date / time fields to the XML schema dateTime or to one of the related XML schema date or time types. Otherwise these fields will cause errors when you consume the service What methods do I need? By default, any operation that is a part of the Document Engine for a table can be available in the tables Web Service. If you need additional methods, add them to the Document Engine first so that ServiceCenter has a process to follow when performing them. If you have methods in the Document Engine that you do not want exposed, delete them from the allowed actions array in the extaccess table. Note: The only Web Services methods that can be customized in ServiceCenter via display actions and Process records are methods that modify data in ServiceCenter, such as the add, update, and delete methods. Retrieving records is always done automatically via the SOAP API based on record selection criteria. Manipulation of the data that is written back to ServiceCenter must be done by the Web Service application that consumes the ServiceCenter data. Are there any security considerations? After you have exposed data over the Web, any client consuming the WSDL you are publishing has access to that data. If there are certain fields that you want to restrict from specific clients, create a different WSDL with those fields removed and have these clients consume that data.
15
11. Click Add to add the counters record. Now the unique id field will be automatically generated. 12. To create a format called pricelist, use Forms Designer Wizard and add all fields but
16
Creating Objects, States and Processes for the currency files To be able to create new actions, you define a Document Engine Object, a State, and appropriate Processes. Because no additional actions will be defined against the currency file, you do not have to create Document Engine settings for it. In the Document Engine, enter the following information:
1. Create an Object record for the curconvert file as shown below:
2. Click Add to save the record. 3. Create an Object record for the pricelist file as shown below:
17
4. Click Add to save the record. 5. Create a default State for the curconvert Object named curconvert.view as shown below:
6. Click Add to save the record. 7. Create a default State for the pricelist Object named pricelist.view as shown below:
Creating the actions in the Document Engine Next you add the following actions against the curconvert and pricelist files that will be available from the Web Service. Currency records should be added, updated, or deleted only; which are the standard actions that are already available. This example: Uses a Web Service to retrieve the current conversion rate for any currency against the US Dollar (USD). Calculates how much a specified amount in a foreign currency represents in USD, and updates the pricelist. (A new file is added for this example.)
The actions are already listed in the State records we created in the previous section. First you create the displayscreen, then the displayactions, and finally the Process records required to execute the actions.
1. Create a displayscreen named curconvert.view as pictured below:
18
3. Add a displayoption for the action that retrieves currency conversion rates from a Web Service
19
4. Click Add to save. 5. Add a displayoption that calculates how much a specified amount in a foreign currency represents
To define the Process that retrieves the currency conversion rate from a Web Service and adds the information to the curconvert file, follow these steps:
7. On the Initial JavaScript Tab enter:
20
9. Make a call to the se.base.method RAD application that performs basic actions to the record, such
10. Click Add to add the new Process record. 11. Define a Process that calculates how much a specified amount in a foreign currency represents in
US Dollars, and stores this information in the pricelist file: Enter the following statements lines in the initial expressions:
Preparing the extaccess records The following steps can be used to publish a ServiceCenter table as a Web Service.
1. Click Menu Navigation -> Utilities -> Tools -> Web Services -> External Access. 2. In the Name field, type the name of the ServiceCenter table you want to publish as a Web
Service.
3. In the Service Name field, type the name of the Web Service that you want to use to publish this
table. You can reuse the same Web Service name to publish multiple tables, but you can only publish a table as part of one Web Service at a time. The name you type for this field becomes the alias name for the service, and becomes part of the Web Service URL. So, if you type MyService for the service name, then the WSDL you are publishing would be called MyService.wsdl. The name cannot contain URL-reserved characters such as spaces, slashes, or colons. 4. In the Object Name field, type the name you want to use to identify the table. This name becomes the alias name for the table and becomes part of the Web Service WSDL. For example, if you type Mytable for the object name, then the SOAP operations for this table include Mytable as part of the WSDL element, such as UpdateMytable, CreateMytable, and DeleteMytable.
21
Note: The name cannot consist of XML-reserved characters such as brackets (< and >), colons (:), or quotation marks (" and ). A best practice is to use an Object Name that is identical to the Name and never contains camel case (where the name contains compound words or phrases that are joined without spaces, and each word is capitalized within the name). Doing so causes an issue indicating that the filename is incorrect or missing when calling the Web Service via ServiceCenter. In some tools, you can modify the XML to include the filename in the SOAP body request as a workaround. However, ServiceCenter and some other tools do not allow modifications. Your Web Service is now ready to be consumed by a custom client. Windows and Web clients are unaffected by changes you make to the extaccess table. Windows and Web clients always use the operator's application profile to determine which tables the user can access and which actions the user can perform.
5. In the Allowed Actions array, select the ServiceCenter Document Engine display actions you want
to enable globally for this table. Each table has its own set of allowable display actions that are defined in the ServiceCenter Document Engine. Enabling or disabling the display actions from this array determines only whether the display action is available through the Web Services API. ServiceCenter still validates the operator credentials supplied with each Web Service request to ensure that the operator has privileges to perform the display action. Click the array field to see a list of allowable display actions for the table you select. 6. In the Action Names field, type the name you want to use in the Web Services API to identify the Document Engine display actions for this table. The name you type for this field becomes the alias name for the display action, and becomes part of the Web Service WSDL. For example, if you type Create for the add action of the mytable object, then the WSDL operation becomes CreateMytable and the WSDL message is CreateMytableRequest. The name cannot consist of XML reserved characters such as brackets (< and >), colons (:), or quotation marks (" and ).
7. Click the Data Policy tab and view the fields that are available for the table you are exposing.
The Exclude field should be set to true for any fields you want to keep out of the Web Service. If you want the field exposed, set the Exclude field to false. 8. Set the API Caption field to give an alias name to the API field. This alias name will appear in the SOAP API. 9. Set the API Data Type field to the appropriate XML data type for the field it represents:
22
10. Click Add. 11. Next create an external access definition record for the curconvert file as depicted below:
12. Click Add to add the record. 13. Create an external access definition record for the pricelist file as shown below:
23
14. Click Add to add the record and restart the ServiceCenter server.
Note: ServiceCenter users and application designers can choose any third-party Web Services development tool kit. However, ServiceCenter publishes only the WSDL files for the Web Service. Troubleshooting the client application is the responsibility of the application developer, and outside the scope of ServiceCenter Customer Support. Use the steps below as a guide to creating your custom Web Service client.
1. Publish the ServiceCenter tables that you want your client to access. You can use the
ServiceCenter Web Services API out-of-the-box or customize the Web Services to meet your needs. 2. Obtain a Web Services client development tool that can create a complete Web Service application, such as Microsoft .NET or Apache Axis, or obtain a tool that generates a complete Web Service application by evaluating the target WSDL file, such as GotDotNet WebServiceStudio. 3. Browse to the URL of your ServiceCenter server and download the WSDL files for the services you want your custom clients to use. Use your Web Services client development tool to browse the WSDL and determine which features you want your custom client to use. The URL of your server must include the listener port and the Web Service name. For example in SC 6.1 or SC 6.2 classic mode, http://<scserver>:<listener port number, default 12670>/IncidentManagement.wsdl
24
connects to the scserver host on port 12670 and requests the IncidentManagement WSDL. In ServiceCenter 6.2 servlet mode, the wsdl for Incident Management can be found by entering http://<servername>:<httpPort or loadBalancer port>/sc62server/PWS/IncidentManagement.wsdl
4. Use your Web Services client development tool to generate the programming language client
code (classes) that will serve as a proxy for the ServiceCenter Web Services API. Tools such as .NET wsdl.exe or Axis wsdl2java can convert WSDL to the code base you choose for your client code. Your custom Web Services client invokes the client code rather than the WSDL directly. 5. Write a client application in the appropriate language of your client development tool. For example, .NET requires either Microsoft Visual C# or Visual Basic, and Axis requires Java.
Retrieve methods usually available and when to use them Retrieve<FileName> Used if only one record will be returned. Throws a fault if multiple records are returned. Retrieve<FileName>KeysList Retrieves the list of unique keys (which does not have to be the unique key of the ServiceCenter dbdicts). The list can either be passed as an array to the Retrieve<FileName>List method, or looped through to pass to the Retrieve<FileName> method. Retrieve<FileName>List Retrieves a list of records with information that was gathered either in the Retrieve<FileName>KeysList method or by passing in a query directly through the instance block. This method expects an array of keys unless the query approach is used.
There are different approaches to retrieving a list of records. When developing a custom client there are actually two separate methods that can be used to retrieve list data. The first approach uses these steps:
1. Send the data query (such as <open.time>>6/30/05</open.time>) to the
RetrieveListKeys method.
2. The result is a list of records where each record contains only the primary key (such as Incident
ID) for those records that match the query. 3. You can either provide the list to the RetrieveList method and receive all records defined by the list in a single XML document, or loop through the list, one record at a time, calling Retrieve once for each record by key. The second approach uses these steps:
25
RetrieveList method. Place the query in the <instance> block instead of the <keys> block. 2. This single method call returns the entire result set (all fields for all records matching the query) in a single XML response. Note: The second approach returns the entire query result set in one method call. If the result set is large you should use the first approach to increase performance. Retrieving data from a ServiceCenter file rather than a Service Note: When using a WSDL for a single table such as contacts, it is best to request the WSDL for the alias name defined in extaccess, such as "Contact" (singular form, upper-case C) rather than for contacts (the actual file name). For example: http://localhost:12670/Contact.WSDL will ensure that you get the ServiceCenter 6.1 style WSDL and API. If you request the WSDL with the actual file name, you will retrieve the 6.0 style WSDL and API. The only reason you would write a new application using the ServiceCenter 6.0 SOAP API is if you must interoperate with a 6.0 server, or with a 6.1 server running 6.0 applications.
Example: Retrieving ServiceCenter price lists into a text file using Connect-It
To set up Connect-It to work with Web Services, the Java Configuration must be set first.
1. Click Java > Configure JVM . 2. Check the checkbox labeled Specify the JRE to use. 3. In the path of the JNI dynamic library of the JRE root directory (JavaHome) enter the path to your 4. In the path of the JNI dynamic library of the JRE enter the path to the jvm.dll including the file
name, such as c:\j2sdk1.4.2_05\jre\bin\client\jvm.dll 5. Save the settings and restart Connect-It for the settings to take effect. 6. Once Connect-It is configured to work with Web Services, you can create the ServiceCenter Web Services Connector with the following connection parameter settings. (All other settings remain the defaults.) Server name: <server name>:<listener port number> Service name: CurrencyManagement Login: falcon
7. Click Finish to save the changes made to the new connector. 8. In our example, the Web Service simply fills information into a delimited text field. The settings for
that connector are as follows: Processing Mode: write Connection protocol: Local / network files Enter a folder name and decide whether to create a separate file for each record retrieved or write all records into one file. On the next screen, decide whether to keep the old files or delete and create a new one with each run.
26
Enter the path to the descriptor file (see below) or create a new descriptor file.
9. Click Finish to create and save the connector.
To create a description file for the text output file (comma delimited text in our example), the following sample code shows a simple .dsc file that can be used for retrieving pricelist information. { TextFileFormat SCPriceList Extension= FormatType=Delimited EscapeChar="\\" Quote="\"" Extracolumn=1 WriteColumn=1 Delimiter=, { String "Item Description" UserType=Default } { Double "Price USD" UserType=Monetary } { Double "Price Foreign" UserType=Monetary } { String "Currency Foreign" UserType=Default } { TimeStamp "Date Entered" UserType=TimeStamp } } Finally the source (Web Services) data and the target date (Delimited Text file) must be mapped as shown below:
10. Because Web Services need to be prompted to produce output, another text file connector must be
created that helps create the request sent to the Web Service. This text file connector is defined as follows: Processing Mode: read Connection Protocol: Local/Network files Location: Read files, file name: c:\temp\connectitinput.txt (see below for content of file)
27
11. Upon successful processing, leave the file in the folder. 12. Use this .dsc file. Enter c:\temp\input.dsc and click Find to create or modify a description
file.
13. Select a document type: Click the down arrow and enter PriceListInput. 14. Click Next. 15. Select a file for the preview. Accept the default c:\temp\connectitinput.txt and click Next. 16. Enter the information shown on the next screen:
17. Click Next. 18. Enter the information shown on the next screen:
28
19. Click Finish. 20. Click Finish to create and save the connector. 21. Now create a mapping between this text file and the ServiceCenter Web Service by connecting
22. Click Produce Now (the F5 button) to fill information from the pricelist file in ServiceCenter
Example: Getting currency information and pricelist information from another ServiceCenter system
This example retrieves currency information from the curconvert file and uses the Web Service to add new records to the pricelist file based on the current conversion rates.
1. Click System Navigator > Menu Navigation > Utilities > Tools > Web Services
2. In the Please enter the URL for the WSDL file field, enter the following:
http://<servername>:<port number>/CurrencyManagement.wsdl
3. Click Proceed -> Add to create the CurrencyManagement JavaScript record in the ScriptLibrary.
29
4. Because authentication is necessary for Web Services to consume ServiceCenter data, the newly
created Service Object needs to be changed to define the userID that is used to sign on to ServiceCenter. Modify the code as shown below. Note: The namespace specified in this.location does not have to be resolvable.
function CurrencyManagement( ) { this.location = new String( "http://localhost:12670/scserver61/ws" ); this.user = "falcon"; this.password = null; this.connectTimeOut = 10; this.sendTimeOut = 10; this.recvTimeOut = 10; this.soapEnvelope = null; this.soapBody = null; this.soapHeader = null; this.attachments = new Array(); this.resultXML = null; this.invoke = invoke;
5. Now that the Script has been added to the ScriptLibrary, you write another JavaScript that can be
used to retrieve the currency conversion data. Enter the JavaScript code as listed below:
function RetrieveCurrencyConversion(RootCurrency, ForeignCurrency) { var CurrConvSvc = new system.library.CurrencyManagement.CurrencyManagement(); var retrieveReq = new system.library.CurrencyManagement.RetrieveCurrencyConversionList(); retrieveReq.newInstance(); retrieveReq.keys[0].RootCurrencyCode.setValue(RootCurrency); retrieveReq.keys[0].CurrencyCode.setValue(ForeignCurrency); try { var retrieveResp = CurrConvSvc.invoke(retrieveReq); if ( retrieveResp.isFault() ) { throw( "SOAP Fault: " + retrieveResp.faultstring.getValue() ); } return retrieveResp.instance; } catch( err ) { return( "Error! " + err ); } } // Below an example on how to call the function and retrieve all Exchange // Rates stored for USD to EUR conversion. This looping through the records // will have to be done from the calling application / java script when // calling the RetrieveCurrencyConversion function. var instanceArrayObj = RetrieveCurrencyConversion("USD", "EUR"); var numRecs = instanceArrayObj.length; var i;
30
creates a new record with updated foreign price and date. Enter the Java Script shown below: function AddUpdatedPriceList(ID, PriceUSD, CurrencyForeign) { var PriceListSvc = new system.library.CurrencyManagement.CurrencyManagement(); var UpdateReq = new system.library.CurrencyManagement.ConvertAddPricelistPricelist(); UpdateReq.model.keys.id.setValue(ID); UpdateReq.model.instance.PriceUSD.setValue(PriceUSD); UpdateReq.model.instance.ForeignCurrencyCode.setValue(CurrencyForeign); try { var updateResp = PriceListSvc.invoke(UpdateReq); if ( updateResp.isFault() ) { throw( "SOAP Fault: " + updateResp.faultstring.getValue() ); } return updateResp.model.instance; } catch( err ) { return( "Error! " + err ); } } var ResRecord = AddUpdatedPriceList(1, 30, "EUR");
directory.
C:\Program Files\ServiceCenter Server\webservices\sample\DotNetSample\ DotNetSample\bin\Debug>dotnetsample -example CloseIncident host localhost port 61170 -incidentId IM1001 -closeCode "User Closure" -resolution "I want to see if this works"
31
Note: If the username and password are not entered specifically, they default to falcon with no password, and the following appears in the sc.log file: 2984 05/19/2006 10:17:29 Process 2984 started on socket 216. 2984 05/19/2006 10:17:29 Process scenter 6.1.1.0 (0082) System: 61170 (0x7d781a00) 2984 05/19/2006 10:17:29 on PC running Windows XP Professional (5.1 Build 2600) from xxxxx (127.0.0.1) 2984 05/19/2006 10:17:29 connected to SOAP client at 127.0.0.1:4072 2984 05/19/2006 10:17:29 Attaching to resources with key 0x7d781a00 2984 05/19/2006 10:17:29 Starting SOAP server 2984 05/19/2006 10:17:29 tpzsoap: soap_bind succeeded. New listening port=4073 2984 05/19/2006 10:17:29 Authentication failure - No "Authorization: Basic" header was supplied, or it contained a zero-length userid 2984 05/19/2006 10:17:29 Exception occurred for method Close and XML request <CloseIncidentRequest xmlns="http://servicecenter.peregrine.com/PWS" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ><model><keys><IncidentID>IM1001</IncidentID></keys><instance><IncidentID xsi:nil="true" /><Category xsi:nil="true" /><OpenTime xsi:nil="true" /><OpenedBy xsi:nil="true" /><Severity xsi:nil="true" /><UpdatedTime xsi:nil="true" /><PrimaryAssignmentGroup xsi:nil="true" /><ClosedTime xsi:nil="true" /><ClosedBy xsi:nil="true" /><ClosureCode>User Closure</ClosureCode><ConfigurationItem xsi:nil="true" /><Location xsi:nil="true" /><AssigneeName xsi:nil="true" /><Contact xsi:nil="true" /><AlertStatus xsi:nil="true" /><ContactLastName xsi:nil="true" /><ContactFirstName xsi:nil="true" /><Company xsi:nil="true" /><BriefDescription xsi:nil="true" /><TicketOwner xsi:nil="true" /><UpdatedBy xsi:nil="true" /><IMTicketStatus xsi:nil="true" /><Subcategory xsi:nil="true" /><SLAAgreementID xsi:nil="true" /><SiteCategory xsi:nil="true" /><ProductType xsi:nil="true" /><ProblemType xsi:nil="true" /><ResolutionFixType>permanent</ResolutionFixType><attachments xsi:nil="true" /></instance></model></CloseIncidentRequest> 2984 05/19/2006 10:17:29 soap_serve - Caught XML API exception scxmlapi(20) - Authentication failure 2984 05/19/2006 10:17:29 Sending 401 Not Authorized challenge 2984 05/19/2006 10:18:03 User falcon has logged in and is using a Floating license (1 out of a maximum 10) 2984 05/19/2006 10:18:06 Activity record added. 2984 05/19/2006 10:18:06 Triggers have been turned on 2984 05/19/2006 10:18:06 Incident IM1001 has been closed by falcon. Related calls will be processed normally.
Troubleshooting
The combination of debugging tools and information gathered from SOAP faults usually helps you find the root cause of an issue easily. Unfortunately, not all Web Services give sufficient SOAP fault messages, which makes debugging the issue more challenging.
32
Important: If you are using a newer WSDL2JS utility (or SOAP ScriptLibrary record), it is likely that the generated JavaScript records will have to be re-generated and the calling JavaScripts have to be re-compiled.
Debugging
Three parameters are most frequently used: debughttp, RTM:3, and debugdbquery:999.
debughttp
Enter debughttp in the server sc.ini file and restart the client to invoke the debugging parameter. For consuming Web Services, the debughttp parameter creates two files in the ServiceCenter Server RUN directory, outbound_http.log and outbound_test.log, and writes additional information into the sc.log file. An excerpt of the outbound_http.log file follows. (See the red areas for the error messages that were captured.) POST /scserver61/ws HTTP/1.0 Host: lp84564igeist:61170 User-Agent: gSOAP/2.2 Content-Type: text/xml; charset=utf-8 Content-Length: 1128 Connection: Close Accept-Encoding: gzip, deflate Authorization: Basic ZmFsY29uOg== SOAPAction: "Retrieve" <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://servicecenter.peregrine.com/PWS"><soap:Body><RetrieveCur rencyConversion attachmentInfo="false" attachmentData="false" ignoreEmptyElements="true" xmlns="http://servicecenter.peregrine.com/PWS"><model query=""><keys query=""><sortcode type="Decimal" mandatory="false" readonly="false"/><CurrencyCode type="String" mandatory="false" readonly="false">EUR</CurrencyCode><Date type="DateTime" mandatory="false" readonly="false"/><RootCurrencyCode type="String" mandatory="false" readonly="false">USD</RootCurrencyCode></keys><instance query="" uniquequery="" recordid=""><CurrencyCode type="String" mandatory="false" readonly="false"/><Date type="DateTime" mandatory="false" readonly="false"/><ExchangeRate type="Float" mandatory="false" readonly="false"/><RootCurrencyCode type="String" mandatory="false"
33
readonly="false"/><attachments></attachments></instance><messages></messa ges></model></RetrieveCurrencyConversion></soap:Body></soap:Envelope>HTTP /1.1 500 Internal Server Error Pragma: thinktime="0" Server: gSOAP/2.2 Cache-Control: no-cache Content-Type: text/xml; charset=utf-8 Content-Length: 657 Connection: Close Set-Cookie: SessionId=16.95.106.150:3655;Version=1 <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAPENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://servicecenter.peregrine.com/PWS"><SOAP-ENV:Body><SOAPENV:Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>scxmlapi(26) - Get request found more than one record</faultstring><detail><appFaultCode>26</appFaultCode><appFaultStrin g>scxmlapi(26) - Get request found more than one record</appFaultString></detail></SOAP-ENV:Fault></SOAP-ENV:Body></SOAPENV:Envelope>POST /scserver61/ws HTTP/1.0 Host: lp84564igeist:61170 User-Agent: gSOAP/2.2 Content-Type: text/xml; charset=utf-8 Content-Length: 1109 Connection: Close Accept-Encoding: gzip, deflate Authorization: Basic ZmFsY29uOg== SOAPAction: "RetrieveList"
34
2. Click the Invoke tab, select the method to test, and then check the input fields, both for values
that were filled with incorrect information that needs to be changed and for criteria that need to be added for a successful test. 3. Click Invoke. 4. An error message is displayed because the not authorized error occurred. Click Continue and click the Request / Response tab. ************** Exception Text ************** System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Client found response content type of 'text/html; charset=utf-8', but expected 'text/xml'. The request failed with the error message: -Not Authorized --.
5. On the left hand side of the Request / Response tab is the authentication information. Enter the
BasicAuthUserName and change the following settings from False to True: AllowAutoRedirect AllowWriteStreamBuffering PreAuthenticate UseCookieContainer UseDefaultCredential
Note: The information entered on the Request/Response tab is not stored and has to be re-entered frequently.
6. Click Send.
In the lower right, the response from the Server will be displayed. In the example shown below, it is the key value for the record that matched the retrieve criteria.
35
Advanced Troubleshooting
How to troubleshoot a Web Service that is behind a closed firewall
Sometimes it may be necessary to troubleshoot a Web Service that is not available. To do so, we can check whether a wsdl file that is stored on the local machine works using test data. Step 1: Test the WSDL2JS
1. Store the wsdl file locally on the server. 2. Click Utilities > Tools > Web Services. Click Run WSDL to JS and enter the following:
If the JavaScript file for the Web Service is generated without error messages and ends with // Ensure that material in lib.SOAP is available lib.SOAP.init(); /// End --------------- then the WSDL to JS program was able to interpret the wsdl file correctly. To correctly write the JavaScript functions to call this Web Service and generated Java Script, check the generated Java Script for the function you want to use, in this case: this.SOAPOperations[ "RetrieveIncident" ] = new soap_Operation( "RetrieveIncident", "Retrieve", "document", "RetrieveIncidentRequest", "RetrieveIncidentResponse" ); The request can be found within that line and refers to the request function further down: function RetrieveIncidentRequest( { this.$$nsPrefix = "ns"; )
36
this.$$attributes = new Array(); this.$$xmlNames = new Array(); this.$$objNames = new Array(); this.$$minOccurs = new Array(); this.getName = getName; this.getXmlName = getXmlName; this.setContent = setContent; this.addContent = addContent; this.getContent = getContent; this.isFault = isFault; this.$$elementChildren = new Array(); this.$$name = "RetrieveIncidentRequest"; this.$$xmlNames[ "RetrieveIncidentRequest" ] = "ns:RetrieveIncidentRequest"; this.attachmentInfo = new Boolean(); this.$$attributes.push( "attachmentInfo" ); this.attachmentData = new Boolean(); this.$$attributes.push( "attachmentData" ); this.ignoreEmptyElements = new Boolean("true"); this.$$attributes.push( "ignoreEmptyElements" ); this.xmlns = new String("http://servicecenter.peregrine.com/PWS"); this.$$attributes.push( "xmlns" ); this.model = new RetrieveIncidentRequest_IncidentModelType(); this.$$elementChildren.push( "model" ); } Step 2: Test the request Once the automatically generated JavaScript code was saved (and userID information was added if necessary), write a calling JavaScript to execute the Web Service. The following is a simple example code for IncidentManagement record retrieval: function RetrieveIncident(incident_id) { var IncMgmtSvc = new system.library.IncidentManagement.IncidentManagement(); var retrieveReq = new system.library.IncidentManagement.RetrieveIncidentRequest(); retrieveReq.model.keys.IncidentID.setValue(incident_id); try { var retrieveResp = IncMgmtSvc.invoke(retrieveReq); if ( retrieveResp.isFault() ) { throw( "SOAP Fault: " + retrieveResp.faultstring.getValue() ); } return retrieveResp.model.instance; } catch( err ) { return( "Error! " + err ); } } retVal=RetrieveIncident("IM1001"); print("Testing the result" + retVal.IncidentID.getValue())
1. To test the request, enter debughttp in the sc.ini file and restart the client. 2. If the file outbound_http.log exists in the servers RUN directory, remove it or remove its
3. Go into the calling JavaScript and click Execute. You will most likely get an error message
because the Web Service you are trying to reach is not available.
37
4. After the execution is complete, open the outbound_http.log file and search for the following:
POST /scserver61/ws HTTP/1.0 Host: lp84564igeist:61170 User-Agent: gSOAP/2.2 Content-Type: text/xml; charset=utf-8 Content-Length: 2680 Connection: Close Accept-Encoding: gzip, deflate Authorization: Basic ZmFsY29uOg== SOAPAction: "Retrieve" <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://servicecenter.peregrine.com/PWS"><soap:Body><ns:Retrieve IncidentRequest attachmentInfo="false" attachmentData="false" ignoreEmptyElements="true" xmlns="http://servicecenter.peregrine.com/PWS"><ns:model><ns:keys><ns:Inc identID type="String" mandatory="false" readonly="false">IM1001</ns:IncidentID></ns:keys><ns:instance><ns:Inciden tID type="String" mandatory="false" readonly="false"/><ns:Category type="String" mandatory="false" readonly="false"/><ns:OpenTime type="DateTime" mandatory="false" readonly="false"/><ns:OpenedBy type="String" mandatory="false" readonly="false"/><ns:Severity type="String" mandatory="false" readonly="false"/><ns:UpdatedTime type="DateTime" mandatory="false" readonly="false"/><ns:PrimaryAssignmentGroup type="String" mandatory="false" readonly="false"/><ns:ClosedTime type="DateTime" mandatory="false" readonly="false"/><ns:ClosedBy type="String" mandatory="false" readonly="false"/><ns:ClosureCode type="String" mandatory="false" readonly="false"/><ns:ConfigurationItem type="String" mandatory="false" readonly="false"/><ns:Location type="String" mandatory="false" readonly="false"/><ns:IncidentDescription></ns:IncidentDescription><ns:Re solution></ns:Resolution><ns:AssigneeName type="String" mandatory="false" readonly="false"/><ns:Contact type="String" mandatory="false" readonly="false"/><ns:JournalUpdates></ns:JournalUpdates><ns:AlertStatus type="String" mandatory="false" readonly="false"/><ns:ContactLastName type="String" mandatory="false" readonly="false"/><ns:ContactFirstName type="String" mandatory="false" readonly="false"/><ns:Company type="String" mandatory="false" readonly="false"/><ns:BriefDescription type="String" mandatory="false" readonly="false"/><ns:TicketOwner type="String" mandatory="false" readonly="false"/><ns:UpdatedBy type="String" mandatory="false" readonly="false"/><ns:IMTicketStatus type="String" mandatory="false" readonly="false"/><ns:Subcategory type="String" mandatory="false" readonly="false"/><ns:SLAAgreementID type="Decimal" mandatory="false" readonly="false"/><ns:SiteCategory type="String" mandatory="false" readonly="false"/><ns:ProductType type="String" mandatory="false" readonly="false"/><ns:ProblemType type="String" mandatory="false" readonly="false"/><ns:ResolutionFixType type="String" mandatory="false" readonly="false"/><ns:Solution></ns:Solution><ns:AttachmentsType></ns:Att achmentsType></ns:instance><ns:MessagesType></ns:MessagesType></ns:model> </ns:RetrieveIncidentRequest></soap:Body></soap:Envelope>HTTP/1.1 200 OK Pragma: thinktime="0" Server: gSOAP/2.2 Cache-Control: no-cache Content-Type: text/xml; charset=utf-8 Content-Encoding: gzip Content-Length: 1246 Connection: Close Set-Cookie: SessionId=16.95.106.150:3487;Version=1
5. You can copy the bold area into an XML editor such as Altova XMLSpy and check whether it is
correct XML. If it is, then the request is deemed to be successful (which does not necessarily mean that it will return data).
38
Step 3: Testing the response After the request has been submitted successfully, you test the response to the request, which is written to the outbound_http.log file. Look for the following text. (The section that is bolded indicates that this is the response message): <?xml version="1.0" encoding="utf-16"?> <SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC= "http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http: //www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/ 2001/XMLSchema" xmlns="http://servicecenter.peregrine.com/PWS"> <SOAP-ENV:Body> <RetrieveIncidentResponse message="Success" returnCode="0" schemaRevisionDate="2005-04-20" schemaRevisionLevel="0" status="SUCCESS" xmlns="http://servicecenter.peregrine.com/PWS" xmlns:cmn="http://servicecenter.peregrine.com/PWS/Common" xsi:schemaLocation="http://servicecenter.peregrine.com/PWS http://lp84564igeist:61170/PWS/Incident.xsd"> <model query="number="IM1001""> <keys> <IncidentID type="String">IM1001</IncidentID> </keys> <instance recordid="IM1001 - Phone in going dead intermittently." uniquequery="number="IM1001""> <IncidentID type="String">IM1001</IncidentID> <Category mandatory="true" type="String">telecoms</Category> <OpenTime type="DateTime">2001-01-01T08:00:00+00:00</OpenTime> <OpenedBy type="String">BOB.HELPDESK</OpenedBy> <Severity type="String">1</Severity> <UpdatedTime type="DateTime">2006-06-06T15:44:53+00:00 </UpdatedTime> <PrimaryAssignmentGroup type="String">TELECOMS </PrimaryAssignmentGroup> <ClosureCode type="String">User Closure</ClosureCode> <ConfigurationItem type="String">JeffPC</ConfigurationItem> <Location type="String">Warminster</Location> <IncidentDescription type="Array"> <IncidentDescription type="String">Phone is going dead intermittently.</IncidentDescription> </IncidentDescription> <Contact type="String">PETERS, JEFF</Contact> <JournalUpdates type="Array"> <JournalUpdates type="String">05/26/06 09:37:13 US/Pacific (falcon):</JournalUpdates> <JournalUpdates type="String">update in ticket updated. </JournalUpdates> <JournalUpdates type="String">03/08/2001 16:11:40 alert stage 3</JournalUpdates> <JournalUpdates type="String">**ALERT**</JournalUpdates> <JournalUpdates type="String">01/23/01 11:29:39 (FALCON):</JournalUpdates> </JournalUpdates> <ContactLastName type="String">Peters</ContactLastName> <ContactFirstName type="String">Jeff</ContactFirstName> <Company type="String">PRGN</Company> <BriefDescription type="String">Phone in going dead intermittently.</BriefDescription> <TicketOwner type="String">BOB.HELPDESK</TicketOwner> <UpdatedBy type="String">CIT-Bridge</UpdatedBy> <IMTicketStatus type="String">Open</IMTicketStatus> <Subcategory type="String">fixed infrastructure</Subcategory> <SLAAgreementID type="Decimal">0</SLAAgreementID> <SiteCategory type="String">D</SiteCategory> <ProductType type="String">fixed infrastructure</ProductType> <ProblemType type="String">not specified</ProblemType> <ResolutionFixType type="String">permanent</ResolutionFixType> </instance> </model> </RetrieveIncidentResponse>
39
</SOAP-ENV:Body> </SOAP-ENV:Envelope>
1. Copy the section mentioned above from the outbound_http.log file into a text file and assign
it a name such as responsetest.xml. 2. Change the calling JavaScript to override the invoke function to read and interpret the contents of the responsetest.xml file. The following is the section of the code needed to do that. // Temporarily override the "invoke" function to replace it with // a function which reads an XML response from a file <ServiceObject>.invoke = function( ) { var resultObj = new Object(); resultObj.responseObj = null; var resultXML = new XML(); resultXML.setContent( "c:\\<path>\\<responsetest.xml>", true ); try { lib.SOAP.deserialize( "<name of the generated JavaScript>", resultXML.getDocumentElement(), resultObj ); } catch( e ) { print( "Error deserializing response: " + e.toString() ); return null; } try { this.soapEnvelope = resultObj.soap_Envelope; this.soapBody = resultObj.soap_Envelope.soap_Body; if ( this.soapEnvelope.soap_Header != undefined ) { this.soapHeader = this.soapEnvelope.soap_Header; } else this.soapHeader = null; return resultObj.soap_Envelope.soap_Body.getContent(); } catch( e ) { print( "Error extracting Response Object: " + e.toString() ); return null; } }
3. Change the line of the calling JavaScript that invokes the Web Service from
<ServiceObject>.invoke to simply invoke to call the invoke function defined within that calling JavaScript. 4. Click Execute to run this modified JavaScript. If it finishes without errors, the response is deemed successful. If any of the above tests fail to complete, contact HP OpenView ServiceCenter Customer Support and provide the wsdl file, the request and response xml text files with any error messages, and the sc.log and outbound_http.log files with debughttp turned on.
40
subsequent POST requests. If the client fails to do this, the servlet container will quickly run out of sessions. Affected customers consuming ServiceCenter 6.2 Web Services will need to use one of the following workarounds: Connect the Web Service to the classic mode listener instead. Note that the service location URL is different for classic mode. In servlet mode, the URL is http://<server>:<port>/sc62server/ws/<module>.wsdl; in classic mode it is only http://<server>:<port>/<module>.wsdl. Also note that classic mode does not support chunked transfer encoding or multipart MIME attachment format. Configure the SOAP stack with which the SOAP API client is written to support cookies. Axis and .NET can both be configured to do this. If the SOAP toolkit supports HTTP 1.1 Keep-Alive but not cookies, you can arrange for the application to echo back the JSESSIONID value in a Cookie header by adding code to the client application to manually create the HTTP header on the second and subsequent requests
Error Messages
Error Message: soap_serve - Caught XML API exception scxmlapi(19) - Doc Engine call failed with cc -1 This error message is issued when the Document Engine did not attempt to write the record, because the Process called via extaccess does not perform a save operation. To fix this issue, change the Document Engine Process to save the record by calling the rca.save Process from the rca.reopen Process. Error Message: <SOAP-ENV:Fault><faultcode>SOAPENV:Server</faultcode><faultstring>scxmlapi(16) - Invalid or missing file name in XML request</faultstring><detail><appFaultCode>16</appFaultCode><appFaultString>s cxmlapi(16) - Invalid or missing file name in XML request</appFaultString></detail></SOAP-ENV:Fault> This error message can be seen if the binaries cannot successfully retrieve the name for the Object to access from the extaccess file. This can be fixed by adding filename=<filename> in the SOAP body of the application. For example: <soap:Body> <ConvertAddPricelistPricelistRequest filename="pricelist" xmlns="http://servicecenter.peregrine.com/PWS"> Note: To prevent this issue, do not use camel case notation (where the name contains compound words or phrases that are joined without spaces, and each word is capitalized within the name.) in the Object Name in the extaccess file. As a best practice, use the name of the dbdicts as the Object Name as well.
41
Error Message: getType() in com.peregrine.webservice.ComputerInstanceTypeDevice cannot override getType() in com.peregrine.webservice.common.StructureType; attempting to use incompatible return type The ConfigurationManagement WSDL is made up of the device extaccess record in addition to a number of joinfiles (such as joincomputer and joindisplaydevice). The following errors occur when you set the API Caption for the type field in the device extaccess record to type or Type and then attempt to compile the WSDL using Apache Ant: build_java: [javac] Compiling 114 source files to C:\ServiceCenter6\Server613\webservices\sample\AxisSample\build [javac] C:\ServiceCenter6\Server613\webservices\sample\AxisSample\src\com\ peregrine\webservice\ComputerInstanceTypeDevice.java:225: getType() in com.peregrine.webservice.ComputerInstanceTypeDevice cannot override getType() in com.peregrine.webservice.common.StructureType; attempting to use incompatible return type [javac] found : com.peregrine.webservice.common.StringType [javac] required: java.lang.String [javac] public com.peregrine.webservice.common.StringType getType() { [javac] [javac] 1 error BUILD FAILED C:\ServiceCenter6\Server613\webservices\sample\AxisSample\ build.xml:184: Compile failed; see the compiler error output for details. To avoid this or similar errors, make sure that the name is valid and does not conflict with previously defined names when you set up alias names (API Captions). All of the common.xsd definitions for data types such as StructureType, ArrayType, have a type attribute, for which Axis manufactures a getType Java method. When it generates a getType method for this new type property/field, those two methods conflict. It does not matter whether you specify type or Type because Axis uses camel-case naming conventions for its generated method names. Whenever an API caption can cause a conflict with a pre-existing function, change it to be something unique; in this case, for example, make the API caption typeSC. Error Message: Invalid element in com.peregrine.webservice. After adding a field to a table which is published through WebServices, or renaming a field which is exposed through ServiceCenter WebServices, the WebServices Client application failed with invalid element exception. In the case of running ServiceCenter Axis Sample WebService Application, the following error is displayed (emphasis added): Failed to execute sample AxisFault faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException faultSubcode: faultString: org.xml.sax.SAXException: Invalid element in com.peregrine.webservice.ContactInstanceType - empid faultActor: faultNode: faultDetail: {http://xml.apache.org/axis/}stackTrace:org.xml.sax.SAXException: Invalid element in com.peregrine.webservice.ContactInstanceType empid at org.apache.axis.encoding.ser.BeanDeserializer.onStartChild(BeanDese rializer.java:255)
42
at org.apache.axis.encoding.DeserializationContext.startElement(Deseri alizationContext.java:1035) at org.apache.axis.message.SAX2EventRecorder.replay(SAX2EventRecorder. java:165) This error will be addressed with SCR 39251 and is caused by the following two situations: When you add a new field through the DBDict Utility and do not intent to expose the field through WSDL, the DBDict Utility fails to default the excluded from API? column in data policy to true. As a result, the new field is published on WSDL. When you try to rename a field with DBDict Utility or System Definition Table that is already exposed through WSDL, DBDict Utility and System Definition Table failed to reserve the WSDL information in Data Policy, API captions, exclude, and API Data type for the renamed field is lost after renaming. As a result, the renamed field is published on WSDL with its ServiceCenter dbdict field name.
As a workaround, after adding or renaming a field in the dbdict using either DBDict Utility or System Definition Utility perform the following steps:
1. 2. 3. 4. 5. 6.
From Main menu, go to Toolkit > WSDL configuration In the name text box, put the table name you just edited. Click search Click on data policy tab Set WSDL info for the new or renamed field. Save and exit.
Attachment handling What do these error messages mean? Error Message: Warning: incoming add attachment request 1 has no href attribute Error: unable to match incoming add attachment request 1 with no href attribute to an attachment part They indicate that the <attachment> elements in the XML in the SOAP requests do not have the href or contentId attribute value that they are supposed to have. The same value is supposed to be in the DIME message part as the cid: value. In SOAP with attachments, something has to act as the correlation between the XML element/attributes that describe the attachment on the one hand, and the actual binary or base64 attachment content which is in a DIME or MIME message on the other hand. This correlation is typically a unique ID specified in an href or contentId attribute. For reasons described below, the ServiceCenter server deliberately allows requests that omit the href or contentId and try to match up the XML and the attachment parts. We report the missing href or contentId value with a message in the sc.log file, as follows: 3784(0x00000fd8) 07/27/2005 16:25:51 Warning: incoming add attachment request 1 has no href attribute The server first tries to get an href or contentId value out of the XML; if it succeeds, it finds the associated DIME attachment by looking for a DIME message part whose id has the same value. If there is no href or contentId, the server tries to match up the <attachment> element with a particular attachment part. However, the logic for this: Assumes that there is a one-to-one correspondence between <attachment> elements and attachment parts.
43
Uses the index of the DOM node of the <attachment> element as an index into the array of binary attachment parts.
This strategy does not work when there are miscellaneous whitespace nodes in the DOM document, because the index number of the DOM node for the <attachment> element is greater than it would otherwise be. The reason ServiceCenter allows requests with no href or contentId is that it is very challenging with some tools and toolkits to arrange for the unique id of an attachment part to be the same in the XML as in the binary attachment part. Though this is trivial when using .NET, when using Axis, the Java code would generate a unique cid: value in the DIME message part dynamically during message serialization. Unless code to set up a handler to participate in serialization (via a callback) is written, it is impossible to match the value in the XML to the value in the DIME message part. To prevent these problems (which made it very hard to write Axis applications that can handle attachments), the ServiceCenter code: Relaxed the schema such that href was not strictly required (use=optional). Added an alternative, optional attribute called contentId, which is used instead of href when serving responses containing attachments to Axis clients. Added code to try to guess the href value that should be present in the XML, if it is missing. If we are processing the Nth <attachment> element (the Nth DOMNode within the set of DOM children for the <attachments> element, where the <attachment> element has neither an href nor a contentId attribute), ServiceCenter tries to look at the attachment part with the same index value to check whether the name, length, and type match. If the number of DOMNode children under <attachments> does not match the number of attachment parts, ServiceCenter cannot process the attachment, and prints the following error in the sc.log file:
3784(0x00000f9c) 07/27/2005 16:25:52 Error: unable to match incoming add attachment request 2 with no href attribute to an attachment part This message says attachment request 2, which seems to be incorrect; because there is only 1 <attachment> element, it should apparently be attachment request 1. However, the attachment element is the second DOM child node of <attachments> due to the whitespace text present as DOM child node 1; the first child node of <attachments> is ignorable whitespace. The workaround is either not to serialize with pretty-printing (such as adding white space nodes to make the XML easier to read for the human eye) when sending requests to ServiceCenter, or to write code that ensures that requests containing attachment operations have either an href or contentId attribute on the <attachment> element. Supported attachment types in ServiceCenter 6.2 are MIME and DIME. We often get the question if the consumer does not support these attachment types, if the SYSATTACHMENTS file can be exposed to get the attachments out of ServiceCenter. This is not supported. The attachments are compressed and cut into <=32K pieces and cannot easily be read from an outside source. A workaround that customers use frequently is receiving the attachment with the parent record, for example via a RetrieveIncident request, and then transforming it into base64 and sending to the consuming application where it can be transformed into the required format. Sample script to send a ticket with attachments from ServiceCenter to ServiceCenter First you will have to have a generated JavaScript for both ServiceCenters. For ServiceCenter 1 it is called IncidentManagement, for SC2 it is called IncidentManagementTarget. Note the lines in bold font that perform the attachment handling: try {
44
var attach; var imService = new lib.IncidentManagement.IncidentManagement(); var request = new lib.IncidentManagement.RetrieveIncidentRequest(); request.model.instance.IncidentID.setValue( "IM1001" ); request.attachmentInfo = true; request.attachmentData = true; imService.user = "falcon"; imService.pwd = ""; imService.setHost("localhost"); var incidentResp = imService.invoke( request ); if ( incidentResp.isFault() ) { print ( incidentResp.detail ); } else { if ( incidentResp.messages.message.length > 0 ) { for ( i=0;i<incidentResp.messages.message.length;i++ ) { print ( "Message: " + incidentResp.messages.message[i].getValue() ); } } print( incidentResp.model.instance.attachments.attachment.length ); print( incidentResp.model.instance.attachments.attachment[0].name ); print( incidentResp.model.instance.attachments.attachment[0].len ); attach = imService.attachments[0]; } var imService2 = new lib.IncidentManagementTarget.IncidentManagement(); var newAttach = new Array(); attach.href = "12345"; attach.action="add"; newAttach.push( attach ); var createIM = new lib.IncidentManagementTarget.CreateIncidentRequest(); imService2.setAttachments( newAttach ); imService2.setHost("localhost"); imService2.user = "falcon"; imService2.pwd = ""; createIM.attachmentData = true; createIM.attachmentInfo = true; createIM.model.instance.OpenedBy.setValue("BOB.HELPDESK"); var a = createIM.model.instance.IncidentDescription.IncidentDescription_newIns tance(); a.setValue("Incident Description"); createIM.model.instance.BriefDescription.setValue("Brief Description"); createIM.model.instance.Category.setValue("telecoms"); createIM.model.instance.Subcategory.setValue("fixed infrastructure"); createIM.model.instance.ProductType.setValue("fixed infrastructure"); createIM.model.instance.ProblemType.setValue("not specified"); createIM.model.instance.InitialImpact.setValue("1"); createIM.model.instance.Severity.setValue("1"); createIM.model.instance.PrimaryAssignmentGroup.setValue("TELECOMS");
45
var attachmentXml = createIM.model.instance.attachments.attachment_newInstance(); attachmentXml.action = attach.action; attachmentXml.name = attach.name; attachmentXml.type = attach.type; attachmentXml.len = attach.value.length; attachmentXml.attachmentType = attach.attachmentType; print( createIM.model.instance.attachments.attachment.length ); response = imService2.invoke(createIM); if ( response.isFault() ) { print ( response.detail ); } else { if ( response.messages.message.length > 0 ) { for ( i=0;i<response.messages.message.length;i++ ) { print ( "Message: " + response.messages.message[i].getValue() ); } } } } catch( e ) { print( e ); }
Appendix
Understanding the return codes provided by the ServiceCenter Web Service
Currently the status attribute always contains either "SUCCESS" or "FAILURE". A best practice is to check either the status to see if it has the value SUCCESS or to check the return code to see if it is zero. All other values equate to FAILURE. The value of the message attribute is a string which corresponds to the return code value. The ServiceCenter server global JavaScript method called RCtoString()will convert a particular integer return code value to the corresponding message text. The following are the currently defined values: 0 = Success 1 = Bad Length 2 = Bad Serial Number 3 = Resource Unavailable 4 = Unable to Terminate 5 = Resource Not Available 6 = Resource Expired 7 = Specified Name Not Found 9 = No (more) records found
46
10 = No messages 11 = No query words 12 = No stop words 13 = No string 14 = No such word 15 = Not enough memory 16 = Already exists 17 = Shutdown error 18 = Stop words not found 19 = Too many documents 20 = Unable to open file for output 21 = Waiting for resource 22 = Word length too long 23 = Duplicate file system 24 = Duplicate IPC Key 25 = IPC Key Not Found 27 = Wrong owner 28 = Not authorized 29 = Invalid Userid Specified 30 = Invalid Password Specified 31 = New Password is Invalid 32 = Password Expired 33 = Authority Revoked 34 = Max Attempts to Login Exceeded 35 = Max Number of Logins Exceeded 36 = Invalid terminal for user 37 = Invalid Authorization Code 38 = Maximum users exceeded 39 = Named user already logged in 40 = Not a named user and no floating users available 41 = User Already Logged In 42 = Forced synchronization 43 = IR read count mismatch 44 = Seek error 45 = 24x7: DBLOG error 46 = Open error
47
47 = Error closing remote file 48 = Duplicate key 49 = Null key 50 = All null keys 51 = Record modified since last retrieved 52 = Record deleted since last retrieved 53 = Trigger Error 54 = Not supported 55 = Record no longer qualifies 56 = Query timed out 57 = Unable to delete file 58 = Partially-keyed or non-keyed query 59 = Error occured in parsing 60 = Shared memory version mismatch 61 = Distributed Lock Manager cannot lock item 62 = Refresh not needed 63 = Userid expired 64 = Userid inactive 65 = SQL conversion skipped for this file 66 = Query could not be parsed 67 = file could not be opened 68 = User is not located in LDAP 69 = User is not allowed to use ODBC driver 70 = Invalid SOAPaction / unrecognized application action 71 = Validation failed 72 = User is not allowed to use SOAP API The following is an example of a failure return code and message: message="No (more) records found" returnCode="9" status="FAILURE" In addition to these return codes, the ServiceCenter administrator can manipulate the detailed return code by setting the value of $L.exit in the document engine processs final expressions to one of the following:
Action or Error Situation record has changed since it was selected cancel processing the record record is locked Request failed validation $L.exit value changed cancel locked bad.val
48
record was deleted since it was selected exit processing normal exit Record should get unlocked Sets exit value to menu to return to the menu Record was added, screen will be refreshed Processing will restart starting with init of file variable Processing will proceed with a new state record Displayed records will be refreshed Displayed joinfile records will be refreshed Category changes Position in record list will be changed Record will be reset to original values Mode will be set to close and close processing will start Restart processing starting with init of file variable Mode will be set to add, which goes into the open state Initializing values to add record An undefined action was passed to the document engine User is not authorized for this action
deleted exit normal unlock menu added restart newstate refresh refreshjoinfile newcat reposition resetrec closestate restart openstate setupadd invalid.action no auth
49
For an anonymous SSL connection with an external Web Service using WSDL2JS, you need a root certificate file which includes the certificate for the CA that signed the remote Web Server's certificate. The cacert.pem file that is shipped with ServiceCenter does not contain the most common CA certificates and needs to be edited as described above. When the root certificate file is saved, the following parameter, which identifies the name of the root certificate or authority's certificate, must be entered into the ServiceCenter server sc.ini file, if it does not yet exist: cacertpem:<name of the root certificate such as cacert.pem> After entering this parameter, restart the ServiceCenter server. If the https://fully qualified server path:portnumber/Service.wsdl connection does not work after you make these changes, it is possible that the distinguished name (DN) used to create the certificate is not identical to the fully qualified server path in the URL. Check which DN the certificate is using by asking the provider of the certificate. If it is different from the fully qualified path used in the URL, request a new certificate where the DN matches the URL. If this cannot be done in a timely manner, the following workaround can be tested: Go to the servers hosts file (which is located in etc/hosts on UNIX systems, and located in c:\winnt\system32\drivers\etc\hosts on Windows systems). In the hosts file, add a line with the fully qualified name of the certificate and the IP address of the machine that runs the Web Service. For example: mymachine.hp.com 10.2.5.77 where mymachine.hp.com is the distinguished name (DN) of the certificate and 10.2.5.77 is the IP address for the server that hosts the Web Service. Note: This is a temporary workaround, and not a permanent fix. As soon as the new certificate is issued, that certificate should be put into the root certificate file, and the entry in the hosts file should be removed. Important: When you use SSL connections on high-frequency Web Services where many requests per second are made, performance is negatively impacted because an SSL handshake occurs for each SOAP request. The SSL handshake involves numerous TCP requests and responses as the two partners identify each other, negotiate the encryption algorithm, and perform other required tasks.
50
Best Practices
Writing a JavaScript for consuming a Web Service
Never modify the JavaScript that is automatically generated by WSDL2JS unless you are specifically instructed to do so by OpenView ServiceCenter Customer Support. To invoke the Web Service, write a JavaScript record that calls the functions generated by WSDL2JS. The JavaScript that invokes an external Web Service should perform the following tasks: Create the Service Object. Create the Request Object. Fill the Request Object with information that defines the request. Invoke the Service Object and pass in the Request Object. Return either the Response Object, an instance of the Response Object, or a specific value of that instance. 6. Perform error handling to test each response. Use try {}, throw {}, catch {}, and the isFault function.
1. 2. 3. 4. 5.
As a best practice, do not reuse the names of variables and functions in the calling JavaScript that are the names of variables and functions in the generated script. This can help avoid confusion. Important: Never use the new keyword on a subordinate object unless it is an array. Unlike conventionally compiled applications that invoke a Web Service, the generated function objects described in this document already use new when instantiating all children, so it is not necessary to do so in the calling JavaScript. The only exception is for arrays, where you use the newInstance() function to generate the array and fill its elements.
51
The constructor for XMLDate can handle several different formats, you can pass it a string, a number of milliseconds, or a JS Date object (as in the example above).
References
Service-Oriented Architecture : A Field Guide to Integrating XML and Web Services, April 2004, Prentice Hall Publishing Web Services: A Technical Introduction, August 2004, Prentice Hall Publishing Java Web Services, March 2004, OReilly World Wide Web Consortium Home Page www.w3c.org Web Services Interoperability Organization Home Page - http://www.ws-i.org/
52
This Web site provides contact information and details about the products, services, and support that HP OpenView offers. HP OpenView online software support provides customer self-solve capabilities. It provides a fast and efficient way to access interactive technical support tools needed to manage your business. As a valued Support customer, you can benefit by being able to: Search for knowledge documents of interest Submit and track progress on support cases Submit enhancement requests online Download software patches Manage a support contract Look up HP support contacts Review information about available services Enter discussions with other software customers Research and register for software training
Note: Most of the support areas require that you register as an HP Passport user and sign in. Many also require an active support contract. To find more information about support access levels, go to the following URL:
http://www.hp.com/managementsoftware/access_level
2007 Hewlett-Packard Development Company, L.P. The information contained herein is subject to change without notice. The only warranties for HP products and services are set forth in the express warranty statements accompanying such products and services. Nothing herein should be construed as constituting an additional warranty. HP shall not be liable for technical or editorial errors or omissions contained herein. ServiceCenter and OpenView are registered trademarks of Hewlett-Packard Development Company, L.P. Sun, Java, and JavaScript are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Systinet is a trademark and/or registered trademark of Systinet Corporation in the United States and/or other countries. Microsoft , Visual Basic, Visual C#, and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Altova and XMLSpy are either registered trademarks or common law trademarks of Altova GmbH in the U.S., the European Union and/or other countries. ITIL is a registered trademark of The Lords Commissioners of Her Majesty's Treasury Acting Through The Office of Government Commerce and Central Computer and Telecomunications Agency. UNIX is a registered trademark of The Open Group. 03/2007