/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 1999-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.gui.headless;
import java.util.Date;
import java.util.Locale;
import java.util.Properties;
import java.io.PrintWriter;
import java.io.CharArrayWriter;
import java.text.NumberFormat;
import java.text.FieldPosition;
import javax.mail.Session;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Transport;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.AddressException;
import org.geotools.util.ProgressListener;
import org.geotools.util.SimpleInternationalString;
import org.geotools.util.logging.Logging;
import org.geotools.resources.i18n.Vocabulary;
import org.geotools.resources.i18n.VocabularyKeys;
import org.opengis.util.InternationalString;
/**
* Reports progress by sending email to the specified address at regular interval.
*
* @since 2.0
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (PMO, IRD)
*/
public class ProgressMailer implements ProgressListener {
/**
* Nom de l'opération en cours. Le pourcentage sera écris à la droite de ce nom.
*/
private String description;
/**
* Langue à utiliser pour le formattage.
*/
private final Locale locale;
/**
* Session à utiliser pour envoyer des courriels.
*/
private final Session session;
/**
* Adresses des personnes à qui envoyer un rapport sur les progrès.
*/
private final Address[] address;
/**
* Laps de temps entre deux courriers électroniques informant des progrès.
* On attendra que ce laps de temps soit écoulés avant d'envoyer un nouveau courriel.
*/
private long timeInterval = 3*60*60*1000L;
/**
* Date et heure à laquelle envoyer le prochain courriel.
*/
private long nextTime;
/**
* {@code true} if the action has been canceled.
*/
private volatile boolean canceled;
private float percent;
/**
* Creates an objects reporting progress to the specified email address.
*
* @param host The server to use for sending emails.
* @param address Email adress where to send progress reports.
* @throws AddressException if the specified address use an invalid syntax.
*/
public ProgressMailer(final String host, final String address) throws AddressException {
this(Session.getDefaultInstance(properties(host)), new InternetAddress[] {
new InternetAddress(address)});
}
/**
* Creates an objects reporting progress to the specified email adresses.
*
* @param session Session to use for sending emails.
* @param address
*/
public ProgressMailer(final Session session, final Address[] address) {
this.session = session;
this.address = address;
this.locale = Locale.getDefault();
nextTime = System.currentTimeMillis();
}
/**
* Retourne un ensemble de propriétés nécessaires pour ouvrir une session.
*
* @param host Nom du serveur à utiliser pour envoyer des courriels.
*/
private static final Properties properties(final String host) {
final Properties props = new Properties();
props.setProperty("mail.smtp.host", host);
return props;
}
/**
* Returns the time laps (in milliseconds) between two emails.
*/
public long getTimeInterval() {
return timeInterval;
}
/**
* Set the time laps (in milliseconds) between two emails.
* The default value is 3 hours.
*/
public synchronized void setTimeInterval(final long interval) {
this.timeInterval = interval;
}
/**
* {@inheritDoc}
*
* @deprecated Replaced by {@link #getTask}.
*/
public String getDescription() {
return description;
}
/**
* {@inheritDoc}
*
* @deprecated Replaced by {@link #setTask}.
*/
public synchronized void setDescription(final String description) {
this.description = description;
}
/**
* {@inheritDoc}
*
* @since 2.3
*/
public void setTask(final InternationalString task) {
setDescription(task.toString());
}
/**
* {@inheritDoc}
*
* @since 2.3
*/
public InternationalString getTask() {
return new SimpleInternationalString(getDescription());
}
/**
* Envoie le message spécifié par courrier électronique.
*
* @param method Nom de la méthode qui appelle celle-ci. Cette information
* est utilisée pour produire un message d'erreur en cas d'échec.
* @param subjectKey Clé du sujet: {@link ResourceKeys#PROGRESS},
* {@link ResourceKeys#WARNING} ou {@link ResourceKeys#EXCEPTION}.
* @param messageText Message à envoyer par courriel.
*/
private void send(final String method, final int subjectKey, final String messageText) {
try {
final Message message = new MimeMessage(session);
message.setFrom();
message.setRecipients(Message.RecipientType.TO, address);
message.setSubject(Vocabulary.getResources(locale).getString(subjectKey));
message.setSentDate(new Date());
message.setText(messageText);
Transport.send(message);
} catch (MessagingException exception) {
Logging.unexpectedException(ProgressMailer.class, method, exception);
}
}
/**
* Envoie par courrier électronique un rapport des progrès.
*
* @param method Nom de la méthode qui appelle celle-ci. Cette information
* est utilisée pour produire un message d'erreur en cas d'échec.
* @param percent Pourcentage effectué (entre 0 et 100).
*/
private void send(final String method, final float percent) {
this.percent = percent;
final Runtime system = Runtime.getRuntime();
final float MEMORY_UNIT = (1024f*1024f);
final float freeMemory = system.freeMemory() / MEMORY_UNIT;
final float totalMemory = system.totalMemory() / MEMORY_UNIT;
final Vocabulary resources = Vocabulary.getResources(locale);
final NumberFormat format = NumberFormat.getPercentInstance(locale);
final StringBuffer buffer = new StringBuffer(description!=null ?
description : resources.getString(VocabularyKeys.PROGRESSION));
buffer.append(": "); format.format(percent/100, buffer, new FieldPosition(0));
buffer.append('\n');
buffer.append(resources.getString(VocabularyKeys.MEMORY_HEAP_SIZE_$1,
new Float(totalMemory)));
buffer.append('\n');
buffer.append(resources.getString(VocabularyKeys.MEMORY_HEAP_USAGE_$1,
new Float(1-freeMemory/totalMemory)));
buffer.append('\n');
send(method, VocabularyKeys.PROGRESSION, buffer.toString());
}
/**
* Send an emails saying that the operation started.
*/
public synchronized void started() {
send("started", 0);
}
/**
* Notifies progress. This method will send an email only if at least the amount
* of time specified by {@link #setTimeInterval} is ellapsed since the last email.
*/
public synchronized void progress(float percent) {
final long time = System.currentTimeMillis();
if (time > nextTime) {
nextTime = time + timeInterval;
if (percent < 1f) percent = 1f;
if (percent > 99f) percent = 99f;
send("progress", percent);
}
}
public float getProgress() {
return percent;
}
/**
* Send an emails saying that the operation finished.
*/
public synchronized void complete() {
send("complete", 100);
}
/**
* Releases any resource used by this object.
*/
public void dispose() {
}
/**
* {@inheritDoc}
*/
public boolean isCanceled() {
return canceled;
}
/**
* {@inheritDoc}
*/
public void setCanceled(final boolean canceled) {
this.canceled = canceled;
}
/**
* Send a warning by email.
*/
public synchronized void warningOccurred(final String source,
final String margin,
final String warning)
{
final StringBuffer buffer=new StringBuffer();
if (source != null) {
buffer.append(source);
if (margin != null) {
buffer.append(" (");
buffer.append(margin);
buffer.append(')');
}
buffer.append(": ");
} else if (margin != null) {
buffer.append(margin);
buffer.append(": ");
}
buffer.append(warning);
send("warningOccurred", VocabularyKeys.WARNING, buffer.toString());
}
/**
* Send an exception stack trace by email.
*/
public synchronized void exceptionOccurred(final Throwable exception) {
final CharArrayWriter buffer = new CharArrayWriter();
exception.printStackTrace(new PrintWriter(buffer));
send("exceptionOccurred", VocabularyKeys.EXCEPTION, buffer.toString());
}
}