on 04-01-2014 4:55 PM
hi all,
I've a source structure like this below in PI.
<MAT>
<doc type>pdf</doc type
<subnumber>1234</subnumber>
<id>45ABC<id>
<matno>ABCD</matno>
<filename>transaction1.pdf</filename>
</MAT>
target structure would be the same but one more field <filecontent> which is bytearray content such as content=[101, 115, 116, 13, 10, 84, 101, 115, 116, 13, 10, 84, 101, 115, 116, 13, 10, 84, 101, 115, 116, 13, 10, 13, 10, 84, 101, 115, 116, 13, 10, 84, 101, 115, 116, 13, 10, 13, 10, 84, 101, 115, 116, 13, 10, 13, 10, 84, 101, 115, 116, 13, 10, 84, 101, 115, 116, 13, 10]
<MAT>
<doc type>pdf</doc type
<subnumber>1234</subnumber>
<id>45ABC<id>
<matno>ABCD</matno>
<filename>transaction1.pdf</filename>
<filecontent>bytearraycontent</filecontent
</MAT>
And target is HTTP post for posting the above attribute names and values in the body of HTML
I am writing a java mapping program because I have to read the <filename> tag value from the incoming xml and read the file from PI server location and convert the file content to bytearray and also to map it to target structure for HTTP post. I am requesting help from java experts here in modifying the program according to this requirement. pls help
package com.usahealth.mapping;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.sap.aii.mapping.api.AbstractTrace;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
public class ReadAttrMap extends AbstractTransformation {
@Override
public void transform(TransformationInput in, TransformationOutput out)
throws StreamTransformationException {
AbstractTrace trace = null;
try {
// Initialize Trace
trace = getTrace();
// Get Input Message as DOM
DocumentBuilderFactory docBFactory = DocumentBuilderFactory
.newInstance();
docBFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = docBFactory.newDocumentBuilder();
Document inDoc = docBuilder.parse(in.getInputPayload()
.getInputStream());
inDoc.getDocumentElement().normalize();
// Read from PayLoad - here is where I need help to read the filename - convert it to byte array and read other xml tag values and pass to target structure for HTTP post. I am using HTTP receiver adapter for posting
} catch (Exception e) {
trace.addInfo(e.getMessage());
throw new StreamTransformationException("Mapping Exception: "
+ e.getMessage(), e);
}
}
}
thx
mike
Hi Michael
I have modified the java mapping so that it will return the output in the format mentioned in the blog.
&doc_type=pdf&subnumber=1234&id=45ABC&matno=ABCD&filename=transaction1.pdf&filecontent=[116,104,105,115,32,105,115,32,116,101,115,116,32,102,105,108,101]
Use this code and see if the HTTP post works successfully or not
package com.sap;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
public class populateTarget extends AbstractTransformation {
public void transform(TransformationInput arg0, TransformationOutput arg1)
throws StreamTransformationException {
// TODO Auto-generated method stub
this.execute(arg0.getInputPayload().getInputStream(), arg1
.getOutputPayload().getOutputStream());
}// end of transform
public void execute(InputStream in, OutputStream out)
throws StreamTransformationException {
try {
DocumentBuilderFactory tfactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder tbuilder = tfactory.newDocumentBuilder();
Document doc = tbuilder.parse(in);
Document newdoc = tbuilder.newDocument();
String outputxml = "";
NodeList nlList = doc.getElementsByTagName("MAT"); // reading the root from input file
Element root = (Element) nlList.item(0);
// building the HTTP body
String doctype = root.getChildNodes().item(1).getNodeName();
String docval = root.getChildNodes().item(1).getTextContent();
outputxml = outputxml + "&" + doctype + "=" + docval;
String subnum = root.getChildNodes().item(3).getNodeName();
String subval = root.getChildNodes().item(3).getTextContent();
outputxml = outputxml + "&" + subnum + "=" + subval;
String id = root.getChildNodes().item(5).getNodeName();
String idval = root.getChildNodes().item(5).getTextContent();
outputxml = outputxml + "&" + id + "=" + idval;
String matnum = root.getChildNodes().item(7).getNodeName();
String matval = root.getChildNodes().item(7).getTextContent();
outputxml = outputxml + "&" + matnum + "=" + matval;
String fname = root.getChildNodes().item(9).getNodeName();
String filename = root.getChildNodes().item(9).getTextContent();
outputxml = outputxml + "&" + fname + "=" + filename;
// read the file from PI AL11 server and generate the byte content array
byte[] fileArray = null;
try {
fileArray = getBytesFromFile(new File("/usr/sap"+filename)); // use the acutal Al11 path here
} catch (IOException e) {
e.printStackTrace();
}
String data = "";
if (fileArray != null) {
for (int i = 0; i < fileArray.length; i++) {
data = data + fileArray[i];
if (i < fileArray.length - 1) {
data = data + ",";
}
}
}
outputxml = outputxml + "&filecontent" + "=" + "[" + data + "]";
out.write(outputxml.getBytes("UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
} // end of execute
// function to get bytes from a input file
private static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
/*
* You cannot create an array using a long type. It needs to be an int
* type. Before converting to an int type, check to ensure that file is
* not loarger than Integer.MAX_VALUE;
*/
if (length > Integer.MAX_VALUE) {
System.out.println("File is too large to process");
return null;
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int) length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while ((offset < bytes.length)
&& ((numRead = is.read(bytes, offset, bytes.length - offset)) >= 0)) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "
+ file.getName());
}
is.close();
return bytes;
} // end of getBytesFromFile
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
hi Indrajit
There is a slight change in the input structure. They can send as many file names as required in one input request. We have to read each file name and create the target structure.
<MAT>
<doc type>pdf</doc type
<subnumber>1234</subnumber>
<id>45ABC<id>
<matno>ABCD</matno>
<file> 0..unbounded
<file_name>file1.pdf<file_name> ----->name of the first file
<file_id>2y7hsjsj</file_id> -------------->unique id of the first file
<file_type>pdf</file_type> --------------->type of the file
<file_name>file2.xml<file_name> ------------->name of the second file
<file_id>8mnk9<file_id> -----------------unique id of the second file
<file_type>xml<file_type> ------------------>type of the file
<file_name>file3.xml> ----------------->name of the third file
<file_id>e783kj3k3</file_id ---------------->unique id of the third file
<file_type>xml</file_type> -------------->type of the file
-------------------------
------------------------
------------------------
---------------------
</file
</MAT>
So the <file> is 0..unbounded structure.
I have to create a target structure like this below.
<MAT>
<doc type>pdf</doc type
<subnumber>1234</subnumber>
<id>45ABC<id>
<matno>ABCD</matno>
<file> 0..unbounded
<file_content>file1.pdf<file_name> ----->byte array content of the first file
<file_id>2y7hsjsj</file_id> -------------->unique id of the first file
<file_type>pdf</file_type> --------------->type of the file
<file_content>file2.xml<file_name> ------------->byte array content of the second file
<file_id>8mnk9<file_id> -----------------unique id of the second file
<file_type>xml</file_type> ---------------------->type of the file
<file_content>file3.xml> ----------------->byte array content of the third file
<file_id>e783kj3k3</file_id ---------------->unique id of the third file
<file_type>xml<file_type> --------------->type of the file
-------------------------
------------------------
------------------------
---------------------
</file
</MAT>
I am writing a java mapping program to read each <filename> tag value from the incoming xml and read the file from PI server location and convert the file content to bytearray and also to map it to target structure which would be XML. There is no more &and = in the target structure. It is plain XML. Can you please help in revisiting the java mapping program based on this change of requirement. I really appreciate your help
thx
mike
There is a mistake in the requirement above. Correcting the input structure and output structure
Input structure
<MAT>
<doc type>pdf</doc type
<subnumber>1234</subnumber>
<id>45ABC<id>
<matno>ABCD</matno>
<file> 0..unbounded
<file_name>file1.pdf<file_name> ----->name of the first file
<file_id>2y7hsjsj</file_id> -------------->unique id of the first file
<file_type>pdf</file_type> --------------->type of the file
</file>
<file>
<file_name>file2.xml<file_name> ------------->name of the second file
<file_id>8mnk9<file_id> -----------------unique id of the second file
<file_type>xml<file_type> ------------------>type of the file
</file>
<file>
<file_name>file3.xml> ----------------->name of the third file
<file_id>e783kj3k3</file_id ---------------->unique id of the third file
<file_type>xml</file_type> -------------->type of the file
</file>
-------------------------
------------------------
------------------------
---------------------
</MAT>
Output structure
<MAT>
<doc type>pdf</doc type
<subnumber>1234</subnumber>
<id>45ABC<id>
<matno>ABCD</matno>
<file> 0..unbounded
<file_content>file1.pdf<file_name> ----->byte array content of the first file
<file_id>2y7hsjsj</file_id> -------------->unique id of the first file
<file_type>pdf</file_type> --------------->type of the file
</file>
<file>
<file_content>file2.xml<file_name> ------------->byte array content of the second file
<file_id>8mnk9<file_id> -----------------unique id of the second file
<file_type>xml</file_type> ---------------------->type of the file
</file>
<file>
<file_content>file3.xml> ----------------->byte array content of the third file
<file_id>e783kj3k3</file_id ---------------->unique id of the third file
<file_type>xml<file_type> --------------->type of the file
</file>
-------------------------
------------------------
------------------------
---------------------
</MAT>
thx
mike
Hi Michael
Use the below code
package com.sap;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
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.Element;
import org.w3c.dom.NodeList;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
public class populateTarget extends AbstractTransformation {
public void transform(TransformationInput arg0, TransformationOutput arg1)
throws StreamTransformationException {
// TODO Auto-generated method stub
this.execute(arg0.getInputPayload().getInputStream(), arg1
.getOutputPayload().getOutputStream());
}// end of transform
public void execute(InputStream in, OutputStream out)
throws StreamTransformationException {
try {
DocumentBuilderFactory tfactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder tbuilder = tfactory.newDocumentBuilder();
Document doc = tbuilder.parse(in);
Document newdoc = tbuilder.newDocument();
NodeList nlList = doc.getElementsByTagName("MAT"); // reading the
// root node
// from input
// file
Element root = (Element) nlList.item(0);
// building the target structure
Element target = newdoc.createElement("MAT");
newdoc.appendChild(target);
Element doctype = newdoc.createElement(root.getChildNodes().item(1)
.getNodeName());
doctype.setTextContent(root.getChildNodes().item(1)
.getTextContent());
target.appendChild(doctype);
Element subnum = newdoc.createElement(root.getChildNodes().item(3)
.getNodeName());
subnum
.setTextContent(root.getChildNodes().item(3)
.getTextContent());
target.appendChild(subnum);
Element id = newdoc.createElement(root.getChildNodes().item(5)
.getNodeName());
id.setTextContent(root.getChildNodes().item(5).getTextContent());
target.appendChild(id);
Element matnum = newdoc.createElement(root.getChildNodes().item(7)
.getNodeName());
matnum
.setTextContent(root.getChildNodes().item(7)
.getTextContent());
target.appendChild(matnum);
// starting parsing all the file names
NodeList filelist = doc.getElementsByTagName("file");
for(int i =0; i < filelist.getLength();i++ )
{
Element filedata = newdoc.createElement("file");
Element file = (Element) filelist.item(i);
Element filecontent = newdoc.createElement("file_content");
String filename = file.getChildNodes().item(1).getTextContent();
// read the file from PI AL11 server and generate the byte content array
byte[] fileArray = null;
try {
fileArray = getBytesFromFile(new File("C:\\"+filename)); // use actual path here
} catch (IOException e) {
e.printStackTrace();
}
String data = "";
if (fileArray != null) {
for (int k = 0; k < fileArray.length; k++) {
data = data + fileArray[k];
if (k < fileArray.length - 1) {
data = data + ",";
}
}
}
filecontent.setTextContent("["+data+"]");
filedata.appendChild(filecontent);
Element file_id = newdoc.createElement("file_id");
file_id.setTextContent(file.getChildNodes().item(3).getTextContent());
filedata.appendChild(file_id);
Element file_type = newdoc.createElement("file_type");
file_type.setTextContent(file.getChildNodes().item(5).getTextContent());
filedata.appendChild(file_type);
target.appendChild(filedata);
}
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
Source source = new DOMSource(newdoc);
Result output = new StreamResult(out);
transformer.transform(source, output);
} catch (Exception e) {
e.printStackTrace();
}
} // end of execute
// function to get bytes from a input file
private static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
/*
* You cannot create an array using a long type. It needs to be an int
* type. Before converting to an int type, check to ensure that file is
* not loarger than Integer.MAX_VALUE;
*/
if (length > Integer.MAX_VALUE) {
System.out.println("File is too large to process");
return null;
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int) length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while ((offset < bytes.length)
&& ((numRead = is.read(bytes, offset, bytes.length - offset)) >= 0)) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "
+ file.getName());
}
is.close();
return bytes;
} // end of getBytesFromFile
}
The output would be like this
I believe this is a simple scenario. Nobody replying. I am losing hope here. Pls help
it has been pending for a week now..and I am not able to do this myself due to the beginner stage in java mapping
appreciate anyone helping on this
mike
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Mike,
First things first, what is your overall scenario? Based on your input I am guessing synchronous SOAP -> PI -> ? but not sure what your target is. Also, if you are going to put binary data in the XML response then what is your encoding requirement for the consumer?
Regards,
Ryan Crosby
Hi Michael
Please find below the complete code
package com.sap;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
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.Element;
import org.w3c.dom.NodeList;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
public class populateTarget extends AbstractTransformation {
public void transform(TransformationInput arg0, TransformationOutput arg1)
throws StreamTransformationException {
// TODO Auto-generated method stub
this.execute(arg0.getInputPayload().getInputStream(), arg1
.getOutputPayload().getOutputStream());
}// end of transform
public void execute(InputStream in, OutputStream out)
throws StreamTransformationException {
try {
DocumentBuilderFactory tfactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder tbuilder = tfactory.newDocumentBuilder();
Document doc = tbuilder.parse(in);
Document newdoc = tbuilder.newDocument();
NodeList nlList = doc.getElementsByTagName("MAT"); // reading the root node from input file
Element root = (Element) nlList.item(0);
// building the target structure
Element target = newdoc.createElement("MAT");
newdoc.appendChild(target);
Element doctype = newdoc.createElement(root.getChildNodes().item(1)
.getNodeName());
doctype.setTextContent(root.getChildNodes().item(1)
.getTextContent());
target.appendChild(doctype);
Element subnum = newdoc.createElement(root.getChildNodes().item(3)
.getNodeName());
subnum
.setTextContent(root.getChildNodes().item(3)
.getTextContent());
target.appendChild(subnum);
Element id = newdoc.createElement(root.getChildNodes().item(5)
.getNodeName());
id.setTextContent(root.getChildNodes().item(5).getTextContent());
target.appendChild(id);
Element matnum = newdoc.createElement(root.getChildNodes().item(7)
.getNodeName());
matnum
.setTextContent(root.getChildNodes().item(7)
.getTextContent());
target.appendChild(matnum);
Element filename = newdoc.createElement(root.getChildNodes()
.item(9).getNodeName());
filename.setTextContent(root.getChildNodes().item(9)
.getTextContent());
target.appendChild(filename);
//adding the new field filecontent to the target xml structure
Element filecontent = newdoc.createElement("filecontent");
// reading file name from input file
String filename1 = root.getChildNodes().item(9).getTextContent();
// read the file from PI AL11 server and generate the byte content array
byte[] fileArray = null;
try {
fileArray = getBytesFromFile(new File("/usr/sap"+filename1)); // use the actual Al11 path here
} catch (IOException e) {
e.printStackTrace();
}
String data = "";
if (fileArray != null) {
for (int i = 0; i < fileArray.length; i++) {
data = data + fileArray[i];
if (i < fileArray.length - 1) {
data = data + ",";
}
}
}
filecontent.setTextContent(data);
target.appendChild(filecontent); // adding byte content array to target xml
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
Source source = new DOMSource(newdoc);
Result output = new StreamResult(out);
transformer.transform(source, output);
} catch (Exception e) {
e.printStackTrace();
}
} // end of execute
// function to get bytes from a input file
private static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
/*
* You cannot create an array using a long type. It needs to be an int
* type. Before converting to an int type, check to ensure that file is
* not loarger than Integer.MAX_VALUE;
*/
if (length > Integer.MAX_VALUE) {
System.out.println("File is too large to process");
return null;
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int) length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while ((offset < bytes.length)
&& ((numRead = is.read(bytes, offset, bytes.length - offset)) >= 0)) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "
+ file.getName());
}
is.close();
return bytes;
} //end of getBytesFromFile
}
Great help!!! Indrajit. Really really appreciate you taking time to do this and I am definitely going to use your code. I will try this and let you know. There is a open bracket '[' and ']' closing bracked missing in the <filecontent> output generated by this java code.
In the meantime, one question. I wanted to do a HTTP POST ultimately and they are expecting like this (shown below) when they receive the POST request from PI.
Header and body. Header will be automatically generated by HTTP_AAE receiver adapter. Body is what I have to worry about I think.
/*header
POST /path/script.cgi HTTP/1.1
From: mike@mike.com
User-Agent: HTTPTool/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 32
*/body
doctype=pdf&subnumber=1234&id=45ABC&matno=ABCD&filename=transaction.pdf&filecontent=[116,104,105,115,32,116,101,115,116,32,102,105,108,101]
And also is there a easy way to do HTTP POST to see how the actual result looks like?
thx a lot..
mike
Hi Michael
You can make a small change in java mapping to include braces ([ and ]).
For the HTTP post , check the document below
It has the HTTP post example with the same format like your format.
Indrajit, thx again
So I believe, the java mapping has to be changed to not pass MAT for create element
// building the target structure Element target = newdoc.createElement("MAT"); - I have to remove this
newdoc.appendChild(target); - have to remove this. Element doctype = newdoc.createElement(root.getChildNodes().item(1) will be changed to item(0)
.getNodeName());
And also to add the logic for [ ]
String data = "[";
if (fileArray != null) {
for (int i = 0; i < fileArray.length; i++) {
if data = "[";
data = data + fileArray[i];
else
if (i < fileArray.length - 1) {
data = data + ",";
endif.
data = data + "]";
is this right?
thx indrajit
-mike
User | Count |
---|---|
83 | |
24 | |
12 | |
9 | |
7 | |
6 | |
5 | |
5 | |
5 | |
4 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.