001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    
020    package org.apache.james.mime4j.samples.transform;
021    
022    import java.io.ByteArrayInputStream;
023    import java.io.IOException;
024    import java.util.Date;
025    import java.util.Random;
026    
027    import org.apache.james.mime4j.dom.Body;
028    import org.apache.james.mime4j.dom.Entity;
029    import org.apache.james.mime4j.dom.Message;
030    import org.apache.james.mime4j.dom.MessageBuilder;
031    import org.apache.james.mime4j.dom.MessageWriter;
032    import org.apache.james.mime4j.dom.Multipart;
033    import org.apache.james.mime4j.dom.TextBody;
034    import org.apache.james.mime4j.dom.field.ParseException;
035    import org.apache.james.mime4j.field.address.AddressBuilder;
036    import org.apache.james.mime4j.message.BodyPart;
037    import org.apache.james.mime4j.message.MessageImpl;
038    import org.apache.james.mime4j.message.DefaultMessageBuilder;
039    import org.apache.james.mime4j.message.DefaultMessageWriter;
040    import org.apache.james.mime4j.message.MultipartImpl;
041    import org.apache.james.mime4j.storage.DefaultStorageProvider;
042    import org.apache.james.mime4j.storage.StorageBodyFactory;
043    import org.apache.james.mime4j.storage.StorageProvider;
044    import org.apache.james.mime4j.storage.TempFileStorageProvider;
045    
046    /**
047     * This code should illustrate how to transform a message into another message
048     * without modifying the original.
049     */
050    public class TransformMessage {
051    
052        // Host name used in message identifiers.
053        private static final String HOSTNAME = "localhost";
054    
055        public static void main(String[] args) throws Exception {
056            // Explicitly set a strategy for storing body parts. Usually not
057            // necessary; for most applications the default setting is appropriate.
058            StorageProvider storageProvider = new TempFileStorageProvider();
059            DefaultStorageProvider.setInstance(storageProvider);
060    
061            // Create a template message. It would be possible to load a message
062            // from an input stream but for this example a message object is created
063            // from scratch for demonstration purposes.
064            Message template = createTemplate();
065    
066            // Create a new message by transforming the template.
067            Message transformed = transform(template);
068    
069            MessageWriter writer = new DefaultMessageWriter();
070    
071            // Print transformed message.
072            System.out.println("\n\nTransformed message:\n--------------------\n");
073            writer.writeMessage(transformed, System.out);
074    
075            // Messages should be disposed of when they are no longer needed.
076            // Disposing of a message also disposes of all child elements (e.g. body
077            // parts) of the message.
078            transformed.dispose();
079    
080            // Print original message to illustrate that it was not affected by the
081            // transformation.
082            System.out.println("\n\nOriginal template:\n------------------\n");
083            writer.writeMessage(template, System.out);
084    
085            // Original message is no longer needed.
086            template.dispose();
087    
088            // At this point all temporary files have been deleted because all
089            // messages and body parts have been disposed of properly.
090        }
091    
092        /**
093         * Copies the given message and makes some arbitrary changes to the copy.
094         * @throws ParseException on bad arguments
095         */
096        private static Message transform(Message original) throws IOException, ParseException {
097            // Create a copy of the template. The copy can be modified without
098            // affecting the original.
099            MessageBuilder builder = new DefaultMessageBuilder();
100            Message message = builder.newMessage(original);
101    
102            // In this example we know we have a multipart message. Use
103            // Message#isMultipart() if uncertain.
104            Multipart multipart = (Multipart) message.getBody();
105    
106            // Insert a new text/plain body part after every body part of the
107            // template.
108            final int count = multipart.getCount();
109            for (int i = 0; i < count; i++) {
110                String text = "Text inserted after part " + (i + 1);
111                BodyPart bodyPart = createTextPart(text);
112                multipart.addBodyPart(bodyPart, 2 * i + 1);
113            }
114    
115            // For no particular reason remove the second binary body part (now
116            // at index four).
117            Entity removed = multipart.removeBodyPart(4);
118    
119            // The removed body part no longer has a parent entity it belongs to so
120            // it should be disposed of.
121            removed.dispose();
122    
123            // Set some headers on the transformed message
124            message.createMessageId(HOSTNAME);
125            message.setSubject("Transformed message");
126            message.setDate(new Date());
127            message.setFrom(AddressBuilder.DEFAULT.parseMailbox("John Doe <jdoe@machine.example>"));
128    
129            return message;
130        }
131    
132        /**
133         * Creates a multipart/mixed message that consists of three parts (one text,
134         * two binary).
135         */
136        private static Message createTemplate() throws IOException {
137            Multipart multipart = new MultipartImpl("mixed");
138    
139            BodyPart part1 = createTextPart("This is the first part of the template..");
140            multipart.addBodyPart(part1);
141    
142            BodyPart part2 = createRandomBinaryPart(200);
143            multipart.addBodyPart(part2);
144    
145            BodyPart part3 = createRandomBinaryPart(300);
146            multipart.addBodyPart(part3);
147    
148            MessageImpl message = new MessageImpl();
149            message.setMultipart(multipart);
150    
151            message.setSubject("Template message");
152    
153            return message;
154        }
155    
156        /**
157         * Creates a text part from the specified string.
158         */
159        private static BodyPart createTextPart(String text) {
160            TextBody body = new StorageBodyFactory().textBody(text, "UTF-8");
161    
162            BodyPart bodyPart = new BodyPart();
163            bodyPart.setText(body);
164            bodyPart.setContentTransferEncoding("quoted-printable");
165    
166            return bodyPart;
167        }
168    
169        /**
170         * Creates a binary part with random content.
171         */
172        private static BodyPart createRandomBinaryPart(int numberOfBytes)
173                throws IOException {
174            byte[] data = new byte[numberOfBytes];
175            new Random().nextBytes(data);
176    
177            Body body = new StorageBodyFactory()
178                    .binaryBody(new ByteArrayInputStream(data));
179    
180            BodyPart bodyPart = new BodyPart();
181            bodyPart.setBody(body, "application/octet-stream");
182            bodyPart.setContentTransferEncoding("base64");
183    
184            return bodyPart;
185        }
186    
187    }