Package org.opoo.press.mail

Source Code of org.opoo.press.mail.OpooPressMailet

/*
* Copyright 2013 Alex Lin.
*
* 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 org.opoo.press.mail;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.Executor;
import org.apache.commons.exec.LogOutputStream;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.exec.ShutdownHookProcessDestroyer;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.apache.mailet.base.GenericMailet;
import org.opoo.press.Application;
import org.opoo.press.Site;
import org.opoo.press.SiteManager;
import org.opoo.press.SlugHelper;
import org.opoo.press.impl.ContextImpl;
import org.opoo.press.impl.PostImpl;
import org.opoo.press.impl.SiteManagerImpl;
import org.opoo.press.slug.ChineseToPinyinSlugHelper;
import org.opoo.press.source.NoFrontMatterException;
import org.opoo.press.source.Source;
import org.opoo.press.source.SourceEntry;
import org.opoo.press.source.SourceParser;
import org.opoo.press.util.LinkUtils;

/**
* Mailet for publish post by mail.
*
* @author Alex Lin
*/
public class OpooPressMailet extends GenericMailet {
  private static final Logger log = LoggerFactory.getLogger(OpooPressMailet.class);
  private static final SimpleDateFormat NAME_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm");
  private static final String[] EXTS = {".html", ".markdown", ".md", ".textile"};
 
  private ShutdownHookProcessDestroyer processDestroyer = new ShutdownHookProcessDestroyer();
  private SlugHelper slugHelper = new ChineseToPinyinSlugHelper();
  private SiteManager siteManager;
  private SourceParser sourceParser;
 
  private String execCommand;// = "mvn deploy";
  private File site;
 
  /* (non-Javadoc)
   * @see org.apache.mailet.base.GenericMailet#init()
   */
  @Override
  public void init() throws MessagingException {
    super.init();
    execCommand = getInitParameter("command", execCommand);
    String siteDir = getInitParameter("site");
   
    log.info("Site directory: " + siteDir);
    log.info("Command: " + execCommand);
   
    if(StringUtils.isBlank(siteDir)){
      throw new IllegalArgumentException("Site is required.");
    }
   
    site = new File(siteDir);
    if(!site.exists() || !site.isDirectory()){
      throw new IllegalArgumentException("Site is not a valid directory.");
    }
   
    new ContextImpl().initialize();
    siteManager = Application.getContext().getSiteManager();
    sourceParser = Application.getContext().getSourceParser();
  }
 
  private void info(PrintWriter out, String message){
    log.info(message);
    out.println(message);
  }
 
  private void warn(PrintWriter out, String message){
    log.warn(message);
    out.println("[WARN] " + message);
  }
 
  private void error(PrintWriter out, String message, Throwable e){
    log.error(message, e);
    out.println(message);
    out.println("------");
    e.printStackTrace(out);
    out.println();
    out.println();
    out.flush();
  }

  @Override
  public void service(Mail mail) throws MessagingException {
    StringWriter writer = new StringWriter();
    PrintWriter out = new PrintWriter(writer);
   
    String subject = "";
    File file = null;
    try{
      MimeMessage mm = mail.getMessage();
      subject = MimeUtility.decodeText(mm.getSubject());
      Date date = mm.getSentDate();
      String content = getTextContent(mm);
      if(content == null){
        info(out, "Can not extract plain text content in mail, skip generate and deploy OpooPress site: " + site);
        replyFailed(mail, subject, writer.toString(), null);
        return;
      }
     
      log.info("===============================");
      log.info("Subject: " + subject);
      log.info("Sent date: " + date);
      log.info("Size: " + mm.getSize());
      if(log.isDebugEnabled()){
        log.debug(content);
      }
     
      file = writeToPostFile(out, subject, content, date);
      executeCommand(out);
     
      out.flush();
      replyPublished(mail, subject, writer.toString(), file);
    } catch (Exception e) {
      error(out, e.getMessage(), e);
      replyFailed(mail, subject, writer.toString(), file);
      return;
    }
  }
 
  private void replyFailed(Mail mail, String subject, String content, File file) throws MessagingException{
    content = "Failed to publish post '" + subject + "'.\n\n========================\n" + content;
    subject = "[FAILED] " + subject;
    reply(mail, subject, content, file);
  }
 
  private void replyPublished(Mail mail, String subject, String content, File file) throws MessagingException{
    content = "Post '" + subject + "' has been published.\n\n========================\n" + content;
    subject = "[PUBLISHED] " + subject;
    reply(mail, subject, content, file);
  }
 
  private void reply(Mail mail, String subject, String content, File file) throws MessagingException{
    MailAddress recipient = mail.getRecipients().iterator().next();
    MailAddress sender = mail.getSender();
   
    Properties props = System.getProperties();
    Session session = Session.getDefaultInstance(props);
    MimeMessage message = new MimeMessage(session);
    message.setFrom(recipient.toInternetAddress());
    message.setRecipient(Message.RecipientType.TO, sender.toInternetAddress());
    message.setSubject(subject);
    message.setSentDate(new Date());
    //message.setText(content);
    setReplyMailContent(message, content, file);
   
    log.info("Reply mail: " + subject + " -> " + sender);
    getMailetContext().sendMail(message);
  }
 
  private void setReplyMailContent(MimeMessage message, String content, File file) throws MessagingException {
    if(file == null){
      message.setText(content);
    }else{
      MimeMultipart mp = new MimeMultipart();
     
      MimeBodyPart bodyPart1 = new MimeBodyPart();
      bodyPart1.setText(content);
      mp.addBodyPart(bodyPart1);
     
      BodyPart bodyPart2 = new MimeBodyPart();
      bodyPart2.setDataHandler(new DataHandler(new FileDataSource(file)));
      bodyPart2.setFileName(file.getName());
      mp.addBodyPart(bodyPart2);
     
      message.setContent(mp);
      //message.saveChanges();
    }
  }

  private File writeToPostFile(PrintWriter out, String subject, String content, Date sentDate) throws Exception {
    if(sentDate == null){
      sentDate = new Date();
    }

    String name = subject;
    String ext = null;
    String title = subject;
    if(subject.indexOf('|') > 0){
      String[] arr = StringUtils.split(subject, '|');
      if(arr.length == 2){
        title = arr[0];
        name = arr[1];
      }
    }
   
    name = slugHelper.toSlug(name);
   
    if(PostImpl.FILENAME_PATTERN.matcher(name).matches()){
      String dateString = name.substring(0, 10);
      try {
        sentDate = NAME_FORMAT.parse(dateString);
      } catch (ParseException e) {
        //throw new RuntimeException("Subject format not valid: " + subject);
        error(out, "Subject format not valid.", e);
      }
      name = name.substring(11);
    }
   
    int indexOfAny = StringUtils.indexOfAny(name, EXTS);
    if(indexOfAny > -1){
      ext = name.substring(indexOfAny);
      name = name.substring(0, indexOfAny);
    }
   
    Site siteObject = siteManager.createSite(site);
    String filename = processPostFileName(siteObject, sentDate, name, ext);
    File postFile = new File(siteObject.getSource(), filename);
   
    File tempFile = prepareTempFile(content, sentDate, title);
    FileUtils.copyFile(tempFile, postFile);
    FileUtils.deleteQuietly(tempFile);
   
    info(out, "File writen: " + postFile);

    return postFile;
  }

  private String getTextContent(Part part) throws MessagingException, IOException{
    if(part.isMimeType("text/plain")){
      return (String) part.getContent();
    }else if(part.isMimeType("multipart/*")){
      Multipart multipart = (Multipart) part.getContent()
            int count = multipart.getCount()
            for(int i = 0 ; i < count ; i++){ 
              String textContent = getTextContent(multipart.getBodyPart(i))
              if(textContent != null){
                return textContent;
              }
            } 
    }
    return null;
  }

  private static String processPostFileName(Site site, Date date, String name, String ext){
    String newPostFileStyle = site.getConfig().get(SiteManagerImpl.NEW_POST_FILE_KEY, SiteManagerImpl.DEFAULT_NEW_POST_FILE);
    Map<String,Object> map = new HashMap<String,Object>();
    map.put("name", name);
    map.put("format", ext != null ? ext.substring(1) : "markdown");
    LinkUtils.addDateParams(map, date);
    String filename = site.getRenderer().renderContent(newPostFileStyle, map);
 
    if(ext != null && !filename.endsWith(ext)){
      log.info("File name extension change: " + filename + " -> " + ext);
      filename = FilenameUtils.removeExtension(filename) + ext;
    }
   
    return filename;
  }
 
  private File prepareTempFile(String content, Date date, String title) throws Exception{
    File file = File.createTempFile("opoopress.mail.", ".post");
    FileUtils.write(file, content, "UTF-8");
   
    SourceEntry sourceEntry = new SourceEntry(file);
    List<String> metaLines = new ArrayList<String>();
    boolean hasFrontMatter = true;
    try {
      Source source = sourceParser.parse(sourceEntry);
      Map<String, Object> meta = source.getMeta();
      if(!meta.containsKey("layout")){
        metaLines.add("layout: post");
      }
      if(!meta.containsKey("date")){
        metaLines.add("date: '" + DATE_FORMAT.format(date) + "'");
      }
      if(!meta.containsKey("title")){
        metaLines.add("title: \"" + title + "\"");
      }
    } catch (NoFrontMatterException e) {
      hasFrontMatter = false;
      metaLines.add(Source.TRIPLE_DASHED_LINE);
      metaLines.add("layout: post");
      metaLines.add("date: '" + DATE_FORMAT.format(date) + "'");
      metaLines.add("title: '" + title + "'");
      metaLines.add(Source.TRIPLE_DASHED_LINE);
    }
   
    if(!metaLines.isEmpty()){
      addMetaLines(file, metaLines, hasFrontMatter);
    }
    return file;
  }
 
  private void addMetaLines(File file, List<String> metaLines, boolean hasFrontMatter) throws IOException {
    log.info("Adding front matter lines...");
    List<String> lines = FileUtils.readLines(file, "UTF-8");
    lines = new ArrayList<String>(lines);
   
    if(hasFrontMatter){
      lines.addAll(1, metaLines);
    }else{
      lines.addAll(0, metaLines);
    }
   
    FileUtils.writeLines(file, "UTF-8", lines);
  }

  private void executeCommand(final PrintWriter out) throws ExecuteException, IOException{
    if(StringUtils.isBlank(execCommand)){
      warn(out, "No command need execute.");
      return;
    }
   
    Executor executor = new DefaultExecutor();
        executor.setWorkingDirectory(site.getParentFile());

        CommandLine command = CommandLine.parse(execCommand);
       
        out.println("========================");
        info(out, String.format("Execute command: %s",  command.toString()));
        out.println("========================");
        LogOutputStream outputStream = new LogOutputStream() {
            protected void processLine(String line, int level){
                log.info(String.format("Command logged an out: %s", line));
                out.println(line);
            }
        };
        LogOutputStream errorStream = new LogOutputStream() {
            protected void processLine(String line, int level){
                log.error(String.format("Command logged an error: %s", line));
                out.println(line);
            }
        };
       
        PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream, errorStream);
        executor.setStreamHandler(streamHandler);
        executor.setProcessDestroyer(processDestroyer);
       
//        (new Thread(new Runnable(){
//            public void run(){
//                try{
//                    executor.execute(command);
//                }
//                catch(Exception e) {
//                    log.warn(String.format("Command exited with error %s", e.getMessage()));
//                }
//            }
//        })).start();
 
    executor.execute(command);
  }
}
TOP

Related Classes of org.opoo.press.mail.OpooPressMailet

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.