bo.com.offercruzmail.LectorBandejaCorreo.java Source code

Java tutorial

Introduction

Here is the source code for bo.com.offercruzmail.LectorBandejaCorreo.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package bo.com.offercruzmail;

import bo.com.offercruz.bl.contratos.IUsuarioBO;
import bo.com.offercruz.bl.impl.control.FactoriaObjetosNegocio;
import bo.com.offercruzmail.contrato.IInterpretadorMensaje;
import bo.com.offercruzmail.contrato.ILectorBandejaEscuchador;
import bo.com.offercruzmail.imp.FormadorMensajes;
import bo.com.offercruzmail.imp.InterpretadorMensajeGenerico;
import bo.com.offercruzmail.utils.HojaExcelHelper;
import bo.com.offercruzmail.utils.UtilitariosMensajes;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.protocol.IMAPProtocol;
import com.sun.mail.util.MailConnectException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.UnknownHostException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.mail.Address;
import javax.mail.AuthenticationFailedException;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.FolderClosedException;
import javax.mail.IllegalWriteException;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.event.MessageCountAdapter;
import javax.mail.event.MessageCountEvent;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.search.FlagTerm;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

/**
 *
 * @author Olvinho
 */
public class LectorBandejaCorreo implements Runnable {

    private static final Logger LOG = Logger.getLogger(LectorBandejaCorreo.class.getName());

    private boolean running;
    private ILectorBandejaEscuchador listener;

    private String usuario;
    private String contrasena;
    private String hostSMTP;
    private String hostIMAP;
    private int puertoSMTP;
    private int puertoIMAP;
    private boolean conexionSegura;
    private String dominio;
    private String email;
    private final int segundos = 10;

    private Properties propiedadesMail;
    private Store store;
    private Session sesion;
    private IMAPFolder bandejaEntrada;
    private Message[] nuevosMensajes;

    private final IMAPFolder.ProtocolCommand comandoNOP;

    private Thread hiloPrincipal;
    private Thread hiloIntentoConexion;
    private Thread hiloManterConexionActiva;

    public LectorBandejaCorreo() {
        this.running = false;
        this.comandoNOP = new IMAPFolder.ProtocolCommand() {
            @Override
            public Object doCommand(IMAPProtocol imapp) throws ProtocolException {
                if (imapp != null) {
                    imapp.simpleCommand("NOOP", null);
                }
                return null;
            }
        };
        nuevosMensajes = null;
    }

    public ILectorBandejaEscuchador getListener() {
        return listener;
    }

    public void setListener(ILectorBandejaEscuchador listener) {
        this.listener = listener;
    }

    private synchronized boolean isRunning() {
        return running;
    }

    private synchronized void setRunning(boolean running) {
        this.running = running;
    }

    public void enviar() {
        try {
            Message mensajeEnviar = new MimeMessage(sesion);
            mensajeEnviar.setFrom(new InternetAddress(email));
            mensajeEnviar.addRecipient(Message.RecipientType.TO, new InternetAddress("ernesto_06_05@hotmail.com"));
            mensajeEnviar.addRecipient(Message.RecipientType.CC, new InternetAddress(email));
            mensajeEnviar.setSubject("Saludo desde java mail");
            mensajeEnviar.setText("Mensaje de correo desde java mail");
            Transport.send(mensajeEnviar);
        } catch (MessagingException ex) {
            Logger.getLogger(LectorBandejaCorreo.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void run() {
        if (listener != null) {
            listener.alIniciar();
        }
        crearHiloMantenerConexion();
        while (isRunning()) {
            FlagTerm ft = new FlagTerm(new Flags(Flags.Flag.SEEN), false);
            try {
                if (!bandejaEntrada.isOpen()) {
                    notificarEvento("Abriendo bandeja de entrada");
                    bandejaEntrada.open(Folder.READ_WRITE);
                    if (!hiloManterConexionActiva.isAlive()) {
                        crearHiloMantenerConexion();
                    }
                }
                notificarEvento("Buscando nuevos mensajes");
                Message[] mensajes;
                if (nuevosMensajes != null) {
                    mensajes = bandejaEntrada.search(ft, nuevosMensajes);
                    nuevosMensajes = null;
                } else {
                    mensajes = bandejaEntrada.search(ft);
                }
                notificarEvento("Se han encontrado " + mensajes.length + " mensaje(s) nuevos");
                int i;
                for (i = 0; i < mensajes.length; i++) {
                    Message mensaje = mensajes[i];
                    mensaje.setFlag(Flags.Flag.SEEN, true);
                    notificarEvento("..Procesando mensaje " + (i + 1) + " de " + mensajes.length);
                    procesarMensaje(mensaje);
                    notificarEvento("..Mensaje " + (i + 1) + " de " + mensajes.length + " procesado");
                }
                if (isRunning()) {
                    notificarEvento("Esperando nuevos mensajes");
                    bandejaEntrada.idle(true);
                    notificarEvento("Fin de la espera de nuevos mensajes");
                }
            } catch (IllegalWriteException ex) {
                notificarError(
                        "La bandeja no permite marcar los mensajes como no ledos, esto provocar una lectura infinita. El lector se detendr");
                break;
            } catch (FolderClosedException ex) {
                notificarEvento("La bandeja fue cerrada inesperadamente, se esperar " + segundos
                        + " segundo(s) y se volver a intentarlo");
                try {
                    Thread.sleep(segundos * 1000);
                } catch (InterruptedException ex1) {
                    notificarError(ex.getMessage());
                    break;
                }
            } catch (MessagingException ex) {
                LOG.log(Level.SEVERE, "Excepcion en el hilo principal", ex);
            }
        }
        notificarEvento("El lector se est deteniendo");

        if (hiloManterConexionActiva != null && hiloManterConexionActiva.isAlive()) {
            hiloManterConexionActiva.interrupt();
        }

        try {
            if (bandejaEntrada.isOpen()) {
                bandejaEntrada.close(false);
            }
            if (store.isConnected()) {
                store.close();
            }
        } catch (MessagingException ex) {
            LOG.log(Level.SEVERE, null, ex);
        }

        if (listener != null) {
            listener.alParar();
        }
    }

    private static final Pattern patronMail = Pattern.compile("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+");
    private IInterpretadorMensaje interprete;
    private File adjunto;

    private void procesarMensaje(Message mensaje) {
        int numeroMensaje = mensaje.getMessageNumber();
        try {
            String emailRemitente = "";
            String asunto = mensaje.getSubject();
            System.out.println(asunto);
            String remitente = mensaje.getFrom()[0].toString();
            System.out.println(remitente);
            System.out.println(mensaje.getContent());
            Matcher matcher = patronMail.matcher(remitente);
            if (matcher.find()) {
                emailRemitente = matcher.group();
            }
            if (!"".equals(emailRemitente)) {
                //Verificamos si esta registrado
                Address[] arrayFrom = { new InternetAddress(email) };
                MimeMessage respuesta;
                respuesta = (MimeMessage) mensaje.reply(false);
                respuesta.setFrom(arrayFrom[0]);
                respuesta.setReplyTo(arrayFrom);
                respuesta.addRecipient(Message.RecipientType.TO, new InternetAddress(emailRemitente));
                IUsuarioBO usuarioBO = FactoriaObjetosNegocio.getInstance().getIUsuarioBO();
                Integer idUsuario = usuarioBO.getIdUsuarioPorEmail(emailRemitente);
                if (idUsuario != null) {
                    Multipart cuerpo = procesarPorAsunto(asunto, idUsuario);
                    if (cuerpo == null) {
                        cuerpo = procesarPorAdjunto(mensaje, idUsuario);
                    }
                    respuesta.setContent(cuerpo);
                } else {
                    respuesta.setContent(FormadorMensajes.getMensajeUsuarioNoRegistrado());
                }
                notificarEvento("....Enviando respuesta");
                Transport.send(respuesta);
                notificarEvento("....La respuesta fue enviada");
                //Eliminamos archivos temporales
                if (interprete != null) {
                    for (File archivo : interprete.obtenerArchivoTemporalesCreados()) {
                        archivo.delete();
                    }
                    interprete.obtenerArchivoTemporalesCreados().clear();
                }
                if (adjunto != null) {
                    adjunto.delete();
                }
            } else {
                notificarEvento("....Imposible determinar el remitente, el mensaje ser ignorado");
            }
        } catch (MessagingException ex) {
            LOG.log(Level.SEVERE, "Error procesando mensaje #" + numeroMensaje, ex);
        } catch (IOException ex) {
            LOG.log(Level.SEVERE, "Error IO procesando mensaje #" + numeroMensaje, ex);
            notificarError(ex.getMessage());
        }
    }

    private Multipart procesarPorAsunto(String asunto, Integer idUsuario) throws MessagingException, IOException {
        asunto = corregirAsunto(asunto);
        if ("".equals(asunto)) {
            return null;
        }
        if ("ayuda".equalsIgnoreCase(asunto) || "manual".equalsIgnoreCase(asunto)
                || "help".equalsIgnoreCase(asunto)) {
            return FormadorMensajes.getMensajeUsuarioAyuda(true);
        }
        if ("reportes".equalsIgnoreCase(asunto)) {
            interprete = InterpretadorMensajeGenerico.getMapaObjetos().get("reportes");
            return interprete.interpretar();
        }
        int i = asunto.indexOf(UtilitariosMensajes.SEPERADOR_PARAMETROS);
        if (i == -1) {
            return null;
        }
        String nombreEntidad = asunto.substring(0, i);
        nombreEntidad = nombreEntidad.replace(" ", "");
        interprete = InterpretadorMensajeGenerico.getMapaObjetos().get(nombreEntidad);
        if (interprete == null) {
            return null;
        }
        asunto = asunto.substring(i + 1, asunto.length());
        interprete.setParametros(asunto);
        interprete.setLectorBandejaCorreo(this);
        interprete.setNombreEntidad(nombreEntidad);
        interprete.setIdUsuario(idUsuario);
        Multipart cuerpo;
        cuerpo = interprete.interpretar();
        return cuerpo;
    }

    private Multipart procesarPorAdjunto(Message mensaje, Integer idUsuario) throws MessagingException {
        adjunto = null;
        try {
            //No se pudo procesar por asunto, leer el adjunto si tiene
            adjunto = UtilitariosMensajes.bajarPrimerAdjunto(mensaje);
        } catch (IOException ex) {
            LOG.log(Level.SEVERE, null, ex);
            return FormadorMensajes.getMensajeUsuarioAyuda();
        }
        if (adjunto == null) {
            return FormadorMensajes.getMensajeUsuarioAyuda();
        }
        FileInputStream fis = null;
        try {

            Workbook libro;
            fis = new FileInputStream(adjunto);
            libro = WorkbookFactory.create(fis);
            Sheet hoja = libro.getSheetAt(0);
            Row fila = hoja.getRow(0);
            if (fila == null) {
                return FormadorMensajes.getMensajeUsuarioAyuda();
            }
            Cell celda = fila.getCell(0);
            if (celda == null) {
                return FormadorMensajes.getMensajeUsuarioAyuda();
            }
            String nombreEntidad = HojaExcelHelper.getValorCelda(celda).toLowerCase();
            interprete = InterpretadorMensajeGenerico.getMapaObjetos().get(nombreEntidad);
            if (interprete == null) {
                return FormadorMensajes.getMensajeUsuarioAyuda();
            }
            interprete.setLectorBandejaCorreo(this);
            interprete.setIdUsuario(idUsuario);
            interprete.setNombreEntidad(nombreEntidad);
            return interprete.interpretarHojaExcel(hoja);
        } catch (IOException | InvalidFormatException ex) {
            LOG.log(Level.SEVERE, "Error Leyendo adjunto", ex);
            return FormadorMensajes.getMensajeUsuarioAyuda();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException ex) {
                    Logger.getLogger(LectorBandejaCorreo.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    private String corregirAsunto(String asunto) {
        if (asunto == null) {
            return "";
        }

        asunto = asunto.toLowerCase().replaceAll(" ", ""); //llevamos a minusculas
        if (asunto.length() > 3) {
            if (asunto.substring(0, 3).equals("re:")) {
                asunto = asunto.substring(3, asunto.length());
            }
        } else if (asunto.length() == 3 && asunto.equals("re:")) {
            asunto = "";
        }
        return asunto.trim();
    }

    public void iniciar() {
        if (!isRunning()) {
            if ((hiloIntentoConexion != null) && (hiloIntentoConexion.isAlive())) {
                return;
            }
            leerPropiedades();
            prepararPropiedadesMail();
            crearHiloIntentoDeConexion();
        }
    }

    private void crearHiloIntentoDeConexion() {
        hiloIntentoConexion = new Thread(new Runnable() {
            @Override
            public void run() {
                String mensajeFalloEvento = "Fallo el intento de conexion";
                notificarEvento("Intentando conectarse");
                try {
                    store = sesion.getStore();
                    if (!store.isConnected()) {
                        store.connect(hostIMAP, usuario, contrasena);
                    }
                    Folder f;
                    f = store.getFolder("INBOX");
                    if (!f.exists()) {
                        notificarError("No existe la carpeta bandeja de entrada");
                        notificarEvento(mensajeFalloEvento);
                        return;
                    }
                    if (!(f instanceof IMAPFolder)) {
                        notificarError("El servidor no soporta carpetas IMAP");
                        notificarEvento(mensajeFalloEvento);
                        return;
                    }
                    bandejaEntrada = (IMAPFolder) f;
                    bandejaEntrada.open(Folder.READ_WRITE);
                    bandejaEntrada.addMessageCountListener(new MessageCountAdapter() {
                        @Override
                        public void messagesAdded(MessageCountEvent e) {
                            super.messagesAdded(e);
                            nuevosMensajes = e.getMessages();
                            notificarEvento(
                                    "Se ha detectado la llegada de " + e.getMessages().length + " mensaje(s)");
                        }
                    });
                    notificarEvento("Se ha conectado al servidor exitosamente");
                    crearHiloPrincipal();
                } catch (NoSuchProviderException ex) {
                    notificarError("El servidor no soporta conecciones IMAP");
                    notificarEvento(mensajeFalloEvento);
                } catch (AuthenticationFailedException ex) {
                    notificarError("No se pudo autenticar con el servidor, revise usuario y contrasea");
                    notificarEvento(mensajeFalloEvento);
                } catch (MailConnectException ex) {
                    if (ex.getCause() instanceof UnknownHostException) {
                        notificarError("No se encuentra el servidor IMAP '" + hostIMAP
                                + "', el servidor no existe no dispone de conexin de internet");
                    } else if (ex.getCause() instanceof ConnectException) {
                        notificarError("La conexin fue rechazada por el servidor '" + hostIMAP
                                + "', el puerto especificado '" + puertoIMAP + "' al parecer no es el correcto");
                    } else {
                        notificarError("Error de conexin: " + ex.getMessage());
                    }
                    notificarEvento(mensajeFalloEvento);
                } catch (MessagingException ex) {
                    LOG.log(Level.SEVERE, null, ex);
                    notificarError("Error inesperado al intentar conectarse: " + ex.getMessage());
                    notificarEvento(mensajeFalloEvento);
                }
            }
        }, "HiloIntentoDeConexion");
        hiloIntentoConexion.start();
    }

    private static final long MAXIMO_TIEMPO_ESPERANDO = 300000; // 5 minutos

    private void crearHiloMantenerConexion() {
        hiloManterConexionActiva = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        Thread.sleep(MAXIMO_TIEMPO_ESPERANDO);
                        notificarEvento("Tiempo de espera mximo agotado");
                        bandejaEntrada.doCommand(comandoNOP);
                    } catch (InterruptedException | FolderClosedException ex) {
                        return;
                    } catch (MessagingException ex) {
                        LOG.log(Level.SEVERE, Thread.currentThread().getName(), ex);
                    }
                }
            }
        }, "HiloMantenerConexionActiva");
        hiloManterConexionActiva.start();
    }

    private void crearHiloPrincipal() {
        setRunning(true);
        hiloPrincipal = new Thread(this, "HiloPrincipalLectorBandeja");
        hiloPrincipal.start();
    }

    private void prepararPropiedadesMail() {
        propiedadesMail = new Properties();
        String protocoloIMAP = (conexionSegura) ? "imaps" : "imap";
        propiedadesMail.setProperty("mail.store.protocol", protocoloIMAP);
        propiedadesMail.put("mail.smtp.host", hostSMTP);
        propiedadesMail.put("mail.smtp.socketFactory.port", puertoSMTP);
        if (conexionSegura) {

            propiedadesMail.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            propiedadesMail.put("mail.smtp.auth", conexionSegura + "");
            propiedadesMail.put("mail.smtp.starttls.enable", conexionSegura + "");
        }
        propiedadesMail.put("mail.smtp.port", puertoSMTP);
        if (puertoIMAP != -1) {
            propiedadesMail.put("mail." + protocoloIMAP + ".port", puertoIMAP);
        }

        sesion = Session.getDefaultInstance(propiedadesMail, new javax.mail.Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(usuario, contrasena);
            }
        });
    }

    private void leerPropiedades() {
        InputStream input = null;
        Properties prop = new Properties();
        try {
            input = new FileInputStream("config.properties");
            prop.load(input);
        } catch (FileNotFoundException | SecurityException ex) {
            LOG.log(Level.WARNING, null, ex);
            throw new RuntimeException(
                    "No se encuentra el archivo de propiedes, o no tiene permisos para leer el archivo");
        } catch (IOException ex) {
            LOG.log(Level.WARNING, null, ex);
            throw new RuntimeException("Error leyendo el archivo de propiedades: " + ex.getMessage());
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException ex) {
                }
            }
        }
        if (prop.getProperty("usuario") == null) {
            throw new RuntimeException("No se encuentra la propiedad 'usuario' en el archivo de configuracin");
        }
        if (prop.getProperty("contrasena") == null) {
            throw new RuntimeException("No se encuentra la propiedad 'contrasena' en el archivo de configuracin");
        }
        if (prop.getProperty("host.smtp") == null) {
            throw new RuntimeException("No se encuentra la propiedad 'host.smtp' en el archivo de configuracin");
        }
        if (prop.getProperty("host.imap") == null) {
            throw new RuntimeException("No se encuentra la propiedad 'host.imap' en el archivo de configuracin");
        }
        if (prop.getProperty("puerto.imap") == null) {
            puertoIMAP = -1;
        } else {
            try {
                puertoIMAP = Integer.valueOf(prop.getProperty("puerto.imap"));
            } catch (NumberFormatException e) {
                throw new RuntimeException(
                        "La propiedad 'puero.imap' del archivo de configuracin debe ser un nmero");
            }
        }

        if (prop.getProperty("puerto.smtp") == null) {
            throw new RuntimeException(
                    "No se encuentra la propiedad 'puerto.smtp' en el archivo de configuracin");
        }
        if (prop.getProperty("conexion.segura") == null) {
            throw new RuntimeException(
                    "No se encuentra la propiedad 'conexion.segura' en el archivo de configuracin");
        }
        if (prop.getProperty("dominio") == null) {
            throw new RuntimeException("No se encuentra la propiedad 'dominio' en el archivo de configuracin");
        }

        usuario = prop.getProperty("usuario");
        contrasena = prop.getProperty("contrasena");
        hostSMTP = prop.getProperty("host.smtp");
        hostIMAP = prop.getProperty("host.imap");

        try {
            puertoSMTP = Integer.valueOf(prop.getProperty("puerto.smtp"));
        } catch (NumberFormatException e) {
            throw new RuntimeException(
                    "La propiedad 'puerto.smtp' del archivo de configuracin debe ser un nmero");
        }

        conexionSegura = Boolean.valueOf(prop.getProperty("conexion.segura"));
        //conexionSegura = false;
        dominio = prop.getProperty("dominio");
        email = (usuario.contains(dominio)) ? usuario : usuario + "@" + dominio;
    }

    public void parar() {
        if (isRunning()) {
            setRunning(false);
            try {
                bandejaEntrada.doCommand(comandoNOP);
            } catch (MessagingException ex) {
                LOG.log(Level.WARNING, Thread.currentThread().getName(), ex);
            }
        }
    }

    public void notificarEvento(String texto) {
        if (listener != null) {
            listener.alRecibirEvento(texto);
        }
    }

    private void notificarError(String mensaje) {
        if (listener != null) {
            listener.alOcurrirError(mensaje);
        }
    }

    public String getEmail() {
        return email;
    }

    public Session getSesion() {
        return sesion;
    }

}