com.adaptris.core.services.aggregator.MimeAggregator.java Source code

Java tutorial

Introduction

Here is the source code for com.adaptris.core.services.aggregator.MimeAggregator.java

Source

/*
 * Copyright 2015 Adaptris Ltd.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

package com.adaptris.core.services.aggregator;

import static com.adaptris.util.text.mime.MimeConstants.HEADER_CONTENT_ENCODING;
import static com.adaptris.util.text.mime.MimeConstants.HEADER_CONTENT_TYPE;
import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isEmpty;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;

import javax.mail.MessagingException;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeUtility;
import javax.validation.constraints.Pattern;

import com.adaptris.annotation.AdvancedConfig;
import com.adaptris.annotation.DisplayOrder;
import com.adaptris.core.AdaptrisMessage;
import com.adaptris.core.CoreConstants;
import com.adaptris.core.CoreException;
import com.adaptris.core.util.ExceptionHelper;
import com.adaptris.util.text.mime.MultiPartOutput;
import com.thoughtworks.xstream.annotations.XStreamAlias;

/**
 * {@link MessageAggregator} implementation that creates a new mime part for each message that needs to be joined up.
 * 
 * <p>
 * The pre-split message is always treated as the first part of the resulting multipart message; the payloads from the split
 * messages form the second and subsequent parts. If the split message contains a specific metadata key (as configured by
 * {@link #setPartContentIdMetadataKey(String)}) then the corresponding value will be used as that parts <code>Content-Id</code>. If
 * the metadata key does not exist, or is not configured, then the split message's unique-id will be used. If the same
 * <code>Content-Id</code> is observed for multiple split messages then results are undefined. The most likely situation is that
 * parts will be lost and only one preserved.
 * </p>
 * <p>
 * Note that the first part's <code>Content-Id</code> will always be the original messages unique-id. Also, if the original message
 * was a Multipart message, then this will be added as a single part to the resulting multipart message (giving you a nested
 * multipart as the first part).
 * </p>
 * <p>
 * As a result of this join operation, the message will be marked as MIME encoded using {@link com.adaptris.core.CoreConstants#MSG_MIME_ENCODED}
 * metadata.
 * </p>
 * 
 * @config mime-aggregator
 * @see CoreConstants#MSG_MIME_ENCODED
 * @author lchan
 * 
 */
@XStreamAlias("mime-aggregator")
@DisplayOrder(order = { "encoding", "overwriteMetadata", "partContentTypeMetadataKey", "partContentIdMetadataKey" })
public class MimeAggregator extends MessageAggregatorImpl {

    @Pattern(regexp = "base64|quoted-printable|uuencode|x-uuencode|x-uue|binary|7bit|8bit")
    @AdvancedConfig
    private String encoding;
    @AdvancedConfig
    private String partContentIdMetadataKey;
    @AdvancedConfig
    private String partContentTypeMetadataKey;

    @Override
    public void joinMessage(AdaptrisMessage original, Collection<AdaptrisMessage> messages) throws CoreException {
        try {
            MultiPartOutput output = createInitialPart(original);
            for (AdaptrisMessage m : messages) {
                output.addPart(createBodyPart(m),
                        getMetadataValue(m, getPartContentIdMetadataKey(), m.getUniqueId()));
                overwriteMetadata(m, original);
            }
            try (OutputStream out = original.getOutputStream()) {
                output.writeTo(out);
            }
            original.addMetadata(CoreConstants.MSG_MIME_ENCODED, Boolean.TRUE.toString());
        } catch (Exception e) {
            throw ExceptionHelper.wrapCoreException(e);
        }
    }

    protected MimeBodyPart createBodyPart(AdaptrisMessage msg) throws MessagingException, IOException {
        InternetHeaders hdrs = new InternetHeaders();
        byte[] encodedData = encodeData(msg.getPayload(), getEncoding(), hdrs);
        hdrs.addHeader(HEADER_CONTENT_TYPE,
                getMetadataValue(msg, getPartContentTypeMetadataKey(), "application/octet-stream"));
        return new MimeBodyPart(hdrs, encodedData);
    }

    protected MultiPartOutput createInitialPart(AdaptrisMessage original) throws MessagingException, IOException {
        MultiPartOutput output = new MultiPartOutput(original.getUniqueId());
        output.addPart(createBodyPart(original),
                getMetadataValue(original, getPartContentIdMetadataKey(), original.getUniqueId()));
        return output;
    }

    /**
     * @return the encoding
     */
    public String getEncoding() {
        return encoding;
    }

    /**
     * Set the encoding to be used for the content.
     * 
     * @param s the encoding to set, defaults to no-encoding (null)
     */
    public void setEncoding(String s) {
        this.encoding = s;
    }

    /**
     * @return the partContentIdMetadataKey
     */
    public String getPartContentIdMetadataKey() {
        return partContentIdMetadataKey;
    }

    /**
     * Set the content ID for a given mime part based on a metadata key.
     * 
     * @param s the partContentIdMetadataKey to set
     */
    public void setPartContentIdMetadataKey(String s) {
        this.partContentIdMetadataKey = s;
    }

    protected String getMetadataValue(AdaptrisMessage msg, String key, String defaultValue) {
        String result = null;
        if (!isEmpty(key) && msg.headersContainsKey(key)) {
            result = msg.getMetadataValue(key);
        }
        return defaultIfEmpty(result, defaultValue);
    }

    private static byte[] encodeData(byte[] data, String encoding, InternetHeaders hdrs)
            throws MessagingException, IOException {
        if (!isBlank(encoding)) {
            hdrs.setHeader(HEADER_CONTENT_ENCODING, encoding);
        }
        try (ByteArrayOutputStream out = new ByteArrayOutputStream();
                OutputStream encodedOut = MimeUtility.encode(out, encoding)) {
            encodedOut.write(data);
            return out.toByteArray();
        }
    }

    /**
     * @return the partContentTypeMetadataKey
     */
    public String getPartContentTypeMetadataKey() {
        return partContentTypeMetadataKey;
    }

    /**
     * The key to derive the content-type.
     * 
     * @param s the partContentTypeMetadataKey to set
     */
    public void setPartContentTypeMetadataKey(String s) {
        this.partContentTypeMetadataKey = s;
    }
}