All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jadex.platform.service.email.EmailAgent Maven / Gradle / Ivy

Go to download

The Jadex platform package contains implementations of platform services as well as the platform component itself.

There is a newer version: 3.0.117
Show newest version
package jadex.platform.service.email;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;

import jadex.bridge.IComponentStep;
import jadex.bridge.IInternalAccess;
import jadex.bridge.SFuture;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.annotation.Service;
import jadex.bridge.service.annotation.ServiceShutdown;
import jadex.bridge.service.component.IRequiredServicesFeature;
import jadex.bridge.service.types.email.Email;
import jadex.bridge.service.types.email.EmailAccount;
import jadex.bridge.service.types.email.IEmailService;
import jadex.commons.IFilter;
import jadex.commons.future.Future;
import jadex.commons.future.IFuture;
import jadex.commons.future.IResultListener;
import jadex.commons.future.ISubscriptionIntermediateFuture;
import jadex.commons.future.ITerminationCommand;
import jadex.commons.future.SubscriptionIntermediateFuture;
import jadex.micro.IntervalBehavior;
import jadex.micro.annotation.Agent;
import jadex.micro.annotation.AgentArgument;
import jadex.micro.annotation.AgentCreated;
import jadex.micro.annotation.Argument;
import jadex.micro.annotation.Arguments;
import jadex.micro.annotation.Binding;
import jadex.micro.annotation.ComponentType;
import jadex.micro.annotation.ComponentTypes;
import jadex.micro.annotation.CreationInfo;
import jadex.micro.annotation.Imports;
import jadex.micro.annotation.ProvidedService;
import jadex.micro.annotation.ProvidedServices;
import jadex.micro.annotation.RequiredService;
import jadex.micro.annotation.RequiredServices;


/**
 *  The email agent can be used to send emails and subscribe for incoming mails.
 */
@Agent
@Service
@Imports({"jadex.bridge.service.types.email.*"})
@Arguments(
{
	@Argument(name="checkformail", description="Delay between checking for new mails.", clazz=long.class, defaultvalue="60000"),
	@Argument(name="account", clazz=EmailAccount.class, defaultvalue="new EmailAccount(\"default_account.properties\")", 
		description="The default email account that is used to send/receive emails.")
})
@ProvidedServices(@ProvidedService(type = IEmailService.class))
@RequiredServices(@RequiredService(name="emailfetcher", type=IEmailFetcherService.class, binding=@Binding(dynamic=true, scope=RequiredServiceInfo.SCOPE_NONE,
	create=true, creationinfo=@CreationInfo(type="fetcher"))))
@ComponentTypes(@ComponentType(name="fetcher", clazz=EmailFetcherAgent.class))
public class EmailAgent implements IEmailService
{
	//-------- constants --------
	
	/** Default SSL versions. */
	protected static final String	DEFAULT_SSL_VERSION;
	
	static
	{
		String	ret;
		try
		{
			SSLServerSocket ssocket = (SSLServerSocket) SSLServerSocketFactory.getDefault().createServerSocket();
			StringBuffer	buf	= new StringBuffer();
			for(String protocol: ssocket.getEnabledProtocols())
			{
				if(buf.length()>0)
				{
					buf.append(" ");
				}
				buf.append(protocol);
			}
			ret	= buf.toString();
		}
		catch(Exception e)
		{
			ret	= "TLSv1 TLSv1.1 TLSv1.2";
		}
		DEFAULT_SSL_VERSION	= ret;
	}
	
	//-------- attributes --------
	
	/** The component. */
	@Agent
	protected IInternalAccess agent;
	
	/** The delay between checking for mail. */
	@AgentArgument
	protected long checkformail;
	
	/** The email account. */
	@AgentArgument
	protected EmailAccount account;
	
	/** The receive behavior. */
	protected IntervalBehavior receive; 
	
	/** The subscriptions (subscription future -> subscription info). */
	protected Map, SubscriptionInfo> subscriptions;

	//-------- agent lifecycle methods --------
	
	/**
	 *  Called on agent start.
	 */
	@AgentCreated
	public IFuture start()
	{
//		System.out.println("email agent started");
		
		if(account==null)
		{
			try
			{
				account = new EmailAccount("default_account.properties");
			}
			catch(Exception e)
			{
			}
		}
		return IFuture.DONE;
	}
	
	/**
	 *  Called when service is shudowned.
	 */
	@ServiceShutdown
	public IFuture shutdown()
	{
		if(subscriptions!=null)
		{
			SubscriptionIntermediateFuture[] subs = subscriptions.keySet().toArray(new SubscriptionIntermediateFuture[subscriptions.size()]);
			for(int i=0; i sendEmail(Email email, EmailAccount acc)
	{
		final Future ret = new Future();
		
		if(acc==null && this.account==null)
		{
//			System.out.println("email agent send email: no account");
			ret.setException(new RuntimeException("No email account given."));
			return ret;
		}
		
		if(email.getReceivers()==null || email.getReceivers().length==0)
		{
			ret.setException(new RuntimeException("No receivers given."));
			return ret;
		}
		
//		System.out.println("email agent trying to send email");
		final EmailAccount account = acc!=null? acc: this.account;
		Properties props = account.getProperties();
		if(props.getProperty("mail.smtp.ssl.protocols")==null)
		{
			props.setProperty("mail.smtp.ssl.protocols", DEFAULT_SSL_VERSION);
		}
		if(props.getProperty("mail.smtps.ssl.protocols")==null)
		{
			props.setProperty("mail.smtps.ssl.protocols", DEFAULT_SSL_VERSION);
		}
		
		// Override account sender, if set in mail.
		if(email.getSender()!=null)
		{
			props.setProperty("mail.from", email.getSender());
		}
		else
		{
			email.setSender(account.getSender());
		}
		
//		props.put("mail.debug", "true");
		
		// Hack!!! bypass certificate check.
//		props.setProperty("mail.smtp.ssl.trust", account.getSmtpHost());

		// Todo: needed?
//		if(account.isSsl())
//		{
//			props.put("mail.smtp.socketFactory.port", ""+account.getSmtpPort());
//			props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
//		}
		
		Session sess;
		
//		System.out.println("account: auth? "+account.isNoAuthentication());
		
		if(account.isNoAuthentication())
		{
			sess = Session.getInstance(props);
		}
		else
		{
			sess = Session.getInstance(props, new Authenticator()
			{
				protected PasswordAuthentication getPasswordAuthentication()
				{
					return new PasswordAuthentication(account.getUser(), account.getPassword());
				}
			});
		}
		
//		Properties props = new Properties();
//		props.setProperty("mail.smtp.auth", "true");
//		props.setProperty("mail.smtps.auth", "true");
////		if(account.isStartTls())
//		{
//			props.put("mail.smtp.starttls.enable", "true");
//		}
////        if(account.isSsl())
////        {
//////	        props.put("mail.smtp.socketFactory.port", account.getPort());
////        	props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
////        }
//        
//		Session sess = Session.getDefaultInstance(props, null);
//		sess.setDebug(true);

		try
		{
			MimeMessage message = new MimeMessage(sess);
			message.setFrom(new InternetAddress(account.getSender()));
			if(email.getContent()!=null)
				message.setContent(email.getContent(), email.getContentType()==null? "text/plain": email.getContentType());
			if(email.getSubject()!=null)
				message.setSubject(email.getSubject());
			String[] recs = email.getReceivers();
			if(recs!=null)
			{
				for(int i=0; i subscribeForEmail(IFilter filter, EmailAccount acc)
	{
		return subscribeForEmail(filter, acc, false);
	}
	
	/**
	 *  Subscribe for email.
	 *  @param filter The filter.
	 *  @param account The email account.
	 */
	public ISubscriptionIntermediateFuture subscribeForEmail(IFilter filter, EmailAccount acc, boolean fullconv)
	{
//		final SubscriptionIntermediateFuture ret = new SubscriptionIntermediateFuture();
		final SubscriptionIntermediateFuture ret = (SubscriptionIntermediateFuture)SFuture.getNoTimeoutFuture(SubscriptionIntermediateFuture.class, agent);
		
		if(acc==null && this.account==null)
		{
			ret.setException(new RuntimeException("No email account given."));
			return ret;
		}
		
		final EmailAccount account = acc!=null? acc: this.account;
		
		ITerminationCommand tcom = new ITerminationCommand()
		{
			public void terminated(Exception reason)
			{
				removeSubscription(ret);
			}
			
			public boolean checkTermination(Exception reason)
			{
				return true;
			}
		};
		ret.setTerminationCommand(tcom);
		
		addSubscription(ret, new SubscriptionInfo(filter, account, fullconv));
		getReceiveBehavior(checkformail);
		
		return ret;
	}
	
	/**
	 *  Add a new subscription.
	 *  @param future The subscription future.
	 *  @param si The subscription info.
	 */
	protected void addSubscription(SubscriptionIntermediateFuture future, SubscriptionInfo si)
	{
		if(subscriptions==null)
			subscriptions = new LinkedHashMap, SubscriptionInfo>();
		subscriptions.put(future, si);
	}
	
	/**
	 *  Remove an existing subscription.
	 *  @param fut The subscription future to remove.
	 */
	protected void removeSubscription(SubscriptionIntermediateFuture fut)
	{
		if(subscriptions==null || !subscriptions.containsKey(fut))
			throw new RuntimeException("Subscriber not known: "+fut);
		subscriptions.remove(fut);
	}
	
	/**
	 *  Check for new emails and notify the 
	 *  corresponding subscribers.
	 */
	protected void checkForNewMails()
	{
//		System.out.println("checking for new mails");
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		agent.getLogger().info("checking for new mails: "+sdf.format(new Date(System.currentTimeMillis())));
		
		if(subscriptions!=null)
		{
			for(final SubscriptionIntermediateFuture fut: subscriptions.keySet().toArray(new SubscriptionIntermediateFuture[0]))
			{
				SubscriptionInfo si = subscriptions.get(fut);
				final long start = System.currentTimeMillis();
				IEmailFetcherService fetcher = (IEmailFetcherService)agent.getComponentFeature(IRequiredServicesFeature.class).getRequiredService("emailfetcher").get();
//				System.out.println("Email fetcher ser: "+fetcher);
				fetcher.fetchEmails(si).addResultListener(new IResultListener>()
				{
					public void resultAvailable(Collection emails) 
					{
						long dur = (System.currentTimeMillis()-start)/1000;
//						System.out.println("Needed for email fetching [s]: "+dur);
						
						if(emails!=null && emails.size()>0)
						{
							for(Email email: emails)
							{
								if(!fut.addIntermediateResultIfUndone(email))
								{
									subscriptions.remove(fut);
								}
							}
						}
					}
					
					public void exceptionOccurred(Exception exception)
					{
						agent.getLogger().warning("Email fetching error: "+exception.getMessage());
					}
				});
				
//				List emails = si.getNewEmails();
//				if(emails!=null && emails.size()>0)
//				{
//					for(Email email: emails)
//					{
//						fut.addIntermediateResult(email);
//					}
//				}
			}
		}
	}
	
	/**
	 *  Get (or create, or renew) the receive behavior.
	 */
	public IntervalBehavior getReceiveBehavior(long delay)
	{
		if(receive==null)
		{
			receive = new IntervalBehavior(agent, delay, new IComponentStep()
			{
				public IFuture execute(IInternalAccess ia)
				{
					checkForNewMails();
					return IFuture.DONE;
				}
			}, false);
		}

		// In any case invoke start to immediately check for new email
		receive.startBehavior().addResultListener(new IResultListener()
		{
			public void resultAvailable(Void result)
			{
//				System.out.println("receive ended");
			}
			
			public void exceptionOccurred(Exception exception)
			{
				System.out.println("exeception checking mail: "+exception);
//				exception.printStackTrace();
			}
		});
		
		return receive;
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy