Skip to Content

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:
  • 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:

 

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)
  • File availability in Sharepoint post javaMap execution

 

<<<<< Parent blog reference…..  Integrate SharePoint using SAP PI

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

  1. Priya Ranjan

    Hi Dilip,

    Thanks for the nice work.

    I followed your blog not getting Access Token. Do we need to Grant Permissions to Add-In from SharePoint Online to our PI system before calling ?

    BR,

     

    (0) 
    1. Dilip Kumar KrishnaDeo Pandey Post author

      Dear Priya,

      If you are getting following error w.r.t. permissions while fetching AccessToken,

      • Access denied. You do not have permission to perform this action or access this resource

      Then consult your SharePoint-Team to follow following help-link, where “Write-Permission” need to be given to client-id/app-id:

       

      Regards,

      Dilip

      (0) 

Leave a Reply