Redundant Namespace declarations in SOA Suite: BPEL

Redundant Namespace declarations in SOA Suite: BPEL

Gepubliceerd: Categorie: Oracle

What are the namespace effects of using the assign activity, compared to the transform activity? This article will show you how to solve duplicate namespace definitions caused by the JMS adapter itself.

Oracle BPEL will generate namespace declarations on almost each XML element when using assigns. Pretty logical considering each assign should generate proper XML on its own. The XML will be valid, but becomes very verbose. To overcome this one can use the transform node (or ora:doXSLTransformForDoc) to specify where to put the namespace declarations for the entire output document.

However, when using JMS adapters we see the carefully transformed XML gets reformatted, adding those redundant namespace definitions again.

Take for instance this example XML message (figure 1):

  1. <hr:Employee xmlns:person="com.qualogy.hr.person" xmlns:common="com.qualogy.common" xmlns:salary="com.qualogy.hr.salary" xmlns:hr="com.qualogy.hr">
  2. <hr:EmployeeNumber>1234567</hr:EmployeeNumber>
  3. <hr:PersonDetails>
  4. <person:Firstname>John</person:Firstname>
  5. <person:Lastname>Doe</person:Lastname>
  6. <common:Email>jdoe@qualogy.com</common:Email>
  7. </hr:PersonDetails>
  8. <hr:DependantPersonDetails>
  9. <person:Firstname>Jane</person:Firstname>
  10. <person:Lastname>Doe</person:Lastname>
  11. <common:Email>jdoe@qualogy.com</common:Email>
  12. </hr:DependantPersonDetails>
  13. <hr:SalaryDetails>
  14. <salary:Amount>100000</salary:Amount>
  15. <salary:BonusAmount>2000</salary:BonusAmount>
  16. <salary:BonusPercentage>20</salary:BonusPercentage>
  17. </hr:SalaryDetails>
  18. </hr:Employee>

Figure 1: Please note Employee being defined in the ‘hr’ namespace,  person detail elements being defined in the ‘person’ namespace, and salary details elements being defined in the ‘salary’ namespace. Namespace declaration is only performed once on the top-level element

Translation using the assign activity

Normally we will translate  from one type to another. For the sake of simplicity we will just translate to the same type. When assigning each element separately using the BPEL assign node (figure 2) a very verbose XML structure will be created as a result (figure 3).

Figure 2: Assigning each element separately from inputVariable to outputVariable
  1. <Employee xmlns="com.qualogy.hr">
  2. <EmployeeNumber>1234567</EmployeeNumber>
  3. <PersonDetails>
  4. <Firstname xmlns="com.qualogy.hr.person">John</Firstname>
  5. <Lastname xmlns="com.qualogy.hr.person">Doe</Lastname>
  6. <Email xmlns="com.qualogy.common">jdoe@qualogy.com</Email>
  7. </PersonDetails>
  8. <DependantPersonDetails>
  9. <Firstname xmlns="com.qualogy.hr.person">Jane</Firstname>
  10. <Lastname xmlns="com.qualogy.hr.person">Doe</Lastname>
  11. <Email xmlns="com.qualogy.common">jdoe@qualogy.com</Email>
  12. </DependantPersonDetails>
  13. <SalaryDetails>
  14. <Amount xmlns="com.qualogy.hr.salary">100000</Amount>
  15. <BonusAmount xmlns="com.qualogy.hr.salary">2000</BonusAmount>
  16. <BonusPercentage xmlns="com.qualogy.hr.salary">20</BonusPercentage>
  17. </SalaryDetails>
  18. </Employee>

Figure 3: Verbose XML structure with lots of duplicate namespace declarations

When translating different types you will typically be doing these  1-on-1 element mappings. Because we are doing an identity transformation we can also choose to just assign the Employee type in one go (figure 4). In figure 5 we have the resulting XML. It still contains some duplicate namespaces.

Figure 4: Assigning Employee in one go, which should only be done if types are actually the same
  1. <Employee xmlns:ns1="com.qualogy.hr" xmlns="com.qualogy.hr">
  2. <ns1:EmployeeNumber>1234567</ns1:EmployeeNumber>
  3. <ns1:PersonDetails xmlns:ns2="com.qualogy.hr.person" xmlns:ns3="com.qualogy.common">
  4. <ns2:Firstname>John</ns2:Firstname>
  5. <ns2:Lastname>Doe</ns2:Lastname>
  6. <ns3:Email>jdoe@qualogy.com</ns3:Email>
  7. </ns1:PersonDetails>
  8. <ns1:DependantPersonDetails xmlns:ns2="com.qualogy.hr.person" xmlns:ns3="com.qualogy.common">
  9. <ns2:Firstname>Jane</ns2:Firstname>
  10. <ns2:Lastname>Doe</ns2:Lastname>
  11. <ns3:Email>jdoe@qualogy.com</ns3:Email>
  12. </ns1:DependantPersonDetails>
  13. <ns1:SalaryDetails xmlns:ns2="com.qualogy.hr.salary">
  14. <ns2:Amount>100000</ns2:Amount>
  15. <ns2:BonusAmount>2000</ns2:BonusAmount>
  16. <ns2:BonusPercentage>20</ns2:BonusPercentage>
  17. </ns1:SalaryDetails>
  18. </Employee>

Figure 5: XML output with some duplicate namespace declarations. Notice the person and common namespaces being redefined.

Translation using the transform activity

The transform activity is commonly used for doing complete XML transformations. It enables developers to define the entire document mapping and where to include the namespace declarations (see figure 6). Using the  transform activity and this XSLT we get an XML output as shown in figure 7. An output without any redundant namespace declarations!

  1. <xsl:template match="/">
  2. <hr:Employee xmlns:salary="com.qualogy.hr.salary" xmlns:common="com.qualogy.common" xmlns:person="com.qualogy.hr.person">
  3. <hr:EmployeeNumber>
  4. <xsl:value-of select="/hr:Employee/hr:EmployeeNumber"/>
  5. </hr:EmployeeNumber>
  6. <hr:PersonDetails>
  7. <person:Firstname>
  8. <xsl:value-of select="/hr:Employee/hr:PersonDetails/person:Firstname"/>
  9. </person:Firstname>
  10. <person:Lastname>
  11. <xsl:value-of select="/hr:Employee/hr:PersonDetails/person:Lastname"/>
  12. </person:Lastname>
  13. <common:Email>
  14. <xsl:value-of select="/hr:Employee/hr:PersonDetails/common:Email"/>
  15. </common:Email>
  16. </hr:PersonDetails>
  17. <hr:DependantPersonDetails>
  18. <person:Firstname>
  19. <xsl:value-of select="/hr:Employee/hr:DependantPersonDetails/person:Firstname"/>
  20. </person:Firstname>
  21. <person:Lastname>
  22. <xsl:value-of select="/hr:Employee/hr:DependantPersonDetails/person:Lastname"/>
  23. </person:Lastname>
  24. <common:Email>
  25. <xsl:value-of select="/hr:Employee/hr:DependantPersonDetails/common:Email"/>
  26. </common:Email>
  27. </hr:DependantPersonDetails>
  28. <hr:SalaryDetails>
  29. <salary:Amount>
  30. <xsl:value-of select="/hr:Employee/hr:SalaryDetails/salary:Amount"/>
  31. </salary:Amount>
  32. <salary:BonusAmount>
  33. <xsl:value-of select="/hr:Employee/hr:SalaryDetails/salary:BonusAmount"/>
  34. </salary:BonusAmount>
  35. <salary:BonusPercentage>
  36. <xsl:value-of select="/hr:Employee/hr:SalaryDetails/salary:BonusPercentage"/>
  37. </salary:BonusPercentage>
  38. </hr:SalaryDetails>
  39. </hr:Employee>
  40. </xsl:template>

Figure 6: XSLT for transforming an Employee to an Employee, modified to only declare namespaces once

  1. <Employee xmlns:person="com.qualogy.hr.person" xmlns:common="com.qualogy.common" xmlns:salary="com.qualogy.hr.salary" xmlns:hr="com.qualogy.hr" xmlns="com.qualogy.hr">
  2. <hr:EmployeeNumber>1234567</hr:EmployeeNumber>
  3. <hr:PersonDetails>
  4. <person:Firstname>John</person:Firstname>
  5. <person:Lastname>Doe</person:Lastname>
  6. <common:Email>jdoe@qualogy.com</common:Email>
  7. </hr:PersonDetails>
  8. <hr:DependantPersonDetails>
  9. <person:Firstname>Jane</person:Firstname>
  10. <person:Lastname>Doe</person:Lastname>
  11. <common:Email>jdoe@qualogy.com</common:Email>
  12. </hr:DependantPersonDetails>
  13. <hr:SalaryDetails>
  14. <salary:Amount>100000</salary:Amount>
  15. <salary:BonusAmount>2000</salary:BonusAmount>
  16. <salary:BonusPercentage>20</salary:BonusPercentage>
  17. </hr:SalaryDetails>
  18. </Employee>

Figure 7: XML output  generated using XSLT containing no duplicate namespace declarations

JMS adapter output

For a basic HTTP synchronous request/response BPEL process this works all fine. The response output as shown in the EM console (in flow view) will be exactly the same as the actual output received by the HTTP client doing the request.

However for JMS endpoints we see a discrepancy between the EM console (figure 8) and the actually received JMS response on the queue (figure 9). As if the JMS adapter is parsing the XML again, adding redundant namespace declarations on the way.

Figure 8: EM Console showing output response which is going to a JMS queue. Note we do not see any redundant namespace declarations!
  1. <?xml version="1.0" encoding="UTF-8" ?><Employee xmlns:person="com.qualogy.hr.person" xmlns:common="com.qualogy.common" xmlns:salary="com.qualogy.hr.salary" xmlns:hr="com.qualogy.hr" xmlns="com.qualogy.hr">
  2. <hr:EmployeeNumber>1234567</hr:EmployeeNumber>
  3. <hr:PersonDetails>
  4. <person:Firstname xmlns="com.qualogy.hr.person">John</person:Firstname>
  5. <person:Lastname xmlns="com.qualogy.hr.person">Doe</person:Lastname>
  6. <common:Email xmlns="com.qualogy.common">jdoe@qualogy.com</common:Email>
  7. </hr:PersonDetails>
  8. <hr:DependantPersonDetails>
  9. <person:Firstname xmlns="com.qualogy.hr.person">Jane</person:Firstname>
  10. <person:Lastname xmlns="com.qualogy.hr.person">Doe</person:Lastname>
  11. <common:Email xmlns="com.qualogy.common">jdoe@qualogy.com</common:Email>
  12. </hr:DependantPersonDetails>
  13. <hr:SalaryDetails>
  14. <salary:Amount xmlns="com.qualogy.hr.salary">100000</salary:Amount>
  15. <salary:BonusAmount xmlns="com.qualogy.hr.salary">2000</salary:BonusAmount>
  16. <salary:BonusPercentage xmlns="com.qualogy.hr.salary">20</salary:BonusPercentage>
  17. </hr:SalaryDetails>
  18. </Employee>

Figure 9: XML response output which is actually received on the JMS queue. Note we suddenly do see redundant namespace declarations!

JMS Adapter using Opaque element

To prevent the JMS adapter to change the XML we can try sending the XML payload as an opaque element instead. For this example we just added an additional JMS endpoint to the composite to send an opaque payload (figure 10). Just copying the configuration from the other JMS adapter except when defining the message. Instead of selecting some XML message type we select Native format (see figure 11).

Figure 10: Composite after adding second JMS endpoint for opaque payload
Figure 11: Selecting a Native format will result in the use of an opaque element

In the BPEL we will now need to cast the transformed XML to a string variable, and base64 encode this string before assigning it to the new opaque output variable (see figure 12, 13, 14 and 15).

Figure 12: BPEL modified to assign message as string, encode it as base64 and assign it to the opaque output variable
Figure 13: Assign XML content as a string to variable MessageAsString
Figure 14: Encode message as base64 using Java embedding. Also add <bpelx:exec import="oracle.soa.common.util.Base64Encoder"/> to import the base64 encoder class
Figure 15: Assign the EncodedMessage base64 variable to the actual JMSOpaqueInput variable used to invoke the JMS endpoint

When sending the message to the JMS queue we now see the following in EM console (figure 16). The translated XML itself has been base64 encoded and is sent in the opaqueElement. When inspecting or dequeuing the JMS message we finally get the proper XML response without redundant namespaces (figure 17).

Figure 16: Opaque payload is now being send to the JMS endpoint
  1. <Employee xmlns:person="com.qualogy.hr.person" xmlns:common="com.qualogy.common" xmlns:salary="com.qualogy.hr.salary" xmlns:hr="com.qualogy.hr" xmlns="com.qualogy.hr">
  2. <hr:EmployeeNumber>1234567</hr:EmployeeNumber>
  3. <hr:PersonDetails>
  4. <person:Firstname>John</person:Firstname>
  5. <person:Lastname>Doe</person:Lastname>
  6. <common:Email>jdoe@qualogy.com</common:Email>
  7. </hr:PersonDetails>
  8. <hr:DependantPersonDetails>
  9. <person:Firstname>Jane</person:Firstname>
  10. <person:Lastname>Doe</person:Lastname>
  11. <common:Email>jdoe@qualogy.com</common:Email>
  12. </hr:DependantPersonDetails>
  13. <hr:SalaryDetails>
  14. <salary:Amount>100000</salary:Amount>
  15. <salary:BonusAmount>2000</salary:BonusAmount>
  16. <salary:BonusPercentage>20</salary:BonusPercentage>
  17. </hr:SalaryDetails>
  18. </Employee>

Figure 17: XML response without redundant namespace declarations from JMS queue

Richard Velden
Over auteur Richard Velden

Oracle Fusion Middleware Developer at Qualogy. Specializes in integration and cloud development using Oracle technologies such as: SOA Suite, Service Bus, Integration and Process Cloud.

Meer posts van Richard Velden
Reacties (1)
  1. om 08:08

    Nice article!

    We can also remove namespace by using XSL, this is what I have used in my current project

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="no"/>

    <xsl:template match="/|comment()|processing-instruction()">
    <xsl:copy>
    <xsl:apply-templates/>
    </xsl:copy>
    </xsl:template>

    <xsl:template match="*">
    <xsl:element name="{local-name()}">
    <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
    <xsl:attribute name="{local-name()}">
    <xsl:value-of select="."/>
    </xsl:attribute>
    </xsl:template>
    </xsl:stylesheet>

    Thanks!

Reactie plaatsen