analytics

jueves, 26 de octubre de 2017

Java enviar email desde codigo ejemplo gmail



Para ver una explicación extendida de este artículo, accede a la versión ampliada.
Vamos a ver cómo enviar emails desde Java con un ejemplo muy sencillo. La dependencia que vamos a emplear podeis encontrarla aquí. Como veis, utilizaremos el paquete javax.mail. Utilizando el SMTP indicado y el PUERTO indicado, funciona correctamente para cuentas de Gmail. Aunque cuidado, es posible que haya que indicar a Gmail en las opciones de personalización que se va a emplear externamente esta cuenta, sino, quizás no nos permita utilizarla desde código.


import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

....

    public static final String USER = "...???....@gmail.com";
    public static final String PASS = ".....???....";
    public static final String HOST = "localhost";
    public static final String SMTP = "smtp.gmail.com";
    public static final String port = "465";

 public static boolean enviarMail(String from, String to, String subject, String text) {

        Properties props = new Properties();
        props.put("mail.smtp.host", SMTP);
        props.put("mail.smtp.socketFactory.port", port);
        props.put("mail.smtp.socketFactory.class",
                "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.port", port);
  
        Session session = Session.getDefaultInstance(props,
            new javax.mail.Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(USER,PASS);
                }
            });
  
        try {
  
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(from));
            message.setRecipients(Message.RecipientType.TO,
                    InternetAddress.parse(to));
            message.setSubject(subject);
            message.setText(text);
  
            Transport.send(message);
  
            System.out.println("Sent mail to "+to);
                        return true;
  
        } catch (MessagingException e) {
                    e.printStackTrace();
                        return false;
        }
    }

....

Java dispositivos de audio



Vamos a poner unas sencillas funciones que nos listarán los dispositivos de audio del sistema, para devolvernos o bien una lista de nombres del dispositivo, o bien una lista de mezcladores del sistema, (para poder después operar con ellos como proceda). No hay mucho más que explicar. Listo para un copy/paste y que sea de utilidad.

    
import java.util.ArrayList;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Line;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;

    
    public static ArrayList<String> getInputDevices(){
        
        ArrayList<String> retVal = new ArrayList<>();
        Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
        Line.Info targetDLInfo = new Line.Info(TargetDataLine.class);       

        for (int cnt = 0; cnt < mixerInfo.length; cnt++) {
            Mixer currentMixer = AudioSystem.getMixer(mixerInfo[cnt]);

            if (currentMixer.isLineSupported(targetDLInfo)) {
                retVal.add(mixerInfo[cnt].getName());                
            }            
        }
        return retVal;
    }
    

    public static ArrayList<String> getOutputDevices(){
        
        ArrayList<String> retVal = new ArrayList<>();
        Mixer.Info[] mixerInfo;
        mixerInfo = AudioSystem.getMixerInfo();        
        Line.Info sourcetDLInfo = new Line.Info(SourceDataLine.class);

        for (int cnt = 0; cnt < mixerInfo.length; cnt++) {
            Mixer currentMixer = AudioSystem.getMixer(mixerInfo[cnt]);
            if (currentMixer.isLineSupported(sourcetDLInfo)) {
                retVal.add(mixerInfo[cnt].getName());
            }
        }
        return retVal;
    }

    public static ArrayList<Mixer> getInputDevicesMixer(){
        
        ArrayList<Mixer> retVal = new ArrayList<>();
        Mixer.Info[] mixerInfo;
        mixerInfo = AudioSystem.getMixerInfo();
        Line.Info targetDLInfo = new Line.Info(TargetDataLine.class);       

        for (int cnt = 0; cnt < mixerInfo.length; cnt++) {
            Mixer currentMixer = AudioSystem.getMixer(mixerInfo[cnt]);

            if (currentMixer.isLineSupported(targetDLInfo)) {
                retVal.add(currentMixer);                
            }            
        }
        return retVal;
    }
    

    public static ArrayList<Mixer> getOutputDevicesMixer(){
        
        ArrayList<Mixer> retVal = new ArrayList<>();
        Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();        
        Line.Info sourcetDLInfo = new Line.Info(SourceDataLine.class);

        for (int cnt = 0; cnt < mixerInfo.length; cnt++) {
            Mixer currentMixer = AudioSystem.getMixer(mixerInfo[cnt]);
            if (currentMixer.isLineSupported(sourcetDLInfo)) {
                retVal.add(currentMixer);
            }
        }
        return retVal;
    }

miércoles, 23 de agosto de 2017

Spring Boot load war


Vamos a ver cómo cargar un .war ajeno a nuestro Tomcat Embebido utilizando Spring Boot.

Aquí ya veíamos como cargar Tomcat embebido con Spring Boot
Aquí vimos cómo utilizar el log de Spring Boot
Y aquí vimos cómo hacer que la conexión de Tomcat sea segura

A nuestro fichero de properties de Spring Boot le añadiremos las líneas del path y el context donde cargará el .war

war.context=/MyApp
war.path=MyApp.war

Y en nuestro código, tendremos que añadir lo siguiente

@Bean
    public EmbeddedServletContainerFactory servletContainerFactory() {
        return new TomcatEmbeddedServletContainerFactory() {

            @Override
            protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
                    Tomcat tomcat) {
                // Ensure that the webapps directory exists
                new File(tomcat.getServer().getCatalinaBase(), "webapps").mkdirs();

                try {

                    String warContext = properties.getProperty("war.context");
                    String warPath = properties.getProperty("war.path");
        
                    System.out.println("Will load " + warPath + " on " + warContext);

                    Context context = tomcat.addWebapp(warContext, new File(warPath).getAbsolutePath());
                    // Allow the webapp to load classes from your fat jar
                    context.setParentClassLoader(getClass().getClassLoader());
                } catch (ServletException ex) {
                    throw new IllegalStateException("Failed to add webapp", ex);
                }
                return super.getTomcatEmbeddedServletContainer(tomcat);
            }

        };
    }

Muy fácil no? y no hay que andar peleándose con la configuración de Tomcat. Spring Boot nos hace la gestión casi automáticamente...
Por cierto, asegúrate de tener la siguiente dependencia en tu POM de Maven

<dependency>
  <groupId>org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-jasper</artifactId>
  <version>8.5.5</version>
</dependency>

Spring Boot Key Alias



Para cargar un certificado de seguridad y poder tener un Tomcat embebido que de soporte a páginas a través de HTTPS, seguiremos los siguientes pasos.

Aquí veíamos como iniciar un Tomcat Embebido con un servicio desde Spring Boot
Y aquí veíamos cómo utilizar el logger de Spring Boot

En el fichero de application.properties de Spring Boot:


server.port=8012
server.ssl.key-store=server.pfx
server.ssl.key-store-password=mypass
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=1


De donde:
- El port es obviamente el puerto en el que se desplegará el Tomcat y dará acceso a HTTPS
- El key-store es el certificado propiamente dicho. Existen varios formatos para el certificado, en este caso hemos usado el formato PKCS12, con un certificado de extensión .pfx. Aquí tienes un convertidor de formatos de certificado que puede ayudarte.
- El keyStoreType es el formato que hemos citado anteriormente
- El keyAlias es interesante profundizar más en él. Vamos a ello


El Key Alias:


Utilizando la herramienta keytool con el siguiente comando

keytool -list -keystore server.pfx

En nuestro caso, nos muestra algo similar a esto

1, 23-ago-2017, PrivateKeyEntry,
Huella Digital de Certificado (SHA1): 44:97:7B:EB:....... etc......

Obtendremos una lista de las entradas del certificado, donde cada línea es encabezada por los alias que incluye el certificado, de manera que si solo tenemos una entrada, por regla general, ésta será un "1", pero podríamos tener otras. Conviene localizar la entrada privada ya que será la que empleemos, y ésta es la que tendremos que poner en el fichero de properties.

Finalmente, si todo va bien, accediendo a

https://localhost:8012

debería funcionar la página. (Nótese que es HTTPS)



lunes, 21 de agosto de 2017

Java evitar mensajes por consola


Java, cómo evitar que nuestra aplicación muestre mensajes por pantalla al ejecutar:


¿Y por qué querríamos no ver los mensajes? Porque en una entrega a cliente es inconcebible que se vean mensajes del tipo "hola! llego a esta funcion!, bien !" o del tipo "NullPointerException". No es presentable y pondrá en seria duda nuestra profesionalidad.


Una opción sería no poner ningún System.out y evitar que las excepciones nos muestren el mensaje, lo cual no termina de ser buena idea, ya que no nos enteraremos de qué ocurre durante la ejecución de nuestra aplicación.

La mejor opción es externalizar todos los mensajes a un fichero de Log. Realmente, ésta sería la mejor opción. Tendremos todos los sucesos guardados, ordenados, con fecha y podremos acceder a ellos posteriormente. Aquí veíamos un ejemplo de uso con Log4J

Sin embargo, hay una opción intermedia, que es capturar los stream de out y err y redirigirlos hacia buffers que no apuntan a ningún sitio. Tal como a continuación se muestra.


    ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
    PrintStream ps1 = new PrintStream(baos1);
     ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
    PrintStream ps2 = new PrintStream(baos1);
    // IMPORTANT: Save the old System.out!
    PrintStream old = System.out;
    PrintStream old2 = System.err;
    // Tell Java to use your special stream
    
    System.out.println("Starting...");
    
    System.setOut(ps1);
    System.setErr(ps2);

    System.out.println("Siguiente...");


En el ejemplo anterior, veremos por consola el mensaje de "Starting", pero el mensaje "Siguiente" ya no lo veremos.

Tomcat embebido https


Vamos a configurar Tomcat desde Java (embebido) para utilizar un certificado de seguridad y poder acceder de manera segura a las aplicaciones que despliegue nuestro Tomcat. (vía HTTPS)

En nuestra función principal o Main:
.....
                Tomcat tomcat = new Tomcat();
                tomcat = new Tomcat();
                
                Service service = tomcat.getService();
                service.addConnector(getSslConnector());

                tomcat.getHost().setAutoDeploy(true);
                tomcat.getHost().setDeployOnStartup(true);
                tomcat.start();
             
                tomcat.getServer().await();
....

La función de configuración del service de Tomcat: (en función de la extensión de nuestro certificado, la keyStoreType tomará el valor de PEM, JKS o PKCS12)


private static Connector getSslConnector() {
    Connector connector = new Connector();
    connector.setPort(8090);
    connector.setSecure(true);
    connector.setScheme("https");
    connector.setAttribute("keyAlias", "tomcat");
    connector.setAttribute("keystorePass", "password");
//    connector.setAttribute("keystoreType", "JKS");
    connector.setAttribute("keystoreType", "PEM");
//    connector.setAttribute("keystoreType", "PKCS12");
    connector.setAttribute("keystoreFile", "private.pem");
    connector.setAttribute("clientAuth", "false");
    connector.setAttribute("protocol", "HTTP/1.1");
    connector.setAttribute("sslProtocol", "TLS");
    connector.setAttribute("maxThreads", "200");
    connector.setAttribute("protocol", "org.apache.coyote.http11.Http11AprProtocol");
    connector.setAttribute("SSLEnabled", true);
    return connector;

}

Una manera más moderna de hacer esto es con Spring Boot, donde además encontraremos más tutoriales y nos dará menos problemas. Aquí y Aquí tienes otros posts relativos a Spring Boot y Tomcat.

jueves, 6 de julio de 2017

Spring Boot utilizar su logger

Vamos a ver cómo podemos utilizar el logger de Spring Boot para poder sacar nuestros mensajes de debug sin reinventar la rueda y utilizando el sistema de log de Spring Boot.
La llamada en sí misma al logger no tiene mucho de especial, se hace de la manera habitual, pero hay que hacer un par de ajustes en configuración.


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SBLogger{
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    public static void main(String[] args) throws Exception {

                // arrancar Spring Boot
                SpringApplication.run(this.getClass(), args);

                logger.debug("Sample debug message");              
logger.info("Sample info message");
logger.warn("Sample warn message");
logger.error("Sample error message");

   }
}



En nuestro fichero pom.xml, entre otras cosas, habrá que añadir lo siguiente

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.19</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-jcl</artifactId>
            <version>2.5</version>
        </dependency>



Como siempre, si no utilizamos Maven, habrá que importar las librerías a mano, entre ellas Spring Boot y las de logging que aparecen en el pom.xml anterior.
Por otro lado, habrá que tocar un poco la configuración de Spring Boot, por lo tanto, en el archivo application.properties, habrá que incluir las siguientes claves.


logging.file=my_file.log
logging.level.org.springframework.web=INFO
logging.level.guru.springframework.blogs.controllers=INFO
logging.level.org.hibernate=ERROR
log4j.logger.org.thymeleaf=DEBUG



Por cierto, si no tienes un fichero de application.properties, deberás crearlo a mano. Spring Boot lo buscará y si lo encuentra, le hará caso a la hora de arrancar. Deberás ubicarlo en /src/main/resources

Java toString en cascada para debug



Vamos a ver cómo podemos hacer el método toString a lo largo de nuestras clases de manera que nos resulte muy cómodo para debugear, sin tener que esforzarse demasiado y manteniendo el orden, cada clase contendrá su output en String adecuado y sólo el suyo. Al final, tendremos un toString() en cascada que cumplirá con dos objetivos

  1. Facilitará el debug y nos resultará muy cómodo
  2. Nos mantendrá el orden y limpieza de código

Veamos cómo conseguirlo, es muy sencillo.

Tendremos dos clases: Call y Connection. La relación entre ellas es que una Call tiene una lista de Connections.



Veamos primero la clase Connection.



public class Connection {
    
    private String phone;
    private int direction = 0;
    private String substate;

     // ... aquí irían los métodos get/set


    @Override
    public String toString() {
        return "Connection{" + "phone=" + phone + ", direction=" + direction + ", substate=" + substate + '}';
    }

    
}



Hasta aquí nada especial, simplemente, vamos a darnos cuenta de que es esencial que el toString esté representado en su lugar, es decir, la representación String de una Connection, deberá estar dentro de la clase Connection. (por motivos de orden y limpieza). Veamos la clase Call.


public class Call {
    
    private String callID="";
    private int state = 0;
    private int type = 0;
    private ArrayList<Connection> connections = new ArrayList<Connection>();
    
    
    // ... aquí irían los métodos get/set

    @Override
    public String toString() {
        String retVal = "Call{" + "callID=" + callID + ", state=" + state + ", type=" + type+"\n" ;
        for (Iterator<Connection> iterator = connections.iterator(); iterator.hasNext();) {
            Connection next = iterator.next();
            retVal+=next.toString()+"\n";
        }
        retVal+="}";
        return retVal;
    }

    
}


Si prestamos atención al método toString, ya vemos en qué va a consistir la estructura en cascada. Simplemente llamando al método toString de una Call, ya nos imprimirá toda la lista de Connections, dado que la clase Connection también implementará su propio toString, como hemos visto anteriormente.

Es muy sencillo, pero muy potente. Para objetos compuestos con varios niveles de profundidad, debugear puede terminar siendo un infierno. Con éste método, cada clase se genera su propio String de debug y al final, simplemente, llamando al toString de la clase cabeza, tendremos el debug completo de todos sus "hijos". Con poco esfuerzo y sin sacrificar la limpieza.



miércoles, 5 de julio de 2017

Java Swing cargar y ver imagen jpg en jPanel



Vamos a ver cómo abrir una imagen, copiarla en un fichero auxiliar y visualizarla en un jPanel. Esto se emplea cuando queremos por ejemplo ver un logotipo cargado desde un fichero.


  1. Primero, utilizaremos jFileChooser para hacer la selección del fichero. 
  2. Después, haremos una copia de la imagen para guardarla en un directorio de nuestro interés. (este paso es opcional)
  3. Por último, visualizaremos la imagen en un jPanel.



Esta es la función que abrirá un diálogo para seleccionar el fichero de imagen a cargar.


      final JFileChooser fc = new JFileChooser();
            int returnVal = fc.showOpenDialog(null);

            if (returnVal == JFileChooser.APPROVE_OPTION) {
                File file = fc.getSelectedFile();
                try {

                    String nombreImg = file.getName();
                    if (nombreImg.endsWith(".jpg")
                            || nombreImg.endsWith(".png")
                            || nombreImg.endsWith(".bmp")
                            || nombreImg.endsWith(".jpeg")) {

                        

                        File dest = new File(System.getProperty("user.dir") + "/" + nombreImg);
                        copyFileUsingStream(file, dest);
                        this.imagen= (dest.getName());
                        loadImage(dest.getName());

                    }

                } catch (Exception ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(null, "Error abriendo fichero");
                }

            }



A continuación, la función de copia de imagen de un origen a un destino. Este paso es solamente opcional. En el ejemplo original, me interesó guardar las imágenes que el usuario seleccionaba en un directorio.


private static void copyFileUsingStream(File source, File dest) throws IOException {
        InputStream is = null;
        OutputStream os = null;
        try {
            is = new FileInputStream(source);
            os = new FileOutputStream(dest);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = is.read(buffer)) > 0) {
                os.write(buffer, 0, length);
            }
        } finally {
            is.close();
            os.close();
        }
    }




Por último, veremos cómo cargar la imagen en un jPanel y poderla visualizar en el panel.


private void loadImage(String name) {

        try {
            String string = System.getProperty("user.dir") + "/" + name;

            ImageIcon ii = new ImageIcon((string));

            ImagePanel panel = new ImagePanel(ii.getImage()); // NOI18N
            jPanel2.add(panel, BorderLayout.CENTER);
            panel.setCustomWidth(jPanel2.getWidth());
            panel.setCustomHeight(jPanel2.getHeight());
            panel.validate();
            panel.repaint();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }




** Cabe destacar que el jPanel donde se visualizará la imagen, está con un Layout tipo BORDERLAYOUT. Por este motivo, al añadir la imagen, se tiene el parámetro BorderLayout.CENTER.


Java cómo poblar de objetos un JList



Vamos a ver un ejemplo muy simple de cómo poblar un JLIST.
Para empezar, introduciremos un jScrollPanel en la ventana y le añadiremos dentro un componente jList. Entonces, en el constructor de la ventana, llamaremos a nuestra función de poblar el jList (loadPersonas) para añadirle los elementos.


private void loadPersonas() {
        
        ArrayList<Persona> lista = new ArrayList<Persona>();
        // .... aquí añadiriamos las personas al array
        // o bien lo recuperaríamos de un fichero o una base de datos
        
        
        jList1.setModel(new AbstractListModel() {

            @Override
            public int getSize() {
                return lista.size();
            }

            @Override
            public Object getElementAt(int index) {
                return lista.get(index);
            }
        });
        
    }




Hay que tener en cuenta un detalle. En la clase Persona, deberemos sobrescribir el método toString, para que en el jList, nos aparezca lo que deseamos (en este caso, el nombre de la persona). En caso de no hacerlo, nos aparecerá el toString que la API de Java implementa por defecto heredado.



Persona.java

....

public String toString(){
     return this.nombre;
}

....


Podemos configurar la propiedad del jList de SELECTION_MODE para que tome el valor de SINGLE, de esta manera, nos aseguramos que solo se podrá seleccionar una persona de la lista.
En el momento que queramos obtener la Persona seleccionada en el jList, podremos simplemente, castear de la siguiente manera:


Persona p = (Persona)jList1.getSelectedValue();



Es fácil tratar con jList e introducirles objetos de clases propias mediante el mecanismo de sobrescribir el método toString().

martes, 4 de julio de 2017

Java Tomcat embebido



Cómo embeber un Tomcat en código Java para ser ejecutado mediante un ejecutable .jar.
Además, cargaremos una web en dicho Tomcat, la cual tendremos previamente empaquetada en un fichero.war, para que sea accesible desde el navegador una vez ejecutada la aplicación. Utilizaremos Maven, Log4j y fichero de Properties, para hacer una aplicación lo más completa posible.

Objetivo: Tener un empaquetado .jar con TODO incluido, es decir, su propio Tomcat que despliega la aplicación .war, de manera que ejecutándolo, podemos acceder a la aplicación web en nuestro navegador. A mí no me suena mal, ya que permite mayor grado de limpieza en la máquina.


A continuación, parte del fichero "pom" de Maven


<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <tomcat.version>8.5.5</tomcat.version>
    </properties>

    <dependencies>
  
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-catalina</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-util</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
  
         <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-websocket</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
  
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>
  
  
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
    
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8080</port>
                    <path>/</path>
                </configuration>
            </plugin>
    
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
      
            
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <!-- get all project dependencies -->
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <!-- MainClass in mainfest make a executable jar -->
                    <archive>
                        <manifest>
                            <mainClass>directorio.hasta.el.Main *****</mainClass>
                        </manifest>
                    </archive>

                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <!-- bind to the packaging phase -->
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
      


      
        </plugins>
    </build>



Y en el fichero de properties:

log.properties=log4j.properties
web.path=/My_App
web.war=C:\\.........\\My_App.war
web.port=8080
web.workingdir=/




El fichero log4j.properties, con la configuración de log4j para que nos escriba un fichero de log y además, nos escriba por consola:


# Root logger option
log4j.rootLogger=DEBUG, file, stdout

# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C:\\LOGS\\mylog.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n



Por último, nuestro Main:


 public static void main(String[] args) {

        Properties properties = getProperties();
        if (properties != null) {
            try {

                // carga fichero de configuracion de log
                PropertyConfigurator.configure(new FileInputStream(properties.getProperty("log.properties")));
                Logger logger = LogManager.getLogger(Main.class);                

                String mWorkingDir = properties.getProperty("web.workingdir");

                Tomcat tomcat = new Tomcat();
                tomcat = new Tomcat();
                int port = Integer.parseInt(properties.getProperty("web.port"));
                tomcat.setPort(port);
                tomcat.setBaseDir(mWorkingDir);
                tomcat.getHost().setAppBase(mWorkingDir);
                tomcat.getHost().setAutoDeploy(true);
                tomcat.getHost().setDeployOnStartup(true);

                try {
                    tomcat.start();
                } catch (LifecycleException e) {                   
                    logger.error("Tomcat could not be started: LifecycleException in Main class");
                    e.printStackTrace();
                }
                logger.debug("Tomcat started on " + tomcat.getHost());

                // Alternatively, you can specify a WAR file as last parameter in the following call e.g. "C:\\Users\\admin\\Desktop\\app.war"
                Context appContext = tomcat.addWebapp(tomcat.getHost(), properties.getProperty("web.path"), properties.getProperty("web.war"));
                logger.debug("Deployed " + appContext.getBaseName() + " as " + appContext.getBaseName());

               
                tomcat.getServer().await();
            } catch (Exception e) {
                System.out.println("Unable to start Tomcat_Embedded_War_Loader.");
                e.printStackTrace();
            }
        }

    }

public static Properties getProperties() {
        Properties prop = new Properties();
        InputStream input = null;

        try {

            input = new FileInputStream("config.properties");
            
            // load a properties file
            prop.load(input);
            

            return prop;
        } catch (IOException ex) {
            ex.printStackTrace();
            return null;
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }