尝试转换DataService结果时的NPE

时间:2014-01-08 13:23:27

标签: xslt nullpointerexception wso2 wso2esb wso2dss

我在WSO2 ESB中构建了一个代理,它接收xml,转换它,转发到WSO2数据服务,转换结果并将其返回给请求者。

根据日志,正在调用DataService,因为打印了结果XML。问题在于结果的转换,发生这种情况:

ERROR - XSLTMediator Unable to perform XSLT transformation using : Value {name ='null', keyValue ='GetAppointmentSchedulePortalReqCS_Response'} against source XPath : s11:Body/child::*[position()=1] | s12:Body/child::*[position()=1]
java.lang.NullPointerException
    at org.apache.synapse.util.jaxp.StreamSourceBuilder.getSource(StreamSourceBuilder.java:55)
    at org.apache.synapse.mediators.transform.XSLTMediator.performXSLT(XSLTMediator.java:289)
    at org.apache.synapse.mediators.transform.XSLTMediator.mediate(XSLTMediator.java:191)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:71)
    at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:114)
    at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:230)
    at org.apache.synapse.core.axis2.SynapseCallbackReceiver.handleMessage(SynapseCallbackReceiver.java:443)
    at org.apache.synapse.core.axis2.SynapseCallbackReceiver.receive(SynapseCallbackReceiver.java:166)
    at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
    at org.apache.synapse.transport.passthru.ClientWorker.run(ClientWorker.java:217)
    at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:662)

XLST文件是:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://ws.wso2.org/dataservice" version="2.0"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xpath-default-namespace="http://www.algartelecom.com.br/SOA/Service/GetAppointmentSchedulePortalReqCS">
    <xsl:output method="xml" indent="yes" />
    <xsl:template match="//xs:GetAppointmentResponse">
        <AppointmentRequest>
            <serviceOrderID>
                <xsl:value-of select="xs:NewAppointment" />
            </serviceOrderID>
            <opportunityID>
                <xsl:value-of select="xs:ServiceTOA" />
            </opportunityID>
            <customerOrderID>
                <xsl:value-of select="xs:MinimalTime" />
            </customerOrderID>
        </AppointmentRequest>
    </xsl:template>
</xsl:transform>

DataService返回的XML是:

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <GetAppointmentResponse xmlns="http://ws.wso2.org/dataservice">
            <NewAppointment>147</NewAppointment>
            <ServiceTOA>TT_P</ServiceTOA>
            <MinimalTime>1</MinimalTime>
            <ReturnCode>0</ReturnCode>
            <ErrorMessage>SUCESSO</ErrorMessage>
        </GetAppointmentResponse>
    </soapenv:Body>
</soapenv:Envelope>

我已经在其他工具中使用XML测试了XSLT,并且转换工作正常! = /

我认为这可能是由DSS添加到GetAppointmentResponse标记的内联命名空间引起的。 使用JRE1.6.0_43,ESB 4.6.0和DSS 3.1.0。请帮忙。

修改

我注意到这个问题确实是由响应中的空体引起的,正如@Kallja所说。

恢复,我有以下情况:

     PROXY1         ->           PROXY2      ->       PROXY3     ->     ENDPOINT
in   xslt->log1->header->send    log2->header->send   xslt->log3        address web service
out  log6->xslt->send            log5->send           xslt->log4->send

通过soapUI直接调用PROXY3,正确调用Web服务并收到响应 但是,调用PROXY2时,日志序列按以下顺序显示:log2log3log5log4

这意味着PROXY2正在对PROXY3进行异步调用。在返回soapUI之前,它不会等待响应的XML。它会产生一个空体。

那么,如何让它同步?我试图通过Callout介体替换Send mediator,但结果是一样的。

1 个答案:

答案 0 :(得分:1)

你得到的NullPointerException似乎表明XPath表达式(在这种情况下,当没有提供任何其他东西时是WSO2 ESB默认值)指向你想要转换的数据返回null。在这种情况下,这意味着您有一个空白的SOAP主体。

您尚未发布您的序列配置,因此我真的没有太多可以使用的工作。

我的建议是你添加一个完整的日志(下面),它将整个SOAP信封以及几个属性打印到ESB控制台和碳日志文件中,就在XSLT中介之前,看看你是否确实有内容在你的有效载荷中。

<log category="INFO" level="full" separator=","/>

我使用以下配置测试了您的转换,并且执行完美。

<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="XsltTestProxy"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence>
         <payloadFactory>
            <format>
               <GetAppointmentResponse xmlns="http://ws.wso2.org/dataservice">
                  <NewAppointment>147</NewAppointment>
                  <ServiceTOA>TT_P</ServiceTOA>
                  <MinimalTime>1</MinimalTime>
                  <ReturnCode>0</ReturnCode>
                  <ErrorMessage>SUCESSO</ErrorMessage>
               </GetAppointmentResponse>
            </format>
            <args/>
         </payloadFactory>
         <log level="custom">
            <property name="message" value="Before XSLT transformation"/>
            <property name="payload" expression="$body"/>
         </log>
         <xslt key="gov:GetAppointmentSchedulePortalReqCS_Response"/>
         <log level="custom">
            <property name="message" value="After XSLT transformation"/>
            <property name="payload" expression="$body"/>
         </log>
         <property name="RESPONSE" value="true"/>
         <header name="To" action="remove"/>
         <send/>
      </inSequence>
   </target>
   <description/>
</proxy>

作为旁注,我建议您将以下属性添加到xsl:stylesheet元素中,以从XSLT输出中删除不必要的SOAP xmlns声明。

exclude-result-prefixes="soapenv"


修改
这个简单的示例配置基于编辑到问题中的执行流程的描述。它显示了如何正确实现相关流程。调用Proxy1时,日志语句按预期顺序显示。

<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="Proxy1" statistics="disable" trace="disable">
    <target endpoint="Proxy2Endpoint">
        <inSequence>
            <!-- Do some XSLT here -->
            <log category="INFO" level="custom" separator=",">
                <property name="message" value="Proxy1 in (1)"/>
                <property expression="$body" name="body"/>
            </log>
            <!-- Do some header magic here -->
            <!-- Implicit send to the endpoint specified in the target element -->
        </inSequence>
        <outSequence>
            <log category="INFO" level="custom" separator=",">
                <property name="message" value="Proxy1 out (6)"/>
                <property expression="/*" name="body"/>
            </log>
            <!-- Do some more XSLT here -->
            <send/>
        </outSequence>
    </target>
</proxy>
<proxy name="Proxy2" statistics="disable" trace="disable" transports="https http">
    <target endpoint="Proxy3Endpoint">
        <inSequence>
            <log category="INFO" level="custom" separator=",">
                <property name="message" value="Proxy2 in (2)"/>
                <property expression="$body" name="body"/>
            </log>
            <!-- Do some header magic here -->
            <!-- Implicit send to the endpoint specified in the target element -->
        </inSequence>
        <outSequence>
            <log category="INFO" level="custom" separator=",">
                <property name="message" value="Proxy2 out (5)"/>
                <property expression="/*" name="body"/>
            </log>
            <send/>
        </outSequence>
    </target>
</proxy>
<proxy name="Proxy3" statistics="disable" trace="disable">
    <target endpoint="ImaginaryWebServiceEndpoint">
        <inSequence>
            <!-- Do some XSLT here -->
            <log category="INFO" level="custom" separator=",">
                <property name="message" value="Proxy3 in (3)"/>
                <property expression="$body" name="body"/>
            </log>
        </inSequence>
        <outSequence>
            <!-- Do some more XSLT here -->
            <log category="INFO" level="custom" separator=",">
                <property name="message" value="Proxy3 out (4)"/>
                <property expression="/*" name="body"/>
            </log>
            <send/>
        </outSequence>
    </target>
</proxy>
<proxy name="ImaginaryWebService" statistics="disable" trace="disable">
    <target>
        <inSequence>
            <log category="INFO" level="custom" separator=",">
                <property name="message" value="Imaginary WebService in"/>
                <property expression="$body" name="body"/>
            </log>
            <payloadFactory>
                <format>
                    <proxy3Response xmlns="">This is the response from the Imaginary WebService</proxy3Response>
                </format>
                <args/>
            </payloadFactory>
            <log category="INFO" level="custom" separator=",">
                <property name="message" value="Imaginary WebService out"/>
                <property expression="/*" name="body"/>
            </log>
            <header action="remove" name="To"/>
            <property action="set" name="RESPONSE" scope="default"
                type="STRING" value="true"/>
            <send/>
        </inSequence>
    </target>
</proxy>
<endpoint name="Proxy2Endpoint">
    <address statistics="disable" trace="disable" uri="http://localhost:8280/services/Proxy2" />
</endpoint>
<endpoint name="Proxy3Endpoint">
    <address statistics="disable" trace="disable" uri="http://localhost:8280/services/Proxy3" />
</endpoint>
<endpoint name="ImaginaryWebServiceEndpoint">
    <address statistics="disable" trace="disable" uri="http://localhost:8280/services/ImaginaryWebService" />
</endpoint>