/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.action.impl;
import static org.apache.commons.lang.StringUtils.isBlank;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.ContentType;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.model.ImapModel;
import org.alfresco.module.org_alfresco_module_rm.action.RMActionExecuterAbstractBase;
import org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipDefinition;
import org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipDisplayName;
import org.alfresco.module.org_alfresco_module_rm.relationship.RelationshipService;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.util.FileCopyUtils;
/**
* Split Email Action
*
* Splits the attachments for an email message out to independent records.
*
* @author Mark Rogers
*/
public class SplitEmailAction extends RMActionExecuterAbstractBase
{
/** I18N */
private static final String MSG_NO_READ_MIME_MESSAGE = "rm.action.no-read-mime-message";
private static final String MSG_EMAIL_DECLARED = "rm.action.email-declared";
private static final String MSG_EMAIL_NOT_RECORD = "rm.action.email-not-record";
/** Relationship Labels */
private static final String REL_FROM = "Message";
private static final String REL_TO = "Attachment";
/** Logger */
private static Log logger = LogFactory.getLog(SplitEmailAction.class);
/** Relationship service */
private RelationshipService relationshipService;
/**
* Gets the relationship service instance
*
* @return The relationship service instance
*/
protected RelationshipService getRelationshipService()
{
return this.relationshipService;
}
/**
* Sets the relationship service instance
*
* @param relationshipService The relationship service instance
*/
public void setRelationshipService(RelationshipService relationshipService)
{
this.relationshipService = relationshipService;
}
/** Unique name of the relationship definition */
private String relationshipUniqueName;
public void bootstrap()
{
Set<RelationshipDefinition> relationshipDefinitions = getRelationshipService().getRelationshipDefinitions();
for (RelationshipDefinition relationshipDefinition : relationshipDefinitions)
{
RelationshipDisplayName displayName = relationshipDefinition.getDisplayName();
String sourceText = displayName.getSourceText();
String targetText = displayName.getTargetText();
if (sourceText.equals(REL_FROM) && targetText.equals(REL_TO))
{
relationshipUniqueName = relationshipDefinition.getUniqueName();
}
}
if (isBlank(relationshipUniqueName))
{
RelationshipDisplayName displayName = new RelationshipDisplayName(REL_FROM, REL_TO);
RelationshipDefinition relationshipDefinition = getRelationshipService().createRelationshipDefinition(displayName);
relationshipUniqueName = relationshipDefinition.getUniqueName();
}
}
/**
* @see org.alfresco.repo.action.executer.ActionExecuterAbstractBase#executeImpl(org.alfresco.service.cmr.action.Action,
* org.alfresco.service.cmr.repository.NodeRef)
*/
@Override
protected void executeImpl(Action action, NodeRef actionedUponNodeRef)
{
// get node type
getNodeService().getType(actionedUponNodeRef);
if (logger.isDebugEnabled())
{
logger.debug("split email:" + actionedUponNodeRef);
}
if (getRecordService().isRecord(actionedUponNodeRef))
{
if (!getRecordService().isDeclared(actionedUponNodeRef))
{
ChildAssociationRef parent = getNodeService().getPrimaryParent(actionedUponNodeRef);
/**
* Check whether the email message has already been split - do nothing if it has already been split
*/
List<AssociationRef> refs = getNodeService().getTargetAssocs(actionedUponNodeRef, ImapModel.ASSOC_IMAP_ATTACHMENT);
if(refs.size() > 0)
{
if (logger.isDebugEnabled())
{
logger.debug("mail message has already been split - do nothing");
}
return;
}
/**
* Get the content and if its a mime message then create atachments for each part
*/
try
{
ContentReader reader = getContentService().getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT);
InputStream is = reader.getContentInputStream();
MimeMessage mimeMessage = new MimeMessage(null, is);
Object content = mimeMessage.getContent();
if (content instanceof Multipart)
{
Multipart multipart = (Multipart)content;
for (int i = 0, n = multipart.getCount(); i < n; i++)
{
Part part = multipart.getBodyPart(i);
if ("attachment".equalsIgnoreCase(part.getDisposition()))
{
createAttachment(actionedUponNodeRef, parent.getParentRef(), part);
}
}
}
}
catch (Exception e)
{
throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_NO_READ_MIME_MESSAGE, e.toString()), e);
}
}
else
{
throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_EMAIL_DECLARED, actionedUponNodeRef.toString()));
}
}
else
{
throw new AlfrescoRuntimeException(I18NUtil.getMessage(MSG_EMAIL_NOT_RECORD, actionedUponNodeRef.toString()));
}
}
/**
* Create attachment from Mime Message Part
* @param messageNodeRef - the node ref of the mime message
* @param parentNodeRef - the node ref of the parent folder
* @param part
* @throws MessagingException
* @throws IOException
*/
private void createAttachment(NodeRef messageNodeRef, NodeRef parentNodeRef, Part part) throws MessagingException, IOException
{
String fileName = part.getFileName();
try
{
fileName = MimeUtility.decodeText(fileName);
}
catch (UnsupportedEncodingException e)
{
if (logger.isWarnEnabled())
{
logger.warn("Cannot decode file name '" + fileName + "'", e);
}
}
Map<QName, Serializable> messageProperties = getNodeService().getProperties(messageNodeRef);
String messageTitle = (String)messageProperties.get(ContentModel.PROP_NAME);
if(messageTitle == null)
{
messageTitle = fileName;
}
else
{
messageTitle = messageTitle + " - " + fileName;
}
ContentType contentType = new ContentType(part.getContentType());
Map<QName, Serializable> docProps = new HashMap<QName, Serializable>(1);
docProps.put(ContentModel.PROP_NAME, messageTitle + " - " + fileName);
docProps.put(ContentModel.PROP_TITLE, fileName);
/**
* Create an attachment node in the same folder as the message
*/
ChildAssociationRef attachmentRef = getNodeService().createNode(parentNodeRef,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, fileName),
ContentModel.TYPE_CONTENT,
docProps);
/**
* Write the content into the new attachment node
*/
ContentWriter writer = getContentService().getWriter(attachmentRef.getChildRef(), ContentModel.PROP_CONTENT, true);
writer.setMimetype(contentType.getBaseType());
OutputStream os = writer.getContentOutputStream();
FileCopyUtils.copy(part.getInputStream(), os);
/**
* Create a link from the message to the attachment
*/
createRMReference(messageNodeRef, attachmentRef.getChildRef());
}
/**
* Create a link from the message to the attachment
*/
private void createRMReference(final NodeRef parentRef, final NodeRef childRef)
{
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
{
@Override
public Void doWork()
{
// add the relationship
getRelationshipService().addRelationship(relationshipUniqueName, parentRef, childRef);
// add the IMAP attachment aspect
getNodeService().createAssociation(
parentRef,
childRef,
ImapModel.ASSOC_IMAP_ATTACHMENT);
return null;
}
});
}
}