IBM Support

JSPs generated as human task clients cannot accomodate xsd:any, choice, and substitution group constructs

Troubleshooting


Problem

In the generated JSF custom client for human tasks, when you want to view or edit messages that contain xsd:any, choice, or substitution group constructs, you cannot see these parts of the message nor modify them.

Cause

Due to a limitation in the Service Data Object API, it is not possible to identify substitution groups or choice elements. If the message contains an xs:any element, there is a wildcard slot about which the generated client cannot make any assumption. Instead you must add custom code to deal with such constructs.

Resolving The Problem

This technote describes the solution for substitution elements. The solution for xs:choice and xs:any is similar.

If there is an element AbstractAccount, which can be subsituted by an element AccountChild, the schema definition might look like this:

<xs:element name="AbstractAccount" type="ns1:AccountType"/>
    <xs:complexType name="AccountType">
      <xs:sequence>
        <xs:element minOccurs="0" name="elt" type="xs:string"></xs:element>
    </xs:sequence>
    <!-- xs:attribute name="attr" type="xs:string" use="optional"/-->
</xs:complexType>

<xs:element name="AccountChild"
    substitutionGroup="ns1:AbstractAccount">
      <xs:complexType>
        <xs:complexContent>
          <xs:extension base="ns1:AccountType">
            <xs:sequence>
              <xs:element minOccurs="0" name="childElt"
                type="xs:string">
              </xs:element>
            </xs:sequence>
        <!-- xs:attribute name="childAttr" type="xs:string" use="optional"/-->
        </xs:extension>
      </xs:complexContent>
    </xs:complexType>
</xs:element>

If the human task uses the type AbstractAccount for its messages, the client generated for this human task will add a warning to the message JSPs:

<h:outputText styleClass="ViewFieldLabel" value="#{bundle['MSG_SUBVIEW_ELEMENT_NOT_SUPPORTED']}"/>
<h:outputText styleClass="Indentend" value="elt is part of xsd:substitutionGroup"/>


To add AccountChild elements instead of AbstractAccount elements, you can replace these lines with the following lines for the input message:

<h:outputText styleClass="ViewFieldLabel" value="elt:"/>
<h:outputText styleClass="ViewReadOnlyField" value="#{toDoMessageHandler.toDoInstance.inputValues['/input1/AbstractAccount/elt']}"/>

<h:outputText styleClass="ViewFieldLabel" value="childElt:"/>
<h:outputText styleClass="ViewReadOnlyField" value="#{toDoMessageHandler.toDoInstance.inputValues['/input1/AbstractAccount/childElt']}"/>


In the case of the output message, inputText elements need to be used.

<h:outputText styleClass="ViewFieldLabel" value="elt: "/>
<h:inputText id="output1field2_ID" styleClass="ViewEntryField" value="#{toDoMessageHandler.toDoInstance.outputValues['/output1/AbstractAccount/elt']}" required="false" />

<h:outputText styleClass="ViewFieldLabel" value="childElt: "/>
<h:inputText id="output1field3_ID" styleClass="ViewEntryField" value="#{toDoMessageHandler.toDoInstance.outputValues['/output1/AbstractAccount/childElt']}" required="false" />


Note: The properties of an AccountChild are accessed by refering to the head element AbstractAccount. Unfortunately, the output JSP will not work immediately because the implementation of the generated client cannot handle the used xPath. Therefore, you must alter the getOutputValues() method of the the com.ibm.wbit.tel.client.jsf.bean.ToDoInstance.
This example shows the original implementation:

public Object getOutputValues(Object dataType) throws PropertyNotFoundException, PropertyPopulationException {
      Object ret = null
        if (outputValues != null) {
          if (dataType instanceof DataObject) {
            ret = DataObjectUtils.populateAll((DataObject) dataType, outputValues);
            } else {
            ret = outputValues.get(SINGLE_PRIMITIVE_TYPE);
            }
            }
        return ret;
}


To alter the above implementation, follow these steps:

  1. As this method is invoked for all message types of the generated client, you must ensure that the custom code is only invoked for the right message type.

  2. Set the ALContext to the application that provides the schema definition and unset the context in a finally statement later again.

  3. Remove the xPaths that relate to the substitution group.

  4. Invoke the populateAll method with all the supported xPaths.

  5. Check if the substitution element already exists.

  6. If the substitution element does not exit, create a new element using the BOFactory service and set the substitution element on the DataObject.

  7. Set the properties of the substitution element

public Object getOutputValues(Object dataType) throws PropertyNotFoundException, PropertyPopulationException {
        Object ret = null;
        if (outputValues != null) {
          if (dataType instanceof DataObject) {
            String typeName = ((DataObject)dataType).getType().getName();
              String uriName = ((DataObject)dataType).getType().getURI();
// System.out.println("TYPE: " + typeName);
// System.out.println("URI: " + uriName);
//
// 0 )Only run the special logic for that right type
//
if ("operation1Response_._type".equals(typeName) && "http://SubstLibrary/ChildIntf".equals(uriName)) {
                try {
//
// 1) Set the searchpath for artifacts appropriately
//    Make sure that the application that contains the artifacts is set. In my case "SubstTest1App"
//
com.ibm.wsspi.al.ALContext.setContext("BPC_CLIENT","SubstTest1App");
//
// 2) Remove the keys out of the map and store the values.
//
          String elt = (String) outputValues.remove("/output1/AbstractAccount/elt");
          String childElt = (String) outputValues.remove("/output1/AbstractAccount/childElt");
//
// 3) Populate all other values using the standard method
//
ret = DataObjectUtils.populateAll((DataObject) dataType, outputValues);
//
// 4) Check whether the substitution element already exists
//
          DataObject output1 = ((DataObject)ret).getDataObject("output1");
          DataObject accountChild = (DataObject) output1.get("AccountChild");
            if (accountChild == null) {
//
// 5) Create the substitution element using the BOFactory
//
      com.ibm.websphere.bo.BOFactory factoryService = (com.ibm.websphere.bo.BOFactory) new com.ibm.websphere.sca.ServiceManager().locateService("com/ibm/websphere/bo/BOFactory");
        accountChild = factoryService.createByElement("http://www.example.org/artifacts/", "AccountChild");
//
// Set the value on the substitution element
//
      output1.set("AccountChild", accountChild);
}
//
// 6) set the properties of the substitution element
//
    accountChild = output1.getDataObject("AccountChild");
      accountChild.set("elt",elt);
        accountChild.set("childElt", childElt);
          } catch (InvalidConfigException e) {
            e.printStackTrace();
              } catch (RuntimeException exception) {
                exception.printStackTrace();
                throw exception;
              }
              finally {
                com.ibm.wsspi.al.ALContext.unset();
                }
                } else {
            ret = DataObjectUtils.populateAll((DataObject) dataType, outputValues);
            }
          } else {
        ret = outputValues.get(SINGLE_PRIMITIVE_TYPE);
        }
      }
    return ret;
    }

[{"Product":{"code":"SSQQFK","label":"WebSphere Integration Developer"},"Business Unit":{"code":"BU053","label":"Cloud & Data Platform"},"Component":"Human Task Editor","Platform":[{"code":"PF016","label":"Linux"},{"code":"PF033","label":"Windows"}],"Version":"6.1.2","Edition":"","Line of Business":{"code":"LOB45","label":"Automation"}},{"Product":{"code":"SSBN76","label":"WebSphere Dynamic Process Edition"},"Business Unit":{"code":"BU053","label":"Cloud & Data Platform"},"Component":" ","Platform":[{"code":"","label":""}],"Version":"6.1.2","Edition":"","Line of Business":{"code":"LOB45","label":"Automation"}}]

Document Information

Modified date:
15 June 2018

UID

swg21306783