Package org.springframework.roo.addon.email

Source Code of org.springframework.roo.addon.email.MailOperationsImpl

package org.springframework.roo.addon.email;

import static org.springframework.roo.addon.email.MailProtocol.SMTP;
import static org.springframework.roo.model.SpringJavaType.ASYNC;
import static org.springframework.roo.model.SpringJavaType.AUTOWIRED;
import static org.springframework.roo.model.SpringJavaType.JAVA_MAIL_SENDER_IMPL;
import static org.springframework.roo.model.SpringJavaType.MAIL_SENDER;
import static org.springframework.roo.model.SpringJavaType.SIMPLE_MAIL_MESSAGE;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.springframework.roo.addon.propfiles.PropFileOperations;
import org.springframework.roo.classpath.TypeLocationService;
import org.springframework.roo.classpath.TypeManagementService;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder;
import org.springframework.roo.classpath.details.FieldMetadataBuilder;
import org.springframework.roo.classpath.details.MethodMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.project.Dependency;
import org.springframework.roo.project.Path;
import org.springframework.roo.project.PathResolver;
import org.springframework.roo.project.ProjectOperations;
import org.springframework.roo.support.logging.HandlerUtils;
import org.springframework.roo.support.util.DomUtils;
import org.springframework.roo.support.util.PairList;
import org.springframework.roo.support.util.XmlElementBuilder;
import org.springframework.roo.support.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
* Implementation of {@link MailOperationsImpl}.
*
* @author Stefan Schmidt
* @since 1.0
*/
@Component
@Service
public class MailOperationsImpl implements MailOperations {

    private static final String LOCAL_MESSAGE_VARIABLE = "mailMessage";
    private static final Logger LOGGER = HandlerUtils
            .getLogger(MailOperationsImpl.class);
    private static final int PRIVATE_TRANSIENT = Modifier.PRIVATE
            | Modifier.TRANSIENT;
    private static final String SPRING_TASK_NS = "http://www.springframework.org/schema/task";
    private static final String SPRING_TASK_XSD = "http://www.springframework.org/schema/task/spring-task-3.1.xsd";
    private static final AnnotatedJavaType STRING = new AnnotatedJavaType(
            JavaType.STRING);
    private static final String TEMPLATE_MESSAGE_FIELD = "templateMessage";

    @Reference private FileManager fileManager;
    @Reference private PathResolver pathResolver;
    @Reference private ProjectOperations projectOperations;
    @Reference private PropFileOperations propFileOperations;
    @Reference private TypeLocationService typeLocationService;
    @Reference private TypeManagementService typeManagementService;

    public void configureTemplateMessage(final String from, final String subject) {
        final String contextPath = getApplicationContextPath();
        final Document document = XmlUtils.readXml(fileManager
                .getInputStream(contextPath));
        final Element root = document.getDocumentElement();

        final Map<String, String> props = new HashMap<String, String>();

        if (StringUtils.isNotBlank(from) || StringUtils.isNotBlank(subject)) {
            Element smmBean = getSimpleMailMessageBean(root);
            if (smmBean == null) {
                smmBean = document.createElement("bean");
                smmBean.setAttribute("class",
                        SIMPLE_MAIL_MESSAGE.getFullyQualifiedTypeName());
                smmBean.setAttribute("id", "templateMessage");
            }

            if (StringUtils.isNotBlank(from)) {
                Element smmProperty = XmlUtils.findFirstElement(
                        "//property[@name='from']", smmBean);
                if (smmProperty != null) {
                    smmBean.removeChild(smmProperty);
                }
                smmProperty = document.createElement("property");
                smmProperty.setAttribute("value", "${email.from}");
                smmProperty.setAttribute("name", "from");
                smmBean.appendChild(smmProperty);
                props.put("email.from", from);
            }

            if (StringUtils.isNotBlank(subject)) {
                Element smmProperty = XmlUtils.findFirstElement(
                        "//property[@name='subject']", smmBean);
                if (smmProperty != null) {
                    smmBean.removeChild(smmProperty);
                }
                smmProperty = document.createElement("property");
                smmProperty.setAttribute("value", "${email.subject}");
                smmProperty.setAttribute("name", "subject");
                smmBean.appendChild(smmProperty);
                props.put("email.subject", subject);
            }

            root.appendChild(smmBean);

            DomUtils.removeTextNodes(root);

            fileManager.createOrUpdateTextFileIfRequired(contextPath,
                    XmlUtils.nodeToString(document), false);
        }

        if (props.size() > 0) {
            propFileOperations.addProperties(Path.SPRING_CONFIG_ROOT
                    .getModulePathId(projectOperations.getFocusedModuleName()),
                    "email.properties", props, true, true);
        }
    }

    /**
     * Returns the canonical path of the user project's applicationContext.xml
     * file.
     *
     * @return a non-blank path
     */
    private String getApplicationContextPath() {
        return pathResolver.getFocusedIdentifier(Path.SPRING_CONFIG_ROOT,
                "applicationContext.xml");
    }

    /**
     * Generates the "send email" method to be added to the domain type
     *
     * @param mailSenderName the name of the MailSender field (required)
     * @param async whether to send the email asynchronously
     * @param targetClassMID the MID of the class to receive the method
     * @param mutableTypeDetails the type to which the method is being added
     *            (required)
     * @return a non-<code>null</code> method
     */
    private MethodMetadataBuilder getSendMethod(
            final JavaSymbolName mailSenderName, final boolean async,
            final String targetClassMID,
            final ClassOrInterfaceTypeDetailsBuilder cidBuilder) {
        final String contextPath = getApplicationContextPath();
        final Document document = XmlUtils.readXml(fileManager
                .getInputStream(contextPath));
        final Element root = document.getDocumentElement();

        // Make a builder for the created method's body
        final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();

        // Collect the types and names of the created method's parameters
        final PairList<AnnotatedJavaType, JavaSymbolName> parameters = new PairList<AnnotatedJavaType, JavaSymbolName>();

        if (getSimpleMailMessageBean(root) == null) {
            // There's no SimpleMailMessage bean; use a local variable
            bodyBuilder.appendFormalLine(SIMPLE_MAIL_MESSAGE
                    .getFullyQualifiedTypeName()
                    + " "
                    + LOCAL_MESSAGE_VARIABLE
                    + " = new "
                    + SIMPLE_MAIL_MESSAGE.getFullyQualifiedTypeName() + "();");
            // Set the from address
            parameters.add(STRING, new JavaSymbolName("mailFrom"));
            bodyBuilder.appendFormalLine(LOCAL_MESSAGE_VARIABLE
                    + ".setFrom(mailFrom);");
            // Set the subject
            parameters.add(STRING, new JavaSymbolName("subject"));
            bodyBuilder.appendFormalLine(LOCAL_MESSAGE_VARIABLE
                    + ".setSubject(subject);");
        }
        else {
            // A SimpleMailMessage bean exists; auto-wire it into the entity and
            // use it as a template
            final List<AnnotationMetadataBuilder> smmAnnotations = Arrays
                    .asList(new AnnotationMetadataBuilder(AUTOWIRED));
            final FieldMetadataBuilder smmFieldBuilder = new FieldMetadataBuilder(
                    targetClassMID, PRIVATE_TRANSIENT, smmAnnotations,
                    new JavaSymbolName(TEMPLATE_MESSAGE_FIELD),
                    SIMPLE_MAIL_MESSAGE);
            cidBuilder.addField(smmFieldBuilder);
            // Use the injected bean as a template (for thread safety)
            bodyBuilder.appendFormalLine(SIMPLE_MAIL_MESSAGE
                    .getFullyQualifiedTypeName()
                    + " "
                    + LOCAL_MESSAGE_VARIABLE
                    + " = new "
                    + SIMPLE_MAIL_MESSAGE.getFullyQualifiedTypeName()
                    + "("
                    + TEMPLATE_MESSAGE_FIELD + ");");
        }

        // Set the to address
        parameters.add(STRING, new JavaSymbolName("mailTo"));
        bodyBuilder
                .appendFormalLine(LOCAL_MESSAGE_VARIABLE + ".setTo(mailTo);");

        // Set the message body
        parameters.add(STRING, new JavaSymbolName("message"));
        bodyBuilder.appendFormalLine(LOCAL_MESSAGE_VARIABLE
                + ".setText(message);");

        bodyBuilder.newLine();
        bodyBuilder.appendFormalLine(mailSenderName + ".send("
                + LOCAL_MESSAGE_VARIABLE + ");");

        final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
                targetClassMID, Modifier.PUBLIC, new JavaSymbolName(
                        "sendMessage"), JavaType.VOID_PRIMITIVE,
                parameters.getKeys(), parameters.getValues(), bodyBuilder);

        if (async) {
            if (DomUtils.findFirstElementByName("task:annotation-driven", root) == null) {
                // Add asynchronous email support to the application
                if (StringUtils.isBlank(root.getAttribute("xmlns:task"))) {
                    // Add the "task" namespace to the Spring config file
                    root.setAttribute("xmlns:task", SPRING_TASK_NS);
                    root.setAttribute("xsi:schemaLocation",
                            root.getAttribute("xsi:schemaLocation") + "  "
                                    + SPRING_TASK_NS + " " + SPRING_TASK_XSD);
                }
                root.appendChild(new XmlElementBuilder(
                        "task:annotation-driven", document).addAttribute(
                        "executor", "asyncExecutor").build());
                root.appendChild(new XmlElementBuilder("task:executor",
                        document).addAttribute("id", "asyncExecutor")
                        .addAttribute("pool-size", "${executor.poolSize}")
                        .build());
                // Write out the new Spring config file
                fileManager.createOrUpdateTextFileIfRequired(contextPath,
                        XmlUtils.nodeToString(document), false);
                // Update the email properties file
                propFileOperations.addPropertyIfNotExists(
                        pathResolver.getFocusedPath(Path.SPRING_CONFIG_ROOT),
                        "email.properties", "executor.poolSize", "10", true);
            }
            methodBuilder.addAnnotation(new AnnotationMetadataBuilder(ASYNC));
        }
        return methodBuilder;
    }

    /**
     * Finds the SimpleMailMessage bean in the Spring XML file with the given
     * root element
     *
     * @param root
     * @return <code>null</code> if there is no such bean
     */
    private Element getSimpleMailMessageBean(final Element root) {
        return XmlUtils.findFirstElement("/beans/bean[@class = '"
                + SIMPLE_MAIL_MESSAGE.getFullyQualifiedTypeName() + "']", root);
    }

    public void injectEmailTemplate(final JavaType targetType,
            final JavaSymbolName fieldName, final boolean async) {
        Validate.notNull(targetType, "Java type required");
        Validate.notNull(fieldName, "Field name required");

        final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
        annotations.add(new AnnotationMetadataBuilder(AUTOWIRED));

        // Obtain the physical type and its mutable class details
        final String declaredByMetadataId = typeLocationService
                .getPhysicalTypeIdentifier(targetType);
        final ClassOrInterfaceTypeDetails existing = typeLocationService
                .getTypeDetails(targetType);
        if (existing == null) {
            LOGGER.warning("Aborting: Unable to find metadata for target type '"
                    + targetType.getFullyQualifiedTypeName() + "'");
            return;
        }
        final ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder(
                existing);

        // Add the MailSender field
        final FieldMetadataBuilder mailSenderFieldBuilder = new FieldMetadataBuilder(
                declaredByMetadataId, PRIVATE_TRANSIENT, annotations,
                fieldName, MAIL_SENDER);
        cidBuilder.addField(mailSenderFieldBuilder);

        // Add the "sendMessage" method
        cidBuilder.addMethod(getSendMethod(fieldName, async,
                declaredByMetadataId, cidBuilder));
        typeManagementService.createOrUpdateTypeOnDisk(cidBuilder.build());
    }

    public void installEmail(final String hostServer,
            final MailProtocol protocol, final String port,
            final String encoding, final String username, final String password) {
        Validate.notBlank(hostServer, "Host server name required");

        final String contextPath = getApplicationContextPath();
        final Document document = XmlUtils.readXml(fileManager
                .getInputStream(contextPath));
        final Element root = document.getDocumentElement();

        boolean installDependencies = true;
        final Map<String, String> props = new HashMap<String, String>();

        Element mailBean = XmlUtils.findFirstElement("/beans/bean[@class = '"
                + JAVA_MAIL_SENDER_IMPL.getFullyQualifiedTypeName() + "']",
                root);
        if (mailBean != null) {
            root.removeChild(mailBean);
            installDependencies = false;
        }

        mailBean = document.createElement("bean");
        mailBean.setAttribute("class",
                JAVA_MAIL_SENDER_IMPL.getFullyQualifiedTypeName());
        mailBean.setAttribute("id", "mailSender");

        final Element property = document.createElement("property");
        property.setAttribute("name", "host");
        property.setAttribute("value", "${email.host}");
        mailBean.appendChild(property);
        root.appendChild(mailBean);
        props.put("email.host", hostServer);

        if (protocol != null) {
            final Element pElement = document.createElement("property");
            pElement.setAttribute("value", "${email.protocol}");
            pElement.setAttribute("name", "protocol");
            mailBean.appendChild(pElement);
            props.put("email.protocol", protocol.getProtocol());
        }

        if (StringUtils.isNotBlank(port)) {
            final Element pElement = document.createElement("property");
            pElement.setAttribute("name", "port");
            pElement.setAttribute("value", "${email.port}");
            mailBean.appendChild(pElement);
            props.put("email.port", port);
        }

        if (StringUtils.isNotBlank(encoding)) {
            final Element pElement = document.createElement("property");
            pElement.setAttribute("name", "defaultEncoding");
            pElement.setAttribute("value", "${email.encoding}");
            mailBean.appendChild(pElement);
            props.put("email.encoding", encoding);
        }

        if (StringUtils.isNotBlank(username)) {
            final Element pElement = document.createElement("property");
            pElement.setAttribute("name", "username");
            pElement.setAttribute("value", "${email.username}");
            mailBean.appendChild(pElement);
            props.put("email.username", username);
        }

        if (StringUtils.isNotBlank(password)) {
            final Element pElement = document.createElement("property");
            pElement.setAttribute("name", "password");
            pElement.setAttribute("value", "${email.password}");
            mailBean.appendChild(pElement);
            props.put("email.password", password);

            if (SMTP.equals(protocol)) {
                final Element javaMailProperties = document
                        .createElement("property");
                javaMailProperties.setAttribute("name", "javaMailProperties");
                final Element securityProps = document.createElement("props");
                javaMailProperties.appendChild(securityProps);
                final Element prop = document.createElement("prop");
                prop.setAttribute("key", "mail.smtp.auth");
                prop.setTextContent("true");
                securityProps.appendChild(prop);
                final Element prop2 = document.createElement("prop");
                prop2.setAttribute("key", "mail.smtp.starttls.enable");
                prop2.setTextContent("true");
                securityProps.appendChild(prop2);
                mailBean.appendChild(javaMailProperties);
            }
        }

        DomUtils.removeTextNodes(root);

        fileManager.createOrUpdateTextFileIfRequired(contextPath,
                XmlUtils.nodeToString(document), false);

        if (installDependencies) {
            updateConfiguration(projectOperations.getFocusedModuleName());
        }

        propFileOperations.addProperties(Path.SPRING_CONFIG_ROOT
                .getModulePathId(projectOperations.getFocusedModuleName()),
                "email.properties", props, true, true);
    }

    public boolean isEmailInstallationPossible() {
        return projectOperations.isFocusedProjectAvailable();
    }

    public boolean isManageEmailAvailable() {
        return projectOperations.isFocusedProjectAvailable()
                && fileManager.exists(getApplicationContextPath());
    }

    private void updateConfiguration(final String moduleName) {
        final Element configuration = XmlUtils.getConfiguration(getClass());

        final List<Dependency> dependencies = new ArrayList<Dependency>();
        final List<Element> emailDependencies = XmlUtils.findElements(
                "/configuration/email/dependencies/dependency", configuration);
        for (final Element dependencyElement : emailDependencies) {
            dependencies.add(new Dependency(dependencyElement));
        }
        projectOperations.addDependencies(moduleName, dependencies);
    }
}
TOP

Related Classes of org.springframework.roo.addon.email.MailOperationsImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.