/*
* Copyright (c) 2013 GigaSpaces Technologies Ltd. All rights reserved
*
* 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 beans;
import java.util.Collection;
import java.util.LinkedList;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.apache.commons.mail.MultiPartEmail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import play.Application;
import play.api.Plugin;
import play.libs.F;
import server.ApplicationContext;
import beans.config.SmtpConf;
/**
* This is a GigaSpaces mailer plugin implementation for play 2.0.
* It is based on the typesage mailer plugin and enhances it to suite our needs.
*
* In order to use it properly, you should add the following row to "play.plugins" file
* 1500:beans.GsMailerPluginImpl
*
*/
public class GsMailer implements Plugin {
private static Logger logger = LoggerFactory.getLogger( GsMailer.class );
private IMailer mockMailer;
private IMailer gsMailer;
private Application app;
public GsMailer( Application application )
{
this.app = application;
}
@Override
public void onStart()
{
try {
logger.info( "starting... " );
mockMailer = new GsMockMailer();
logger.info( "enabled {}", enabled() );
} catch ( RuntimeException e ) {
System.out.println( "e = " + e );
}
}
@Override
public void onStop()
{
logger.info( "stopping" );
}
@Override
public boolean enabled()
{
logger.info( "checking if enabled..." );
return app.configuration().getBoolean( "smtp.enabled" ) != Boolean.FALSE;
}
private IMailer getGsMailer(){
if ( gsMailer == null ){
gsMailer = new GsMailerImpl( ApplicationContext.get().conf().smtp );
}
return gsMailer;
}
private boolean isMock(){
return ApplicationContext.get().conf().smtp.mock;
}
public IMailer email()
{
return isMock() ? mockMailer : getGsMailer();
}
public static class GsMailConfiguration{
public String charset = "utf-8";
public String subject = "";
public String bodyText = "";
public String bodyHtml = "";
public Mailer from;
public Mailer replyTo;
public MailerCollection to = new MailerCollection( );
public MailerCollection cc = new MailerCollection( );
public MailerCollection bcc = new MailerCollection( );
public HeaderCollection headers = new HeaderCollection();
public GsMailConfiguration setCharset( String charset )
{
this.charset = charset;
return this;
}
public GsMailConfiguration setSubject( String subject )
{
this.subject = subject;
return this;
}
public GsMailConfiguration setBodyText( String bodyText )
{
this.bodyText = bodyText;
return this;
}
public GsMailConfiguration setBodyHtml( String bodyHtml )
{
this.bodyHtml = bodyHtml;
return this;
}
public GsMailConfiguration setFrom( String email, String name )
{
this.from = new Mailer().setEmail( email ).setName( name );
return this;
}
public GsMailConfiguration setReplyTo( Mailer replyTo )
{
this.replyTo = replyTo;
return this;
}
public GsMailConfiguration addHeader( String name, String value ){
headers.add( new Header().setName( name ).setValue( value ) );
return this;
}
public GsMailConfiguration addRecipient( RecipientType type, String email, String name){
return addRecipient( type, new Mailer().setName( name ).setEmail( email ));
}
public GsMailConfiguration addRecipient( RecipientType type, Mailer mailer ){
switch ( type ) {
case TO:
to.add( mailer );
break;
case CC:
cc.add( mailer );
break;
case BCC:
bcc.add( mailer );
break;
}
return this;
}
@Override
public String toString()
{
return "GsMailConfiguration{" +
"charset='" + charset + '\'' +
", subject='" + subject + '\'' +
", bodyText='" + bodyText + '\'' +
", bodyHtml='" + bodyHtml + '\'' +
", from=" + from +
", replyTo=" + replyTo +
", to=" + to +
", cc=" + cc +
", bcc=" + bcc +
", headers=" + headers +
'}';
}
}
public static class Header{
public String name;
public String value;
public Header setName( String name )
{
this.name = name;
return this;
}
public Header setValue( String value )
{
this.value = value;
return this;
}
}
public static abstract class CustomCollection<T>{
Collection<T> innerCollection = new LinkedList<T>( );
public void foreach( F.Function<T, ?> function ){
if ( !CollectionUtils.isEmpty( innerCollection )){
for ( T t : innerCollection ) {
try{
function.apply( t );
}catch(Throwable e){
throw new RuntimeException( "error while invoking action",e );
}
}
}
}
public void add( T ... t )
{
add( CollectionUtils.arrayToList( t ) );
}
public void add( Collection<T> t )
{
this.innerCollection.addAll( t );
}
@Override
public String toString()
{
return innerCollection.toString();
}
}
public static class HeaderCollection extends CustomCollection<Header>{
}
public static class Mailer{
public String email = null;
public String name = null;
public Mailer setEmail( String email )
{
this.email = email;
return this;
}
public Mailer setName( String name )
{
this.name = name;
return this;
}
public boolean isValid(){
return StringUtils.isNotBlank( email ) && StringUtils.isNotBlank( name );
}
@Override
public String toString()
{
return "Mailer{" +
"email='" + email + '\'' +
", name='" + name + '\'' +
'}';
}
}
private static class MailerCollection extends CustomCollection<Mailer>{ }
private static abstract class MailerAction{
abstract public void apply( Mailer mailer);
}
public static enum RecipientType{
TO, CC, BCC
}
private static class AddMailerAction implements F.Function<Mailer, Void> {
private RecipientType type;
private Email email;
private AddMailerAction( RecipientType type, Email email )
{
this.type = type;
this.email = email;
}
@Override
public Void apply( Mailer mailer )
{
try{
switch ( type ) {
case TO:
email.addTo( mailer.email, mailer.name);
break;
case CC:
email.addCc( mailer.email, mailer.name );
break;
case BCC:
email.addBcc( mailer.email, mailer.name );
break;
}
}catch(Exception e){
logger.error( String.format( "unable to apply action on mailer {}", mailer ),e );
}
return null;
}
}
public static interface IMailer{
public void send( GsMailConfiguration mailDetails );
}
public static class GsMailerImpl implements IMailer{
SmtpConf smtpConf;
public GsMailerImpl( SmtpConf conf )
{
this.smtpConf = conf;
// super( conf.getHost(), conf.getPort(), conf.isSsl(), new Some( conf.getUser() ), new Some( conf.getPassword() ) );
}
public void send( GsMailConfiguration mailDetails )
{
try {
final MultiPartEmail email = createEmailer( mailDetails.bodyText, mailDetails.bodyHtml );
email.setCharset( mailDetails.charset );
email.setSubject( mailDetails.subject );
email.setFrom( mailDetails.from.email, mailDetails.from.name );
if ( mailDetails.replyTo != null ){
email.addReplyTo( mailDetails.replyTo.email, mailDetails.replyTo.name );
}
mailDetails.to.foreach( new AddMailerAction( RecipientType.TO, email ) );
mailDetails.cc.foreach( new AddMailerAction( RecipientType.CC, email ) );
mailDetails.bcc.foreach( new AddMailerAction( RecipientType.BCC, email ) );
mailDetails.headers.foreach( new F.Function<Header, Void>() {
@Override
public Void apply( Header header ) throws Throwable
{
email.addHeader( header.name, header.value );
return null;
}
} );
email.setHostName( smtpConf.host );
email.setSmtpPort( smtpConf.port );
email.setSSL( smtpConf.ssl );
email.setTLS( smtpConf.tls );
if ( smtpConf.auth ) {
email.setAuthentication( smtpConf.user, smtpConf.password );
}
email.setDebug( smtpConf.debug );
email.send();
} catch ( Exception e ) {
// guy - we should consider adding here email recovery mechanism
throw new RuntimeException( "unable to send email", e );
}
}
/**
* Creates an appropriate email object based on the content type.
*
* @param bodyText -
* @param bodyHtml -
* @return -
*/
protected MultiPartEmail createEmailer( String bodyText, String bodyHtml ) throws EmailException
{
if ( StringUtils.isEmpty( bodyHtml ) ) {
MultiPartEmail e = new MultiPartEmail();
e.setMsg( bodyText );
return e;
} else if ( StringUtils.isEmpty( bodyText ) ) {
return new HtmlEmail().setHtmlMsg( bodyHtml );
} else {
return new HtmlEmail().setHtmlMsg( bodyHtml ).setTextMsg( bodyText );
}
}
}
public static class GsMockMailer implements IMailer{
private static Logger logger = LoggerFactory.getLogger(GsMockMailer.class);
@Override
public void send( GsMailConfiguration mailDetails )
{
logger.info( "sending email : {}" , mailDetails.toString() );
}
}
}