001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.servicemix.soap.interceptors.mime;
018    
019    import java.io.ByteArrayOutputStream;
020    import java.io.FilterOutputStream;
021    import java.io.IOException;
022    import java.io.OutputStream;
023    import java.util.ArrayList;
024    import java.util.Enumeration;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.Properties;
029    
030    import javax.activation.DataHandler;
031    import javax.mail.Header;
032    import javax.mail.MessagingException;
033    import javax.mail.Session;
034    import javax.mail.util.ByteArrayDataSource;
035    import javax.mail.internet.MimeBodyPart;
036    import javax.mail.internet.MimeMessage;
037    import javax.mail.internet.MimeMultipart;
038    
039    import org.apache.servicemix.soap.api.Fault;
040    import org.apache.servicemix.soap.api.InterceptorChain;
041    import org.apache.servicemix.soap.api.Message;
042    import org.apache.servicemix.soap.core.AbstractInterceptor;
043    
044    /**
045     * @author <a href="mailto:gnodet [at] gmail.com">Guillaume Nodet</a>
046     */
047    public class AttachmentsOutInterceptor extends AbstractInterceptor {
048    
049        public static final String PIPE_ATTACHMENT_STREAM = "PipeAttachmentStream";
050        
051        public static final String SOAP_PART_ID = "soap-request";
052        
053        public void handleMessage(final Message message) {
054            if (message.getAttachments().size() == 0) {
055                return;
056            }
057            OutputStream os = message.getContent(OutputStream.class);
058            if (os == null) {
059                throw new NullPointerException("OutputStream content not found");
060            }
061            try {
062                ByteArrayOutputStream baos = new ByteArrayOutputStream();
063                message.setContent(OutputStream.class, baos);
064                message.put(Message.CONTENT_TYPE, "multipart/related; type=\"text/xml\"; start=\"<" + SOAP_PART_ID + ">\"");
065                InterceptorChain chain = message.get(InterceptorChain.class);
066                chain.doIntercept(message);
067                writeMultipartMessage(message, os, baos.toByteArray());
068            } catch (MessagingException e) {
069                throw new Fault(e);
070            } catch (IOException e) {
071                throw new Fault(e);
072            }
073        }
074        
075        protected boolean getBoolean(Message message, String name, boolean def) {
076            Object b = message.get(name);
077            if (b instanceof Boolean) {
078                return ((Boolean) b).booleanValue();
079            } else if (b != null) {
080                return Boolean.parseBoolean(b.toString());
081            } else {
082                return def;
083            }
084        }
085    
086        @SuppressWarnings("unchecked")
087        private void writeMultipartMessage(Message message, OutputStream out, byte[] data) throws MessagingException, IOException {
088            MimeMultipart parts = new MimeMultipart("related; type=\"text/xml\"; start=\"<" + SOAP_PART_ID + ">\"");
089            Session session = Session.getDefaultInstance(new Properties(), null);
090            MimeMessage mime = new MimeMessage(session);
091            // Add soap part
092            MimeBodyPart soapPart = new MimeBodyPart();
093            soapPart.setContentID("<" + SOAP_PART_ID + ">");
094            soapPart.addHeader("Content-Transfer-Encoding", "8bit");
095            soapPart.setDataHandler(new DataHandler(new ByteArrayDataSource(data, "text/xml")));
096            parts.addBodyPart(soapPart);
097            // Add attachments
098            for (Iterator itr = message.getAttachments().entrySet().iterator(); itr.hasNext();) {
099                Map.Entry entry = (Map.Entry) itr.next();
100                String id = (String) entry.getKey();
101                DataHandler dh = (DataHandler) entry.getValue();
102                MimeBodyPart part = new MimeBodyPart();
103                part.setDataHandler(dh);
104                part.setContentID("<" + id + ">");
105                part.addHeader("Content-Transfer-Encoding", "binary");
106                parts.addBodyPart(part);
107            }
108            mime.setContent(parts);
109            mime.setHeader(Message.CONTENT_TYPE, parts.getContentType());
110            // We do not want headers, so 
111            //  * retrieve all headers
112            //  * skip first 2 bytes (CRLF)
113            mime.saveChanges();
114            Enumeration<Header> headersEnum = mime.getAllHeaders();
115            List<String> headersList = new ArrayList<String>();
116            while (headersEnum.hasMoreElements()) {
117                headersList.add(headersEnum.nextElement().getName().toLowerCase());
118            }
119            String[] headers = headersList.toArray(new String[0]);
120            // Skip first 2 bytes
121            OutputStream os = new FilterOutputStream(out) {
122                private int nb = 0;
123                public void write(int b) throws IOException {
124                    if (++nb > 2) {
125                        super.write(b);
126                    }
127                }
128            };
129            // Write
130            mime.writeTo(os, headers);
131        }
132    
133    }