21 jun 2017

Nginx - Instalacion y configuracion

Introduccion


Web Server Load Balancing with NGINX Plus

Nginx es uno de los servidores web más populares del mundo y es responsable de alojar algunos de los sitios más grandes y de mayor tráfico en Internet. Es más fácil de usar que Apache en la mayoría de los casos y puede usarse como un servidor web o un proxy inverso.

Wikipedia: "nginx (pronunciado en inglés “engine X”) es un servidor web/proxy inverso ligero de alto rendimiento y un proxy para protocolos de correo electrónico (IMAP/POP3).
Es software libre y de código abierto, licenciado bajo la Licencia BSD simplificada; también existe una versión comercial distribuida bajo el nombre de nginx plus.3 Es multiplataforma, por lo que corre en sistemas tipo Unix (GNU/Linux, BSD, Solaris, Mac OS X, etc.) y Windows.
El sistema es usado por una larga lista de sitios web conocidos,5 como: WordPress, Netflix, Hulu, GitHub, Ohloh, SourceForge, TorrentReactor y partes de Facebook (como el servidor de descarga de archivos zip pesados)."

Instalacion


Dentro de Ubuntu, disponemos de su paquete oficial, por lo que la instalacion se hace bastante sencilla.


1
2
sudo apt-get update
sudo apt-get install nginx

Ajuste el Firewall


No tenemos porque tenerlo activado, en un server de produccion entiendo que sí ;), pero para nuestras pruebas locales no haría falta.
En caso de tener el FW, lo configuramos así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
sudo ufw app list

sudo ufw allow 'Nginx HTTP'

sudo ufw status


Output
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Nginx HTTP                 ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

En línea 1 sacamos la lista de reglas a aplicar.
Vemos en la línea 3 como aplicar a la parte de HTTP. Nos habrá salido también:

  • Nginx Full: Este perfil abre tanto el puerto 80 (tráfico web normal, sin cifrar) como el puerto 443 (tráfico cifrado TLS / SSL)
  • Nginx HTTP: Este perfil abre sólo el puerto 80 (normal, tráfico web no cifrado)
  • Nginx HTTPS: Este perfil abre sólo el puerto 443 (tráfico cifrado TLS / SSL)

En el status, ya podemos observar cómo queda configurado el trafico


Servicio de Nginx



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: en
   Active: active (running) since mié 2017-06-21 22:51:45 CEST; 1min 17s ago
 Main PID: 6683 (nginx)
   CGroup: /system.slice/nginx.service
           ├─6683 nginx: master process /usr/sbin/nginx -g daemon on; master_pro
           ├─6684 nginx: worker process                           
           ├─6685 nginx: worker process                           
           ├─6686 nginx: worker process                           
           ├─6687 nginx: worker process                           
           ├─6688 nginx: worker process                           
           ├─6689 nginx: worker process                           
           ├─6690 nginx: worker process                           
           └─6691 nginx: worker process   

Los comandos para trabajar con Nginx son:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
sudo systemctl stop nginx

sudo systemctl start nginx

sudo systemctl restart nginx

sudo systemctl reload nginx

sudo systemctl disable nginx

sudo systemctl enable nginx

Bastantes descriptivos todos ellos.

Estructura de Nginx


  • /etc/nginx/nginx.conf: El directorio de configuración de nginx. Todos los archivos de configuración de Nginx residen aquí.
  • /etc/nginx/nginx.conf: El archivo de configuración principal de Nginx. Esto se puede modificar para realizar cambios en la configuración global de Nginx.
  • /etc/nginx/sites-available: El directorio donde se pueden almacenar los "bloques de servidor" por sitio. Nginx no utilizará los archivos de configuración que se encuentren en este directorio a menos que estén vinculados al directorio sites-enabled (ver abajo). Normalmente, toda la configuración del bloque del servidor se realiza en este directorio y se habilita mediante la vinculación al otro directorio.
  • /etc/nginx/sites-enabled/: Se almacena el directorio donde están habilitados los "bloques de servidor" por sitio. Por lo general, estos se crean mediante la vinculación a los archivos de configuración que se encuentran en el directorio sites-available.
  • /etc/nginx/snippets: Este directorio contiene fragmentos de configuración que se pueden incluir en cualquier otro lugar de la configuración de Nginx. Los segmentos de configuración potencialmente repetibles son buenos candidatos para la refactorización en fragmentos.

Registros del Servidor



  • /var/log/nginx/access.log: Cada solicitud a su servidor web se registra en este archivo de registro a menos que Nginx esté configurado para hacerlo de otra manera.
  • /var/log/nginx/error.log: Cualquier error Nginx se registrará en este registro.

Conclusion


Como vemos, la instalación es bastante sencilla. En próximos posts, veremos más a fondo la configuración a aplicar para crear nuestro site.
Read More

Struts2 - Action (profundizando) y III

Introduccion

Tras la entradas anteriores
Struts2 - Action (profundizando)
Struts2 - Action (profundizando) II

Vamos a ver la ultima parte sobre los Actions que sería la parte de Error and Action Message


Action Error and Action Message

1. etiqueta ActionError : Esta etiqueta se utiliza en conjunción con la validación de la clase de acción para campos de formulario. Si la validación falla por cualquier campos de formulario, podemos añadir los errores de acción y luego Struts 2 reenvía la petición de “entrada” a la página de resultados en la que podemos utilizar esta etiqueta para mostrar los mensajes de error. 
Esta etiqueta es útil en la validación del lado del servidor para campos de formulario y luego volver  a la página de entrada con el mensaje de error. Sintaxis de esta etiqueta es:


2. etiqueta actionmessage: Esta etiqueta se utiliza para mostrar un mensaje personalizado añadido por las clases de acción en la página de resultados. Por ejemplo, podemos utilizar esta etiqueta para recibir a un usuario y mostrar la última hora de entrada en la parte superior de la página. 
La sintaxis de esta etiqueta es:


Ambas etiquetas generan una lista desordenada de los errores de acción o mensajes añadidos en la clase de acción.

Objetivos

Seguimos con nuestro proyecto:

Vemos que ahora tenemos un fichero global.properties


1
2
3
4
5
6
7
8
9
#global messages
msg.welcome=Hi
label.username=User Name
label.password=Password
label.submit.login=Login

#error messages
error.username.required=User Name is required field
error.password.required=Password is required field

Vemos ahora nuestro LoginModelDrivenAction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.mr.knight.struts2.action;

import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.ResultPath;
import org.apache.struts2.convention.annotation.Results;

import com.mr.knight.beans.User;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

@org.apache.struts2.convention.annotation.Action("loginModelDriven")
@Namespace("/User")
@ResultPath("/")
@Results({ @Result(name = "success", location = "homeModelDriven.jsp"),
  @Result(name = "input", location = "loginModelDriven.jsp") })
public class LoginModelDrivenAction extends ActionSupport implements Action, ModelDriven<User> {

 @Override
 public String execute() throws Exception {
  if ("jose".equals(user.getUserID()) && "admin".equals(user.getPassword())) {
   user.setUserName("Jose Caballero");
   addActionMessage("Welcome Admin, do some work.");
   return SUCCESS;
  } else {
   addActionError("User name is not valid");
   addActionError("Password is wrong");
   return INPUT;
  }
 }

 @Override
 public User getModel() {
  return user;
 }

 private User user = new User();

}


Vemos los métodos:
addActionMessage("Welcome Admin, do some work.");
addActionError("User name is not valid");

Y vemos como se representan:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%@ page language="java" contentType="text/html; charset=US-ASCII"
 pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%-- Using Struts2 Tags in JSP --%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Login Page</title>
<!-- Adding CSS for Styling of error messages -->
<style type="text/css">
.errorDiv {
 background-color: gray;
 border: 1px solid black;
 width: 400px;
 margin-bottom: 8px;
}
</style>
</head>
<body>
 <h3>Welcome User, please login below</h3>
 <s:if test="hasActionErrors()">
  <div class="errorDiv">
   <s:actionerror />
  </div>
 </s:if>
 <s:form action="loginModelDriven">
  <s:textfield name="userID" label="User Name"></s:textfield>
  <s:textfield name="password" label="Password" type="password"></s:textfield>
  <s:submit value="Login"></s:submit>
 </s:form>
</body>
</html>



Con esto termino la serie de 3 posts sobre las Action class de Struts2.
Para el lector queda el profundizar en estos temas, y enlazarlo con la parte del Backen final, bien con conexiones a servicios REST, o con una conexión a BD directamente.
Read More

Struts2 - Action (profundizando) II

Introducción


Ya hemos visto en el anterior post un poco de teoría
Struts2 - Action (profundizando)

Vamos a ver ahora un par de ejemplos, con las aproximaciones que hace Struts2 para el manejo de la info que viaja en la app. Es decir, esos Beans que se manejan en la aplicación, querremos usarlos de una u otra manera.
Las dos aproximaciones que tenemos son:
1. Object-backed action classes
2. ModelDriven action classes


Objetivo


Nuestro proyecto debe quedar algo por estilo. Recuerda que siempre lo tienes disponible desde mi enlace a GitHub.


Bean


Como hemos dicho, lo primero es que la información viaje a través de la aplicación, para lo cual vamos a hacer uso de un Bean de usuario.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.mr.knight.beans;

public class User {
 private String userID;
 private String password;
 private String userName;

 public String getUserID() {
  return userID;
 }

 public void setUserID(String userID) {
  this.userID = userID;
 }

 public String getPassword() {
  return password;
 }

 public void setPassword(String password) {
  this.password = password;
 }

 public String getUserName() {
  return userName;
 }

 public void setUserName(String userName) {
  this.userName = userName;
 }
}

Primera aproximación. Object-backed Action Class


Vamos a ver las modificaciones que debemos realizar.
Lo primero es fijarnos que debemos una variable para manejar el Bean.

LoginObjectBackedAction.java


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.mr.knight.struts2.action;

import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.ResultPath;
import org.apache.struts2.convention.annotation.Results;

import com.mr.knight.beans.User;
import com.opensymphony.xwork2.Action;

@org.apache.struts2.convention.annotation.Action("loginObject")
@Namespace("/User")
@ResultPath("/")
@Results({ @Result(name = "success", location = "homeObject.jsp"),
  @Result(name = "input", location = "loginObject.jsp") })
public class LoginObjectBackedAction implements Action {

 @Override
 public String execute() throws Exception {
  if ("jose".equals(getUser().getUserID()) && "admin".equals(getUser().getPassword())) {
   getUser().setUserName("Jose Caballero");
   return SUCCESS;
  } else {
   return INPUT;
  }
 }

 private User user;

 public User getUser() {
  return user;
 }

 public void setUser(User user) {
  this.user = user;
 }

}

A nivel de la vista, debemos referenciar esa misma variable, para aunque mal dicho, "inyectárselo" al JSP.

loginObject.jsp


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<%@ page language="java" contentType="text/html; charset=US-ASCII"
    pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Login Page</title>
</head>
<body>
    <h3>Welcome User, please login below</h3>
    <s:form action="loginObject">
        <s:textfield name="user.userID" label="User Name"></s:textfield>
        <s:textfield name="user.password" label="Password" type="password"></s:textfield>
        <s:submit value="Login"></s:submit>
    </s:form>
</body>
</html>

Vemos como para hacer referencia al Bean User, lo marcamos como tal, y luego referenciamos sus propiedades.

Segunda aproximación. ModelDriven Action Class


Para las Action ModelDriven, tenemos que implementar com.opensymphony.xwork2.ModelDriven. Esta interfaz es de tipo parametrizado utilizando genéricos de Java y necesitamos proporcionar el tipo como nuestra de la clase bean. La interfaz ModelDriven  contiene sólo un método getModel () que necesitamos para implementar y devolver el Bean.

El otro punto importante a destacar es que el Action debe tener una variable de nivel de clase para el bean y necesitamos crear una instancia.
Esto se ve mejor con un ejemplo:

LoginModelDrivenAction.java


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.mr.knight.struts2.action;

import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.ResultPath;
import org.apache.struts2.convention.annotation.Results;

import com.mr.knight.beans.User;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

@org.apache.struts2.convention.annotation.Action("loginModelDriven")
@Namespace("/User")
@ResultPath("/")
@Results({ @Result(name = "success", location = "homeModelDriven.jsp"),
  @Result(name = "input", location = "loginModelDriven.jsp") })
public class LoginModelDrivenAction extends ActionSupport implements Action, ModelDriven<User> {

 @Override
 public String execute() throws Exception {
  if ("jose".equals(user.getUserID()) && "admin".equals(user.getPassword())) {
   user.setUserName("Jose Caballero");
   addActionMessage("Welcome Admin, do some work.");
   return SUCCESS;
  } else {
   addActionError("User name is not valid");
   addActionError("Password is wrong");
   return INPUT;
  }
 }

 @Override
 public User getModel() {
  return user;
 }

 private User user = new User();

}

loginModelDriven.jsp


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%@ page language="java" contentType="text/html; charset=US-ASCII"
 pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%-- Using Struts2 Tags in JSP --%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Login Page</title>
<!-- Adding CSS for Styling of error messages -->
<style type="text/css">
.errorDiv {
 background-color: gray;
 border: 1px solid black;
 width: 400px;
 margin-bottom: 8px;
}
</style>
</head>
<body>
 <h3>Welcome User, please login below</h3>
 <s:if test="hasActionErrors()">
  <div class="errorDiv">
   <s:actionerror />
  </div>
 </s:if>
 <s:form action="loginModelDriven">
  <s:textfield name="userID" label="User Name"></s:textfield>
  <s:textfield name="password" label="Password" type="password"></s:textfield>
  <s:submit value="Login"></s:submit>
 </s:form>
</body>
</html>

homeModelDriven.jsp


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<%@ page language="java" contentType="text/html; charset=US-ASCII"
 pageEncoding="US-ASCII"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Welcome Page</title>
<style type="text/css">
.welcome {
 background-color: green;
 border: 1px solid black;
 width: 400px;
}

//
ul.actionMessage is added by Struts2 API 
ul.actionMessage li {
 color: yellow;
}
</style>
</head>
<body>
 <h3>Example msg</h3>
 <s:if test="hasActionMessages()">
  <div class="welcome">
   <s:actionmessage />
  </div>
 </s:if>
 <br>
 <br>
 <s:property value="getText('msg.welcome')" />
 <s:property value="userName" />
</body>
</html>


Como podemos ver, es más cómodo no referencias a la variable del Action que tenemos con el Bean. Nos independiza un poco más del hecho de que sea uno u otro objeto el que la maneje.


Resumen


Si nos fijamos en ambos enfoques, el enfoque ModelDriven es fácil de implementar y mantener, ya que no requiere cambios en las páginas JSP.
Ahora cada cual...


Read More

20 jun 2017

Struts2 - Action (profundizando)

Introduccion


En los anteriores posts de la serie de artículos sobre Struts2, comentamos que Struts2, se centra, al igual que su antecesor, en el patrón MVC.

Recordamos la imagen. Y vemos como los Actions, son la parte de la C del MVC.

Vamos a ver que aproximaciones tenemos, y qué más podemos hacer con ellos.

Action


Un action, vamos a ponernos a muy alto nivel, se encarga de ser la parte "frontal" de la aplicación, es decir, la parte encargada de manejar la Request.

Action - Tareas


1. Contiene la logica de negocio. Obviamente, si esta es muy grande, lo más lógico es apoyarse en Helpers classes para integrarlas posteriormente en el Action.
2. Trasnporta los datos. Luego veremos, que podremos mapear los Beans directamente, y podremos gestionar las peticiones a través de Struts, incluyendo esos datos que vienen de la vista.
3. Determinar el resultado. Para ello hemos visto que podemos tener SUCCESS, ERROR, INPUT, etc...

Tipos de Action

Tipo 1. Simple.

  En este caso, simplemente ejecutamos el método execute(), y prácticamente se convierte en una redirección.

Tipo 2. Implementing Action interface. 

  Aqui ya tenemos más juego, puesto que nos permite tener algunas constantes para ofrecer el resultado (SUCCESS, ERROR, NONE, INPUT and LOGIN).

Tipo 3. Using Struts 2 Annotations.

  Podemos crear una clase Action, haciendo uso de anotaciones. Algo bastante potente, y que nos permite tener el código ordenado.

Tipo 4. Extender ActionSupport Class. 

  Con esta extension, podemos acceder todo el tema de Validation y soporte para i18n.


Read More

18 jun 2017

Struts2 - construyendo la aplicacion III

Objetivos


Resultado de imagen de log4j

Añadiremos un sistema de Loggin a nuestra aplicacion.

1. Introducción


Log4j es una librería adicional de java que permite a nuestra aplicación mostrar mensajes de información de lo que está sucediendo en ella, lo que habitualmente se conoce como un log. Tiene la ventaja de ser dinámico y, por tanto, configurable.

2. Configuración


Una de las ventajas de Log4j es que es configurable a través de un fichero, bien un properties o un xml.
En nuestro caso lo colocaremos en la carpeta de Resources.

3. Niveles de Log o Traza



  • trace() El menos importante, que se suele usar en la fase de desarrollo. Es el típico System.out.println(“paso por aquí”).
  • debug() Información útil para depurar. Algún resultado parcial, el valor de alguna variable, etc.
  • info() Información sobre la aplicación que pueden tener cierto interés para ser mostrados en el log. Se establece una conexión con base de datos, se conecta un cliente a nuestro servidor, un usuario entra en sesión, se guarda la sesión en base de datos, etc.
  • warn() Advertencias o fallos sin importancia para la ejecución del programa. Un usuario introduce una contraseña errónea, un fichero de configuración no existe y la aplicación coge la configuración por defecto que se establezca en el código, etc.
  • error() Errores importantes, pero que no obligan a terminar la aplicación. No se puede conectar a la base de datos pero hay ciertas funcionalidades que sí pueden seguir ofreciéndose, aun sin base de datos.
  • fatal() Errores que obligan a terminar la aplicación. Se acaba la memoria disponible.


4. Fichero de configuración


Es lo más importante, porque un sistema muy cargado de Logs "no sirve de nada", cuidado con esta afirmación, hay ahora mismo procesos en Big Data que darían mucho juego.
El caso es que estamos haciendo trabajar a la máquina (no deja de ser una escritua en disco, lo más costoso a no ser que hablemos de SSD), por lo tanto debemos se cautelosos con este tema.
Un fichero básico podría ser:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">
 
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
     
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
       <layout class="org.apache.log4j.PatternLayout"> 
          <param name="ConversionPattern" value="%d %-5p %c.%M:%L - %m%n"/> 
       </layout> 
    </appender>
  
    <!-- specify the logging level for loggers from other libraries -->
    <logger name="com.opensymphony">
        <level value="DEBUG" />
    </logger>
 
    <logger name="org.apache.struts2">
         <level value="DEBUG" />
    </logger>
    <logger name="com.mr.knight.struts2">
         <level value="DEBUG" />
    </logger>   
   <!-- for all other loggers log only info and above log messages -->
     <root>
        <priority value="INFO"/> 
        <appender-ref ref="STDOUT" /> 
     </root> 
     
</log4j:configuration>

5. Para hacerlo funcionar


Añadimos la dependencia MAVEN en el pom.xml

Generamos el logger y lo usamos

LoginAction.java:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import org.apache.log4j.Logger;

....


public class LoginAction {
 final static Logger logger = Logger.getLogger(LoginAction.class);


.....

 public String execute() throws Exception {
  logger.debug("Execute");
  if ("jose".equals(getName()) && "admin".equals(getPwd())) {
   logger.debug("Success");
   return "SUCCESS";
  } else {
   logger.debug("Error validating");
   return "INPUT";
  }
 }

6. Resultado



1
2
3
4
5
6
7
8
jun 18, 2017 10:47:42 AM org.apache.catalina.startup.Catalina start
INFORMACIÓN: Server startup in 2184 ms
2017-06-18 10:48:03,746 DEBUG com.mr.knight.struts2.action.LoginAction.execute:26 - Execute
2017-06-18 10:48:03,749 DEBUG com.mr.knight.struts2.action.LoginAction.execute:31 - Error validating
2017-06-18 10:48:05,698 DEBUG com.mr.knight.struts2.action.LoginAction.execute:26 - Execute
2017-06-18 10:48:05,699 DEBUG com.mr.knight.struts2.action.LoginAction.execute:31 - Error validating
2017-06-18 10:48:21,467 DEBUG com.mr.knight.struts2.action.LoginAction.execute:26 - Execute
2017-06-18 10:48:21,468 DEBUG com.mr.knight.struts2.action.LoginAction.execute:28 - Success


Quedaría pendiente, el migrarlo a log4j2


Recuerda, tienes que hacer commit ;)
Read More

17 jun 2017

Struts2 - validaciones

Objetivo


Si queremos validar formularios desde Struts, algo util pero que de cara a UX pues no te sabría decir. Hay cientos (uy cientos!!! ) de artículos al respecto.
Yo soy de la manera de pensar que la validacion, debe ser por un lado "transparente" al usuario, es decir, no debe repetir todos los campos, es más, no debería repetir ninguno. Pero también es cierto que debemos medir cuidadosamente la seguridad del site.
En ese equilibrio, residirá el éxito. Si el usuario se "aburre" de rellenar campos, y además, le estamos fastidiando con validaciones, pues vamos apañados para que vuelva a venir.
Ahora bien, resulta que solemos pensar como lo que somos, developers, y claro, ahí es donde nos entran las dudas, somos cómodos y queremos hacer una validación estricta pero fácil de programar, etc. Pues señores, va a ser que no, los usuarios quieren (queremos ¿O no somos usuarios nosotros mismos?) algo sencillo, pero que se sientan seguros, por lo que nos tocará bajar al nivel que corresponda y hacer las cosas lo mejor posible, pero recordad "lo bueno es enemigo de lo mejor, y este a su vez de lo perfecto".

1. ¿Que necesitamos?


Pues poca cosa:
import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;

....

@Action(value = "login", results = {
        @Result(name = "SUCCESS", location = "welcome.jsp"),
        @Result(name = "ERROR", location = "error.jsp"),
        @Result(name = "INPUT", location = "login.jsp")})

....

 @RequiredStringValidator(message = "Please enter VALID NAME.")
 public void setName(String name) {
  this.name = name;
 }

 @RequiredStringValidator(message = "Please enter your PASS.")
 public void setPwd(String pwd) {
  this.pwd = pwd;
 }

Hemos añadido un validator, uno de los que hay, repito eso de bajar al nivel que deseemos.
¿Dónde lo hemos puesto? Pues donde se rellena el dato, en el SET

2. ¿Y donde nos manda?

Ahí está el único detalle. Lo debemos redirigir a la misma página que teníamos, es decir a la de login.jsp, y lo va a hacer "magicamente" a través del resultado INPUT, el cual debemos mapear.

3. ¿Ya está?


Pues no, porque debemos indicar en el JSP lo que necesitamos validar.


1
2
3
4
5
 <s:form action="login" method="post" validate="true">
  <s:textfield name="name" label="User Name"></s:textfield>
  <s:textfield name="pwd" label="Password" type="password"></s:textfield>
  <s:submit value="Login"></s:submit>
 </s:form>

Y si ahora nos fijamos, tenemos el VALIDATE a true.

4. ¿Ahora sí?


Ahora podemos probar a dejar en blanco la PASS y/o el USER, pero depende de la lógica que demos en el EXECUTE() validaremos el contenido. Es decir, esto nos valida el campo, pero no que lo hayamos puesta sea lo que necesitemos.


Read More

Struts2 - construyendo la aplicacion II

Objetivos
Vamos a ver como se organiza internamente a nivle de rutas y a nivel de contexto una aplicacion en Struts2.
Como siempre en aplicaciones JEE, las configuraciones no son nada intuitivas, y nos conviene preguntar a el sabelotodo Google sobre la cuestion de como es la estructura de un proyecto JEE. En este punto hay que tener cuidado con la sobreinformación y qué debemos elegir.
Yo no voy a entrar a discutirlo, si no a ver qué podemos encontrarnos y como se traduce.

1. Introdución

Partimos de los posts anteriores (Struts2 - construyendo la aplicacion).
Lo habíamos dejado en la parte que añadíamos las Anotaciones, y también habíamos visto que es lo mismo que usar el XML.

2. ¿De qué hablamos?

Vale más una imagen que mil palabras que decía aquel.
namespace map url

Conceptos a entender:
- Servlet Context: aunque me podéis arrear pero bien, pero vamos a decir que es el "nombre de la app", realmente no, pero para que nos entendamos.
- namespace: Lo definimos nosotros, y nos permite tener una cierta lógica y orden en la url en sí misma.
- Struts Action: pues eso.

3. ¿Cómo se traduce?

Pues de la siguiente manera:

@Namespaces(value={@Namespace("/User")})
@Result(location="/User/login.jsp")
@Actions(value={@Action(""),@Action("home")})

El namespace lo definimos nosotros, y nos definirá la manera de "llamar" a la url.
Vemos que ahora ponemos el @Result, y diremos: "aaahhhh claro! Coincide", pues sí y no.
Sí coincide, pero uno referencia al Disco y otro a la URL.
¿Y pueden coincidir?
Pues también sí y no.
*"Jose nos está liando".
Pues sí puede coincidir, siempre que sigamos la convención de Struts2 y coloquemos todo bajo:
 “WEB-INF/content/”.

¿Y entonces ...? Mi aplicación no la quiero ahí
Pues el workaround que te puedo decir que en mi caso funciona es:

import org.apache.struts2.convention.annotation.Result;
@ResultPath


@Namespaces(value={@Namespace("/User")})
@ResultPath(value="/")
@Result(location="login.jsp")
@Actions(value={@Action(""),@Action("home")})
public class HomeAction extends ActionSupport{

}

Y ahora sí. Ya tenemos la URL como queremos y las carpetas como nos de la gana:
http://localhost:8080/MiAppStruts2/User/home.action




Y si ya sabemos esto, podemos resumirlo, y en el siguiente proyecto ya lo tenemos. Volvemos a nuestro struts.xml, y ponemos este contenido (como estamos usando anotaciones podemos quitar el resto):


1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.convention.result.path" value="/"></constant>
</struts>


4. ¿Y qué más?

Pues bien, hasta aquí la parte de saber donde se encuentra cada cosa. Como sabemos de lo que más cuesta es sentarnos en nuestro puesto el primer día de proyecto, y saber de qué estamos hablando.
Espero que esto os ayude a localizar rápidamente las cosas.

Y no os olvidéis de hacer commit!

Read More

Struts2 - construyendo la aplicacion

Objetivos


En esta serie de POSTs vamos a dejar preparado el entorno, para que simplemente nos dediquemos a desarrollar sobre Struts2.
Vamos a abarcar las anotaciones, enlace con GIT, Paginas de resultados, etc.

1. Introducción


Como comentaba en el anterior post (Struts - Start Project) hay varias maneras de hacer o referenciar a Struts2. Estas podríamos resumirlas en:
1. struts.xml
2. Por nomenclatura de las clases (sufijos)
3. Anotaciones

No te voy a decir cual es mejor o peor, porque dependerá de la estructura del proyecto en sí misma. Lo que sí debes pensar siempre, en que en los equipos de trabajos, que suelen ser grandes, cuanto más doc implícita haya, mejor para el equipo. El tema de la doc da para otro post al completo, y no nos pondríamos de acuerdo nunca.


2. Configuracion de Anotations


Vamos a dar por hehco, que hemos seguido el anterior post y tenemos la aplicación tal cual estaba.

Paso 1.

Vamos a "eliminar", yo nunca hago borrados físicos, siempre es mejor hacer copias de seguridad y renombrados.

$ cp struts.xml struts.xml.bck


Paso 2.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>MiAppStruts2</display-name>
  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    <init-param>
      <param-name>actionPackages</param-name>
      <param-value>com.mr.knight.struts2.actions</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

Si nos fijamos estamos diciendole a Struts que los Actions los busque en ese paquete.

Paso 3.


Tenemos que editar las classes y añadir lo necesario para las anotaciones:.
HomeAction.java

package com.mr.knight.struts2.action;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Actions;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Namespaces;
import org.apache.struts2.convention.annotation.Result;

import com.opensymphony.xwork2.ActionSupport;
/**
 * An empty class for default Action implementation for:
 * 
 *  
 *      /login.jsp
 *  
 * HomeAction class will be automatically mapped for home.action
 * Default page is login.jsp which will be served to client
 * @author jf
 *
 */

@Namespaces(value={@Namespace("/User"),@Namespace("/")})
@Result(location="/login.jsp")
@Actions(value={@Action(""),@Action("home")})
public class HomeAction extends ActionSupport{

}



Vemos que la nomenclatura es autoexplicativa. Y si volvemos a abrir el Struts.xml (ves como no tenías que haberlo borrado ;) ), te darás cuenta que es prácticamente igual.

Paso 4.


Vamos a transformar LoginAction.java:

package com.mr.knight.struts2.action;

import org.apache.struts2.convention.annotation.Action;

/**
 * Notice the @Action annotation where action and result pages are declared
 * Also notice that we don't need to implement Action interface or extend ActionSupport
 * class, only we need is an execute() method with same signature
 * @author jf
 *
 */
@Action(value = "login", results = {
        @Result(name = "SUCCESS", location = "/welcome.jsp"),
        @Result(name = "ERROR", location = "/error.jsp") })
@Namespaces(value={@Namespace("/User"),@Namespace("/")})
public class LoginAction{
 
 public String execute() throws Exception {
  if("jose".equals(getName()) && "admin".equals(getPwd()))
  return "SUCCESS";
  else return "ERROR";
 }
 
 //Java Bean to hold the form parameters
 private String name;
 private String pwd;
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getPwd() {
  return pwd;
 }
 public void setPwd(String pwd) {
  this.pwd = pwd;
 }
 
}


En este caso podemos observar, como los resultados se los podemos indicar la igual que hacíamos con el xml.

Paso 5. Control de versiones.


Como el proyecto empieza a crecer, y a nadie le gusta perder su trabajo, os dejo una reseña de como unir vuestro proyecto a GIT.
Lo voy a hacer desde Eclipse, aunque sinceramente, todo lo podría resumir en un git init, git commit, y git push, por consola y a partir de ahí que usaráis vuestra aplicacion de GIT preferida.
Pero por si no quereis salir de Eclipse.

Lo primero es en vuestra cuenta de GIT preferida (GITHub, Bitbucket, etc...), creais el proyecto, solo eso.
Y os quedais con la URL del repositorio:

Acto seguido desde Eclipse:
Boton Derecho en el proyecto > Team > Commit
Resultado de imagen de eclipse team commit

Seleccionais los ficheros, dais siguiente, y llegará un momento que os pedirá el repo al que quereis hacer commit en Origin y rama Master (ver doc de GIT).
Le poneis la URL que habeis copiado antes de GITHub, vuestro user y pass, y listo.



Hasta aquí, la primera parte de cómo podemos arrancar la aplicación, y como vamos a empezar a darle forma para que nos permita trabajar de manera colaborativa.
Read More

Spring-Boot - Introduccion

¿Que es spring-boot?


Spring es un framework muy utilizado, algo más en tiempos en los que las SPA (Single Page Application) no cogieron tanta velocidad, pero sí en los años en los que desarrollo MVC primaba por encima de todo.
Como parte del crecimiento de su ecosistema varios proyectos fueron desarrollados tales como Spring Data, Spring Security, etc. Pero, la integración de estos proyectos requieren de configuración, la cual es considerada una tarea repetitiva en los diversos proyectos y el cual ha traído problemas a algunos.

La siguiente imagen lo refleja:

(Fuente: http://www.arquitecturajava.com/wp-content/uploads/SpringBootIntroduccion.png)

Cuando creamos nuestra aplicacion, principalmente existen tres pasos a realizar .
1) Crear un proyecto Maven/Gradle y descargar las dependencias necesarias.
2) Desarrollamos la aplicación
3) Desplegamos en un servidor.

¿Nos interesa de verdad a nuestro equipo de developer, para crear una aplicacion, siempre ajustada en plazos, tenerlos "invirtiendo" tiempo en los puntos 1 y 2? Yo creo que no.
Normalmente, suele haber una parte del equipo dedicado a estas tareas, que lo harán no sé si mejor o peor, pero seguramente mucho más rápido.

Vamos a verlo

Empezamos por gusar el "wizard" de Spring:
http://start.spring.io/

Ahora podremos ver que nos ha descargado un ZIP.

Pero, esto para un editor nos sirve de poco, así que vamos a facilitarnos las cosas un poco más:

 mvn eclipse:eclipse  

Con esto ya tenemos listo el proyecto para ser editado por Eclipse.


Un poco más

Vamos a modificar nuestras clases para que queden así:

HelloWorldApplication.java

 package com.mrknight;  
 import org.springframework.boot.SpringApplication;  
 import org.springframework.boot.autoconfigure.SpringBootApplication;  
 import org.springframework.boot.SpringApplication;  
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;  
 import org.springframework.boot.autoconfigure.SpringBootApplication;  
 import org.springframework.context.annotation.ComponentScan;  
 @SpringBootApplication  
 @ComponentScan(basePackages="com.mrknight")  
 public class HelloWorldApplication {  
      public static void main(String[] args) {  
           SpringApplication.run(HelloWorldApplication.class, args);  
      }  
 }  

ControladorHello.java

 package com.mrknight;  
 import org.springframework.stereotype.Controller;  
 import org.springframework.web.bind.annotation.RequestMapping;  
 import org.springframework.web.bind.annotation.ResponseBody;  
 @Controller  
 public class ControladorHello {  
  @RequestMapping("/")  
  @ResponseBody  
  String home() {  
  return "HolaMundo";  
  }  
 }  


Y probamos, ejecutando como una apliccion Java normal:


Y vemos que se ejecuta, ya que trae un servidor incorporado.

 http://localhost:8080/  

Hasta aquí, esta introducción.




Read More