cancel
Showing results for 
Search instead for 
Did you mean: 

Java Error in RFC Lookup in XSLT Mapping usinf Java helper class

Former Member
0 Kudos

Hi All,

I am doing RFC Lookup in XSLT Mapping using Java Helper class.

The Lookup works fine when called one RFC at a time However my requirement is I want to do 2 Lookups.

Both Lookups works when done individually however when I call both lookups in one mapping I get following error "javax.xml.transform.TransformerException: DOMSource whose Node is null."

Following is the code I have written in XSLT for the lookup:

<xsl:template name="Lookup_1">

<xsl:param name="STDPN"/>

<rfc:RFC_READ_TABLE>

<QUERY_TABLE>KNA1</QUERY_TABLE>

<OPTIONS><item><TEXT>

<xsl:value-of select="$STDPN"/>

</TEXT></item>

</OPTIONS>

<FIELDS>

<item>

<FIELDNAME>KUNNR</FIELDNAME>

</item>

</FIELDS>

</rfc:RFC_READ_TABLE>

</xsl:variable>

<xsl:variable name="response" xmlns:lookup="java:urn.mt.pi" select="lookup:execute($request, 'BS_D, 'cc_RfcLookup', $inputparam)"/>

<xsl:element name="STDPN">

<xsl:value-of select="$response//DATA/item/WA"/>

</xsl:element>

</xsl:template>

<xsl:template name="Lookup_2">

<xsl:param name="BELNR"/>

<xsl:variable name="Query">AGMNT = '<xsl:value-of select="$BELNR"/>'</xsl:variable>

<xsl:variable name="request1">

<rfc:RFC_READ_TABLE>

<QUERY_TABLE>ZTABLE</QUERY_TABLE>

<OPTIONS><item><TEXT>

<xsl:value-of select="$Query"/>

</TEXT></item>

</OPTIONS>

<FIELDS>

<item>

<FIELDNAME>KUNAG</FIELDNAME>

</item>

</FIELDS>

</rfc:RFC_READ_TABLE>

</xsl:variable>

<xsl:variable name="response1" xmlns:lookup="java:urn.mt.pi" select="lookup:execute($request1, 'BS_D','cc_RfcLookup', $inputparam)"/>

<xsl:element name="BELNR">

<xsl:value-of select="$response1//DATA/item/WA"/>

</xsl:element>

</xsl:template>

My Question: Am I doing anything wrong? Or Is it possible to call multiple lookups in one XSLT?

Thanks and Regards,

Atul

Accepted Solutions (0)

Answers (2)

Answers (2)

Former Member
0 Kudos

Hi All,

I tried to debug the Java code and following are my observations:

When RfcLookup is called for second time one of the parameters to the Java method is getting passed as NULL and hence we are getting the error "javax.xml.transform.TransformerException: DOMSource whose Node is null."

The Parameter 'Request' which is of type nodelist is becoming null(However I am passing second node details in my XSLT mapping with proper values and don't know why it is appearing as null)

Can anybody help me in understand why is this happening? Also how do we solve this problem?

Thanks and Regards,

Atul

0 Kudos

Hi Atul,

I had the same problem like you had.

The main Problem is that with the example code the request variable is created as NodeList object. In XSLT a variable is somekind of a constant and can't be changed. As the request object is empty after the first request the programm fails at the following line:

Source source = new DOMSource(request.item(0));

So I've created a workaround for this problem.

In the call of the template I've put the request as a parameter object at the template call:

<xsl:with-param name="req">

<rfc:PLM_EXPLORE_BILL_OF_MATERIAL xmlns:rfc="urn:sap-com:document:sap:rfc:functions">

  <APPLICATION>Z001</APPLICATION>

  <FLAG_NEW_EXPLOSION>X</FLAG_NEW_EXPLOSION>

  <MATERIALNUMBER><xsl:value-of select="value"/></MATERIALNUMBER>

  <PLANT>FSD0</PLANT>

  <VALIDFROM><xsl:value-of select="//Recordset/Row[name='DTM-031']/value"/></VALIDFROM>

  <BOMITEM_DATA/>

</rfc:PLM_EXPLORE_BILL_OF_MATERIAL>

</xsl:with-param>

With this change the request will be provided as a String object and not as a NodeList object.

Afterwards the RfcLookup.java has to be changed to the following:

package com.franke.mappings;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;

import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.sap.aii.mapping.lookup.Channel;
import com.sap.aii.mapping.api.StreamTransformationConstants;
import com.sap.aii.mapping.api.AbstractTrace;
import com.sap.aii.mapping.lookup.RfcAccessor;
import com.sap.aii.mapping.lookup.LookupService;
import com.sap.aii.mapping.lookup.XmlPayload;


/**
* @author Thorsten Nordholm Søbirk, AppliCon A/S
*
* Helper class for using the XI Lookup API with XSLT mappings for calling RFCs.
* The class is generic in that it can be used to call any remote-enabled
* function module in R/3. Generation of the XML request document and parsing of
* the XML response is left to the stylesheet, where this can be done in a very
* natural manner.
*
* TD:
* Changed the class that request is sent as String, because of IndexOutOfBound-exception
* When sending multiple requests in one XSLT mapping.
*
*/
public class RfcLookup {
     /**
     * Execute RFC lookup.
     * @param request RFC request - TD: changed to String
     * @param service name of service
     * @param channelName name of communication channel
     * @param inputParam mapping parameters
     * @return Node containing RFC response
     */
     public static Node execute( String request,
             String service,
             String channelName,
             Map inputParam)

     {
          AbstractTrace trace = (AbstractTrace) inputParam.get(StreamTransformationConstants.MAPPING_TRACE);
          Node responseNode = null;


          try {
              // Get channel and accessor
              Channel channel = LookupService.getChannel(service, channelName);
              RfcAccessor accessor = LookupService.getRfcAccessor(channel);

 

               // Serialise request NodeList - TD: Not needed anymore as request is String
               /*TransformerFactory factory = TransformerFactory.newInstance();
               Transformer transformer = factory.newTransformer();

               Source source = new DOMSource(request.item(0));
               ByteArrayOutputStream baos = new ByteArrayOutputStream();
               StreamResult streamResult = new StreamResult(baos);
               transformer.transform(source, streamResult);*/

  

                // TD: Add xml header and remove linefeeds for the request string
                request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+request.replaceAll("[\r\n]+", ""); 
  
                // TD: Get byte Array from request String to send afterwards
                byte[] requestBytes = request.getBytes();
  
               // TD: Not used anymore as request is String
                //byte[] requestBytes = baos.toByteArray();

                trace.addDebugMessage("RFC Request: " + new String(requestBytes));

                // Create input stream representing the function module request message
                InputStream inputStream = new ByteArrayInputStream(requestBytes);

              

                // Create XmlPayload
                XmlPayload requestPayload =LookupService.getXmlPayload(inputStream);

                // Execute lookup
                XmlPayload responsePayload = accessor.call(requestPayload);
                InputStream responseStream = responsePayload.getContent();
                TeeInputStream tee = new TeeInputStream(responseStream);

                // Create DOM tree for response
                DocumentBuilder docBuilder =DocumentBuilderFactory.newInstance().newDocumentBuilder();
                Document document = docBuilder.parse(tee);
                trace.addDebugMessage("RFC Response: " + tee.getStringContent());
                responseNode = document.getFirstChild();

          } catch (Throwable t) {
               StringWriter sw = new StringWriter();
               t.printStackTrace(new PrintWriter(sw));
               trace.addWarning(sw.toString());
          }
          return responseNode;

     }
     /**
     * Helper class which collects stream input while reading.
     */
     static class TeeInputStream extends InputStream {
           private ByteArrayOutputStream baos;
           private InputStream wrappedInputStream;

           TeeInputStream(InputStream inputStream) {
                baos = new ByteArrayOutputStream();
                wrappedInputStream = inputStream;
           }
           /**
           * @return stream content as String
           */

           String getStringContent() {
                return baos.toString();

           }
          /* (non-Javadoc)
          * @see java.io.InputStream#read()
          */
          public int read() throws IOException {
               int r = wrappedInputStream.read();
               baos.write(r);
               return r;
         }
     }
}

Then you need to compile and upload this class and it should work.

I hope that this helps you.

Best regards

Till

pablosilva80
Explorer
0 Kudos

Use XSL

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

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:doc="urn:sap-com:document:sap:rfc:functions" version="2.0">

  <xsl:output indent="yes"></xsl:output>

  <xsl:variable name="Fields" select="RFC_READ_TABLE/TABLES/FIELDS/item"></xsl:variable>

  <xsl:template match="RFC_READ_TABLE">

    <xsl:element name="rows">

      <xsl:for-each select="TABLES/DATA/item">

        <xsl:apply-templates select="WA"></xsl:apply-templates>

      </xsl:for-each>

    </xsl:element>

  </xsl:template>

  <xsl:template match="WA">

    <xsl:variable name="Data" select="."></xsl:variable>

    <xsl:element name="row">

      <xsl:for-each select="$Fields">

        <xsl:element name="{FIELDNAME}">

          <xsl:value-of select="substring($Data, OFFSET+1, LENGTH)"></xsl:value-of>

        </xsl:element>

      </xsl:for-each>

    </xsl:element>

  </xsl:template>

</xsl:stylesheet>

udo_martens
Active Contributor
0 Kudos

Hi Atul,

configure used RFC receiver adapter / parameter "Maximum Connections" with a value greater than 1.

Regards,

Udo

Former Member
0 Kudos

Hi Udo,

Thanks for your reply.

I forgot to mention one more thing in the question that - In the Log of test mapping I can see the response node of Second RFC getting data from SAP. The problem is After that node only the Mentioned error occurs...! I feel XSLT is nto able to parse / convert the data from Response node.(I also tried to change the name of Node as Response1 but it did not work).

The details of error are as follows:

javax.xml.transform.TransformerException: DOMSource whose Node is null.

at com.sap.engine.lib.jaxp.TransformerImpl.invokeDocHandlerMethodsFor(TransformerImpl.java:659)

at com.sap.engine.lib.jaxp.TransformerImpl.transformSimple(TransformerImpl.java:273)

at com.sap.engine.lib.jaxp.TransformerImpl.transform(TransformerImpl.java:236)

at urn.mt.pi.interfaces.id027.RfcLookup.execute(RfcLookup.java:59)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:88)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:61)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:60)

at java.lang.reflect.Method.invoke(Method.java:391)

at com.sap.engine.lib.xsl.xpath.functions.JLBFunction.execute(JLBFunction.java:144)

at com.sap.engine.lib.xsl.xpath.ETFunction.evaluate(ETFunction.java:111)

at com.sap.engine.lib.xsl.xpath.XPathProcessor.innerProcess(XPathProcessor.java:55)

at com.sap.engine.lib.xsl.xpath.XPathProcessor.process(XPathProcessor.java:43)

at com.sap.engine.lib.xsl.xpath.XPathProcessor.process(XPathProcessor.java:50)

at com.sap.engine.lib.xsl.xslt.XSLVariable.process(XSLVariable.java:99)

at com.sap.engine.lib.xsl.xslt.XSLNode.processFromFirst(XSLNode.java:296)

at com.sap.engine.lib.xsl.xslt.XSLTemplate.process(XSLTemplate.java:281)

at com.sap.engine.lib.xsl.xslt.XSLStylesheet.callTemplate(XSLStylesheet.java:1355)

at com.sap.engine.lib.xsl.xslt.XSLCallTemplate.process(XSLCallTemplate.java:111)

at com.sap.engine.lib.xsl.xslt.XSLNode.processFromFirst(XSLNode.java:296)

at com.sap.engine.lib.xsl.xslt.XSLElement.process(XSLElement.java:248)

at com.sap.engine.lib.xsl.xslt.XSLNode.processFromFirst(XSLNode.java:296)

at com.sap.engine.lib.xsl.xslt.XSLElement.process(XSLElement.java:248)

at com.sap.engine.lib.xsl.xslt.XSLNode.processFromFirst(XSLNode.java:296)

at com.sap.engine.lib.xsl.xslt.XSLElement.process(XSLElement.java:248)

at com.sap.engine.lib.xsl.xslt.XSLNode.processFromFirst(XSLNode.java:296)

at com.sap.engine.lib.xsl.xslt.XSLElement.process(XSLElement.java:248)

at com.sap.engine.lib.xsl.xslt.XSLNode.processFromFirst(XSLNode.java:296)

at com.sap.engine.lib.xsl.xslt.XSLTemplate.process(XSLTemplate.java:281)

at com.sap.engine.lib.xsl.xslt.XSLStylesheet.process(XSLStylesheet.java:469)

at com.sap.engine.lib.xsl.xslt.XSLStylesheet.process(XSLStylesheet.java:437)

at com.sap.engine.lib.xsl.xslt.XSLStylesheet.process(XSLStylesheet.java:394)

at com.sap.engine.lib.jaxp.TransformerImpl.transformWithStylesheet(TransformerImpl.java:413)

at com.sap.engine.lib.jaxp.TransformerImpl.transform(TransformerImpl.java:238)

at com.sap.aii.ibrep.server.mapping.ibrun.RepMappingTransformer.transform(RepMappingTransformer.java:150)

at com.sap.aii.ibrep.server.mapping.ibrun.RepXSLTMapping.execute(RepXSLTMapping.java:81)

at com.sap.aii.ibrep.server.mapping.ibrun.RepMappingHandler.run(RepMappingHandler.java:80)

at com.sap.aii.ibrep.server.mapping.rt.MappingHandlerAdapter.run(MappingHandlerAdapter.java:107)

at com.sap.aii.ibrep.server.mapping.ServerMapService.transformInterfaceMapping(ServerMapService.java:127)

at com.sap.aii.ibrep.server.mapping.ServerMapService.transform(ServerMapService.java:104)

at com.sap.aii.ibrep.sbeans.mapping.MapServiceBean.transform(MapServiceBean.java:40)

at com.sap.aii.ibrep.sbeans.mapping.MapServiceRemoteObjectImpl0_0.transform(MapServiceRemoteObjectImpl0_0.java:167)

at com.sap.aii.ibrep.sbeans.mapping.MapServiceRemoteObjectImpl0_0p4_Skel.dispatch(MapServiceRemoteObjectImpl0_0p4_Skel.java:104)

at com.sap.engine.services.rmi_p4.DispatchImpl._runInternal(DispatchImpl.java:330)

at com.sap.engine.services.rmi_p4.DispatchImpl._run(DispatchImpl.java:201)

at com.sap.engine.services.rmi_p4.server.P4SessionProcessor.request(P4SessionProcessor.java:136)

at com.sap.engine.core.service630.context.cluster.session.ApplicationSessionMessageListener.process(ApplicationSessionMessageListener.java:33)

at com.sap.engine.core.cluster.impl6.session.MessageRunner.run(MessageRunner.java:41)

at com.sap.engine.core.thread.impl3.ActionObject.run(ActionObject.java:37)

at java.security.AccessController.doPrivileged(AccessController.java:219)

at com.sap.engine.core.thread.impl3.SingleThread.execute(SingleThread.java:104)

at com.sap.engine.core.thread.impl3.SingleThread.run(SingleThread.java:176)

Thanks and Regards,

Atul

former_member201987
Participant
0 Kudos

Hello Atul,

I am also trying the same RFC lookup from XSLT.

Can you please help me. I have posted a thread on below link.

Thanks,

Suraj