8Siebel Virtual Business Components

Siebel Virtual Business Components

This chapter describes the virtual business component (VBC), its uses, and restrictions. This chapter also describes how you can create a new VBC in Siebel Tools. The following topics are included:

About Virtual Business Components

A virtual business component (VBC) provides a way to access data that resides in an external data source using a Siebel business component. The VBC does not map to an underlying table in the Siebel Database. You create a new VBC in Siebel Tools workspace and deliver the workspace. The VBC calls a Siebel business service to provide a transport mechanism.

You can take two approaches to use VBCs, as illustrated in the following figure:

  • Use the XML Gateway business service to pass data between the VBC and one of the Siebel transports, such as the EAI HTTP Transport or the EAI MSMQ Transport.

  • Write your own business service in Siebel eScript or in Siebel VB to implement the methods described in this chapter.

Two Approaches to Building Virtual Business Components

    Using VBCs for Your Business Requirements

    The following features enhance the functionality of VBCs to better assist you in meeting your business requirements:

    • VBCs support drilldown behavior:

      • You can drill down on a VBC to a standard business component, another VBC, or the same VBC.

      • You can drill down onto a VBC from a standard business component, another VBC, or the same VBC.

    • A parent applet can be based on a VBC.

    • You can define VBCs that can participate as a parent in a business object. The VBC you define can be a parent to a standard BC or a VBC.

    • You still can use an older version of the XML format or property set by setting the VBC Compatibility Mode parameter to the appropriate version. For information, see the table in the topic Setting User Properties for the Virtual Business Component .

    • You can pass search and sort specifications to the business service used by a VBC.

    • You can use the Validation, Pre Default Value, Post Default Value, Link Specification, and No Copy attributes of the VBC fields.

    • You can use predefined queries with VBCs.

    • You can have picklists based on VBCs, and use picklist properties such as No Insert, No Delete, No Update, No Merge, Search Specification, and Sort Specification.

    • You can use the Cascade Delete, Search Spec, Sort Spec, No Insert, No Update, and No Delete link properties when a VBC is the child business component on the link.

    • You can use the No Insert, No Update, No Delete, Search Spec, Sort Spec, and Maximum Cursor Size business component properties.

      Usage and Restrictions for Virtual Business Components

      The following are the uses and restrictions of VBCs:

      • You can define a business object as containing both standard business components and VBCs.

      • When configuring applets based on VBCs, use CSSFrame (Form) and CSSFrameList (List) instead of specialized applet classes.

      • (Optional) Using the same name for the VBC field names and the remote data source field names can reduce the amount of required programming.

      • VBCs cannot be docked, so they do not apply to remote users.

      • VBCs cannot contain a multivalue group (MVG).

      • VBCs do not support many-to-many relationships.

      • A pick applet based on a VBC instantiates the VBC without any parent reference (no link is used). As result, the VBC business service does not receive the source field value from the parent component If the VBC business service must access the current parent business component context, then you can use the ActiveBusObject method of the TheApplication object in a business service server script to do the following:

        • Obtain the current business object instance (assuming this is the instance with this VBC).

        • Instantiate the parent business component (assuming the name of the parent BC is known).

        • Obtain the parent business component field for referencing it as a source (the field must be active in the current parent business component).

      • VBCs cannot be loaded using Enterprise Integration Manager.

      • Standard business components cannot contain multivalue groups based on VBCs.

      • VBCs cannot be implemented using any business component class other than CSSBCVExtern. This means specialized business components such as Quotes and Forecasts cannot be implemented as VBCs.

      • You cannot use Workflow Monitor to monitor VBCs.

      • You cannot execute queries against VBCs when the search specification uses a function that is normally supported for Query mode against regular business components, such as ParentFieldValue().

        Using Virtual Business Components

        To use VBCs to share data with an external application, perform the following high-level tasks:

          Creating a New Virtual Business Component

          You create a new VBC in Siebel Tools.

          To create a new virtual business component

          1. In Siebel Tools, lock the appropriate project.

          2. In the Object Explorer, select the Business Component object.

          3. Right-click, and then choose New Record.

          4. Name the business component.

          5. Select the project you locked in Step 1.

          6. Set the class to CSSBCVExtern. This class provides the VBC functionality.

            Setting User Properties for the Virtual Business Component

            When defining the VBC, you must provide the user properties shown in the following table.

            Table Setting Virtual Business Component User Properties

            User Property Description

            Service Name

            The name of the business service.

            Service Parameters

            (Optional) Any parameters required by the business service. The Siebel application passes this user property, as an input argument, to the business service.

            Remote Source

            (Optional) External data source that the business service is to use. This property allows the VBC to pass a root property argument to the underlying business service, but it does not allow a connection directly to the external datasource. The Siebel application passes only this user property as an input argument.

            VBC Compatibility Mode

            (Optional) Determines the format of the property set passed from a VBC to a business service, or the format in which the outgoing XML from the XML Gateway will be. A valid value is Siebel xxx, where xxx can be any Siebel release number. Some examples would be Siebel 6 or Siebel 7.0.4. If xxx is less than 7.5, the format will be in a release that is earlier than release 7.5. Otherwise, a new property set, and the XML format will be passed.

            If you are creating a VBC in version 7.5 or higher, then it is not necessary to define this new user property, because the default is to use the new PropertySet from a VBC and the new outgoing XML from the XML Gateway.

            For your existing VBC implementation, update your VBC definition by adding this new user property, and setting it to Siebel xxx, where xxx is the version number that you want.

            To define user properties for a virtual business component

            1. In the Object List Editor in Siebel Tools, select the virtual business component for which you want to define user properties.

            2. In the Object Explorer, expand the Business Component tree, and then select Business Component User Prop.

            3. In the Object List Editor, click in the Business Component User Props list, right-click, and then choose New Record.

            4. Type the name of the user property, such as Service Name, in the Name field.

            5. Type the value of the user property, such as a business service name, in the Value field.

            6. Repeat the process for every user property you want to define for this VBC.

            Note: For the list of different property sets and their format, see Examples of the Outgoing XML Format and Examples of the Incoming XML Format.

              XML Gateway Service

              The XML Gateway business service communicates between Siebel Business Applications and external data sources using XML as the data format. For information on XML format, see Examples of the Outgoing XML Format and Examples of the Incoming XML Format. The XML Gateway business service can be configured to use one of the following transports:

              • EAI MQSeries Server Transport

              • EAI HTTP Transport

              • EAI MSMQ Transport

              You can configure the XML Gateway by specifying the transport protocol and the transport parameters you use in the Service Parameters User Property of the VBC, as shown in the following table. When using the XML Gateway, specify the following user properties for your VBC.

              Table User Properties

              Name Value

              Service Name

              XML Gateway

              Service Parameters

              variable1 name=variable1 value; variable2 name=variable2 value>;...

              Remote Source

              External Data Source

              VBC Compatibility Mode

              Siebel xxx, where xxx can be any Siebel release number.

              Note: You can concatenate multiple name-value pairs using a semicolon (;), but do not use any spaces between the name, the equal sign, the value, and the semicolon.

              For example, if you want to specify the EAI HTTP Transport, then you can use something like the following:

              "Transport=EAI HTTP Transport;HTTPRequestURLTemplate=<your  
              URL>;HTTPRequestMethod=POST"
              

              You can also implement a VBC with MQSeries. The following procedure lists the steps you take to implement this.

              To implement a VBC with MQSeries

              1. Call the EAI Business Integration Manager (Server Request) business service.

              2. Define another service parameter for the name of a workflow to run, with the following user properties on the VBC:

                • Service Name. XML Gateway.

                • Service Parameters. Transport=EAI Business Integration Manager (Server Request);ProcessName=EAITEST.

              3. Define a workflow, EAITEST, to call the EAI MQSeries Server Transport with the SendReceive method.

              4. Define a new process property, <Value>, on the workflow, and use it as an output argument on the EAI MQSeries Server Transport step in the workflow.

                XML Gateway Methods

                The XML Gateway provides the methods presented in the following table.

                Table XML Gateway Methods

                Method Description

                Init

                Initializes the XML Gateway business service for every business component.

                Delete

                Deletes a given record in the remote data source.

                Insert

                Inserts a record into a remote data source.

                PreInsert

                Performs an operation that tests for the existence of the given business component. Only default values are returned from the external application.

                Query

                Queries the given business component from the given data source.

                Update

                Updates a record in the remote data source.

                  XML Gateway Method Arguments

                  The XML Gateway init, delete, insert, preInsert, query, and update methods take the arguments presented in the following table.

                  Table XML Gateway Arguments

                  Argument Description

                  Remote Source

                  The VBC Remote Source user property. The remote source from which the service is to retrieve data for the business component. This must be a valid connect string. When configuring the repository business component on top of the specialized business component class CSSBCVExten, you can define a user property Remote Source to allow the Transport Services to determine the remote destination and any connect information. If this user property is defined, then it is passed to every request as the remote-source tag.

                  Business Component Id

                  Unique key for the given business component.

                  Business Component Name

                  Name of the business component or its equivalent, such as a table name.

                  Parameters

                  The VBC Service Parameters user property. A set of string parameters required for initializing the XML Gateway.

                    About Handling White Space

                    White space is handled by the XML parser while processing the request from the XML Gateway business service. When the white space is part of the XML syntax, it must be discarded by the XML parser and not preserved (passed on to the processing application). If the white space is in any other location (such as in element content within a document), then it must be preserved according to the XML specification, because it might have some meaning.

                    For example:

                    <mydata>
                    <mytag>stuff</mytag>
                    </mydata>
                    

                    and

                    <mydata><mytag>stuff</mytag></mydata>
                    

                    are different to an XML parser.

                    To preserve white space, use the xml:space attribute with the value preserve, for example:

                    <mydata xml:space="preserve">
                    <mytag>stuff and more stuff</mytag>
                    </mydata>
                    

                    The value of xml:space applies to all children of the element containing the attribute unless overridden by one of the children.

                    For more information on white space handling and the xml:space attribute, see Microsoft Developer Network (http://msdn.microsoft.com).

                      Examples of the Outgoing XML Format

                      Examples of the XML documents generated and sent by the XML Gateway to the external system are presented in the following table. These examples are based on the Siebel eScript example in Custom Business Service Examples. See DTDs for XML Gateway Business Service for examples of the DTDs that correspond to each of these methods.

                      Note: The XML examples in this chapter have extraneous carriage returns and line feeds for ease of reading. Delete all the carriage returns and line feeds before using any of the examples.

                      Table Outgoing XML Tags and Descriptions

                      Method Format of the XML Stream Description

                      Delete Request

                      <siebel-xmlext-delete-req>

                      <buscomp id="1">Contact</buscomp>

                      <remote-source>http://throth/ servlet/VBCContacts</remote-source>

                      <row>

                      <value field="AccountId">146</value>

                      <value field="Name">Max Adams</value>

                      <value field="Phone">(408)234-1029</<value>

                      <value field="Location">San Jose</value>

                      <value field="AccessId">146</value>

                      </row>

                      </siebel-xmlext-delete-req>

                      siebel-xmlext-delete-req

                      This tag requests removal of a single record in the remote system.

                      Init Request

                      <siebel-xmlext-fields-req>

                      <buscomp id="1">Contact</buscomp>

                      <remote-source>http://throth/ servlet/VBCContacts</remote-source>

                      </siebel-xmlext-fields-req>

                      • siebel-xmlext-fields-req

                      This tag fetches the list of fields supported by this instance.

                      • buscomp Id

                      The business component ID.

                      • remote-source

                      The remote source from which the service is to retrieve data for the business component.

                      Insert Request

                      <siebel-xmlext-insert-req>

                      <buscomp id="1">Contact</buscomp>

                      <remote-source>http://throth/ servlet/VBCContacts</remote-source>

                      <row>

                      <value field="AccountId">1-6</value>

                      <value field="Name">Max Adams</value>

                      <value field="Phone">(398)765-1290</value>

                      <value field="Location">Troy</value>

                      <value field="AccessId"></value>

                      </row>

                      </siebel-xmlext-insert-req>

                      siebel-xmlext-insert-req

                      This tag requests the commit of a new record in the remote system.

                      The insert-req XML stream contains values for fields entered through the business component.

                      PreInsert Request

                      <siebel-xmlext-preinsert-req>

                      <buscomp id="1">Contact</buscomp>

                      <remote-source>http://throth/ servlet/VBCContacts</remote-source>

                      </siebel-xmlext-preinsert-req>

                      siebel-xmlext-preinsert-req

                      This tag allows the connector to provide default values. This operation is called when a new row is created, but before any values are entered through the business component interface.

                      Query Request

                      <siebel-xmlext-query-req>

                      <buscomp id="1">Contact</buscomp>

                      <remote-source>http://throth/ servlet/VBCContacts</remote-source>

                      <max-rows>6/max-rows>

                      <search-string>=([Phone] IS NOT NULL) AND ([AccountId] = "1-6")</search-string>

                      <search-spec>

                      <node node-type="Binary Operator">AND

                      <node node-type="Unary Operator">IS NOT NULL

                      <node node- type="Identifier">Phone</node></node>

                      <node node-type="Binary Operator">=

                      <node node- type="Identifier">AccountId</node>

                      <node value-type="TEXT" node-type="Constant">1-6</node>

                      </node>

                      </node>

                      </search-spec>

                      <sort-spec>

                      <sort field="Location">ASCENDING</sort>

                      <sort field="Name">DESCENDING</sort>

                      </sort-spec>

                      </Siebel-xmlext-query-req>

                      • siebel-xmlext-query-req

                      This tag queries by example. The query-req XML stream contains parameters necessary to set up the query. In this example, the query requests that record information be returned from the remote system.

                      • max-rows

                      Maximum number of rows to be returned. The value is the Maximum Cursor Size defined at the VBC plus one. If the Maximum Cursor Size property is not defined at the VBC, then the max-rows property is not passed.

                      • search-string

                      The search specification used to query and filter the information.

                      • search-spec

                      Hierarchical representation of the search-string. For information, see Search-Spec Node-Type Values.

                      • sort-spec

                      List of sort fields and sort order.

                      Note: In some cases you might retrieve external data for display in a child list applet, using a link to a parent business component. If the parent business component field on which the link is based is empty, then the query request is sent without a search-spec tag, but instead with the following tag: match field=" Child BC Fieldname "/>

                      Update Request

                      <buscomp id="2">Contact</buscomp>

                      <remote-source>http://throth/ servlet/VBCContacts</remote-source>

                      <row>

                      <value changed="false" field="AccountId">1-6</value>

                      <value changed="false" field="Name">Max Adams</value>

                      <value changed="true" field="Phone">(408)234-1029</value>

                      <value changed="true" field="Location">San Jose</value>

                      <value changed="false" field="AccessId">146</value>

                      </row>

                      </siebel-xmlext-update-req>

                      siebel-xmlext-update-req

                      This tag requests changes to the field values for an existing row.

                      All values for the record are passed with the value tags, and with the changed attribute identifying the ones that have been changed through the Siebel application.

                      Search-Spec Node-Type Values

                      The search-string is in the Siebel query language format. The search-string is parsed by the Siebel query object and then turned into the hierarchical search-spec. The following table shows the different search-spec node-types and their values.

                      Table Search-Spec Node-Types

                      Node-Type PropertySet and XML Representation

                      Constant

                      Example: <node node-type = "Constant"

                      value-type="NUMBER">1000</node>

                      The valid value-types are TEXT, NUMBER, DATETIME, UTCDATETIME, DATE, and TIME.

                      Identifier

                      Example: <node node-type="Identifier">Name</node>

                      The value Name is a valid business component field name.

                      Unary Operator

                      Example: <node node-type="Unary Operator">NOT</node>

                      The valid values are NOT, EXISTS, IS NULL, IS NOT NULL.

                      Binary Operator

                      Example: <node node-type= "Binary Operator" >AND</node>

                      The valid values are LIKE, NOT LIKE, SOUNDSLIKE, =, <>, <=, <, >=, >, AND, OR, +, -, *, /, ^.

                      Examples of the Incoming XML Format

                      The following table contains examples of XML documents that are sent from an external system to the XML Gateway in response to a request. These examples are based on the Siebel eScript example in Custom Business Service Examples. See DTDs for XML Gateway Business Service for examples of the DTDs that correspond to each of these methods.

                      Table Incoming XML Tags and Descriptions

                      Method Format of the XML Stream Description

                      Delete Return

                      <siebel-xmlext-delete-ret/>

                      siebel-xmlext-delete-ret.

                      Only the XML stream tag is returned.

                      Error

                      <siebel-xmlext-status>

                      <status-code>4</code>

                      <error-field>Name</error-field>

                      <error-text>Name must not be empty</error-text>

                      </siebel-xmlext-status>

                      Format of the XML stream expected by the Siebel application in case of an error in the external application. If the error is specific to a field, then the field name must be specified.

                      The tags for this XML stream, and the entire XML stream, are optional:

                      • siebel-xmlext-status

                        This tag is used to check the status returned by the external system.

                      • status-code

                        This tag overrides the return value.

                      • error-text

                        This tag specifies textual representation of the error, if it is available. This tag appears in addition to the standard error message. For example, if the Siebel application attempts to update a record in the external system with a NULL Name, and this is not allowed in the external system, then the error text is set to: "Name must not be empty."

                      Init Return

                      <siebel-xmlext-fields-ret>

                      <support field="AccountId"/>

                      <support field="Name"/>

                      <support field="Phone"/>

                      <support field="Location"/>

                      <support field="AccessId"/>

                      </siebel-xmlext-fields-ret>

                      siebel-xmlext-fields-ret

                      The fields-ret XML stream return contains the list of VBC fields supported by the external application for this instance.

                      The following field names are reserved by the Siebel application, and must not appear in this list:

                      • Id

                      • Created

                      • Created By

                      • Updated

                      • Updated By

                      Insert Return

                      <siebel-xmlext-insert-ret>

                      <row>

                      <value field="AccountId">1-6</value>

                      <value field="Name">Max Adams</value>

                      <value field="Phone">(398)765-1290</value>

                      <value field="Location">Troy</value>

                      <value field="AccessId">146</value>

                      </row>

                      </siebel-xmlext-insert-ret>

                      siebel-xmlext-insert-ret

                      If the remote system has inserted records, then they can be returned to be reflected in the business component in an insert-ret XML stream in the row tag format as the insert-ret stream.

                      PreInsert Return

                      <siebel-xmlext-preinsert-ret>

                      <row>

                      <value field="Location">San Jose</value>

                      </row>

                      </siebel-xmlext-preinsert-ret>

                      siebel-xmlext-preinsert-ret

                      Returns default values for each field, if there is any default value.

                      Query Return

                      <siebel-xmlext-query-ret>

                      <row>

                      <value field="AccountId">1-6</value>

                      <value field="Name">Sara Chen</value>

                      <value field="Phone">(415)298-7890</value>

                      <value field="Location">San Francisco</value>

                      <value field="AccessId">128</value>

                      </row>

                      <row>

                      <value field="AccountId">1-6</ value>

                      <value field="Name">Eric Brown</value>

                      <value field="Phone">(650)123-1000</value>

                      <value field="Location">Palo Alto </value>

                      <value field="AccessId">129</value>

                      </row>

                      </siebel-xmlext-query-ret>

                      • siebel-xmlext-query-ret

                      The query-ret XML stream contains the result set that matches the criteria of the query.

                      • row

                        This tag indicates the number of rows returned by the query. Each row must contain one or more value tags. The attributes that appear in row tags must be able to uniquely identify the rows. If there is a unique key in the remote data source, then it appears in the result set. If not, a unique key is generated. It is necessary to identify specific rows for DML operations.

                      • value

                        This tag specifies the field and value pairs and must be the same for each row in the set.

                      Update Return

                      <siebel-xmlext-update-ret>

                      <row>

                      <value field="Location">San Jose</value>

                      <value field="Phone">(408)234-1029</value>

                      </row>

                      </siebel-xmlext-update-ret>

                      siebel-xmlext-update-ret

                      If the remote system updated fields, then the fields can be returned to be reflected in the business component in an update-ret XML stream in the row tag format as the update-ret stream.

                      External Application Setup

                      When you have your XML Gateway Service configured, set up your external application accordingly to receive and respond to the requests. At a minimum, the external application must support the Init() and Query() methods, and depending upon the functionality provided by the VBC, the remaining methods might or might not be necessary.

                      Custom Business Service Methods

                      Your business service must implement the Init and Query methods as described in this topic. The Delete, PreInsert, Insert, and Update methods are optional, and depend on the functionality required by the VBC.

                      Note: Custom business services can be based only on the CSSService class, as specified in Siebel Tools.

                      These methods pass property sets between the VBC and the business service. VBC methods take property sets as arguments. Each method takes two property sets: an Inputs property set and an Outputs property set. The methods are called by the CSSBCVExtern class in response to requests from other objects that refer to, or are based on the VBC.

                      If VBCs are used, then custom business services are written to access external relational databases. However, it is recommended that you use external business components (EBCs) to access these databases instead of writing custom business services. For more information on EBCs, see External Business Components.

                        Common Method Parameters

                        The following table shows the input parameters common to every method. Note that all these parameters are at the root property set.

                        Table Common Input Parameters

                        Parameter Description

                        Remote Source

                        (Optional) Specifies the name of an external data source. This is the VBC’s Remote Source user property, if defined. For information, see the table in topic Setting User Properties for the Virtual Business Component.

                        Business Component Name

                        Name of the active VBC.

                        Business Component Id

                        Internally generated unique value that represents the VBC.

                        Parameters

                        (Optional) The VBC’s Service Parameters user property, if defined. For information, see the table in topic Setting User Properties for the Virtual Business Component. A set of parameters required by the business service.

                        VBC Compatibility Mode

                        (Optional) This is the VBC’s Compatibility Mode user property, if defined. For information, see the table in topic Setting User Properties for the Virtual Business Component.

                        When a response has been received, the method packages the response from the external data source into the output’s property set.

                          Business Services Methods and Their Property Sets

                          The following examples display each method's input and output property sets for a VBC Contact that displays simple contact information for a given account. These examples are based on the example in the Custom Business Service Examples.

                          The output property set of the Insert and Update methods for VBC does not affect the data in the business component, unlike the Query method, which uses the output property set to populate the business component. The output property set for Insert and Update is used to indicate that what fields or record has been changed.

                          Note: All the optional parameters have been omitted from these examples to simplify them.

                            Delete Method

                            The Delete method is called when a record is deleted. The following figure illustrates the property set for the Delete input.

                            Delete Input Property Set

                            The following is the XML representation of the property set shown in the previous figure:

                            <?xml version="1.0" encoding="UTF-8" ?>

                            <?Siebel-Property-Set EscapeNames="true"?> 
                            <PropertySet 
                            		Business_spcComponent_spcId="1"
                            		Business_spcComponent_spcName="Contact">
                            		<PropertySet
                            		AccountId="1-6"
                            		Name="Max Adams"
                            		Phone="(408)234-1029"
                            		Location="San Jose" 
                            		AccessId="146" /> 
                            		</PropertySet>
                            

                            The following figure illustrates the property set for the Delete output.


                            Delete Output Property Set

                            The following is the XML representation of the property set shown in the previous figure:

                            <?xml version="1.0" encoding="UTF-8" ?> 
                            <?Siebel-Property-Set EscapeNames="true"?> 
                            <PropertySet />
                            

                              Error Return Method

                              The following figure illustrates the property set for the Error Return, when an error is detected.

                              Error Return Property Set

                              The following is the XML representation of the property set shown in the previous figure:

                              <?xml version="1.0" encoding="UTF-8" ?> 
                              <?Siebel-Property-Set EscapeNames="true"?> 
                              <PropertySet>
                              	<Status Status="4" 
                              		Error_spcField="Name"
                              		Error_spcText="Name must not be empty"/> 
                              </PropertySet>
                              

                                Init Method

                                The Init method is called when the VBC is first instantiated. It initializes the VBC. It expects to receive the list of fields supported by the external system.

                                Note: When a field is not initialized in the Init method of the VBC, the Update method is not fired when the field gets updated.

                                The following figure illustrates the property set for the Init input.

                                Init Input Property Set

                                The following is the XML representation of the property set shown in the previous figure:

                                <?xml version="1.0" encoding="UTF-8"?> 
                                <?Siebel-Property-Set EscapeNames="true"?> 
                                <PropertySet 
                                	Business_spcComponent_spcId="1"
                                	Business_spcComponent_spcName="Contact"/> 
                                

                                The following figure illustrates the property set for the Init output.


                                Init Output Property Set

                                The following is the XML representation of the property set shown in the previous figure:

                                <?xml version="1.0" encoding="UTF-8" ?> 
                                <?Siebel-Property-Set EscapeNames="true"?> 
                                <PropertySet 
                                	AccountId="" 
                                	Name="" 
                                	Phone="" 
                                	Location="" 
                                	AccessId="" /> 
                                

                                  Insert Method

                                  The Insert method is called when a New Record is committed. The following figure illustrates the property set for the Insert input.

                                  Insert Input Property Set

                                  The following is the XML representation of the property set shown in the previous figure:

                                  <?xml version="1.0" encoding="UTF-8" ?> 
                                  <?Siebel-Property-Set EscapeNames="true"?> 
                                  <PropertySet 
                                  	Business_spcComponent_spcId="1"
                                  	Business_spcComponent_spcName="Contact">
                                  	<PropertySet
                                  		AccountId="1-6"
                                  		Name="Max Adams"
                                  		Phone="(398)765-1290" 
                                  		Location="Troy"
                                  		AccessId="" /> 
                                  </PropertySet>
                                  

                                  The following figure illustrates the property set for the Insert output.

                                  Note: The property set for the Insert output does not affect the data in the business component. The output property set for Insert is used to indicate what fields or records were changed.

                                  Insert Output Property Set

                                  The following is the XML representation of the property set shown in the previous figure:

                                  <?xml version="1.0" encoding="UTF-8" ?> 
                                  <?Siebel-Property-Set EscapeNames="true"?> 
                                  <PropertySet 
                                  	<PropertySet
                                  		AccountId="1-6"
                                  		Name="Max Adams"
                                  		Phone="(398)765-1290" 
                                  		Location="Troy"
                                  		AccessId="146" /> 
                                  </PropertySet>
                                  

                                    PreInsert Method

                                    The PreInsert method is called when a New Record operation is performed. It supplies default values. The following figure illustrates the property set for the PreInsert input.

                                    PreInsert Input Property Set

                                    The following is the XML representation of the property set shown in the previous figure:

                                    <?xml version="1.0" encoding="UTF-8"?> 
                                    <?Siebel-Property-Set EscapeNames="true"?> 
                                    <PropertySet 
                                    	Business_spcComponent_spcId="1"
                                    	Business_spcComponent_spcName="Contact"/>
                                    

                                    The following figure illustrates the property set for the PreInsert output.


                                    PreInsert Output Property Set

                                    The following is the XML representation of the property set shown in the previous figure:

                                    <?xml version="1.0" encoding="UTF-8" ?> 
                                    <?Siebel-Property-Set EscapeNames="true"?> 
                                    <PropertySet>
                                    	<PropertySet Location="San Jose" /> 
                                    </PropertySet>
                                    

                                      Query Method

                                      The Query method is called when a search is performed. The Query method must be supported by every VBC. Each record that matches the query is represented as a property set. For example, if 5 records match the query, then there will be 5 child property sets. Each property set contains a list of field names, that is field value pairs representing the values of each field for that particular record. The following figure illustrates the property set for the Query input and is followed by its XML representation.


                                      Query Input Property Set

                                      The following is the XML representation of the property set shown in the previous figure:

                                      <?xml version="1.0" encoding="UTF-8" ?> 
                                      <?Siebel-Property-Set EscapeNames="true"?> 
                                      <PropertySet
                                      	max-rows="6"
                                      	search-string="([Phone] IS NOT NULL) AND ([AccountId] = "1-6")"
                                      	Business_spcComponent_spcId="1" 
                                      	Business_spcComponent_spcName="Contact">
                                      	<PropertySet AccountId="1-6" /> 
                                      		<search-spec>
                                        			<node node-type="Binary Operator">AND 
                                        			<node node-type="Unary Operator">IS NOT NULL 
                                        			<node node-type="Identifier">Phone</node> 
                                        			  </node>
                                         			 <node node-type="Binary Operator">= 
                                         			 <node node-type="Identifier">AccountId</node> 
                                         			 <node value-type="TEXT" node-type="Constant">1-6</node> 
                                          		</node>
                                        	</node>
                                      </search-spec>
                                      <sort-spec>
                                        		<sort field="Location">ASCENDING</sort> 
                                        		<sort field="Name">DESCENDING</sort> 
                                      	</sort-spec>
                                      </PropertySet>
                                      

                                      The following figure illustrates the property set for the Query output.

                                      Query Output Property Set

                                      The following is the XML representation of the property set shown in the previous figure:

                                      <?xml version="1.0" encoding="UTF-8" ?> 
                                      <?Siebel-Property-Set EscapeNames="true"?> 
                                      <PropertySet>
                                      	<PropertySet 
                                      		AccountId="1-6"
                                      		Name="Sara Chen"
                                      		Phone="(415)298-7890" 
                                      		Location="San Francisco"
                                      		AccessId="128" /> 
                                      <PropertySet 
                                      		AccountId="1-6"
                                      		Name="Eric Brown"
                                      		Phone="(650)123-1000" 
                                      		Location="Palo Alto"
                                      		AccessId="129" /> 
                                      </PropertySet>
                                      

                                        Update Method

                                        The Update method is called when a record is modified. The following figure illustrates the property set for the Update input.

                                        Update Input Property Set

                                        The following is the XML representation of the property set shown in the previous figure:

                                        <?xml version="1.0" encoding="UTF-8" ?> 
                                        <?Siebel-Property-Set EscapeNames="true"?> 
                                        <PropertySet 
                                        	Business_spcComponent_spcId="1"
                                        	Business_spcComponent_spcName="Contact">
                                        <PropertySet
                                        	Field_spcName="AccountId"
                                        	Changed="false"
                                        	Field_spcValue="1-6"/>
                                        <PropertySet
                                        	Field_spcName="Name"
                                        	Changed="false"
                                        	Field_spcValue="MaxAdams"/>
                                        <PropertySet
                                        	Field_spcName="Phone"
                                        	Changed="true"
                                        	Field_spcValue="(408)234-1029"/>
                                        <PropertySet
                                        	Field_spcName="Location"
                                        	Changed="true"
                                        	Field_spcValue="SanJose"/>
                                        <PropertySet
                                        	Field_spcName="AccessId"
                                        	Changed="false"
                                        	Field_spcValue="146" />  
                                        </PropertySet>
                                        

                                        The following figure illustrates the property set for the Update output.

                                        Note: The property set for Update output does not affect the data in the business component. The output property set for Update is used to indicate what fields or records were changed.
                                        Update Output Property Set

                                        The following is the XML representation of the property set shown in the previous figure:

                                        <?xml version="1.0" encoding="UTF-8" ?> 
                                        <?Siebel-Property-Set EscapeNames="true"?> 
                                        <PropertySet 
                                        	<PropertySet
                                        		Phone=="(408)234-1029"
                                        		Location="San Jose" /> 
                                        </PropertySet>
                                        

                                          Custom Business Service Examples

                                          These examples show the implementation of a business service for a VBC in both Siebel eScript and Siebel VB:

                                            Siebel eScript Business Service Example for a VBC

                                            The following is an example of Siebel eScript implementation of a business service for a VBC. The fields configured for this simple VBC are AccountId, Name, Phone, Location, and AccessId. AccessId is the primary key in the external data source. AccessId is included in the VBC fields to make updating and deleting the fields simple and is configured as a hidden field.

                                            Caution: Do not use Siebel CRM system fields, such as Id, as output properties. Undesired application behavior might result.
                                              function Service_PreInvokeMethod (MethodName, Inputs, Outputs) {
                                               if (MethodName == "Init") {
                                                  return(Init(Inputs, Outputs));
                                               }
                                               else if (MethodName == "Query") {
                                            							      return(Query(Inputs, Outputs));
                                               }
                                               else if (MethodName == "PreInsert") {
                                                  return(PreInsert(Inputs, Outputs));
                                               }
                                               else if (MethodName == "Insert") {
                                                  return(Insert(Inputs, Outputs));
                                               }
                                               else if (MethodName == "Update") {
                                                  return(Update(Inputs, Outputs));
                                               }
                                               else if (MethodName == "Delete") {
                                                  return(Delete(Inputs, Outputs));
                                               }
                                               else { 
                                                  return (ContinueOperation);
                                               }
                                              }
                                              function Init (Inputs, Outputs) {
                                               // For debugging purposes...
                                               logPropSet(Inputs, "InitInputs.xml");
                                               Outputs.SetProperty("AccountId", "");
                                               Outputs.SetProperty("Name", "");
                                               Outputs.SetProperty("Phone", "");
                                               Outputs.SetProperty("AccessId", "");
                                               Outputs.SetProperty("Location", "");
                                               // For debugging purposes...
                                               logPropSet(Outputs, "InitOutputs.xml");
                                               return (CancelOperation);
                                              }
                                              function Query(Inputs, Outputs) {
                                               // For debugging purposes...
                                               logPropSet(Inputs, "QueryInputs.xml");
                                               var selectStmt = "select * from Contacts ";
                                               var whereClause = "";
                                                var orderbyClause = "";
                                               // You have the following properties if you want to use them
                                               // Inputs.GetProperty("Business Component Name")
                                               // Inputs.GetProperty("Business Component Id")
                                               // Inputs.GetProperty("Remote Source")
                                               // If you configured Maximum Cursor Size at the buscomp,
                                               // get max-rows property
                                               var maxRows = Inputs.GetProperty("max-rows");
                                               // get search-string
                                               var searchString = Inputs.GetProperty("search-string");
                                                if (searchString != "" )
                                                {
                                               // convert the search-string into a where clause
                                               searchString = stringReplace(searchString, '*', '%');
                                               searchString = stringReplace(searchString, '[', ' ');
                                               searchString = stringReplace(searchString, ']', ' ');
                                               searchString = stringReplace(searchString, '~', ' ');
                                               searchString = stringReplace(searchString, '"', "'");
                                                whereClause = " where ";
                                                 whereClause = whereClause + searchString;
                                               }
                                               // match, search-spec, sort-spec
                                               var childCount = Inputs.GetChildCount();
                                               var child, sortProp;
                                               for (var i = 0; i < childCount; i++)
                                               {
                                                  child = Inputs.GetChild(i);
                                                  if (child.GetType() == "")
                                                  {
                                                  // Use this child property set if you want to use the old match field list.
                                                  // We are not using this in this example.  We'll use search-string instead.
                                                  }
                                                  else if (child.GetType() == "search-spec")
                                                  {
                                                  // Use this child property set if you want to use the hierarchical
                                                  // representation of the search-string.
                                                  // We are not using this in this example.  We'll use search-string instead.
                                                  }
                                                  else if (child.GetType() == "sort-spec")
                                                  {
                                                  // This child property set has the sort spec.  We'll use this in this example
                                                  orderbyClause = " order by ";
                                                  var sortFieldCount = child.GetChildCount();
                                                  for (var j = 0; j < sortFieldCount; j++)
                                                  {
                                                     // Compose the order by clause.
                                                     sortProp = child.GetChild(j);
                                                     orderbyClause += sortProp.GetProperty("field");
                                                     var sortOrder = sortProp.GetValue();
                                                     if (sortOrder == "DESCENDING")
                                                        orderbyClause += " desc";
                                                     if (j < sortFieldCount-1)
                                                        orderbyClause += ", ";
                                                     }
                                                  }
                                               }
                                               // Now, our complete select statement is...
                                               selectStmt += whereClause + orderbyClause;
                                               // Now, query the data source.
                                               var conn = getConnection();
                                               var rs = getRecordset();
                                               rs.Open(selectStmt, conn);
                                               // We will return no more than maxRows of records.
                                               var count = rs.RecordCount;
                                               if (maxRows != "")
                                                  if (count > maxRows)
                                                     count = maxRows
                                               // Iterate through the record set and add them to the Outputs PropertySet.
                                               var fcount, fields, row;
                                               for (i = 0; i < count; i++)
                                               {
                                                  row = TheApplication().NewPropertySet();
                                                  fields = rs.Fields();
                                                  fcount = fields.Count;
                                                  for (j = 0; j < fcount; j++)
                                                  {
                                                  var fieldValue = fields.Item(j).Value;
                                                  if (fieldValue == null)
                                                     row.SetProperty(fields.Item(j).Name, "");
                                                  else
                                                     row.SetProperty(fields.Item(j).Name, fieldValue);
                                                  }
                                                  Outputs.AddChild(row);
                                                  rs.MoveNext();
                                               }
                                               // For debugging purposes...
                                               logPropSet(Outputs, "QueryOutputs.xml" );
                                               // clean up
                                               child = null;
                                               sortProp = null;
                                               row = null;
                                               rs.Close();
                                               rs = null;
                                               conn.Close();
                                               conn = null;
                                               return (CancelOperation);
                                              }
                                              function PreInsert (Inputs, Outputs) {
                                               // For debugging purposes...
                                               logPropSet(Inputs, "PreInsertInputs.xml");
                                               var defaults = TheApplication().NewPropertySet();
                                               defaults.SetProperty("Location", "KO");
                                               Outputs.AddChild(defaults);
                                               // For debugging purposes...
                                               logPropSet(Outputs, "PreInsertOutputs.xml");
                                               // Cleanup
                                               defaults = null;
                                               return (CancelOperation);
                                              }
                                              function Insert (Inputs, Outputs) {
                                               // For debugging purposes...
                                               logPropSet(Inputs, "InsertInputs.xml");
                                               var fieldList = "";
                                               var valueList = "";
                                               // Inputs must have only 1 child property set.
                                               var child = Inputs.GetChild(0);
                                               var fieldName = child.GetFirstProperty();
                                               var fieldValue;
                                               while (fieldName != "")
                                               {
                                                  fieldValue = child.GetProperty(fieldName);
                                                  if (fieldValue != "")
                                                  {
                                                  if (fieldList != "")
                                                  {
                                                     fieldList += ", ";
                                                     valueList += ", ";
                                                  }
                                                  fieldList += fieldName;
                                                  valueList += "'" + fieldValue + "'";
                                                  }
                                                  fieldName = child.GetNextProperty();
                                               }
                                               // The insert statement is...
                                               var insertStmt = "insert into Contacts (" + fieldList + ") values (" + valueList + ")";
                                               // Now, inserting into the data source...
                                               var conn = getConnection();
                                               conn.Execute (insertStmt);
                                               // In this example, we must query back the record just inserted to get
                                               // the value of its primary key.  We made this primary key part of the buscomp
                                               // to make update and delete easy.  The primary key is "AccessId".
                                               var selectStmt = "select * from Contacts where ";
                                               var whereClause = "";
                                               child = Inputs.GetChild(0)
                                               fieldName = child.GetFirstProperty();
                                               while (fieldName != "")
                                               {
                                                  fieldValue = child.GetProperty(fieldName);
                                                  if (fieldName != "AccessId")
                                                  {
                                                  if (whereClause != "")
                                                     whereClause += " and ";
                                                  if (fieldValue == "")
                                                     whereClause += fieldName + " is null";
                                                  else
                                                     whereClause += fieldName + "='" + fieldValue + "'";
                                                  }
                                                  fieldName = child.GetNextProperty();
                                               }
                                               // The select statement is...
                                               selectStmt += whereClause;
                                               // Now, let's select the new record back
                                               var rs = getRecordset();
                                               rs.Open(selectStmt, conn);
                                               // We're expecting only one row back in this example.
                                               var fcount, fields, row, fieldValue;
                                               row = TheApplication().NewPropertySet();
                                               fields = rs.Fields();
                                               fcount = fields.Count();
                                               for (var j = 0; j < fcount; j++)
                                               {
                                                  fieldValue = fields.Item(j).Value();
                                                  if (fieldValue == null)
                                                     row.SetProperty(fields.Item(j).Name(), "");
                                                  else
                                                     row.SetProperty(fields.Item(j).Name(), fieldValue);
                                               }
                                               Outputs.AddChild(row);
                                               // For debugging purpose...
                                               logPropSet(Outputs, "InsertOutputs.xml");
                                               // Cleanup
                                               child = null;
                                               row = null;
                                               rs.Close();
                                               rs = null;
                                               conn.Close();
                                               conn = null;
                                               return (CancelOperation);
                                              }
                                              function Update (Inputs, Outputs) {
                                               // For debugging purposes...
                                               logPropSet(Inputs, "UpdateInputs.xml");
                                               var child;
                                               var childCount = Inputs.GetChildCount();
                                               var fieldName, fieldValue;
                                               var updateStmt = "update Contacts set ";
                                               var setClause = "";
                                               var whereClause;
                                               // Go through each child in Inputs and construct the
                                               // necessary sql statements for update and query
                                               for (var i = 0; i < childCount; i++)
                                               {
                                                  child = Inputs.GetChild(i);
                                                  fieldName = child.GetProperty("Field Name");
                                                  fieldValue = child.GetProperty("Field Value");
                                                  // We only have to update changed fields.
                                                  if (child.GetProperty("Changed") == "true")
                                                  {
                                                     if (setClause != "")
                                                        setClause += ", ";
                                                     if (fieldValue == "")
                                                        setClause += fieldName + "=null";
                                                     else
                                                        setClause += fieldName + "='" + fieldValue + "'";
                                                  }
                                                  if (fieldName == "AccessId")
                                                     whereClause = " where AccessId = " + fieldValue;
                                               }
                                               // The update statement is...
                                               updateStmt += setClause + whereClause;
                                               // Now, updating the data source...
                                               var conn = getConnection();
                                               conn.Execute (updateStmt);
                                               // How to construct the Outputs PropertySet can vary, but in this example
                                               // We'll query back the updated record from the data source.
                                               var selectStmt = "select * from Contacts" + whereClause;
                                               // Now, let's select the updated record back
                                               var rs = getRecordset();
                                               rs.Open(selectStmt, conn);
                                               // We expect only one row back in this example.
                                               // In this example, we're returning all the fields and not just
                                               // the updated fields.  You can only return those updated
                                               // fields with the new value in the Outputs property set.
                                               var fcount, fields, row, fieldValue;
                                               row = TheApplication().NewPropertySet();
                                               fields = rs.Fields();
                                               fcount = fields.Count();
                                               for (var j = 0; j < fcount; j++)
                                               {
                                                  fieldValue = fields.Item(j).Value();
                                                  if (fieldValue == null)
                                                     row.SetProperty(fields.Item(j).Name(), "");
                                                  else
                                                     row.SetProperty(fields.Item(j).Name(), fieldValue);
                                               }
                                               Outputs.AddChild(row);
                                               // For debugging purposes...
                                               logPropSet(Outputs, "UpdateOutputs.xml");
                                               // Cleanup
                                               child = null;
                                               row = null;
                                               rs.Close();
                                               rs = null;
                                               conn.Close();
                                               conn = null;
                                               return (CancelOperation);
                                              }
                                              function Delete (Inputs, Outputs) {
                                               // For debugging purposes...
                                               logPropSet(Inputs, "DeleteInputs.xml");
                                               // Inputs must have only 1 child property set.
                                               var child = Inputs.GetChild(0);
                                               // In this example, we're only using the AccessId
                                               // (it is the primary key in the Contacts db)
                                               // for the delete statement for simplicity.
                                               var deleteStmt = "delete from Contacts where AccessId = " + 
                                            child.GetProperty("AccessId");
                                               // Now, delete the record from the data source.
                                               var conn = getConnection();
                                               conn.Execute(deleteStmt);
                                               // For debugging purposes...
                                               logPropSet(Outputs, "DeleteOutputs.xml");
                                               // Returning empty Outputs property set.
                                               // clean up
                                               conn.Close();
                                               conn = null;
                                               return (CancelOperation);
                                              }
                                            

                                            The following functions are helper functions:

                                              function getConnection () {
                                               // VBCContact is the ODBC data source name
                                               var connectionString = "DSN=VBCContact";
                                               var uid = "";
                                               var passwd = "";
                                               var conn = COMCreateObject("ADODB.Connection");
                                               conn.Mode = 3;
                                               conn.CursorLocation = 3;
                                               conn.Open(connectionString , uid, passwd);
                                               return conn;
                                              }
                                              function getRecordset() {
                                               var rs = COMCreateObject("ADODB.Recordset");
                                               return rs;
                                              }
                                              function logPropSet(inputPS, fileName) {
                                               // Use EAI XML Write to File business service to write
                                               // inputPS property set to fileName file in c:\temp directory.
                                               var fileSvc = TheApplication().GetService("EAI XML Write to File");
                                               var outPS = TheApplication().NewPropertySet();
                                               var fileLoc = "c:\\temp\\" + fileName;
                                               var tmpProp = inputPS.Copy();
                                               tmpProp.SetProperty("FileName", fileLoc);
                                               fileSvc.InvokeMethod("WritePropSet", tmpProp, outPS);
                                               // clean up
                                               outPS  = null;
                                               fileSvc = null;
                                               tmpProp = null;
                                              }
                                              function stringReplace (string, from, to) {
                                               // Replaces from with to in string
                                               var stringLength = string.length;
                                               var fromLength = from.length;
                                               if ((stringLength == 0) || (fromLength == 0)) 
                                               return string; 
                                               var fromIndex = string.indexOf(from);
                                               if (fromIndex < 0)
                                                  return string; 
                                               var newString = string.substring(0, fromIndex) + to; 
                                               if ((fromIndex + fromLength) < stringLength)
                                                  newString += stringReplace(string.substring(fromIndex+fromLength, stringLength), 
                                            from, to); 
                                               return newString;
                                              }
                                            

                                              Siebel VB Business Service Example for a VBC

                                              The following is an example of Siebel VB implementation of a business service for a VBC. The fields configured for this simple VBC are AccountId, Name, Phone, and Location.

                                              Caution: Do not use Siebel CRM system fields, such as Id, as output properties. Undesired application behavior might result.
                                              (declarations)
                                              Option Explicit
                                              Declare Function stringReplace(mystr As String, fromchar As String, tochar As 
                                              String) As String
                                              Declare Function getData(execSQL As String, Results As PropertySet) As Integer
                                              Function getData(execSQL As String, Results As PropertySet) As Integer
                                              Dim sSrv As String, sDbn As String
                                              Dim sUsr As String, sPsw As String
                                              Dim oCon As Object, oRec As Object
                                              Dim Row As PropertySet
                                              Dim FileName, TextToSave
                                              ' *** SQL Server connectivity parameters
                                              sSrv = "v817.siebel.com" '*** Oracle tns
                                              sUsr = "system" '*** SQL Server: a user's login Id
                                              sPsw = "manager" '*** SQL Server: a user's password
                                              ' *** Create SQL Server ADODB connection dynamically
                                              Set oCon = CreateObject("ADODB.Connection")
                                              oCon.Open "Provider=MSDAORA;" & _
                                              "Data Source=" & sSrv & ";"  & _
                                              "User ID="     & sUsr & ";" & "Password=" & sPsw & ";"
                                              ' *** Perform SQL query
                                              Set oRec = oCon.Execute(execSQL)
                                              ' *** Process SQL query result and save into file
                                              While Not oRec.Eof
                                                Set Row=TheApplication.NewPropertySet()
                                                Row.SetProperty "AccountId", oRec.Fields.Item("AccountId").Value
                                                Row.SetProperty "Name", oRec.Fields.Item("Name").Value
                                                Row.SetProperty "Location", oRec.Fields.Item("Location").Value
                                                Row.SetProperty "Phone", oRec.Fields.Item("Phone").Value
                                                Results.AddChild Row
                                                Set Row = Nothing
                                                oRec.MoveNext
                                              Wend
                                              ' *** Object cleanup
                                              Set oRec = Nothing
                                              Set oCon = Nothing
                                              getData = 0
                                              End Function
                                              Sub Init(Inputs As PropertySet, Outputs As PropertySet)
                                              Outputs.SetProperty "AccountId", ""
                                              Outputs.SetProperty "Name", ""
                                              Outputs.SetProperty "Phone", ""
                                              Outputs.SetProperty "Location", ""
                                              End Sub
                                              Sub Query(Inputs As PropertySet, Outputs As PropertySet)
                                              Dim sselectStmt As String
                                              Dim swhereClause As String
                                              Dim sorderbyClause As String
                                              Dim ssearchstring As String
                                              Dim child As PropertySet
                                              Dim sortProp As PropertySet
                                              Dim childCount As Integer
                                              Dim i As Integer
                                              Dim ret As Integer
                                              Dim FileName, TextToSave
                                              sselectStmt = "select * from siebel.Contact2 "
                                              swhereClause = "where "
                                              sorderbyClause= "order by "
                                              ssearchstring = Inputs.GetProperty("search-string")
                                              If Len(ssearchstring) > 0 Then
                                                ssearchstring = stringReplace(ssearchString, "*", "%")
                                                ssearchstring = stringReplace(ssearchString, "[", " ")
                                                ssearchstring = stringReplace(ssearchString, "]", " ")
                                                ssearchstring = stringReplace(ssearchString, "~", " ")
                                                ssearchstring = stringReplace(ssearchString, chr$(34), "'")
                                                sselectStmt = sselectStmt & swhereClause & ssearchstring
                                              End If
                                              ' Write select statement to this file
                                              FileName = "C:\Test.txt" 
                                              TextToSave = "select is " & sselectStmt
                                              Open FileName For Append As #1
                                              Print #1, TextToSave
                                              Close #1
                                              ret = getData(sselectStmt, Outputs)
                                              End Sub
                                              Function stringReplace(mystr As String, fromchar As String, tochar As String) As 
                                              String
                                              'Replace all occurrences of fromchar in mystr with tochar
                                              Dim i As Long
                                              If Len(mystr) = 0 Or Len(fromchar) = 0 Then
                                              stringReplace = mystr
                                              Else
                                              i = InStr(1, mystr, fromchar)
                                              Do While i > 0
                                              mystr = Left(mystr, i - 1) & tochar & Mid(mystr, i + Len(fromchar))
                                              i = i + Len(fromchar)
                                              i = InStr(i, mystr, fromchar)
                                              Loop
                                              stringReplace = mystr
                                              End If
                                              End Function
                                              Function Service_PreInvokeMethod (MethodName As String, Inputs As PropertySet, 
                                              Outputs As PropertySet) As Integer
                                              Service_PreInvokeMethod = ContinueOperation
                                              If MethodName = "Init" Then
                                              Service_PreInvokeMethod = CancelOperation
                                              Init Inputs, Outputs
                                              Exit Function
                                              End If
                                              If MethodName = "Query" Then
                                              Service_PreInvokeMethod = CancelOperation
                                              Query Inputs, Outputs
                                              Exit Function
                                              End If
                                              End Function