Best Practices for Publishing and Consuming Web Services with ServiceCenter

Best Practices for Publishing and Consuming Web Services with ServiceCenter® Introduction ..............................................................
Author: Amos Small
3 downloads 2 Views 844KB Size
Best Practices for Publishing and Consuming Web Services with ServiceCenter®

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 .............................................................4 Example: Getting up-to-date currency data from a Web Service .............................................................5 Publishing ServiceCenter data.....................................................................................................................8 Things to consider prior to publishing data ..............................................................................................9 Example: Publishing data from the currency and curconvert files.........................................................11 Consuming a ServiceCenter Web Service.................................................................................................18 Retrieving data from ServiceCenter .......................................................................................................19 Example: Retrieving ServiceCenter price lists into a text file using Connect-It .....................................20 Example: Getting currency information and pricelist information from another ServiceCenter system ..23 Using the ServiceCenter Web Services examples in the RUN directory....................................................25 Troubleshooting .............................................................................................................................................26 Debugging .................................................................................................................................................26 debughttp...............................................................................................................................................26 RTM:3 and debugdbquery:999 ..............................................................................................................27 Testing your WSDL using .NET Web Service Studio.................................................................................27 Advanced Troubleshooting ........................................................................................................................29 How to troubleshoot a Web Service that is behind a closed firewall ......................................................29 Error Messages .........................................................................................................................................33 Appendix........................................................................................................................................................35 Using SSL connections to connect to an external Web Service ................................................................35 Steps to take when modifying an existing extaccess record...................................................................36 Syntax for Entity References in XML .........................................................................................................36 Best Practices............................................................................................................................................36 Writing a JavaScript for consuming a Web Service ...............................................................................36 Writing expressions in extaccess .......................................................................................................37 References ....................................................................................................................................................37 For more information......................................................................................................................................38

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 user’s 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.

Figure 1: Typical example of Web Services

Definitions, Acronyms and Abbreviations Term

Definition

Consuming

Using a Web Service by calling its methods, supplying the appropriate calling parameters

Publishing

Providing a Web Service by answering a call and returning the expected results

WSDL

Web Services Description Language, which is a standard, structured way of describing SOAP messages and Web Services

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.

2

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.

The ServiceCenter Web Services features The ServiceCenter Web Services features provide the ability to communicate and integrate with applications in an open and efficient manner. These services are useful in many ways. They provide the ability to use a third-party application inside ServiceCenter, manipulate ServiceCenter data inside your custom application, or transfer data among separate ServiceCenter systems. With this flexibility comes the responsibility for developers and administrators to design and implement their integrations well, and to remain well versed in the concepts and practices of well built Web Services.

Introduction to Web Services in ServiceCenter ServiceCenter 6.0 provides both a standard common integration to other industry applications and the ability to publish ServiceCenter information as Web Services. This initial implementation was table-oriented rather than service-oriented, meaning that data was exposed one table at a time using the table name in ServiceCenter. Although the 6.0 Web Services API achieved its essential objective of exposing ServiceCenter application functionality via Web Services, it was hard to use because: •

It required knowledge of the historic low-level ServiceCenter schema. For example you had to know that the probsummary table is where ServiceCenter stores incident records.



It did not use XML schema data types such as dateTime. This meant that dates were served to Web Services client programs as strings, formatted according to operator-specific preferences rather than in a standard, predictable, time zone-independent format.



ServiceCenter 6.0 also required users to consume Web Services on a special, dedicated “apiserver” TCP/IP port that was separate from the actual ServiceCenter server port; and this port could handle only a single SOAP request at a time. 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.

3

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.

Consuming an external Web Service from ServiceCenter You can configure ServiceCenter to connect to and exchange information with remote Web Services. ServiceCenter uses a built-in Web server to send and receive SOAP messages to Web Services, but internally the server uses JavaScript™ to create and format the proper SOAP messages. Note: For a production application that needs services that are not available within your corporate intranet (such as postal address verification, email address verification, and currency conversions) HP recommends that you investigate offerings from established for-fee Web Services vendors. Although there are a lot of free and demo Web Services, we do not recommend basing a production application on such services, since availability of the service is not guaranteed. Several Web sites such as www.xmethods.net publish lists of available free and fee-based Web Services. (Be sure to click the full list button to see the complete list of Web Services.) To consume a Web Service from ServiceCenter perform the following steps. 1. Obtain the URL to the Web Service's WSDL file. 2. Examine the WSDL either as a text file, or using a third-party graphical WSDL analysis tool to

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.

Example: Calling a Web Service sample from the ScriptLibrary The ServiceCenter ScriptLibrary contains a JavaScript sample that invokes a delayed stock quote Web Service. To test it, go to the Database Manager in ServiceCenter and select the ScriptLibrary format. Select the record named DelayedStockQuoteTest and you will see the following Java Script: var stockQuoteService = new lib.DelayedStockQuote.DelayedStockQuote(); // Create the Service Object for the delayed stock quote Web Service var getQuote = new lib.DelayedStockQuote.GetQuote(); // Create the Request Object for the GetQuote request

4

var symbol = "GOOG"; // define the stock symbol to search for getQuote.StockSymbol.setValue( symbol ); getQuote.LicenseKey.setValue("0"); // define the stock symbol and license key for the request var getQuoteResponse = stockQuoteService.invoke(getQuote); // invoke the web service using the Service Object and passing the // Request Object var quoteResult = getQuoteResponse.GetQuoteResult; // retrieve the response of the previous request var tradeDateTime = quoteResult.LastTradeDateTime.getValue(); // get the value of the last trade date and time var xmlDt = new XMLDate( tradeDateTime ); // and convert it to an XML formatted date. print( "Most recent trade of " + quoteResult.CompanyName.getValue() + " was at " + quoteResult.LastTradeAmount.getValue() + " at " + xmlDt.JSDate() ); Note: This example script does not abide to coding best practices. Refer to the Best Practices section in the Appendix for more information. Enter any stock symbol in the “var symbol =” line, such as: var symbol = "HPQ" This would retrieve the latest stock quote for Hewlett Packard. Save the record and click Execute to invoke the Web Service. The result will be the following message: Most recent trade of HEWLETT PACKARD C was at 32.88 at Tue May 23 2006 03:25:00 GMT-0700 (Pacific Daylight Time)

Example: Getting up-to-date currency data from a Web Service The ServiceCenter Request Management module is used to order products and services from international vendors for users around the world. Sometimes, it may be more cost efficient to order from another country than to order locally. The examples in this document show how to get current currency information and calculate an objects’ price in different currencies. If you were to incorporate these Web Services into a production system, make sure to always use license-based Web Services that guarantee their availability. 1. Find a provider that publishes a currency exchange rate WSDL

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, refer to the XigniteCurrencies record in the ScriptLibrary file. 2. In ServiceCenter, go to Menu Navigator and click Utilities –> Tools –> Web Services. Click

Run WSDL to JS. 3. Enter the URL to the WSDL, such as :

http://www..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)

5

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() 7. 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;

6

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; } 8. Check which parameters the invoke() function expects:

function invoke( requestObj, headerObj ) In this case, the headerObj was optional (was “nullsub’ed” in the JavaScript code), so the requestObj is the only required argument. 9. 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"; this.$$xmlNames[ "ConversionRateResponse" ] = "ConversionRateResponse"; this.ConversionRateResult = new s_double(); this.$$elementChildren.push( "ConversionRateResult" ); } 10. Call this function with the method defined in the $$elementChildren.push section (shown above

in bold). 11. Use getValue (or a similarly defined function) to read the result of the request.

function getValue( ) { return this.$$value; } 12. Use the calling JavaScript to update values in ServiceCenter. Rewrite the calling JavaScript to

be a callable function such as: function GetCurrencyFromSC() {

7

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(); } } 13. 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.

Publishing ServiceCenter data Publishing ServiceCenter data can be used to expose files and methods to add or update records within ServiceCenter from any application. This application could be a custom made C# or Java program. An interface program such as Connect-It or another ServiceCenter system could consume the published ServiceCenter data as well.

8

To expose a set of ServiceCenter tables as a Web Service, click Utilities -> Tools -> Web Services -> External Access and create or update the related extaccess records and data policy records. As an example, the Change Management Service contains two tables: cm3r and cm3t. When the ChangeManagement Web Service is exposed, the wsdl will contain field names and actions for both ServiceCenter files. In the extaccess record, note the Object Names of Change and Changetask. These Object Names are going to be exposed via the WSDL rather than the sometimes cryptic table names. The following picture shows how the extaccess and datadict portions of the WSDL configuration utility work together with Document Engine and the dbdict.

Things to consider prior to publishing data Before publishing ServiceCenter data via a Web Service, there are several things to consider. When investigated thoroughly, each of the following items will serve to improve the organization and performance of the Web Services. Can I use the out of the box WSDLs? The ITIL-standard WSDLs that are provided with ServiceCenter should be used whenever possible. They have been tested extensively and are well documented, which makes them easier to use. If you are interested in using one of these WSDLs but wish to make some changes to them, you should make a copy of the original WSDL by copying the corresponding datadict and extaccess record(s) to maintain their integrity in case you need to go back to them. What items do I need to expose? Though an entire table and even an entire database can be exposed via Web Services, doing so would cause bad performance and confuse users. Only the data that is needed by a client should be exposed. This prevents excess traffic and decreases the amount of storage that your client may need to use. What data types should I use? ServiceCenter has a more lenient data typing policy than the XML schema data typing policy used for Web Services. Certain field types in ServiceCenter can correspond to multiple data types in the XML schema data type policy. For example, the ServiceCenter decimal data type could be a decimal, a floating number, or an integer in the XML schema data type policy.

9

In addition, the actual formatting of data varies between ServiceCenter and XML schema data types. This is especially true of ServiceCenter date/time fields that use a different order than XML schema dates. Because some Web Services may require changes to field data format, you can now define the XML Schema data type to which you want ServiceCenter to convert the field's data when you publish the field as part of a Web Service. For outbound data, the ServiceCenter server automatically converts the ServiceCenter data to the format you select in the data policy record for the ServiceCenter field. For inbound data, the 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

ServiceCenter Data Type

Base64Type

used for binary data

BooleanType

Boolean

ByteType

Decimal

DateTimeType

Date/Time

DateType

Date/Time

TimeType

Date/Time

DurationType

Date/Time

DecimalType

Decimal

DoubleType

Decimal

IntType

Decimal

LongType

Decimal

ShortType

Decimal

FloatType

Decimal

StringType

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 table’s 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.

10

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.

Example: Publishing data from the currency and curconvert files In this example, we prepare the data from the currency and curconvert files for use by other applications via a Web Service. The examples in this document build on each other and must be executed in the same order in which they appear. Preparation step: Create a new dbdict called “pricelist” The pricelist file will be used to store how much an item costs in local and foreign currency. Go to System Definition, right-click Table, and click New Table. Enter pricelist in the Table Name field and click OK. Click Add, Delete or Edit Fields and Keys Click New Field and enter the following information: Field name: item.description Field Type: text 5. Click New Field and enter the following information: Field name: price.usd Field Type: decimal 6. Click New Field and enter the following information: Field name: price.foreign Field Type: decimal 7. Click New Field and enter the following information: Field name: currency.foreign Field Type: text 8. Click New Field and enter the following information: Field name: date.entered Field Type: Date/Time 9. Click Save 10. The unique key for this file is “id." To fill this field automatically, you add a counter record. Go to Database Manager, enter counters in the file and format fields, and enter the following information: 1. 2. 3. 4.

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

sysmodtime, sysmodcount and sysmoduser to the new format.

11

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:

4. Click Add to save the record.

12

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:

8. Click Add to save the record.

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:

13

2. Create the displayscreen for pricelist.view as shown below:

3. Add a displayoption for the action that retrieves currency conversion rates from a Web Service

and adds the information to the curconvert file:

14

4. Click Add to save. 5. Add a displayoption that calculates how much a specified amount in a foreign currency

represents in US Dollars, and add the information to the pricelist file

6. Click Add to save.

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:

var curr_code=system.vars.$L_file.currency_code; system.vars.$G_USDConvRate=system.library.CurrencyConvertorRUN.GetCurren cies(curr_code, "USD");

8. On the RAD Tab enter the following initialization expressions

rate in $L.file=$G.USDConvRate date in $L.file=tod() $L.bg=true $L.obj.name={"curconvert"} 9. Make a call to the se.base.method RAD application that performs basic actions to the record,

such as updates or in our example an add, as shown below:

15

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: $L.rate=jscall("CurrencyConvertorRUN.GetCurrencies", currency.foreign in $L.file, "USD") price.foreign in $L.file=price.usd in $L.file*val($L.rate, 1) date.entered in $L.file=tod() 9. Fill in the RAD tab as shown below:

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

16

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:

10. Click Add. 11. Next create an external access definition record for the curconvert file as depicted below:

17

12. Click Add to add the record. 13. Create an external access definition record for the pricelist file as shown below:

14. Click Add to add the record and restart the ServiceCenter server.

Consuming a ServiceCenter Web Service A ServiceCenter Web Service can be consumed by a custom client or by an application that directly consumes Web Services, such as ServiceCenter or Connect-It. A Web Service development tool kit that can generate a complete Web Service application from a .wsdl file is required to create a custom client that can access the ServiceCenter Web Service. A good understanding of Web Services and SOAP versions 1.1 or 1.2 is also recommended.

18

There are several Web Services development tool kits that you can use to develop custom Web Services clients. •

Microsoft Visual Studio® .NET



Systinet WASP™



Glue



Apache Axis



Sun™ Web Services Developer Pack

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, http://:/IncidentManagement.wsdl connects to the scserver host on port 12670 and requests the 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.

Retrieving data from ServiceCenter The ServiceCenter online documentation is a valuable resource for implementing and troubleshooting. The following items are known issues and workarounds that need to be considered when building a custom Web Service client application. •

ServiceCenter currently returns only one record at a time as a GetResponse.



If there are no records returned from a request, no body section appears in the response message.



To query data in a file, use a Get or GetListKeys request followed by a GetListData request.

Retrieve methods usually available and when to use them •

Retrieve — Used if only one record will be returned. Throws a fault if multiple records are returned.



RetrieveKeysList — 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 RetrieveList method, or looped through to pass to the Retrieve method.



RetrieveList — Retrieves a list of records with information that was gathered either in the RetrieveKeysList method or by passing in a query directly through

19

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 >6/30/05) 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 RetrieveList 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: 1. Send the data query such as >6/30/05) directly to the

RetrieveList method. Place the query in the “” block instead of the “” 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 JRE, for example c:\j2sdk1.4.2_05\jre. 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: : 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

20

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

21

Processing Mode: read Connection Protocol: Local/Network files Location: Read files, file name: c:\temp\connectitinput.txt (see below for content of file)

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:

22

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

the two. The mapping is shown below:

22. Click Produce Now (the F5 button) to fill information from the pricelist file in ServiceCenter

into a delimited text file via Web Services.

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 and click

Run WSDL2JS. 2. In the “Please enter the URL for the WSDL file” field, enter the following:

http://:/CurrencyManagement.wsdl 3. Click Proceed -> Add to create the CurrencyManagement JavaScript record in the ScriptLibrary. 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.

23

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; for ( i = 0; i < numRecs; i++ ) { print( instanceArrayObj[i].ExchangeRate.getValue() ); }

24

6. Create a JavaScript in the same ScriptLibrary record that reads a pricelist record and then

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");

Using the ServiceCenter Web Services examples in the RUN directory Both the AxisSample and the DotNetSample directories contain documents with setup instructions. In AxisSample this document is called readme.txt. In DotNetSample the document is called WebServices README.doc. The AxisSample\bin directory contains a selection of batch files that can be run directly, if JDK 1.4 or higher and Apache Ant are both installed on the machine. The DotNet samples have to be compiled before running. To run an example of closing an existing Incident Record from the DotNetSample directory: 1. Follow the instructions in the WebServices README.doc file located in the DotNetSample

directory. 2. Enter the following in the Visual Studio .Net Command prompt to close an incident:

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" 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

25

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 IM1001User Closurepermanent 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.

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"

26

EURUSDHTTP /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 SOAP-ENV:Serverscxmlapi(26) - Get request found more than one record26scxmlapi(26) - Get request found more than one recordPOST /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"

RTM:3 and debugdbquery:999 Sometimes the Web Service itself is working correctly, but actions performed by the Document Engine within ServiceCenter are not performing as expected. The RTM:3 and debugdbquery:999 parameters can expose such issues that occur within the application layer of ServiceCenter. The debugging information produced by these parameters can be found in the sc.log file in the ServiceCenter server RUN directory.

Testing your WSDL using .NET Web Service Studio The .NET Web Service Studio is a free software tool that can be downloaded from http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=65a1d4ea-0f7a-41bd-8494e916ebc4159c. 1. Enter the WSDL EndPoint (which is the URL that points to the WSDL) and click Get to get the

list of methods available for this WSDL.

27

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.

28

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: file://.wsdl 3. Click Proceed.

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. 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();

29

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 server’s RUN directory, remove it or remove its

contents so that there will be a fresh file to read. 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. 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" IM1001 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). 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): IM1001 IM1001 telecoms 2001-01-01T08:00:00+00:00 BOB.HELPDESK 1 2006-06-06T15:44:53+00:00 TELECOMS User Closure JeffPC Warminster Phone is going dead intermittently.

31

PETERS, JEFF 05/26/06 09:37:13 US/Pacific (falcon): update in ticket updated. 03/08/2001 16:11:40 alert stage 3 **ALERT** 01/23/01 11:29:39 (FALCON): Peters Jeff PRGN Phone in going dead intermittently. BOB.HELPDESK CIT-Bridge Open fixed infrastructure 0 D fixed infrastructure not specified permanent 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 .invoke = function( ) { var resultObj = new Object(); resultObj.responseObj = null; var resultXML = new XML(); resultXML.setContent( "c:\\\\", true ); try { lib.SOAP.deserialize( "", 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() );

32

return null; } } 3. Change the line of the calling JavaScript that invokes the Web Service from

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

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: SOAPENV:Serverscxmlapi(16) - Invalid or missing file name in XML request16scxmlapi(1 6) - Invalid or missing file name in XML request 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=”” in the SOAP body of the application. For example: 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. 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() {

33

[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 (i.e. “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. 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 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 element with a particular attachment part. However, the logic for this: •

Assumes that there is a one-to-one correspondence between elements and attachment parts.



Uses the index of the DOM node of the 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 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).

34



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 element (the Nth DOMNode within the set of DOM children for the element, where the 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 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 element, it should apparently be “attachment request 1.” However, the attachment element is the second DOM child node of due to the whitespace text present as DOM child node 1; the first child node of 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 element.

Appendix Using SSL connections to connect to an external Web Service When using SSL connections to an external Web Service, the ServiceCenter server acts like a client and must be set up accordingly. The Web Service provider must send the root certificate or authority’s certificate to the ServiceCenter administrator. If it is a certificate hierarchy, all certificates must be sent. The ServiceCenter administrator then opens the ServiceCenter root certificate using a text editor such as Windows Notepad, and copies the certificates into the file. If the file does not exist because ServiceCenter itself was not yet set up to use SSL, you can simply copy the root certificate file from the Web Service Provider into the ServiceCenter RUN directory. If the file did exist and the new certificates were copied into it, the file will look like the following: -----BEGIN CERTIFICATE----MIIEDTCCAvUCCQCNvarTXFgHhjANBgkqhkiG9w0BAQQFADCBiDELMAkGA1UEBhMC VVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTYW4gRGllZ28xGjAYBgNVBAoTEVBl […] K06z24M9KPblX/9dN+5CtNAcODsPwpfKLbWOjLzGvSsPK2SFzQKGYREb5ULl5TKz lQ5Rlfn17nhe9Ifwyn0EuPpe0GZbL5cgRqC7v6siH4Mo -----END CERTIFICATE---------BEGIN CERTIFICATE----MIIEDDCCAvQCCQDwJNn8mBramjANBgkqhkiG9w0BAQQFADCBiDELMAkGA1UEBhMC VVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTYW4gRGllZ28xGjAYBgNVBAoTEVBl […] LeSAtTshwhz5ZQ0OniRz/ZAW5kRBwc+OGwFasxCES2hogQA32NiGFVTISISzK/eq HTXj+2FvCR2jCOXiorHeROX2+sgj1ScGVyeTRk5LZck= -----END CERTIFICATE-----

When the root certificate file is saved, the following parameter must be entered in the ServiceCenter server sc.ini file, if it does not yet exist: cacertpem:

Identifies the name of the root certificate or authority's certificate.

After entering this parameter, restart the ServiceCenter server.

35

If the https://fully qualified server path:portnumber/Service.wsdl connection does not work after you make these changes, it is possible that the 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 server’s hosts file (located in etc/hosts on UNIX® systems; 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, such as mymachine.hp.com

10.2.5.77

where mymachine.hp.com is the 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, 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 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 request/responses as the two partners identify each other, negotiate the encryption algorithm, and perform other required tasks.

Steps to take when modifying an existing extaccess record 1. After you modify the extaccess record and save it, always re-start the ServiceCenter server 2. Rebuild the Service Object by re-running WSDL2JS if ServiceCenter is the consumer. 3. Modify the calling applications if either the actions, the field names, or the object name have

changed, and calling applications refer to them.

Syntax for Entity References in XML Character represented

Entity Reference

>

greater than

>