| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.maven.plugins.announcement; |
| |
| import javax.mail.internet.AddressException; |
| import javax.mail.internet.InternetAddress; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.UnsupportedEncodingException; |
| import java.util.List; |
| |
| import org.apache.maven.model.Developer; |
| import org.apache.maven.plugin.MojoExecutionException; |
| import org.apache.maven.plugins.annotations.Execute; |
| import org.apache.maven.plugins.annotations.Mojo; |
| import org.apache.maven.plugins.annotations.Parameter; |
| import org.apache.maven.plugins.announcement.mailsender.ProjectJavamailMailSender; |
| import org.apache.maven.project.MavenProject; |
| import org.codehaus.plexus.logging.Logger; |
| import org.codehaus.plexus.logging.console.ConsoleLogger; |
| import org.codehaus.plexus.mailsender.MailMessage; |
| import org.codehaus.plexus.mailsender.MailSenderException; |
| import org.codehaus.plexus.util.IOUtil; |
| import org.codehaus.plexus.util.ReaderFactory; |
| |
| /** |
| * Goal which sends an announcement through email. |
| * |
| * @author aramirez@exist.com |
| * @version $Id$ |
| * @since 2.0-beta-2 |
| */ |
| @Mojo(name = "announcement-mail", threadSafe = true) |
| @Execute(goal = "announcement-generate") |
| public class AnnouncementMailMojo extends AbstractAnnouncementMojo { |
| // ========================================= |
| // announcement-mail goal fields |
| // ========================================= |
| |
| /** |
| * Possible senders. |
| */ |
| @Parameter(property = "project.developers", required = true, readonly = true) |
| private List<Developer> from; |
| |
| /** |
| * The id of the developer sending the announcement mail. Only used if the {@code mailSender} attribute is not set. |
| * In this case, this should match the id of one of the developers in the pom. If a matching developer is not found, |
| * then the first developer in the pom will be used. |
| */ |
| @Parameter(property = "changes.fromDeveloperId") |
| private String fromDeveloperId; |
| |
| /** |
| * Mail content type to use. |
| * |
| * @since 2.1 |
| */ |
| @Parameter(defaultValue = "text/plain", required = true) |
| private String mailContentType; |
| |
| /** |
| * Defines the sender of the announcement email. This takes precedence over the list of developers specified in the |
| * POM. if the sender is not a member of the development team. Note that since this is a bean type, you cannot |
| * specify it from command level with |
| * |
| * <pre> |
| * -D |
| * </pre> |
| * |
| * . Use |
| * |
| * <pre> |
| * -Dchanges.sender='Your Name <you@domain>' |
| * </pre> |
| * |
| * instead. |
| */ |
| @Parameter(property = "changes.mailSender") |
| private MailSender mailSender; |
| |
| /** |
| * Defines the sender of the announcement. This takes precedence over both ${changes.mailSender} and the list of |
| * developers in the POM. |
| * <p/> |
| * This parameter parses an email address in standard RFC822 format, e.g. |
| * |
| * <pre> |
| * -Dchanges.sender='Your Name <you@domain>' |
| * </pre> |
| * |
| * . |
| * |
| * @since 2.7 |
| */ |
| @Parameter(property = "changes.sender") |
| private String senderString; |
| |
| /** |
| * The password used to send the email. |
| */ |
| @Parameter(property = "changes.password") |
| private String password; |
| |
| /** |
| */ |
| @Parameter(defaultValue = "${project}", readonly = true, required = true) |
| private MavenProject project; |
| |
| /** |
| * Smtp Server. |
| */ |
| @Parameter(property = "changes.smtpHost", required = true) |
| private String smtpHost; |
| |
| /** |
| * Port. |
| */ |
| @Parameter(property = "changes.smtpPort", defaultValue = "25", required = true) |
| private int smtpPort; |
| |
| /** |
| * If the email should be sent in SSL mode. |
| */ |
| @Parameter(property = "changes.sslMode", defaultValue = "false") |
| private boolean sslMode; |
| |
| /** |
| * If the option startTls should be used. |
| * |
| * @since 2.10 |
| */ |
| @Parameter(property = "changes.startTls", defaultValue = "false") |
| private boolean startTls; |
| |
| /** |
| * Subject for the email. |
| */ |
| // CHECKSTYLE_OFF: LineLength |
| @Parameter( |
| property = "changes.subject", |
| defaultValue = "[ANNOUNCEMENT] - ${project.name} ${project.version} released", |
| required = true) |
| private String subject; |
| // CHECKSTYLE_ON: LineLength |
| |
| /** |
| * The file that contains the generated announcement. |
| * |
| * @since 2.10 |
| */ |
| @Parameter(property = "changes.announcementFile", defaultValue = "announcement.vm", required = true) |
| private String announcementFile; |
| |
| /** |
| * Directory where the generated announcement file exists. |
| * |
| * @since 2.10 |
| */ |
| @Parameter(defaultValue = "${project.build.directory}/announcement", required = true) |
| private File announcementDirectory; |
| |
| /** |
| * The encoding used in the announcement template. |
| * |
| * @since 2.10 |
| */ |
| @Parameter(property = "changes.templateEncoding", defaultValue = "${project.build.sourceEncoding}") |
| private String templateEncoding; |
| |
| /** |
| * Directory which contains the template for announcement email. |
| * |
| * @deprecated Starting with version 2.10 this parameter is no longer used. You must use |
| * {@link #announcementDirectory} instead. |
| */ |
| @Parameter |
| private File templateOutputDirectory; |
| |
| /** |
| * Recipient email address. |
| */ |
| @Parameter(required = true) |
| private List<Object> toAddresses; |
| |
| /** |
| * Recipient cc email address. |
| * |
| * @since 2.5 |
| */ |
| @Parameter |
| private List<Object> ccAddresses; |
| |
| /** |
| * Recipient bcc email address. |
| * |
| * @since 2.5 |
| */ |
| @Parameter |
| private List<Object> bccAddresses; |
| |
| /** |
| * The username used to send the email. |
| */ |
| @Parameter(property = "changes.username") |
| private String username; |
| |
| private ProjectJavamailMailSender mailer = new ProjectJavamailMailSender(); |
| |
| public void execute() throws MojoExecutionException { |
| // Fail build fast if it is using deprecated parameters |
| if (templateOutputDirectory != null) { |
| throw new MojoExecutionException("You are using the old parameter 'templateOutputDirectory'. " |
| + "You must use 'announcementDirectory' instead."); |
| } |
| |
| // Run only at the execution root |
| if (runOnlyAtExecutionRoot && !isThisTheExecutionRoot()) { |
| getLog().info("Skipping the announcement mail in this project because it's not the Execution Root"); |
| } else { |
| File file = new File(announcementDirectory, announcementFile); |
| |
| ConsoleLogger logger = new ConsoleLogger(Logger.LEVEL_INFO, "base"); |
| |
| if (getLog().isDebugEnabled()) { |
| logger.setThreshold(Logger.LEVEL_DEBUG); |
| } |
| |
| mailer.enableLogging(logger); |
| |
| mailer.setSmtpHost(getSmtpHost()); |
| |
| mailer.setSmtpPort(getSmtpPort()); |
| |
| mailer.setSslMode(sslMode, startTls); |
| |
| if (username != null) { |
| mailer.setUsername(username); |
| } |
| |
| if (password != null) { |
| mailer.setPassword(password); |
| } |
| |
| mailer.initialize(); |
| |
| if (getLog().isDebugEnabled()) { |
| getLog().debug("fromDeveloperId: " + getFromDeveloperId()); |
| } |
| |
| if (file.isFile()) { |
| getLog().info("Connecting to Host: " + getSmtpHost() + ":" + getSmtpPort()); |
| |
| sendMessage(); |
| } else { |
| throw new MojoExecutionException("Announcement file " + file + " not found..."); |
| } |
| } |
| } |
| |
| /** |
| * Send the email. |
| * |
| * @throws MojoExecutionException if the mail could not be sent |
| */ |
| protected void sendMessage() throws MojoExecutionException { |
| File file = new File(announcementDirectory, announcementFile); |
| String email = ""; |
| final MailSender ms = getActualMailSender(); |
| final String fromName = ms.getName(); |
| final String fromAddress = ms.getEmail(); |
| if (fromAddress == null || fromAddress.equals("")) { |
| throw new MojoExecutionException("Invalid mail sender: name and email is mandatory (" + ms + ")."); |
| } |
| getLog().info("Using this sender for email announcement: " + fromAddress + " < " + fromName + " > "); |
| try { |
| MailMessage mailMsg = new MailMessage(); |
| mailMsg.setSubject(getSubject()); |
| mailMsg.setContent(readAnnouncement(file)); |
| mailMsg.setContentType(this.mailContentType); |
| mailMsg.setFrom(fromAddress, fromName); |
| |
| for (Object o1 : getToAddresses()) { |
| email = o1.toString(); |
| getLog().info("Sending mail to " + email + "..."); |
| mailMsg.addTo(email, ""); |
| } |
| |
| if (getCcAddresses() != null) { |
| for (Object o : getCcAddresses()) { |
| email = o.toString(); |
| getLog().info("Sending cc mail to " + email + "..."); |
| mailMsg.addCc(email, ""); |
| } |
| } |
| |
| if (getBccAddresses() != null) { |
| for (Object o : getBccAddresses()) { |
| email = o.toString(); |
| getLog().info("Sending bcc mail to " + email + "..."); |
| mailMsg.addBcc(email, ""); |
| } |
| } |
| |
| mailer.send(mailMsg); |
| getLog().info("Sent..."); |
| } catch (MailSenderException e) { |
| throw new MojoExecutionException("Failed to send email < " + email + " >", e); |
| } |
| } |
| |
| /** |
| * Read the content of the generated announcement file. |
| * |
| * @param file the file to be read |
| * @return Return the announcement text |
| * @throws MojoExecutionException if the file could not be found, or if the encoding is unsupported |
| */ |
| protected String readAnnouncement(File file) throws MojoExecutionException { |
| try { |
| if (templateEncoding == null || templateEncoding.isEmpty()) { |
| templateEncoding = ReaderFactory.FILE_ENCODING; |
| getLog().warn("File encoding has not been set, using platform encoding '" + templateEncoding |
| + "', i.e. build is platform dependent!"); |
| } |
| |
| try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), templateEncoding)) { |
| return IOUtil.toString(reader); |
| } |
| } catch (FileNotFoundException fnfe) { |
| throw new MojoExecutionException("File not found. " + file); |
| } catch (UnsupportedEncodingException uee) { |
| throw new MojoExecutionException("Unsupported encoding: '" + templateEncoding + "'"); |
| } catch (IOException ioe) { |
| throw new MojoExecutionException("Failed to read the announcement file.", ioe); |
| } |
| } |
| |
| /** |
| * Returns the identify of the mail sender according to the plugin's configuration: |
| * <ul> |
| * <li>if the {@code mailSender} parameter is set, it is returned</li> |
| * <li>if no {@code fromDeveloperId} is set, the first developer in the list is returned</li> |
| * <li>if a {@code fromDeveloperId} is set, the developer with that id is returned</li> |
| * <li>if the developers list is empty or if the specified id does not exist, an exception is thrown</li> |
| * </ul> |
| * |
| * @return the mail sender to use |
| * @throws MojoExecutionException if the mail sender could not be retrieved |
| */ |
| protected MailSender getActualMailSender() throws MojoExecutionException { |
| if (senderString != null) { |
| try { |
| InternetAddress ia = new InternetAddress(senderString, true); |
| return new MailSender(ia.getPersonal(), ia.getAddress()); |
| } catch (AddressException e) { |
| throw new MojoExecutionException("Invalid value for change.sender: ", e); |
| } |
| } |
| if (mailSender != null && mailSender.getEmail() != null) { |
| return mailSender; |
| } else if (from == null || from.isEmpty()) { |
| throw new MojoExecutionException("The <developers> section in your pom should not be empty. " |
| + "Add a <developer> entry or set the mailSender parameter."); |
| } else if (fromDeveloperId == null) { |
| final Developer dev = from.get(0); |
| return new MailSender(dev.getName(), dev.getEmail()); |
| } else { |
| for (Developer developer : from) { |
| if (fromDeveloperId.equals(developer.getId())) { |
| return new MailSender(developer.getName(), developer.getEmail()); |
| } |
| } |
| throw new MojoExecutionException( |
| "Missing developer with id '" + fromDeveloperId + "' in the <developers> section in your pom."); |
| } |
| } |
| |
| // ================================ |
| // announcement-mail accessors |
| // ================================ |
| |
| public List<Object> getBccAddresses() { |
| return bccAddresses; |
| } |
| |
| public void setBccAddresses(List<Object> bccAddresses) { |
| this.bccAddresses = bccAddresses; |
| } |
| |
| public List<Object> getCcAddresses() { |
| return ccAddresses; |
| } |
| |
| public void setCcAddresses(List<Object> ccAddresses) { |
| this.ccAddresses = ccAddresses; |
| } |
| |
| public List<Developer> getFrom() { |
| return from; |
| } |
| |
| public void setFrom(List<Developer> from) { |
| this.from = from; |
| } |
| |
| public String getFromDeveloperId() { |
| return fromDeveloperId; |
| } |
| |
| public void setFromDeveloperId(String fromDeveloperId) { |
| this.fromDeveloperId = fromDeveloperId; |
| } |
| |
| public MailSender getMailSender() { |
| return mailSender; |
| } |
| |
| public void setMailSender(MailSender mailSender) { |
| this.mailSender = mailSender; |
| } |
| |
| public String getPassword() { |
| return password; |
| } |
| |
| public void setPassword(String password) { |
| this.password = password; |
| } |
| |
| public MavenProject getProject() { |
| return project; |
| } |
| |
| public void setProject(MavenProject project) { |
| this.project = project; |
| } |
| |
| public String getSmtpHost() { |
| return smtpHost; |
| } |
| |
| public void setSmtpHost(String smtpHost) { |
| this.smtpHost = smtpHost; |
| } |
| |
| public int getSmtpPort() { |
| return smtpPort; |
| } |
| |
| public void setSmtpPort(int smtpPort) { |
| this.smtpPort = smtpPort; |
| } |
| |
| public boolean isSslMode() { |
| return sslMode; |
| } |
| |
| public void setSslMode(boolean sslMode) { |
| this.sslMode = sslMode; |
| } |
| |
| public boolean isStartTls() { |
| return startTls; |
| } |
| |
| public void setStartTls(boolean startTls) { |
| this.startTls = startTls; |
| } |
| |
| public String getSubject() { |
| return subject; |
| } |
| |
| public void setSubject(String subject) { |
| this.subject = subject; |
| } |
| |
| public String getAnnouncementFile() { |
| return announcementFile; |
| } |
| |
| public void setAnnouncementFile(String announcementFile) { |
| this.announcementFile = announcementFile; |
| } |
| |
| public File getAnnouncementDirectory() { |
| return announcementDirectory; |
| } |
| |
| public void setAnnouncementDirectory(File announcementDirectory) { |
| this.announcementDirectory = announcementDirectory; |
| } |
| |
| public List<Object> getToAddresses() { |
| return toAddresses; |
| } |
| |
| public void setToAddresses(List<Object> toAddresses) { |
| this.toAddresses = toAddresses; |
| } |
| |
| public String getUsername() { |
| return username; |
| } |
| |
| public void setUsername(String username) { |
| this.username = username; |
| } |
| } |