splitForLength(): UDF per splitting dei testi

Scenario

Mapping grafico.

Requisito

In un contesto di generazione IDoc verso ECC, occorre generare i segmenti di testo E1EDT01/E1EDT02 e/o E1EDP01/E1EDP02 partendo da una stringa in ingresso.


l’UDF splitForLength() è utile nella generazione dei segmenti di testo negli idoc sia nella sezione testata E1EDKT1/E1EDKT2 che in quella di posizione E1EDPT1/E1EDPT2

In particolare, l’UDF consente di generare tanti contesti E1ED*T2 quante sono le sottostringhe di src che si ottengono dividendola per la lunghezza ln.

public void splitForLength(String[] mst, String[] src, String[] ln, ResultList result, Container container) throws StreamTransformationException{
/*
@Author: Nicola Martella | www.nick4name.eu
Genera un context (ResultList) sulla base dello splitting della stringa src in tante sottostringhe quante ne occorrono dividendola per la 
lunghezza indicata in ln.
La funzione gestisce i contesti multipli su mst e src.
*/
 
	 AbstractTrace _trc =  container.getTrace();
	 // _trc.addWarning(source.substring(s, s + len)); //*******************
	 
	int len = Integer.parseInt(ln[0]);
	result.clear();
 
	int isrc = -1;
	for (int imst=0; imst < mst.length; imst++){
		if (mst[imst].equals(ResultList.SUPPRESS)){
			result.addSuppress();
		} else if (mst[imst].equals(ResultList.CC)) {
			//
		} else {
			isrc++;
			String source = src[isrc];

			if (!source.equals("")){    
				if (len >= source.length()){
					result.addValue(source);
				} else {

				int e = source.length() / len;
				e = ((source.length() % len) > 0 ? e + 1 : e); 

				int s = 0;
				for (int i = 0; i < e; i++){
					if (source.length() - s > len){
					result.addValue(source.substring(s, s + len));
					} else {
						result.addValue(source.substring(s));
					}
					s += len;
				}
			} 
				result.addContextChange();
			} 
		}
	}
 	return;
}

Implementazione per testi di testata

Questo genera le occorrenze di E1EDKT2 sulla base del numero di sottostringhe di TDLINE

Questo, per ciascun contesto, effettua lo splitting di TDLINE in ingresso e scrive le sottostringhe prodotte nei campi TDLINE in uscita.

Implementazione per testi di posizione

Questo genera le occorrenze di E1EDPT2 sulla base del numero di sottostringhe di TDLINE

Questo, per ciascun contesto, effettua lo splitting di TDLINE in ingresso e scrive le sottostringhe prodotte nei campi TDLINE in uscita.

Nel seguente esempio, il contesto in entrata all’UDF – 1mo param, è così configurato:

E1EDP01 con testo (true)

E1EDP01 senza testo (false) -> SUPPRESS

E1EDP01 con testo (true)


createContext

Crea contesti in numero pari ai parametri della function.

Utile per generare un array di parametri da passare in input a qualcosa.

public void createContext(String[] parm1, String[] parm2, ResultList result, Container container) throws StreamTransformationException{
AbstractTrace _trc = container.getTrace();
//_trc.addWarning("parm1:"+parm1.length);

result.clear();
result.addValue(parm1[0]);
result.addValue(parm2[0]);

return;

}

In questo esempio, l’udf si aspetta 2 parametri che generano altrettanti contesti in uscita


Dynamic Configuration URL PlainHTTP

Assegnazione URL a cc PlainHTTP in modalità Assign Type URL Address

Assegnazione URL a cc PlainHTTP in modalità Assign Type HTTP Destination
public String PlainHTTPDestDynConf(String value, Container container) 
	throws StreamTransformationException{ 
	try { 
		String url = value; 
		DynamicConfiguration conf = (DynamicConfiguration) container .getTransformationParameters() .get(StreamTransformationConstants.DYNAMIC_CONFIGURATION); 
		DynamicConfigurationKey key=DynamicConfigurationKey.create("http://sap.com/xi/XI/System/HTTP", "TargetURL"); 
		conf.put(key, url); 
		return url; 
	} catch(Exception e) { 
		String exception = e.toString(); 
		return exception; 
	} 
}

getTimestamp()

   public String getTimestamp(Container container) throws StreamTransformationException {
      String DATE_FORMAT_NOW = "yyyyMMdd_HHmmss_SSS";
      Calendar cal = Calendar.getInstance();
      java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(DATE_FORMAT_NOW);
      return sdf.format(cal.getTime());
   }

GlobalContainer

Per condividere un valore fra le UDF di un mapping

   public String initCounter(Container container) throws StreamTransformationException {
      container.getGlobalContainer().setParameter("COUNTER", "0");
      return in;
   }

   public String increaseCounter(Container container) throws StreamTransformationException {
      int theCounter = (new Integer((String) container.getGlobalContainer().getParameter("COUNTER"))).intValue();
      theCounter++;
      container.getGlobalContainer().setParameter("COUNTER", String.valueOf(theCounter));
      return String.valueOf(theCounter);
   }

getSystemName

Utile come input ad un FixedValue laddove l’output dipende dal tipo di ambiente sviluppo, test o produzione.

   public String getSystemName(String dummy, Container container) throws StreamTransformationException{
      /* Ritorna il SysID dell'istanza PI in esecuzione */
      return System.getProperty("SAPSYSTEMNAME");
   }

SOAPLookup

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;

import javax.xml.transform.stream.StreamResult;

import com.sap.aii.mapping.api.AbstractTrace;
import com.sap.aii.mapping.lookup.*;
import com.sap.aii.mappingtool.tf7.rt.*;

import javax.xml.transform.dom.DOMSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import javax.xml.parsers.*;

import org.w3c.dom.*;

/*
* * Chiamata del communication channel chName relativo al business system
* receiver busSys. * Il parametro emailValue e’ relativo allo specfico
* webservice e rappresenta il parametro d’ingresso allo stesso.
*/ public String SOAPinvoke(String chName, String busSys, String emailValue, Container container) {
AbstractTrace trace = container.getTrace();
String internalID = “”;
try {
/*
* * Pass the Business System and Communication Channel as input to the *
* getChannel(). * BS_SOAPLOOKUP – Business System *
* CC_Webservice_SOAP_CURRENCY_CONVERTOR – Receiver SOAP Adapter
*/ Channel channel = LookupService.getChannel(busSys, chName);
SystemAccessor accessor = LookupService.getSystemAccessor(channel);
InputStream inputStream = null;
/*
* * Construct the SOAP Request Message using the InputParameters * emailValue
* is the Input Parameter.
*/ /* LA SEGUENTE ISTRUZIONE E’ RELATIVA ALLO SPECIFICO WEBSERVICE */ Document req = createRequestPayload(
emailValue);
/* ============================================================ */ String SOAPxml = returnXML(req);
inputStream = new ByteArrayInputStream(SOAPxml.getBytes());
XmlPayload payload = LookupService.getXmlPayload(inputStream);
/*
* * The SOAP call is made here and the response obtained is in the *
* SOAPOutPayload.
*/ Payload SOAPOutPayload = accessor.call(payload);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream inp = SOAPOutPayload.getContent();
Document doc = builder.parse(inp);
/* LA SEGUENTE ISTRUZIONE E’ RELATIVA ALLO SPECIFICO WEBSERVICE */ internalID = returnResponse(doc);
/* ============================================================ */ } catch (Exception e) {
trace.addWarning(“Error” + e);
}
return internalID;
}

/*
* * Crea il payload di request per il webservice da invocare. * Questa funzione
* dipende dallo specifico webservice.
*/ private static Document createRequestPayload(String emailValue) throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();
doc.setXmlStandalone(true);
Element el = doc.createElementNS(“http://sap.com/xi/SAPGlobal20/Global”, “glob:CustomerByElementsQuery_sync”);
Node nroot = doc.appendChild(el);
Node ncsbe = nroot.appendChild(doc.createElement(“CustomerSelectionByElements”));
el = doc.createElementNS(“http://sap.com/xi/AP/CustomerExtension/BYD/A1WY2”,
“a1w:ExternalUnicCode_EA8AE8AUBVHCSXVYS0FJ1R3ON”);
Node neuc = ncsbe.appendChild(el);
Node nsbt = neuc.appendChild(doc.createElement(“SelectionByText”));
Node niec = nsbt.appendChild(doc.createElement(“InclusionExclusionCode”));
niec.setTextContent(“I”);
Node nibtc = nsbt.appendChild(doc.createElement(“IntervalBoundaryTypeCode”));
nibtc.setTextContent(“1”);
Node nlbn = nsbt.appendChild(doc.createElement(“LowerBoundaryName”));
nlbn.setTextContent(emailValue);
Node npc = nroot.appendChild(doc.createElement(“ProcessingConditions”));
Node nqhui = npc.appendChild(doc.createElement(“QueryHitsUnlimitedIndicator”));
nqhui.setTextContent(“false”);
return doc;
}

/* * Ritorna la String relativa al DOM dell’XML. */ private static String returnXML(Document doc)
throws javax.xml.transform.TransformerFactoryConfigurationError, javax.xml.transform.TransformerException {
javax.xml.transform.Transformer transformer = javax.xml.transform.TransformerFactory.newInstance()
.newTransformer();
StringWriter output = new StringWriter();
javax.xml.transform.Source input = new DOMSource(doc);
transformer.transform(input, new StreamResult(output));
return output.toString();
}

/*
* * Ritorna il payload relativo alla risposta del webservice invocato. * Questa
* funzione dipende dallo specifico webservice.
*/ static private String returnResponse(Document doc) throws XPathExpressionException {
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
Node nroot = ((NodeList) xpath.compile(“//InternalID/text()”).evaluate(doc, XPathConstants.NODESET)).item(0);
return nroot.getNodeValue();
}


removeSUPPRESS

   public void removeSUPPRESS(String[] inp, ResultList result, Container container)
         throws StreamTransformationException {
      result.clear();
      for (int i = 0; i < inp.length; i++) {
         if (!(inp[i].equals(ResultList.SUPPRESS)) && !(inp[i].equals("")) && !(inp[i].equals(null))) {
            result.addValue(inp[i]);
         }
      }
      return;
   }

Rimuove gli elementi ResultList.SUPPRESS e <null> dal contesto.

Dato il seguente payload in inbound

<?xml version="1.0" encoding="UTF-8"?>
<ns0:MT_A xmlns:ns0="urn:develop:n4n.eu:SUPPRESS">
	<row>
		<KEY>FFX</KEY>
		<DATA>A</DATA>
	</row>
	<row>
		<KEY>AAA</KEY>
		<DATA>B</DATA>
	</row>
	<row>
		<KEY>AAA</KEY>
		<DATA>C</DATA>
	</row>
	<row>
		<KEY>FFX</KEY>
		<DATA>D</DATA>
	</row>
</ns0:MT_A>

occorre produrre in outbound un analogo payload con solo i row il cui  KEY = ‘FFX’.

Dato il mapping sotto, si visualizzano le code sulla removeContext.

Si può constatare che la removeContext rimuove i contesti SUPPRESS (grigi), Change Context, e conserva i valori SUPPRESS (azzurri) corrispondenti agli elementi senza FFX.

dove

Aggiungendo removeSUPPRESS dopo la removeContext si produrrà il seguente risultato

dove gli elementi SUPPRESS (azzurri) sono stati rimossi lasciando solo quelli relativi ai row con FFX.