SAP Process Integration

Post pdf file in Sharepoint using SAP PI Java Map

Overview:

  • In this blog, we will see, how any pdf file of “SAP-Ecc-System” can be send to Sharepoint via SAP-PI.
  • Sharepoint provides REST API details which can be used to post file in specific directory of Sharepoint.
  • Using SAP-PI’s interface pdf file will be send to Sharepoint over these REST API details.

About SAP-PI’s interface design:

  • To acheive above, we will design a SAP-PI interface “Outbound Asynchronous File-to-File scenario”.
  • Pdf file will be made available by respective SAP-ECC’s program in to specific “SAP Ecc’s Application directory”.
  • Using SAP-PI’s Sender-File-Adapter (comm. channel), the pdf files will be picked up from source directory one by one.
  • Using a JavaMap program configured in the same scenario, read pdf file will be send to Sharepoint with the same file naming conventions.
  • Receiver-File-Adapter (comm. channel) will generate a constant dummy file in sap app directory with overwrite feature.

Functionality of JavaMap program will be as follows:

  • This JavaMap uses a resource xml file where Sharepoint REST API details are present.
  • Get file (which was read using Sender-File-Adapter) as an input stream into JavaMap program and convert it to ByteArrayStream
  • Using Dynamic Configuration Variable, get original file Name.
  • Read Sharepoint REST-API details from resource file
  • And send pdf ByteArrayStream to SharePoint REST details with same filename.
  • While accessing SharePoint, first we get access token then we post Sharepoint-REST.

Pre-requisites for JavaMap:

  • JavaMap will be developed using Eclipse.
  • Standard external Jar file required for JavaMap:
    • json-simple-1.1.1.jar (this is required in both Eclipse and in SAP-PI’s Integration Repository which can be imported inside a new Imported_Archive of same namespace of scenario)
    • aii_map_api.jar (this is required only in Eclipse)
  • And post completion, it will be exported as ‘.jar’ file which can be used in SAP-PI’s respective interface

SAP-PI Scenario Development Steps:

  • Steps in “Enterprise Services (Repository) Builder”:
    • Create one dummy DataType only one input element
    • Create one message type referring above dummy datatype
    • Create one Service Interface Inbound asynchronous referring above message type, say “SI_IN”
    • Create one Service Interface Outbound asynchronous referring above message type, say “SI_OUT”
    • Create one “Imported Archive” to import external jar file “json-simple-1.1.1.jar”
    • Create 2nd “Imported Archive” to import this blog’s JavaMap example program
    • Create one Operation Mapping, use in Source operation select “SI_OUT” and in Target operation select “SI_IN”. Inside Mapping program select 2nd “Imported Archive”.
  • Steps in “Integration (Directory) Builder”
    • According to above config of “Repository”, configure Integrated Directory’s Scenario
    • Two communication channels required
      • one Sender File-Adapter: will be used to read ‘.pdf’ files from SAP’s directory
      • one Receiver File-Adapter: its job is to complete the scenario config only, it will keep on over-writing same file in sap’s directory for each file-transfer-trigger with fix dummy “fileName”.

SAP PI JavaMap program to post pdf file in Sharepoint :

  • JavaMap project view in Eclipse:

SAP Process Integration

  • Resource file “Service_Credentials.xml”, which is been used in JavaMap to refer for Sharepoint-REST-API details:

<?xml version=”1.0″ encoding=”UTF-8″?>
<ServiceData>
<SharePoint_REST>
<client_Id>clientIdShp</client_Id>
<client_secret>shpSecret</client_secret>
<tenant_Id>shpTenant</tenant_Id>
<client_Domain>ShpHost (without sharepoint.com)</client_Domain>
<SharePoint_SiteURL>https://host/teams/SPdev/AlertsCount</SharePoint_SiteURL>
<SharePoint_AccessTokenUrl>https://accounts.accesscontrol.windows.net/(tenantId)/tokens/OAuth/2</SharePoint_AccessTokenUrl>
<SharePoint_FolderName>folderName</SharePoint_FolderName>
</SharePoint_REST>
</ServiceData>

  • JavaMap Source Code:

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;

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

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.sap.aii.mapping.api.AbstractTrace;
import com.sap.aii.mapping.api.DynamicConfiguration;
import com.sap.aii.mapping.api.DynamicConfigurationKey;
import com.sap.aii.mapping.api.StreamTransformation;
import com.sap.aii.mapping.api.StreamTransformationConstants;
import com.sap.aii.mapping.api.StreamTransformationException;

public class BackLogPdfToShp implements StreamTransformation{
/*
public static void main(String[] args) {
//This function helps to test JavaMap inside eclipse
try{
BackLogPdfToShp myClass = new BackLogPdfToShp();
FileInputStream in = new FileInputStream(“D:/xyz/TestInput.pdf”);
FileOutputStream out = new FileOutputStream(“d:/xyz/TestLog.xml”);
myClass.execute(in, out);
}catch (Exception e){
e.printStackTrace();
}
}
*/

private static Map param;
public void setParameter(Map map)
{
param = map;
if (param == null){
param = new HashMap();
}
}
private static AbstractTrace trace = null;
private static String mapTrace = “”;
public void execute(InputStream in, OutputStream out) throws StreamTransformationException {
/**
* This function gets “read pdf file” as an inputStream and post it to SharePoint
*/

try{
trace = (AbstractTrace) param.get(StreamTransformationConstants.MAPPING_TRACE);
mapTrace = “”;
mapTrace = mapTrace + ” Begin of JavaMap ‘BackLogPdfToShp()’ ” + “\n”;

//Get fileName using DynamicConfigurationVariables
String fileName = getFileNameUsingDynmConfig();
mapTrace = mapTrace + ” File found with name: ” + fileName + “\n”;

//Read pdf file from PI’s File Adapter
mapTrace = mapTrace + ” convert Pdf(inputStream) To ByteArray .. ” + “\n”;
byte[] bytes = convertInputstreamToByte(in); //convert Pdf(inputStream) To ByteArray ..

//Get SharePoint access token
mapTrace = mapTrace + ” Read Sharepoint REST details from file ‘Service_Credentials.xml'” + “\n”;
readServiceDetails_FromXml();

mapTrace = mapTrace + ” Get Sharepoint accesstoken… ” + “\n”;
String accesstoken = SharePoint_getAccessToken();

//Write pdf file into Sharepoint
mapTrace = mapTrace + ” Write file into Sharepoint ” + “\n”;
String shpResponse = SharePoint_WriteFile(accesstoken, bytes, fileName);

//Transform Output Document
String outputXML = “<?xml version=\”1.0\”?>”
+ “\n” +”<JavaMap_Log>”
+ “\n” +”<SharePoint_Response><![CDATA[” + shpResponse + “]]></SharePoint_Response>”
+ “\n” +”<JavaMap_Trace><![CDATA[” + mapTrace + “]]></JavaMap_Trace>”
+ “\n” +”</JavaMap_Log>”;
Document docOut = convertStringToDocument(outputXML);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transform = tf.newTransformer();
transform.transform(new DOMSource(docOut), new StreamResult(out));

}catch (Exception e) {
trace.addInfo(“||Exception in JavaMap ‘BackLogPdfToShp’: ” + e.getMessage());
mapTrace = mapTrace + ” ” + e.getMessage();
}
//System.out.println(mapTrace);
}

private static String getFileNameUsingDynmConfig(){
/**
* This function gets file name of read file via ‘Sender-File-Adapter’ using DynamicConfiguration variable
*/
String fileName = “”;
try
{
DynamicConfiguration conf = (DynamicConfiguration)param.get(“DynamicConfiguration”);
DynamicConfigurationKey key = DynamicConfigurationKey.create(“http://sap.com/xi/XI/System/File”, “FileName”);
fileName = conf.get(key); //get File name
}catch(Exception ex){
;
}
return fileName;
}

private byte[] convertInputstreamToByte(InputStream in) {
/**
* This function converts InputStream to ByteArray
*/
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
try {
for (int readNum; (readNum = in.read(buf)) != -1;) {
bos.write(buf, 0, readNum);
}
} catch (IOException ex) {
mapTrace = mapTrace + ” ” + ex.getMessage();
}
byte[] bytes = bos.toByteArray();
return bytes;
}

private static String shp_clientId = “”;
private static String shp_clientSecret = “”;
private static String shp_tenantId = “”;
private static String shp_clientDomain = “”;
private static String shpUrl_AccessToken= “”;
private static String shp_FolderName = “”;
private static String shpUrl_SiteURL = “”;

private void readServiceDetails_FromXml() throws IOException, ParserConfigurationException, SAXException{
/**
* This function read SharePoint-REST API details mentioned in resource file “Service_Credentials.xml”
*/
//Get reference of ResourceFile ‘Service_Credentials.xml’
InputStream is_ShpCrd = getClass().getResourceAsStream(“Service_Credentials.xml”);

//Parse it to Document
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
Document xmlDocCrd = dbBuilder.parse(is_ShpCrd); //Parse input to create document tree

//—-Start: Get SharePoint Credentials from XmlFile ——
NodeList ndList_shp = xmlDocCrd.getElementsByTagName(“SharePoint_REST”);
for(int i1 = 0; i1 < ndList_shp.getLength(); i1++){
Node nd_1 = ndList_shp.item(i1);
for(Node nd_2 = nd_1.getFirstChild(); nd_2 != null; nd_2 = nd_2.getNextSibling()){
if(nd_2.getNodeName().equals(“client_Id”)){
if(nd_2.getFirstChild() != null){
shp_clientId = nd_2.getFirstChild().getNodeValue();
}else{
mapTrace = mapTrace + “<client_Id> is empty” + “\n”;
}
}
if(nd_2.getNodeName().equals(“client_secret”)){
if(nd_2.getFirstChild() != null){
shp_clientSecret = nd_2.getFirstChild().getNodeValue();
}else{
mapTrace = mapTrace + “<client_secret> is empty” + “\n”;
}
}
if(nd_2.getNodeName().equals(“tenant_Id”)){
if(nd_2.getFirstChild() != null){
shp_tenantId = nd_2.getFirstChild().getNodeValue();
}else{
mapTrace = mapTrace + “<tenant_Id> is empty” + “\n”;
}
}
if(nd_2.getNodeName().equals(“client_Domain”)){
if(nd_2.getFirstChild() != null){
shp_clientDomain = nd_2.getFirstChild().getNodeValue();
}else{
mapTrace = mapTrace + “<client_Domain> is empty” + “\n”;
}
}
if(nd_2.getNodeName().equals(“SharePoint_AccessTokenUrl”)){
if(nd_2.getFirstChild() != null){
shpUrl_AccessToken = nd_2.getFirstChild().getNodeValue();
}else{
mapTrace = mapTrace + “<SharePoint_AccessTokenUrl> is empty” + “\n”;
}
}
if(nd_2.getNodeName().equals(“SharePoint_SiteURL”)){
if(nd_2.getFirstChild() != null){
shpUrl_SiteURL = nd_2.getFirstChild().getNodeValue();
}else{
mapTrace = mapTrace + “<SharePoint_SiteURL> is empty” + “\n”;
}
}
if(nd_2.getNodeName().equals(“SharePoint_FolderName”)){
if(nd_2.getFirstChild() != null){
shp_FolderName = nd_2.getFirstChild().getNodeValue();
}else{
mapTrace = mapTrace + “<SharePoint_FolderName> is empty” + “\n”;
}
}
}
}
//—-End : Get SharePoint Credentials from XmlFile ——

}

private static String SharePoint_getAccessToken(){
/**
* This function is to get SharePoint Access token.
* SharePoint REST-URL to get access token is:
* URL : https://accounts.accesscontrol.windows.net/<tenantID>/tokens/OAuth/2
METHOD : GET
*/

String accessToken = “”;
try {
mapTrace = mapTrace +” ||…SharePoint Client Id: “+ shp_clientId+ “\n”;
mapTrace = mapTrace +” ||…SharePoint Tenant Id: “+ shp_tenantId+ “\n”;
mapTrace = mapTrace +” ||…SharePoint Client Secret: “+ shp_clientSecret+ “\n”;
mapTrace = mapTrace +” ||…SharePoint Client Domain: “+ shp_clientDomain+ “\n”;

//SharePoint AccessToken URL
String wsURL = shpUrl_AccessToken;
mapTrace = mapTrace +” ||…SharePointAccessToken URL: ” + wsURL+ “\n”;

//Create HttpConenction
URL url = new URL(wsURL);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;

//Set header
httpConn.setRequestProperty(“Content-Type”, “application/x-www-form-urlencoded”);
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.setRequestMethod(“POST”);

//Prepare RequestData
String jsonParam =
“grant_type=client_credentials” +
“&client_id=”+shp_clientId+”@”+shp_tenantId +
“&client_secret=” + shp_clientSecret +
“&resource=00000003-0000-0ff1-ce00-000000000000/”+ shp_clientDomain + “.sharepoint.com@” + shp_tenantId;

//Send Request
DataOutputStream wr = new DataOutputStream(httpConn.getOutputStream ());
wr.writeBytes(jsonParam);
wr.flush();
wr.close();

//Read the response
String httpResponseStr = “”;
InputStreamReader isr = null;
if (httpConn.getResponseCode() == 200) {
isr = new InputStreamReader(httpConn.getInputStream());
} else {
isr = new InputStreamReader(httpConn.getErrorStream());
}
BufferedReader in = new BufferedReader(isr);
String strLine = “”;
while ((strLine = in.readLine()) != null) {
httpResponseStr = httpResponseStr + strLine;
}

//Extracting accessToken from httpResponseStr which is a JSON format string
/*
Sample HTTP Response String(httpResponseStr) is as below:
{“token_type”:”Bearer”,”expires_in”:”3599″,”not_before”:”1509537628″,”expires_on”:”1509541528″,”resource”:””,”access_token”:”xyz”}
*/
JSONParser parser = new JSONParser(); //Jar file reference required: json-simple-1.1.1.jar
JSONObject jsonObj = (JSONObject)parser.parse(httpResponseStr);
accessToken = (jsonObj.get(“access_token”)).toString(); //get value of element

mapTrace = mapTrace + ” ||…SharePointAccessToken found as: ” + accessToken + “\n”;
} catch (Exception e) {
mapTrace = mapTrace + ” ” + e.getMessage();
}
return accessToken;
}

private static String SharePoint_WriteFile(String accessToken, byte [] requestStr, String fileName) throws IOException{
/**
* This function is to POST input to SharePoint as a file.
* SharePoint-REST-URL Details to Write a file is as below:
URL : http://<siteurl>/_api/web/GetFolderByServerRelativeUrl(‘/FolderName’)/Files/add(url=’FileName’,overwrite=false)
METHOD : POST
BODY : “Contents of file”
Headers :
Authorization: “Bearer ” + accessToken
X-RequestDigest: form digest value
content-length:length of post body
*/

String responseStr = “”;
try {
String wsUrl = shpUrl_SiteURL + “/_api/web/GetFolderByServerRelativeUrl(‘”
+ shp_FolderName + “‘)/Files/add(url='”
+ fileName +”‘,overwrite=true)”;

mapTrace = mapTrace + “\n” + ” ||…URL: ” + wsUrl;

//Create HttpURLConnection
URL url = new URL(wsUrl);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;

//Set Header
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.setRequestMethod(“POST”);
httpConn.setRequestProperty(“Authorization”, “Bearer ” + accessToken);

//Send Request
DataOutputStream dos = new DataOutputStream(httpConn.getOutputStream ());
dos.write(requestStr); //Writing PDF byte[] Stream
dos.flush();
dos.close();

//Read the response.
if (httpConn.getResponseCode() == 200) {
responseStr = ” ||…File ‘”+ fileName + “‘ has been written into SharePoint with Success-HTTP-ResponseCode: “+ httpConn.getResponseCode() +”\n”;
}else{
responseStr += ” ||…Response-” + httpConn.getResponseCode() + ” ” + httpConn.getResponseMessage() +”: Error while writing file ‘”+ fileName + “‘ in SharePoint.\n”;
}
mapTrace = mapTrace + “\n” + responseStr;
} catch (Exception e) {
mapTrace = mapTrace + “\n” + ” ||…Error while Posting file to SharePoint: “+ e.getMessage() + ” [JavaFunction SharePoint_WriteFile()]\n”;
}
return responseStr;
}

private static Document convertStringToDocument(String xmlStr) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try
{
builder = factory.newDocumentBuilder();
Document doc = builder.parse( new InputSource( new StringReader( xmlStr ) ) );
return doc;
} catch (Exception e) {
mapTrace = mapTrace + ” ” + e.getMessage();
}
return null;
}
}

  • While exporting file (.jar), make sure resource file is present in jar:

SAP Process Integration

Testing of JavaMap from PI Scenario:

  • Once Sender-File-Adapter picks up file from logs which picks up file from sap directory, JavaMap gets invoked and as per its functionality it behaves to post same pdf file in Sharepoint. Its step-by-step process can be understood from following log screen
  • JavaMap custom log (can be seen from SXMB_MONI of SAP-PI)

SAP Process Integration

  • File availability in Sharepoint post javaMap execution

SAP Process Integration

Leave a Reply

Your email address will not be published. Required fields are marked *