on 05-21-2007 12:04 AM
Hi there
We have configured a sender email adapter to receive text/csv attachments and save them to a file system. What we are having a problem with is reading the attachment name. So we are using Dynamis Configuration to create the file name using the subject line - Which is not ideal. Ideally we would like to use the same name as the origianl attachment but haven't found any way of doing that. We even tried using Content-type in the Variable Header (XHeaderName1) suing variable transport binding but it doesn't show up in the Dynamic Config part of the SOAP message.
Is there any way of reading the name of the file attachment? We are on PI release 7.0.
Any help would be appreciated.
Cheers
Salil
Wait for SP12, then you can read the attachment name with a self-written adapter module with the method getContentType.
There is no standard way for this.
Regards
Stefan
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Stefan,
can you plz elaborate on your idea?
I guess you are referring to PI 7.0 SP12. I'm on XI 3.0, what is the equivalent, SP20?
I appreciate your inputs/links.
Salil, were you able to get the attachement name using adapter module? Can you please share the solution with the community?
thx
praveen
Hi Salil,
I have a SOAP-PI-Proxy synchronous scenario.
I need to set the name of excel attachment getting created in PI .
Could you please guide?
https://scn.sap.com/thread/3955194
Thanks,
Indu Khurana.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Salil.
I'm new in this forum. I'm a XI developer and I'm working for the first time whit a Mail Adapter.
I need to save the mail attachement in a file system. Can you tell me how do you reach this goal? Did you use an ejb or in other way?
Thank's in advance,
Daniela.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Praveen
Yes, I was able to retrieve the attachment name from the email adapter by writing an adapter module. Obviously this only works when you are on SP20 for XI 3.0 or SP12 for XI 7.0.
Here is the code (very basic - since I have no experience in JAVA) from the adapter module . All this does is pass the filename to Dynamic Configuration to be picked up later.
Regards
Salil
/*
Created on Jul 19, 2007
*
To change the template for this generated file go to
Window>Preferences>Java>Code Generation>Code and Comments
*/
package emailPackage;
import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import com.sap.aii.af.mp.module.*;
import com.sap.aii.af.ra.ms.api.*;
/**
@author Salil.Mehta
To change the template for this generated type comment go to
Window>Preferences>Java>Code Generation>Code and Comments
@ejbHome<{com.sap.aii.af.mp.module.ModuleHome}>
@ejbLocal<{com.sap.aii.af.mp.module.ModuleLocal}>
@ejbLocalHome<{com.sap.aii.af.mp.module.ModuleLocalHome}>
@ejbRemote<{com.sap.aii.af.mp.module.ModuleRemote}>
@stateless
*/
public class emailClass implements SessionBean, Module{
private SessionContext myContext;
public void ejbRemove() {
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void setSessionContext(SessionContext context) {
myContext = context;
}
public void ejbCreate() throws CreateException{
}
public ModuleData process(ModuleContext moduleContext,
ModuleData inputModuleData)
throws ModuleException{
// put your code here
try {
Message msg = (Message) inputModuleData.getPrincipalData();
TextPayload payload = msg.getDocument();
// This gets the content in the attachment
String attname = payload.getContentType();
// Unfotunately the ContentType looks like
// - application/octet-stream;name="filename.csv" -
// So we have to get the filename from there
// Step 1 - replace all quotes with spaces
String quoteMark = "\"";
String space = "";
String newAttachment = attname.replaceAll(quoteMark, space);
// Step 2 - Now that we have replaced the quotes let's pick up the file name
String splCharacter = "=";
int ind = newAttachment.lastIndexOf(splCharacter) + 1;
String fileName = newAttachment.substring(ind, newAttachment.length());
// Step 3 - Set this filename in the Dynamic configuration of the message
msg.setMessageProperty("http://xyz.com/email", "FileName", fileName);
inputModuleData.setPrincipalData(msg);
} catch (Exception e) {
ModuleException me = new ModuleException(e);
throw me;
}
return inputModuleData;
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you very much Salil.
I've question, why does this piece work only on P 7.0 SP12 or XI 3.0 SP20? Adapter modules can be written for earlier SPs as well, can they not be?
We are currently on XI 3.0 SP17, planning to upgrading to PI 7.0 SP12 soon.
Will your module not work XI 3.0 SP17?
thanks
praveen
Hi Vitor
Here is the solution -
1. Use the payloadSwap Bean as described in the blog below to ensure that the attachment of the email becomes the Message payload instead of the body ....
/people/michal.krawczyk2/blog/2005/12/18/xi-sender-mail-adapter--payloadswapbean--step-by-step
2. Use Netweaver Developer Studio to create an EJb Module with the code supplied by me. This code grabs the attachment name and adds it to the Dynamic Configuration section of the Message. Here is a link to Stefan Grube's webinar on custom adapter module development -
3. In our integration scenario we are saving the email attachment to a file. so on the receiver file adapter we used to Dynamic Configuration Bean to get the Attachment name from the Dynamic Config section of the Message and name the file the same as the attahcmnet name from the email.
/people/jin.shin/blog/2007/04/27/sap-netweaver-xi-variable-substitution-with-adapter-specific-message-attributes-via-dynamicconfigurationbean
4. If your attachment was an XML (actually any other format could be converted into XML by writing another Bean for the sender mail adapter or maybe the MessageTransform Bean would do the job) you could use the Dyanmic Config in your mapping itself in a user defined function. Here is the code for that UDF. We called it getAttachmentName .............
public String getAttachmentName(Container container){
DynamicConfiguration conf = (DynamicConfiguration) container.getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);
DynamicConfigurationKey key = DynamicConfigurationKey.create("http://xyz.com/email","FileName");
String value = conf.get(key);
return value;
}
Hope this helps
Salil
p.s) I've got to say SDN is a great place to get your questions answered as I have mostly got mine.
Salil, I'm not using mapping on my scenario, because I'm receiving generic XML files.
(like the blog /people/william.li/blog/2006/09/08/how-to-send-any-data-even-binary-through-xi-without-using-the-integration-repository)
As I'm using only Integration Directory, I'm not able to use that UDF you provided. Is there any way to set it up directly on adapter ?
Thanks again
Hi Vitor
There are 2 scenarios that I can think of -
1. You are saving the email attachment as a file. In that case use step 3 in the earlier reply to get the attachment name and save the file witht that name.
2. You are sending the XML straight to a receiver using HTTP, IDOC, JDBC etc. in which case you would need the attachment name much earlier that step 3. For that I guess you would have to write another adapter module on the sender mail adapter(at Position 3 where position1 = payloadswap bean, 2 = custom module to get the attachment name) and add an xml tag to your incoming message. These adapter modules are really powerful and are like user exits in ABAP. In that case you would have to change the Data Type in the Integration repository to reflect that extra tag. Here is some code from a module we wrote to totally change the structure of the xml coming in. The key thing to remember is this module is that you can read the whole message byte by byte. There might be smarter ways of doing it (like using the SAP XML parser factory class) but since I'm not a Java programmer I stuck to the basics. Here's the code( you could also look at the example given in sap help where they remove (or add I'm not sure) CR(carriage return) from CRLF (CR Line feed).
**********************************************************************************************
/*
Created on Aug 8, 2007
*
To change the template for this generated file go to
Window>Preferences>Java>Code Generation>Code and Comments
*/
package jdbcPackage;
import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import com.sap.aii.af.mp.module.*;
import com.sap.aii.af.ra.ms.api.*;
/**
@author Salil.Mehta Soltius NZ Ltd
*
To change the template for this generated type comment go to
Window>Preferences>Java>Code Generation>Code and Comments
*/
public class jdbcClass implements SessionBean, Module {
private SessionContext myContext;
public void ejbRemove() {
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void setSessionContext(SessionContext context) {
myContext = context;
}
public void ejbCreate() throws CreateException {
}
public ModuleData process(
ModuleContext moduleContext,
ModuleData inputModuleData)
throws ModuleException {
// put your code here
try {
Message msg = (Message) inputModuleData.getPrincipalData();
XMLPayload payload = msg.getDocument();
String payEnc = payload.getEncoding();
byte[] payByte = payload.getContent();
byte[] payByteOut = new byte[payByte.length];
byte[] payByteTemp = new byte[payByte.length];
int i;
int j;
int actualCount = 0;
char xmlTagFound = ' ';
char endXmlTagFound = ' ';
char tagFound = ' ';
System.arraycopy(payByte, 0, payByteTemp, 0, payByte.length);
// Step 1 - Conversions
// convert "< to <" and "> to >"
// convert " to "
// This will remove any carriage returns and line feeds
// and the <XML* and </XML* tags plus the <row> and </row> tags
for (i = 0; i < payByte.length; i++) {
// convert < to < and > to >
if (payByteTemp<i> == '&') {
if (payByteTemp[i + 1] == 'l') {
if (payByteTemp[i + 2] == 't') {
if (payByteTemp[i + 3] == ';') {
payByteTemp<i> = '<';
payByteTemp[i + 1] = '\n';
payByteTemp[i + 2] = '\n';
payByteTemp[i + 3] = '\n';
}
}
}
}
if (payByteTemp<i> == '&') {
if (payByteTemp[i + 1] == 'g') {
if (payByteTemp[i + 2] == 't') {
if (payByteTemp[i + 3] == ';') {
payByteTemp<i> = '>';
payByteTemp[i + 1] = '\n';
payByteTemp[i + 2] = '\n';
payByteTemp[i + 3] = '\n';
}
}
}
}
if (payByteTemp<i> == '&') {
if (payByteTemp[i + 1] == 'q') {
if (payByteTemp[i + 2] == 'u') {
if (payByteTemp[i + 3] == 'o') {
if (payByteTemp[i + 4] == 't') {
if (payByteTemp[i + 5] == ';') {
payByteTemp<i> = '"';
payByteTemp[i + 1] = '\n';
payByteTemp[i + 2] = '\n';
payByteTemp[i + 3] = '\n';
payByteTemp[i + 4] = '\n';
payByteTemp[i + 5] = '\n';
}
}
}
}
}
}
// This will take in the initial xml declaration from the Byte array
// And we also don't want the stuff after the xml declaration till
// we reach the first <row> tag
if (xmlTagFound == ' ') {
if (payByteTemp<i> == '>') {
xmlTagFound = 'X';
}
payByteOut[actualCount++] = payByteTemp<i>;
if (xmlTagFound == 'X') {
payByteOut[actualCount++] = '\r';
}
continue;
}
if (xmlTagFound == 'X') {
if (payByteTemp<i> == '<') {
if (payByteTemp[i + 1] == 'r') {
if (payByteTemp[i + 2] == 'o') {
if (payByteTemp[i + 3] == 'w') {
if (payByteTemp[i + 4] == '>') {
xmlTagFound = 'Y';
} else {
continue;
}
} else {
continue;
}
} else {
continue;
}
} else {
continue;
}
} else {
continue;
}
}
// Carriage return and line feed
if ((payByteTemp<i> == '\r') || (payByteTemp<i> == '\n')) {
continue;
}
// <XML_*> tag
if (payByteTemp<i> == '<') {
if (payByteTemp[i + 1] == 'X') {
if (payByteTemp[i + 2] == 'M') {
if (payByteTemp[i + 3] == 'L') {
tagFound = 'X';
endXmlTagFound = ' ';
continue;
}
}
}
}
// </XML_*> tag
if (payByteTemp<i> == '<') {
if (payByteTemp[i + 1] == '/') {
if (payByteTemp[i + 2] == 'X') {
if (payByteTemp[i + 3] == 'M') {
if (payByteTemp[i + 4] == 'L') {
tagFound = 'X';
endXmlTagFound = 'X';
continue;
}
}
}
}
}
// <row> tag
if (payByteTemp<i> == '<') {
if (payByteTemp[i + 1] == 'r') {
if (payByteTemp[i + 2] == 'o') {
if (payByteTemp[i + 3] == 'w') {
if (payByteTemp[i + 4] == '>') {
tagFound = 'X';
continue;
}
}
}
}
}
// </row> tag
if (payByteTemp<i> == '<') {
if (payByteTemp[i + 1] == '/') {
if (payByteTemp[i + 2] == 'r') {
if (payByteTemp[i + 3] == 'o') {
if (payByteTemp[i + 4] == 'w') {
if (payByteTemp[i + 5] == '>') {
tagFound = 'X';
continue;
}
}
}
}
}
}
if ((payByteTemp<i> == '>') && (tagFound == 'X')) {
tagFound = ' ';
continue;
}
if (tagFound == ' ') {
if (endXmlTagFound == 'X') {
continue;
}
payByteOut[actualCount++] = payByteTemp<i>;
}
}
byte[] payByteExp = new byte[actualCount];
System.arraycopy(payByteOut, 0, payByteExp, 0, actualCount);
payload.setContent(payByteExp);
msg.setDocument(payload);
inputModuleData.setPrincipalData(msg);
} catch (Exception e) {
ModuleException me = new ModuleException(e);
throw me;
}
return inputModuleData;
}
}
Salil,
This was very useful thread. How did you test your adapter module? Did you every time deployed it on to XI server and tested using a test mail?
Stefan Grube - Could you help or tell me how to test an adapter module? The only issue is, what would at runtime the statement - Message msg = (Message) inputModuleData.getPrincipalData(); would return?
Is there a way to test the modules before we actually deploy them on to the server?
VJ
Thanks for that Stefan.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
87 | |
10 | |
10 | |
10 | |
7 | |
6 | |
6 | |
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.