Package net.sourceforge.cruisecontrol.publishers

Source Code of net.sourceforge.cruisecontrol.publishers.HTMLEmailPublisher

/********************************************************************************
* CruiseControl, a Continuous Integration Toolkit
* Copyright (c) 2001-2003, ThoughtWorks, Inc.
* 651 W Washington Ave. Suite 600
* Chicago, IL 60661 USA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*     + Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*
*     + Redistributions in binary form must reproduce the above
*       copyright notice, this list of conditions and the following
*       disclaimer in the documentation and/or other materials provided
*       with the distribution.
*
*     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************/
package net.sourceforge.cruisecontrol.publishers;

import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.StringTokenizer;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.util.ValidationHelper;
import net.sourceforge.cruisecontrol.util.XMLLogHelper;
import net.sourceforge.cruisecontrol.util.Util;

import org.apache.log4j.Logger;
import org.apache.tools.ant.launch.Locator;

/**
* Used to publish an HTML e-mail that includes the build report
*
* @author Jeffrey Fredrick
* @author Alden Almagro
* @author <a href="vwiewior@valuecommerce.ne.jp">Victor Wiewiorowski</a>
*/
public class HTMLEmailPublisher extends EmailPublisher {

    private static final Logger LOG = Logger.getLogger(HTMLEmailPublisher.class);

    private String xslFile;
    private String xslDir;
    private String css;
    private String logDir;
    private String messageMimeType = "text/html";
    private String charset;

    // Should reflect the same stylesheets as buildresults.jsp in the JSP
    // reporting application
    private String[] xslFileNames =
        {
            "header.xsl",
            "buildresults.xsl"
        };

    /*
     *  Called after the configuration is read to make sure that all the mandatory parameters
     *  were specified..
     *
     *  @throws CruiseControlException if there was a configuration error.
     */
    public void validate() throws CruiseControlException {
        super.validate();

        if (logDir != null) {
            verifyDirectory("HTMLEmailPublisher.logDir", logDir);
        } else {
            LOG.debug("Using default logDir \"logs/<projectname>\"");
        }

        if (xslFile == null) {
            if (xslDir == null) {
                // try to obtain the dir relative to the current classpath
                xslDir = getXslDirFromClasspath();
            }
            verifyDirectory("HTMLEmailPublisher.xslDir", xslDir);
            if (css == null) {
                // same for css
                css = getCssFromClasspath();
            }
            verifyFile("HTMLEmailPublisher.css", css);

            String[] fileNames = getXslFileNames();
           
            if (fileNames == null) {
                throw new CruiseControlException("HTMLEmailPublisher.getXslFileNames() can't return null");
            }

            for (int i = 0; i < fileNames.length; i++) {
                String fileName = fileNames[i];
                verifyFile(
                    "HTMLEmailPublisher.xslDir/" + fileName,
                    new File(xslDir, fileName));
            }
        } else {
            verifyFile("HTMLEmailPublisher.xslFile", xslFile);
        }
    }

    /**
     * @return the absolute path where the cruisecontrol.css file is located,
     * or null if it can't be found.
     */
    private String getCssFromClasspath() {
        File cssFile = new File(getCruiseRootDir(), "reporting/jsp/webcontent/css/cruisecontrol.css");
        if (cssFile.exists()) {
            return cssFile.getAbsolutePath();
        }
        return null;
    }

    /**
     * @return the absolute path where the xsl dir is located,
     * or null if it can't be found.
     */
    private String getXslDirFromClasspath() {
        File xsl = new File(getCruiseRootDir(), "reporting/jsp/webcontent/xsl");
        if (xsl.isDirectory()) {
            return xsl.getAbsolutePath();
        }
        return null;
    }

    /**
     * @return the root directory of the running cruisecontrol installation.
     * Uses Ant's Locator.
     */
    private File getCruiseRootDir() {
        File classDir = Locator.getClassSource(getClass());
        if (classDir != null) {
            try {
                // we're probably in main/dist/cruisecontrol.jar, so three parents up
                File rootDir = classDir.getParentFile().getParentFile().getParentFile();
                if (LOG.isDebugEnabled()) {
                    LOG.debug("rootDir seems to be " + rootDir.getAbsolutePath()
                            + " (classDir = " + classDir.getAbsolutePath() + ")");
                }
                return rootDir;
            } catch (NullPointerException npe) {
                // don't know where we are, then...
                return null;
            }
        }
        return null;
    }

    private void verifyDirectory(String dirName, String dir) throws CruiseControlException {
        ValidationHelper.assertFalse(dir == null, dirName + " not specified in configuration file");
        File dirFile = new File(dir);
        ValidationHelper.assertTrue(dirFile.exists(), dirFile + " does not exist: " + dirFile.getAbsolutePath());
        ValidationHelper.assertTrue(dirFile.isDirectory(),
                dirFile + " is not a directory: " + dirFile.getAbsolutePath());
    }

    private void verifyFile(String fileName, String file) throws CruiseControlException {
        ValidationHelper.assertFalse(file == null, fileName + " not specified in configuration file");
        verifyFile(fileName, new File(file));
    }

    private void verifyFile(String fileName, File file) throws CruiseControlException {
        ValidationHelper.assertTrue(file.exists(), fileName + " does not exist: " + file.getAbsolutePath());
        ValidationHelper.assertTrue(file.isFile(), fileName + " is not a file: " + file.getAbsolutePath());
    }

    /**
     * sets the content as an attachment w/proper mime-type
     */
    protected void addContentToMessage(String htmlContent, Message msg) throws MessagingException {
        MimeMultipart attachments = new MimeMultipart();
        MimeBodyPart textbody = new MimeBodyPart();
        String contentType = getContentType();
        textbody.setContent(htmlContent, contentType);
        attachments.addBodyPart(textbody);

        msg.setContent(attachments);
    }

    String getContentType() {
        if (charset != null) {
            return messageMimeType + "; charset=\"" + charset + "\"";
        } else {
            return messageMimeType;
        }
    }


    /**
     * updates xslFileNames, based on value of xslFileList
     * If first character is +  the list is appended, otherwise
     * the list is replaced. xslFileNames is comma or space-separated
     * list of existing files, located in xslDir. These files are used,
     * in-order, to generate HTML email. If xslFileNames is not
     * specified, xslFileList remains as default.
     * if xslFile is set, this is ignored.
     */
    public void setXSLFileList(String relativePathToXslFile) {
        if (relativePathToXslFile == null || relativePathToXslFile.equals("")) {
            throw new IllegalArgumentException("xslFileList shouldn't be null or empty");
        }

        relativePathToXslFile = relativePathToXslFile.trim();
        boolean appending = relativePathToXslFile.startsWith("+");
       
        if (appending) {
            relativePathToXslFile = relativePathToXslFile.substring(1);
        }

        StringTokenizer st = new StringTokenizer(relativePathToXslFile, " ,");
        int numTokens = st.countTokens();

        int i;
        if (appending) {
            i = xslFileNames.length;
        } else {
            i = 0;
        }
        String[] newXSLFileNames = new String[i + numTokens];
        System.arraycopy(xslFileNames, 0, newXSLFileNames, 0, i);
       
        while (st.hasMoreTokens()) {
            newXSLFileNames[i++] = st.nextToken();
        }
       
        setXSLFileNames(newXSLFileNames);
    }

    /**
     * If xslFile is set then both xslDir and css are ignored. Specified xslFile
     * must take care of entire document -- html open/close, body tags, styles,
     * etc.
     */
    public void setXSLFile(String fullPathToXslFile) {
        xslFile = fullPathToXslFile;
    }

    /**
     * Directory where xsl files are located.
     */
    public void setXSLDir(String xslDirectory) {
        xslDir = xslDirectory;
    }

    /**
     * Method to override the default list of file names that will be looked
     * for in the directory specified by xslDir. By default these are the
     * standard CruseControl xsl files: <br>
     * <ul>
     *   header.xsl
     *   maven.xsl
     *   etc ...
     * </ul>
     * I expect this to be used by a derived class to allow someone to
     * change the order of xsl files or to add/remove one to/from the list
     * or a combination.
     * @param fileNames
     */
    protected void setXSLFileNames(String[] fileNames) {
        if (fileNames == null) {
            throw new IllegalArgumentException("xslFileNames can't be null (but can be empty)");
        }
        xslFileNames = fileNames;
    }

    /**
     * Provided as an alternative to setXSLFileNames for changing the list of
     * files to use.
     * @return xsl files to use in generating the email
     */
    protected String[] getXslFileNames() {
        return xslFileNames;
    }

    /**
     * Path to cruisecontrol.css.  Only used with xslDir, not xslFile.
     */
    public void setCSS(String cssFilename) {
        css = cssFilename;
    }

    /**
     * Path to the log file as set in the log element of the configuration
     * xml file.
     */
    public void setLogDir(String directory) {
        if (directory == null) {
            throw new IllegalArgumentException("logDir cannot be null!");
        }

        logDir = directory;
    }

    public void setCharset(String characterSet) {
        charset = characterSet;
    }

    /**
     * Create the message to be mailed
     *
     * @param logHelper utility object that has parsed the log files
     * @return created message; empty string if logDir not set
     */

    // TODO: address whether this should ever return null;
    // dependent also on transform(File) and createLinkLine()
    protected String createMessage(XMLLogHelper logHelper) {
        String message = "";

        File inFile = null;
        try {
            if (logDir == null) {
                // use the same default as ProjectXMLHelper.getLog()
                logDir = "logs" + File.separator + logHelper.getProjectName();
            }
            inFile = new File(logDir, logHelper.getLogFileName());
            message = transform(inFile);
        } catch (Exception ex) {
            LOG.error("error transforming " + (inFile == null ? null : inFile.getAbsolutePath()), ex);
            try {
                String logFileName = logHelper.getLogFileName();
                message = createLinkLine(logFileName);
            } catch (CruiseControlException ccx) {
                LOG.error("exception getting logfile name", ccx);
            }
        }

        return message;
    }

    protected String transform(File inFile) throws TransformerException, FileNotFoundException, IOException {
        StringBuffer messageBuffer = new StringBuffer();

        TransformerFactory tFactory = TransformerFactory.newInstance();

        if (xslFile != null) {
            File xslFileAsFile = new File(xslFile);
            appendTransform(inFile, messageBuffer, tFactory, xslFileAsFile);
        } else {
            appendHeader(messageBuffer);
            messageBuffer.append(createLinkLine(inFile.getName()));

            File xslDirectory = new File(xslDir);
            String[] fileNames = getXslFileNames();
            for (int i = 0; i < fileNames.length; i++) {
                String fileName = fileNames[i];
                File xsl = new File(xslDirectory, fileName);
                messageBuffer.append("<p>\n");
                appendTransform(inFile, messageBuffer, tFactory, xsl);
            }

            appendFooter(messageBuffer);
        }

        return messageBuffer.toString();
    }

    protected String createLinkLine(String logFileName) {
        StringBuffer linkLine = new StringBuffer("");
        String buildResultsURL = getBuildResultsURL();

        if (buildResultsURL == null) {
            return "";
        }

        int startName = logFileName.lastIndexOf(File.separator) + 1;
        int endName = logFileName.lastIndexOf(".");
        String baseLogFileName = logFileName.substring(startName, endName);
        StringBuffer url = new StringBuffer(buildResultsURL);
        if (buildResultsURL.indexOf("?") == -1) {
            url.append("?");
        } else {
            url.append("&");
        }
        url.append("log=");
        url.append(baseLogFileName);

        linkLine.append("View results here -> <a href=\"");
        linkLine.append(url);
        linkLine.append("\">");
        linkLine.append(url);
        linkLine.append("</a>");

        return linkLine.toString();
    }

    protected void appendTransform(File inFile, StringBuffer messageBuffer, TransformerFactory tFactory, File xsl)
        throws IOException, TransformerException {

        Transformer transformer = tFactory.newTransformer(new StreamSource(xsl));
        CharArrayWriter writer = new CharArrayWriter();
        try {
            transformer.transform(new StreamSource(inFile), new StreamResult(writer));
        } catch (Exception e) {
            LOG.error("error transforming with xslFile " + xsl.getName(), e);
            return;
        }
        messageBuffer.append(writer.toCharArray());
    }

    protected void appendHeader(StringBuffer messageBuffer) throws IOException {
        messageBuffer.append("<html><head>\n");
        String baseUrl = getBuildResultsURL();
        if (baseUrl != null) {
            messageBuffer.append("<base href=\"" + baseUrl + "\">\n");
        }
        messageBuffer.append("<style>\n");

        Util.appendFileToBuffer(css, messageBuffer);

        messageBuffer.append("\n</style>\n</head><body>\n");
    }

    protected void appendFooter(StringBuffer messageBuffer) {
        messageBuffer.append("\n</body></html>");
    }

}
TOP

Related Classes of net.sourceforge.cruisecontrol.publishers.HTMLEmailPublisher

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.