martes, 9 de agosto de 2016

Bean Validation en Spring

Bean Validation en Spring

1. Introduccion a Bean Validation en Spring

Trabajaremos con las siguientes dependencias Maven:


javax.validation
validation-api
1.1.0.Final
compile


org.hibernate
hibernate-validator
5.1.0.Final
runtime




org.jboss.logging
jboss-logging
3.2.0.GA
runtime

1.1. Que es "Bean Validation"

En grandes aplicaciones, nos encontramos con el caso de tener que almacenar complejos objetos de negocio que se han de persistir de alguna manera.

La mayoria de estos objetos han de cumplir una serie de reglas de negocio. Por ejemplo, pensemos en un objeto “Usuario”, muy posible que los valores de sus atributos “username”, “password” deban ser “No nulos”, cumplir con una determinada longitud minima e incluso un contener un conjunto de caracteres especificos. Por otro lado, un objeto “CarritoDeCompra”, podria estar restringido a que su atributo “cantidad” sea mayor que 0 antes de ser guardar y “duracionCompra” estar dentro de un rango que permita la aplicacion.

A veces, dichas reglas de negocio pueden tornarse bastante complejas. La expresion regular que se usa para validar una dirección “e-mail”.

^[a-z0-9`!#$%^&*'{}?/+=|_~-]+(\.[a-z0-9`!#$%^&*'{}?/+=|_~-]+)*@ ([a-z0-9]([a-z0-9-]*[a-z0-9])?)+(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$

Esta parte de validacion de reglas de negocio, puede resultar bastante engorrosa teniendo en cuenta el numero de reglas por Objeto(s) y la cantidad de codigo que requieren. Veamos un ejemplo de objeto “Cliente”:


/*Ejemplo de validacion corriente del objeto "Customer" */

if(customer.getFirstName() == null ||
customer.getFirstName().trim().length() == 0)
throw new ValidationException("validate.customer.firstName");
if(customer.getLastName() == null || customer.getLastName().trim().length() == 0)
throw new ValidationException("validate.customer.lastName");
if(customer.getGovernmentId() == null ||
customer.getGovernmentId().trim().length() == 0)
throw new ValidationException("validate.customer.governmentId");
if(customer.getBirthDate() == null ||
customer.getBirthDate().isAfter(yearsAgo(18)))
throw new ValidationException("validate.customer.birthDate");
if(customer.getGender() == null)
threw new ValidationException("validate.customer.gender");
if(customer.getBadgeNumber() == null ||
customer.getBadgeNumber().trim().length() == 0)
throw new ValidationException("validate.customer.badgeNumber");
if(customer.getAddress() == null || customer.getAddress().trim().length() == 0)
throw new ValidationException("validate.customer.address");
if(customer.getCity() == null || customer.getCity().trim().length() == 0)
throw new ValidationException("validate.customer.city");
if(customer.getState() == null || customer.getState().trim().length() == 0)
throw new ValidationException("validate.customer.state");
if(customer.getPhoneNumber() == null ||
customer.getPhoneNumber().trim().length() == 0)
throw new ValidationException("validate.customer.phoneNumber");
if(customer.getEmail() == null || customer.getEmail().trim().length() == 0 ||
!EMAIL_REGEX.matcher(customer.getEmail()).matches())
throw new ValidationException("validate.customer.email");
if(customer.getDepartment() == null ||
lookupService.getDepartment(customer.getDepartment()) == null)
throw new ValidationException("validate.customer.department");
if(customer.getLocation() == null ||
lookupService.getLocation(customer.getLocation()) == null)
throw new ValidationException("validate.customer.location");

Como vemos, no hemos escrito aún el codigo para persistir a “customer” y vemos la cantidad de necesario para verificar unicamente si “customer” es correcto.

Afortunadamente, el API de Bean Validation nos permitira validar de manera declarativa (como veremos) los distintos beans. Esto se realiza a traves de unas anotaciones con las que se escriben las reglas de negocio para una clase dada, junto con el API para manejar los objetos de Validacion.

Basada en la JSR 303, JavaBean Validation 1.0, se añadio a la plataforma Java EE 6. Por otro lado Javabean validation 1.1, se basa en la JSR 349, es su sucesora en Java EE 7. Esta ultima añade como mejora, la validacion de los argumentos y validacion de los valores de retorno de un metodo, permite ademas el uso de “expresiones” dentro de los mensajes de error de validacion. En los ejemplos usaremos la implementacion Hibernate Validator 5.1.

1.2. Hibernate Validator

Mientras que JSR 349 especifica que debe cumplir el API de validacion y los metadatos. Hibernate Validator 5.0 es la implementacion de dicha JSR 349, ademas es la mas comunmente usada. (Existe una version 5.1 con numerosas mejoras).

Hibernate Validator es el punto de partida del standard Bean Validation. Inicialmente, Hibernate Validator formaba parte del framework ORM Hibernate, aportando la validacion de entidades antes de persistirlas en la base de datos. Mas tarde, evolucionaria hacia el estandard Bean Validation.

1.3. Comprendiendo Annotation Metadata Model

El funcionamiento de Bean Validation se realiza mediante la anotacion de atributos, metodos y demas, de manera que establecemos una restriccion sobre el elemento anotado. Para cualquier anotacion cuya “retention policy” es runtime (la anotacion sigue existiendo despues de compilar y esta disponible como metadato en runtime) y que se anota mediante @javax.validation.Constraint representa dichas restriccion. El API provee con anotaciones predefinidas, pero es posible crear nuestras propias “javax.validation.ConstraintValidator”. Un ConstraintValidator se encarga de procesar un tipo de constraint concreto. is responsible for evaluating a particular constraint type. Las constraints que aporta el API por defecto, no se crean a partir de ConstraintValidator s ya que se manejan de manera interna por el API.

Las anotaciones de Constraint al aplicarlas a un atributo, indican al validador que debe comprobar que se cumple, cada vez que se invoca el metodo de validacion en una instancia de dicha clase. Cuando se coloca en un setter/getter de un JavaBean, se trata de una alternativa a anotar directamente el atributo. Anotar un metodo de un interfaz indica que la constraint debe aplicarse sobre el valor de retorno de dicho metodo. Anotar uno o varios parametros de un metodo de un interfaz indica que dichos parametros han de validarse antes de la ejecucion del metodo. Estas dos ultimas formas de aplicar constraints facilitan el estilo de “programacion por contrato” (PbC). El creador del interfaz, especifica un contrato que debe cumplir dicha interfaz, como unos valores que deben ser siempre “No Nulos”, o que los parametros de sus metodos deben cumplir ciertas reglas. El consumidor del interfaz, de manera que la parte de la implementacion y la parte consumidora sabran que el contrato se rompe si se viola alguna de las constraints.

Con las anotaciones Bean Validation usadas como constraints de PbC , necesitamos crear un proxy para validar las clases de contendran la implementacion. Esto nos sugiere de una forma la Inyeccion de Dependencias (DI), de los Consumidores para realizar la llamada efectiva al proxy con su implementacion. Existen varios Java EE AS que implementan la capacidad que ofrece Java EE 7 de realizar Programacion por Contrato, mediante proxies que aplican DI validada. Sin embargo, cuando usamos un contenedor de servlets como puede ser Tomcat, debemos aportar nuestra propia solucion para DI.

1.4. Aplicar Bean Validation en Spring

El Framework Spring, crea automaticamente los proxies necesarios para los beans que maneja y que usan Java Bean Validation. Las llamadas a los metodos anotados, se interceptan y validan apropiadamente, ya sea o bien los argumentos que pasa el Consumer son validos, o bien que el valor retornado por la implementacion es correcto. De esta manera, es frecuente el uso de Bean Validation en clases de tipo @Service ya que de forma conceptual, se trata de los beans que han de manejar la logica de negocio. El framework tambien valida cualquier tipo de objeto o metodo anotado con constraints que se pasan a un metodo de @Controller si dichos parametros se marcan con @javax.validation.Valid .

2. Configurar Bean Validation en Spring

Aun cuando no configuremos Bean Validation dentro de Spring, podemos hacer uso de la validacion, si lo tenemos dentro de nuestras dependencias.

Una prueba seria:


ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 
Validator validator = factory.getValidator(); 

Set  violations = validator.validate(employee); 
if(violations.size() > 0) 
throw new ConstraintViolationException(violations); 

Aunque el codigo funcionaria, no es nuestra intencion usarlo asi. Queremos usarlo de manera mas automatizada, para conseguirlo debemos configurar 4 puntos:

1. Declarar un “validator” 2. Configurar Message localization para el “validator” 3. Declarar “method validation processor” 4. Incluir el validator en Spring MVC form validation

En cuanto a la Maven dependency de Hibernate Validator excluye la dependencia JBoss Logging API (ya que Hibernate la usa en lugar de la dependencia Commons Logging como su API para loggings), y esto se hace en runtime, por lo que JBoss Logging dependency se declara de forma independiente. El artifact hibernate-validator declara una dependencia sobre una version de jboss-logging que no soporta Log4j 2, asi que es necesario incluir la dependencia mas reciente que lo soporte. La exclusion no es absolutamente necesaria, pero se muestra como aclaracion.

Antes de la version de Spring 4.0, el soporte para Bean Validation se centraba en las implementaciones Hibernate Validator 4.2 o 4.3. Esto es debido a que dicha implementacion aporta ciertas caracteristicas necesarias para aspectos de Spring i18n. Sin embargo en Spring 4.0, cualquier implementacion de Bean Validations 1.1 funciona ya que en esta version dichas caracteristicas se han estandarizado. En caso de estar restringidos al uso de Bean Validation 1.0 nos vemos forzados a usar Hibernate Validator (4.2 o 4.3).

2.1. Configurar Spring Validator Bean

El soporte automatico para validar objetos en Spring es anterior a que los estandares de Bean Validation apareciesen. La interfaz org.springframework.validation.Validator indica una forma de validar objetos basada en annotation constraints. Dichas constraints y su aplicacion se uso al principio dentro del proyecto llamado Spring Modules Validation, que desaparecio al aparecer el estandar JSR 303. Actualmente esta interfaz de Spring Validator sirve como facade para el API Bean Validation. Es importante tener esto en cuenta ya que los errores de validacion que reporta Spring los realiza a traves del interfaz org.springframework.validation.Errors y no en una coleccion retornada de tipo Set<javax .validation.ConstraintViolation<?>> . . La interfaz Errors, permite acceder a uno o varios objetos org.springframework.validation.ObjectError y a uno o varios org.springframework .validation.FieldError. A fecha actual, es posible usar Spring Validator o bien javax.validation.Validator, segun prefiramos, pero existen casos en los que nos vemos forzados a utilizar Spring Validator y sus objetos Errors .

Nota Para evitar confundirnos, cada vez que nos referimos a “ Validator ”, nos estamos refiriendo a javax.validation.Validator a menos que se indique lo contrario. Sin embargo en “Spring Validator” nos referimos a org.springframework.validation.Validator

Al configurar soporte para validacion en Spring, hemos de declarar un Bean especifico (una clase que extienda de org.springframework.validation.beanvalidation.SpringValidatorAdapter que implemente tanto a “Validator” como “Spring Validator” . De forma interna, este Bean utiliza un Validator para dar soporte en operaciones de ambas interfaces (facade). Podemos usar una de estas dos opciones:

javax.validation.beanvalidation.CustomValidatorBean

javax.validation.beanvalidation.LocalValidatorFactoryBean

En la mayoria de casos, usamos “LocalValidatorFactoryBean”, ya que permite recuperar el objeto interno Validator y al mismo tiempo nos permite utilizar el mismo “MessageSource” y ficheros de mensajes que se usan para realizar el resto de la i18n en la aplicacion. De una forma sencilla, configurar el bean “LocalValidatorFactoryBean” seria instanciarlo y retornarlo de esta manera.


/*****/
@Bean methodo de la clase RootContextConfiguration class: 

@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() 
{ 
return new LocalValidatorFactoryBean(); 
} 

El Bean “LocalValidatorFactoryBean” detectara de manera automatica la implementacion de Bean Validation dentro del classpath, si se trata de Hibernate Validator o de otra implementacion, y usara javax.validation.ValidatorFactory, como factoria por detras. No es necesario configurar el fichero de validacion “META-INF/validation.xml”. Aunque a veces, existen mas de un proveedor de Bean Validation en el classpath (un ejemplo seria al ejecutar la aplicacion dentro de un AS como GlashFish o WebSphere).

En estos casos, no sabemos a ciencia cierta, cual es el proveedor de Bean Validation que seleccionara Spring, que incluso puede variar de una vez a otra. En este caso es recomendable establecer el proveedor de forma manual.


/****/
@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() 
{ 
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); 
validator.setProviderClass(HibernateValidator.class); 
return validator; 
} 

La unica pega de realizar esta configuracion es que necesitamos que la dependencia Hibernate Validator se realize en tiempo de compilacion en lugar de runtime. Esto sobrecarga de mensajes en tiempo de compilacion, en los que nuestro IDE, puede resaltar nuestro codigo con sugerencias a clases que no son las que hemos de usar. Para evitar esto, es posible cargar las clases de manera dinamica, lo que tiene como contrapartida que cualquier error en declaracion de codigo no se detectara en tiempo de compilacion.

/******/
@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() 
throws ClassNotFoundException 
{ 
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); 
validator.setProviderClass(Class.forName( 
"org.hibernate.validator.HibernateValidator" 
)); 
return validator; 
}

Establecer la clase de Bean Validation provider, no es necesario en el contenedor de Servlet Tomcat, no aplicaremos esta tecnica.

2.2. Configurar Mensajes de error de validacion y su Localization

Mas adelante, veremos como añadir constraints a nuestras clases y entidades. Cuando hacemos esto, es posible indicar un mensaje de error que se asocia a cada constraint o bien un codigo de error. De esta forma, permitimos que dicho mensje de error sea posible de internazionalizar antes de ser mostrado al usuario. Por defecto la internacionalizacion en Bean Validation utiliza bundle files de tipo “ValidationMessages.properties” , “ValidationMessages_[language].properties” , “ValidationMessages_[language]_[region].properties”.... Estos ficheros deben estar en el classpath (/WEB-INF/classes ). Con la implementacion de Bean Validation 1.1, es posible sin embargo, crear nuestro propia internacionalizacion mediante javax.validation.MessageInterpolator .De cualquier forma, en cada caso debemos indicar una la Locale que debe usar el Validator cada vez que este se activa. Spring, nos facilita la tarea de crear nuestro propio “MessageInterpolator” y elimina el tener que preocuparse de pasar cada vez la Locale. Lo que necesitamos es establecer MessageSource en el “LocalValidatorFactoryBean” que declaramos dentro de RootContextConfiguration de manera que de forma automatica provee un interpolator para el MessageSource en concreto:

/*****/
... 
@Bean 
public MessageSource messageSource() 
{ 
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); 
messageSource.setCacheSeconds(-1); 
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name()); 
messageSource.setBasenames( 
"/WEB-INF/i18n/titles", "/WEB-INF/i18n/messages", 
"/WEB-INF/i18n/errors", "/WEB-INF/i18n/validation" 
); 
return messageSource; 
} 
@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() 
{ 
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); 
validator.setValidationMessageSource(this.messageSource()); 
return validator; 
} 
... 
/*****/


Una vez configurado “LocalValidatorFactoryBean” para usar nuestro “MessageSource” , podemos crear mensajes de validacion segun la Locale de manera correcta en tiempo de ejecucion.

2.3. Usar Method Validation Bean Post-Processor

El concepto de Spring bean post-processors se usa para configurar, personalizar y si necesario reemplazar aquellos beans que existen en nuestra configuracion antes del que el contenedor complete su proceso de arraque. Configurado el org.springframework.beans.factory.config.BeanPostProcessor sus implementaciones se ejecutan antes de que un bean se inyecte dentro de otros beans que dependen de el, por ejemplo:

a) AutowiredAnnotationBeanPostProcessor es un bean del framework que se crea automaticamente cuando configuramos Spring. Controla las anotaciones @Autowire y @Inject y de inyectar dichos valores.

b) InitDestroyAnnotationBeanPostProcessor controla implementaciones de InitializingBean (o metodos anotados con @PostConstruct ) y las implementaciones de DisposableBean (o metodos anotados con @PreDestroy) y ejecuta dichos metodos en la fase apropiada de su ciclo de vida.

c) Algunos post-processors pueden incluso reemplazar el bean. El caso de AnnotationBeanPostProcessor se encarga de buscar aquellos bean con metodos @Async y reemplaza dichos beans con proxies de manera que dichos metodos puedan ser llamados de manera asincrona. La mayoria de los bean post-procesors que necesitamos, como los descritos anteriormente, se crean de manera automatica. Sin embargo, para dar soporte a la validacion de los argumentos de metodos y sus valores de retorno necesitamos crear un org.springframework.validation.beanvalidation .MethodValidationPostProcessor, para que se generen los proxy de la ejecucion los metodos validados. Esta fase no es tan sencialla como la de instanciar un bean MethodValidationPostProcessor ya que por defecto utiliza el validation provider del classpath (sin haber asignado nuestro MessageSource). En su lugar, podemos configurarlo para que use LocalValidatorFactoryBean que creamos anteriormente.

@Bean 
public LocalValidatorFactoryBean localValidatorFactoryBean() { ... } 
@Bean 
public MethodValidationPostProcessor methodValidationPostProcessor() 
{ 
MethodValidationPostProcessor processor = 
new MethodValidationPostProcessor(); 
processor.setValidator(this.localValidatorFactoryBean()); 
return processor; 
} 
@Bean 
public ObjectMapper objectMapper() { ... } 

Este MethodValidationPostProcessor cotrola las clases que se anotan con “@org.springframework .validation.annotation.Validated” o “@javax.validation.executable.ValidateOnExecution” de forma que crea un proxy de dichas clases, de forma que la validacion de los parametros de los metodos se realiza “antes” de la ejecucion del metodo. Y para el valor de retorno, la validacion ocurre justo despues de la ejecucion del metodo.

2.4. Configurar que Spring MVC use el mismo Bean Validator

A diferencia de “MethodValidationPostProcessor” que creamos anteriormente que usa una instancia de Validator, el controlador de objetos form de Spring MVC y la validacion de parametros de los metodos, usan una instancia de Spring Validator. Esto soporte, proveyendo de argumentos de tipo Errors a los metodos que esperan el parametro @Valid ya que la interfaz Errors es mas sencilla de usar que una coleccion de ConstraintViolations. Afortunadamente, “LocalValidatorFactoryBean” implementa ambos interfaces, por defecto Spring MVC, crea una instancia de Spring Validator aparte que oculta la que se creo en la raiz de lel root application context.

Para modificar esta configuracion por defecto, es necesario modificar la clase “ServletContextConfiguration” dicha clase que hereda de “WebMvcConfigurerAdapter”, sobrecargar el metodo getValidator y devolver el validato que habiamos creado en el root application context.


@Inject SpringValidatorAdapter validator; 
... 
@Override 
public Validator getValidator() 
{ 
return this.validator; 
} 

Con este cambio, Spring MVC usara el Validator que configuramos, para validar el controlador deseado, los parametros de sus metodos y valores de retorno.

3. Añadir anotaciones de validacion a nuestros Beans

Para poder realizar Bean Validation, la aplicacion Spring trabaja con 2 tipos de bean principalmente:

a) POJOs o JavaBeans -es el caso de entidades y objetos de formulario que aparecen como parametro en un metodo o son el resultado que devuelve.

b) Beans propios de Spring como @Controller y @Service que usan los anteriores en sus metodos y tipos de retorno.

Ambos tipos de bean utilizan anotaciones constraint de Bean Validation, pero de distinta manerja. En esta seccion veremos como aplicar annotation constraints a POJO,s. Mas adelante lo haremos sobre Beans propios de Spring.

3.1. Comprender las Built-in Constraint Annotations

Aunque es posible definir nuestras propias constraints, el API de Bean Validation trae varias annotation constraints predefinidas, que muy a menudo es suficientemente completo para nuestro uso. Dichas constraints vienen en el paquete javax.validation.constraints .

Aqui mostramos la mayoria de ellas:

1) @Null — Se aplica sobre cualquier tipo de objeto y asegura que el elemento anotado es null

2) @NotNull — Tambien se aplica sobre cualquier tipo de objeto. Se asegura de que el valor es No null.

3) @AssertTrue y @AssertFalse — Se asegura que el valor anotado es true en la primera y false en la segunda. Por ello el parametro anotado o el valor de retorno debe ser de tipo Boolean. Un Boolean con valor null se considera valido en ambas constraints por lo que han de acompañarse de @NotNull si no se acepta dicho valor.

4) @DecimalMax — Declara el valor maximo para un tipo numerico. Puede anotar atributos, parametros de metodo, y metodos de tipos BigDecimal , BigInteger , CharSequence ( String ), byte , Byte , short , Short , int , Int , long , and Long . Los tipos double , Double , float , and Float, no son soportados debido a la cuestion de precision. Una CharSequence se pasa a decimal antes de aplicar la validacion y si se trata de un valor null, se considera valido. Ademas la anotacion acepta un atributo “inclusive=true”, que inidica si la comprobacion debe realizarse de forma inclusiva (menor o igual que) o exclusiva (menor que).

5) @DecimalMin — Igual que la anotacion anterior aplicado al valor menor.

6) @Digits — Se utiliza para asegurar que el elemento anotado es parseable a number (si se trata de una CharSequence) y a continuacion comprueba de que tipo se trata (si es un CharSequence , BigDecimal , BigInteger , byte , Byte , short , Short , int , Int , long , o Long ). El atributo obligatorio “integer” indica el numero maximo numero de digitos enteros en la secuencia, mientras que el atributo “fraction” indica el numero maximo de digitos tras el punto. Los valores nulos son aceptados.

7) @Future — Asegura que el elemento Date o Calendar, contiene un valor mayor al instante actual, ya sea cercano o lejano. Los valores null son aceptados.

8) @Past — Asegura que el elementot Date and Calendar, contiene un valor inferior al instante actual. Valores nulos son aceptados.

9) @Max y @Min — Semejante a @DecimalMax y @DecimalMin, pero no puede aplicarse sobre elementos CharSequence y no tienen el atributo “inclusive”, ya que son siempre inclusive (menor o igual que). Los elementos de valor “null” se consideran validos.

10) @Pattern — Esto nos permite declarar una expresion regular hacia un elemento de tipo CharSequence ( String ) debe cumplir, y considera los valores null como validos. Acepta un flag adicional que soporta un array de elementos del enum Pattern.Flag. Los valores soportados son: Patter.Flag. 1) CANON_EQ — Equivalentes canonicalmente 2) CASE_INSENSITIVE — Mayuscula o minuscula indiferentemente 3) COMMENTS — Permite que existan espacios en blanco y comentarios (“aaa”) dentro del patron 4) DOTALL — Activa el modo todocon puntos 5) MULTILINE — Activa el modo multiline 6) UNICODE_CASE — Activa el modo Unicode 7) UNIX_LINES — Activa el modo unix (CRLF)

11) @Size — Establece los limites inclusivos de @Max y @Min a la longitudo de la CharSequence ( String ), el numero de valores de la Colleccion, el numero de entradas en un Map, o el numero de elelemntos de un array de cualquier tipo.

3.2. Atributos comunes de Annotation Constraints

Como vemos existe una gran cantidad de constraints que podemos usar. Ademas de eso, existen atributos especificos de dichas anotaciones que ya hemos comentado, toda anotacion de constraint tiene ademas el siguiente numero de atributos opcionales. Los cuales deben estar tambien presentes en una constraint propia hayamos cread.

1) message — Este atributo indica que mensaje debe mostrarse al usuario. Si el mensaje esta contenido entre llaves ( message="{employee.firstName.notBlank}" ), el contenido representa un codigo que debe ser localizado. Por defecto apunta a un codigo de mensaje que es diferente para cada tipo de constraint. 2) groups — Se trata de un array de Class que indica que grupo de validacion o grupos pertenece esta constraint. Por defecto si el array esta vacio, esto indica que la constraint pertenece a su grupo por defecto. Mas adelante se explicara que son los grupos de validacion. 3) payload — Otro array de Class, dichas clases deben heredar de javax .validation.Payload . Los Payloads aportan meta-informacion al proveedor de validacion (al Constraint Validator), que debe realizar dicha validacion. Esto hace que los payloads no puedan migrar de un proveedor a otro en las anotations constraints que vienen por defecto (ya que el API no declara typos de payload), sin embargo pueden ser utiles a la hora de construir nuestras propias constraints. Podemos usar los payloads para cualquier cosa dentro de nuestra propia constraint (aportarnos cierta informacion extra).

Para finalizar, todas estas annotation constraints declararn una anotation interna: @List que nos permite aplicar varias constraints encadenadas, para un elemento en concreto. Por ejemplo, podemos anotar un elemento con varios @Max mediante @Max.List.

3.3. Ejemplo de Annotation Constraints

Para comprender mejor el uso basico de constraints, usaremos el ejemplo del principio de la clase “Customer”, se trata de un POJO y muestra una validacion de las reglas de negocio mediante annotations.


public class Customer 
{ 
private long id; 
@NotNull(message = "{validate.customer.firstName}") 
private String firstName; 
@NotNull(message = "{validate.customer.lastName}") 
private String lastName; 
private String middleName; 
@NotNull(message = "{validate.customer.governmentId}") 
private String governmentId; 
@NotNull(message = "{validate.customer.birthDate}") 
@Past(message = "{validate.customer.birthDate}") 
private Date birthDate; 
@NotNull(message = "{validate.customer.gender}") 
private Gender gender; 
@NotNull(message = "{validate.customer.badgeNumber}") 
private String badgeNumber; 
@NotNull(message = "{validate.customer.address}") 
private String address; 
@NotNull(message = "{validate.customer.city}") 
private String city; 
@NotNull(message = "{validate.customer.state}") 
private String state; 
@NotNull(message = "{validate.customer.phoneNumber}") 
private String phoneNumber; 
@NotNull(message = "{validate.customer.email}") 
@Pattern( 
regexp = "^[a-z0-9`!#$%^&*'{}?/+=|_~-]+(\\.[a-z0-9`!#$%^&*'{}?/+=" + 
"|_~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?)+(\\.[a-z0-9]" + 
"([a-z0-9-]*[a-z0-9])?)*$", 
flags = {Pattern.Flag.CASE_INSENSITIVE}, 
message = "{validate.customer.email}" 
) 
private String email; 
 
// mutators and accessors 
} 

Deberiamos tener en cuenta algunos puntos:

a) La mayoria de los atributos estan anotados con @NotNull, b) No existe sustitucion para la linea “trim().length() > 0”,lo que puede volverse un problema de redundancia de codigo rapidamente. c) La expresion regular para validar el e-mail es bastante grande y puede volverse engorrosa si se usa en varias partes. d) birthDate is se comprueba para verificar que se encuentra en el pasado, no para comprob ar que es mayor de edad, ademas el elemento debe ser de un tipo Date previo a Java 8.

De esta manera, podemos realizar validaciones incluso crear las nuestras propias. Sin embargo hay que tener en cuenta que no es valido para todo tipo de validacion. Ya que a menudo necesitamos comprobar que existe el attributo (acceder a base de datos u otro), y esas tareas requieren una validacion mas manual.

3.4. La annotation @Valid para realizar Recursive Validation

Hasta ahora hemos ido anotando atributos sencllos como Strings mediante las validation constraints. Que ocurre en el caso de que el elemento a validar es un tipo complejo que contiene a su vez elementos anotados con constraints?

En este ejemplo:

public class Helicopter 
{ 
@NotNull 
private String name; 
@NotNull
private AirPort origin; 
@NotNull 
private AirPort destination; 
@NotNull 
private List<Person> crew; 
@NotNull 
private Person engineer; 
@NotNull 
private Person pilot; 
// mutators and accessors 
} 

Las clases AirPort y Person de este ejemplo son POJOs con sus propios atributos que estan a su vez anotados con validation constraints. Estos objetos anidados no se validan automaticamente. Para asegurarnos de que se validan, debemos anotar estos atributos como @Valid, lo cual indica que un atributo, parametro, o metodo debe validarse en cascada. that a field, parameter, or method (return value) should result in cascading validation.


public class Helicopter 
{ 
@NotNull 
private String name; 
@NotNull
@Valid private AirPort origin; 
@NotNull 
@Valid private AirPort destination; 
@NotNull 
@Valid private List<Person> crew; 
@NotNull 
@Valid private Person engineer; 
@NotNull 
@Valid private Person pilot; 
// mutators and accessors 
} 

Si AirPort o Person, contiene atributos que a su vez estan marcados con @Valid, la validacion continua en profundidad hasta llegar a comprobar todos los valores.

Existe un riesgo, sin embargo, cuando el validator detecta un bucle infinito causado por ejemplo debido a “referencias ciclicas”, de manera que termina la validacion sin detectar error despues de que el circulo de referencias le alcanza.

3.5. Validation Groups

Los grupos de validacion nos permiten activar y desactivar ciertas constraints segun el grupo al que pertenecen y segun que grupos estan activos en ese momento. Esto es muy similar a los Bean Definition Profiles de Spring. Un grupo se representa a traves de cualquier interfaz de marcado. La interfaz debe de no contener ninguna constantes o metodos ya que no sera utilizados. En su lugar, el objeto de Classe interfaz, representa al grupo cuando se define una constraint. A continuacion, en tiempo de validacion, el Validator aplica unicamente aquellas constraints cuyo grupo de Class se indica cuando se realizo la llamada a uno de los metodos: validate, validateProperty o validateValue

Por ejemplo, consideremos una entrada en varios pasos a partir de un UI, en la cual los atributos se van rellenando en cada pagina. Podriamos desear validar que los valores de atributos sean los correctos en cada paso, pero tambien podriamos querer almacenar todos esos valores en un mismo objeto form. Mediante los groups, resulta sencillo:


public interface UiScreen1 { } 
public interface UiScreen2 { } 
public interface UiScreen3 { } 

public class Form 
{ 
@NotNull(groups = UiScreen1.class) 
private String field1; 
@NotNull(groups = UiScreen2.class) 
private String field2; 
@NotNull(groups = UiScreen2.class) 
private String field3; 
@NotNull(groups = UiScreen3.class) 
private String field4; 
// mutators and accessors 
} 

A continuacion, cuando debamos validar, solo es necesario pasar el grupo de class apropiado a cada llamada de Validator, y se aplicaran las constraints que corresponden a dichos grupos. Si usamos javax.validation .groups.Default, si ademas queremos evaluar las constraints sin ningun grupo predefinido.

/*esto seria */
// en metodo para paso 1 
Set<ConstraintViolation<Form>> violations = 
validator.validate(form, Default.class, UiScreen1.class) 
// para el metodo del paso 2 
Set<ConstraintViolation<Form>> violations = 
validator.validate(form, Default.class, UiScreen1.class, UiScreen2.class) 
// en metodo para el paso 3 
Set<ConstraintViolation<Form>> violations = 
validator.validate(form, Default.class, UiScreen1.class, UiScreen2.class, UiScreen3.class) 

Si una constraint no declara ningun grupo, se toma el grupo por defecto. De la misma manera, si una llamada a validate , validateProperty , o validateValue no contiene ningun grupo aplicara tambien el grupo por defecto.

Los grupos de Validation son ademas utiles para aplicar una misma constraint de manera distinta segun el grupo. Asi @Size.List y @Size, por ejemplo, es posible indicar que un elemento de tipo String debe tener una longitud determinada si se valida por un grupo y otra longitud si se valida por otro grupo (o grupos).

/**ejemplo en el que se aplica una constraint de distintas formas **/
public class BusinessObject 
{ 
@Size.List({ 
@Size(min = 5, max = 100, groups = {Default.class, Group1.class}), 
@Size(min = 20, max = 75, groups = Group2.class) 
}) 
private String value; 
// mutators and accessors 
} 

Como suele ser, Spring simplifica el uso de grupos de validation. En vez de tener que acceder al validador directamente, podemos establecer en una anotacion que grupos deben estar activos al validar un elemento. Veremos mas acerca de esto en la siguiente seccion.

3.6. Comprobar la validez de una Constraint en tiempo de compilacion

En el lenguaje Java existen reglas acerca de que anotaciones podemos usar y donde, establecido mediante java.lang.annotation.ElementType y los valores establecidos a traves de @java.lang.annotation.Target para una definicion particular de anotacion. Sin embargo, las reglas acerca de donde es posible aplicar las constraints de validacion son mucho mas complejas que las que se soportan de forma nativa. Por ejemplo, las anotaciones de constraint pueden aplicarse a ElementyType.METHOD (y otras) en tiempo de compilacion, pero esto pasa por encima el hecho de que las anotaciones de constraint son solo validas en metodos de instancia y no en metodos static (es una diferencia que ElementType no tiene en cuenta). De la misma manera, las constraints solo son validas en metodos de instancias y no en metodos static, sin embargo el compilador no puede capturar esta diferencia tampoco. Aun mas importante que esto, las distintas constraints se limitan a distintos tipos (no es posible usar @Future sobre Strings por ejemplo), y necesitas una manera de asegurarte que aplicamos estas constraints de forma correcta.

El API “Hibernate Validator” dispone de un procesador de anotaciones que en tiempo de compilacion toma control de cierta parte y evita que dicho codigo compile, si las restricciones explicadas anteriormente no se cumplen. Esto facilita, poder aplicar dichas “constraints de validacion” de manera mas sencilla ya que sino el compilador dara error, lanzando una javax.annotation.ConstraintDeclarationException . Para disponer del annotation processor, necesitamos añadir las siguientes dependencias:

 
org.hibernate 
hibernate-validator-annotation-processor 
5.1.0.Final 
compile 
true 
 

La razon por la que esta dependencia se marca como opcional es que Hibernate Validator no la necesita en tiempo runtime. Solo se llama en tiempo de compilacion, de manera que se detecta el anotation processor existente. La parte positiva de hacerlo asi es que el processor se aplica de forma automatica en la fase build de Maven y en la compilacion desde el IDE. La parte negativa es que las clases se encuentran en el classpath y nuestro IDE nos las ofrecera como opcion.

Existen otras formas de instalar annotation processors dentro de Maven y de nuestro IDE. Por ejempo, es posible añadir la dependencia dentro del plug-in del compilador a usar, en lugar de dentro de las dependencias del proyecto, lo que evita que aparezcan en el classpath, pero nos fuerza a separar anotation processor de nuestro IDE.

domingo, 10 de julio de 2016

Implementacion de servicios asincronos y scheduled con Spring

Doc template

1. @Async y @Scheduled en Spring (Introduccion)

Cuando rediseñamos las distintas capas de logica de negocio y de prentacion, a menudo nos encontramos con la problematica de manejar tareas automatizadas o asincronas. Por ejemplo, el borrado de antiguas conversaciones de un foro de mensajes o tener que enviar e-mails de “newletter” a usuarios. Como vemos, la invocacion de estos servicios no depende directamente de la interacción de un usuario a través de un controlador. Asi que, como podemos realizar esta llamada? En el caso de envio masivo de e-mails. Vemos, que no es una buena practica enviar un solo e-mail con todos los destinatarios, ya que revelariamos las direcciones de correo al resto, si por otro lado cargasemos el campo BCC, esto suele marcar el correo como Spam o incluso peor, poner el servidor de correo dentro de una lista negra. Por lo que lo mas recomendable en un servicio de “newsletter”, es enviar un correo a cada destinatario, lo cual puede tener una duracion más larga de lo que pensamos. Para poder realizar esto, necesitamos ejecutar una tarea asincrona en segundo plano.

Spring ofrece mecanismos para planificar una tarea o bien ejecutar codigo de manera asincrona pero uno de los mayores cuellos de botella, reside en el manejo de los threads. En una aplicacion que se ejecuta dentro de un contenedor de Servlets, no se pueden lanzar uno o mas Threads cada vez que se necesite, sin que esto impacte el resto. Por ello, es importante gestionar el uso de Threads de manera que no castigue el rendimiento global. La parte que mas recursos consume es la creacion y abandono de threads, ya que puede causar problemas de falta de memoria, lo cual suele terminar bastante mal. Uno de los problemas que se suelen obviar es que la creacion y destruccion de threads implica un gran consumo de recursos, que afecta al rendimiento. Asi que una buena practica consiste en el uso de un Pool de Threads que reutilize dichos threads en lugar de crearlos y destruirlos y que ademas los planifica, poniendo en cola procesos, cuando no se dispone de suficiente CPU.

Spring, por su parte, incluye dicha gestion de Threads para ello aporta las anotaciones:

@org.springframework.scheduling.annotation.Async y @org.springframework.scheduling.annotation.Scheduled para indicar que un metodo a de ejecutarse de manera asincrona y de forma planificada respectivamente.

Esto no es tan sencillo como aplicar dichas anotaciones a los metodos que deseemos ejecutar de esta manera, sino que es necesaria alguna configuracion previa. Lo primero que necesitamos es activar estas caracteristicas. Por defecto los metodos anotados como @Async o como @Scheduled, no usan el mismo Pool de threads, pero para este caso, si es lo deseado, ya que de esta manera, podemos usar los recursos de nuestra aplicacion de la forma mas eficiente (estamos dentro del mismo contenedor).

Para hacer esto, vamos a explicar de forma breve, que hay debajo de todo esto:

2. Comprender "Executor" y "Scheduler"

En el Framework Spring existen dos conceptos parecidos “executors” y “schedulers”. Una clase “Executor” hace lo que intuitivamente se entiende, ejecutar una tarea. En sus requerimientos no se especifica si esto ha de ser de forma sincrona o asincrona, esto depende de sus diferentes implementaciones, que especifican como ha de ejecutarse.

La interfaz java.util.concurrent.Executor especifica que ha de ejecutar un Runnable.

Spring extiende este interfaz con org.springframework.core.task.TaskExecutor

Spring aporta la interfaz org.springframework.scheduling.TaskScheduler que incluye distintos metodos para planificar una tarea una o mas veces y en un punto del futuro

Existen varias implementaciones de estos interfaces, y la mayoria incluyen ambos. El mas usado es “org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler”, que comprende ambas caracteristicas de “executor” y de “scheduler” y un pool de threads, para la ejecucion de manera ordenada y eficiente. Cuando nuestra aplicacion se cierra, esta clase asegura de que todos los threads que se crearon se cierran de forma eficiente, para evitar problemas de memoria y otros. Esta clase implementa ademas la interfaz “java.util.concurrent.ThreadFactory”. Gracias a esto, podemos declarar un bean “ThreadPoolTaskScheduler”, y complementar cualquier dependencia con las interfaces “Executor” , “TaskExecutor” , “TaskScheduler” , o “ThreadFactory” . La configuracion se vuelve mas facil de configurar como veremos a continuacion.

3. Configurar Spring para soportar tareas asincronas / planificadas (Scheduler /Asynchronous)

Para poder anotar metodos que se ejecutaran de forma asincrona con @Async, es necesario que en @Configuration indiquemos @EnableAsync. De la misma manera para poder ejecutar tareas planificadas con @Scheduled, debemos indicar @EnableScheduling. Podemos hacerlo en nuestra clase principal, para que dicha configuracion este disponible a todos los Beans de la aplicacion. Sin embargo, estas anotaciones, tienen una configuracion por defecto, que es posible que necesitemos adaptar. Para poder hacer esto, debemos implementar la interfaz AsyncConfigurer que devuelva el async Executor deseado e implementar la clase “SchedulingConfigurer” para asignar el dicho Executor al objeto de la clase Scheduler.

@Configuration
@EnableAsync(proxyTargetClass = true)
@EnableScheduling
...
public class RootContextConfiguration

implements AsyncConfigurer, SchedulingConfigurer

{

private static final Logger log = LogManager.getLogger();

private static final Logger schedulingLogger =

LogManager.getLogger(log.getName() + ".[scheduling]");

...



@Bean
public ThreadPoolTaskScheduler taskScheduler()
{
log.info("Setting up thread pool task scheduler with 20 threads.");406  

ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();

scheduler.setPoolSize(20);

scheduler.setThreadNamePrefix("task-");

scheduler.setAwaitTerminationSeconds(60);

scheduler.setWaitForTasksToCompleteOnShutdown(true);

scheduler.setErrorHandler(t -> schedulingLogger.error(

"Unknown error occurred while executing task.", t

));

scheduler.setRejectedExecutionHandler(

(r, e) -> schedulingLogger.error(

"Execution of task {} was rejected for unknown reasons.",r

)

);

return scheduler;

}

@Override
public Executor getAsyncExecutor()

{

Executor executor = this.taskScheduler();

log.info("Configuring asynchronous method executor {}.", executor);

return executor;

}



@Override

public void configureTasks(ScheduledTaskRegistrar registrar)

{

TaskScheduler scheduler = this.taskScheduler();

log.info("Configuring scheduled method executor {}.", scheduler);

registrar.setTaskScheduler(scheduler);

}

}

Solo mostramos el nuevo codigo añadido, el atributo “proxyTargetClass” dentro de la anotacion@EnableAsync le indica a Spring que debe usar la libreria CGLIB para aplicar mediante ella proxy a las clases con metodos anotados como async o scheduled en lugar de tener que crear interfaces Java. Esto permite declarar metodos async en beans que incluso no implementan dicho interfaz. Si pusiesemos el atributo a “false”, restringiriamos el uso de metodos async y scheduled a aquellos que implementan la interfaz. El metodo de creacion de @Bean muestra scheduler como un bean mas que puede ser inyectado en cualquier otro. El metodo “getAsyncExecutor” (de la interfaz “AsyncConfigurer” ) le indica a Spring que use la misma planificacion para los metodos asincronos, y el metodo “configureTasks” (de “SchedulingConfigurer” ), le indica a Spring que use el mismo planificador para todos los metodos de ejecucion scheduled.

La manera como funciona esto es que “getAsyncExecutor” y “configureTasks” invocan a “taskScheduler” , no se tratra de dos TaskScheduler distintos? E incluso un tercero cuando Spring invoca el metodo anotado con @Bean? En realidad, solamente se invoca una instancia de “TaskScheduler”. Los proxies Spring invocan los metodos @Bean de manera que no se crea mas de una vez. Como resultado de la primera invocacion a @Bean, se cachea de manera que se usa en llamadas futuras. Esto permite que varios metodos de la configuracion invoquen metodos anotados con @Bean sin que esto implique la creacion del mismo. Asi que solo se instancia a un TaskScheduler en la configuracion, la que se indica en la declaracion del bean y se usara por los metodos “getAsyncExecutor” y “configureTasks”. Es posible verlo en los logs dentro de cada llamada.

3.1. Crear y utilizar metodos con @Async

El framework Spring soporta la ejecucion de metodos @Async “wrapeando” dichos bean en un proxy.

Cuando Spring inyecta un bean con metodos @Async dentro de otro que depende de este, lo que hace es inyectar el proxy, no el propio bean. Por lo que el bean, invoca la llamada del metodo del proxy. Cuando se trata de metodos “no asincronos”, lo que hace el proxy es unicamente delegar en el metodo del bean. Pero en metodos anotados @Async o @javax.ejb.Asynchronous , el proxy indica al “executor” que debe ejecutar dicho metodo y termina inmediatamente. Este funcionamiento tiene una consecuencia importante: Si un bean invoca a uno de sus propios metodos anotado con @Async, dicho metodo no se ejecutara de forma asincrona, ya que no existe un proxy de esta manera.

Asi que si, lo que queremos es que un metodo se ejecute de manera asincrona, debemos invocarlo desde otro bean.

Nota: En realidad esto no es una regla fija. Esto sucede cuando aplicamos proxies basandonos en interfaces Java, es entonces cuando no podemos ejecutar dicho metodo desde el mismo objeto. Sin embargo, con proxies que aporta CGLIB, podemos crear un proxy sobrecargando cada metodo de la clase original. Asi es como funciona por ejemplo, el cacheo del metodo anotado con @Bean – Spring aplica dicha tecnica de de proxy a las clases anotadas con @Configuration. Al estar habilitada la libreria CGLIB para proxy desde la configuracion si es posible invocar los metodos anotados con @Async dentro de la misma clase, y se ejecutaran de forma asincrona. Sin embargo, no es una buena practica, ya que un cambio en la configuracion puede desmontar todo el funcionamiento.

4. Ejemplos de servicios ClockAlarmService y FakeClockAlarmService

Para mostrar el funcionamiento, veremos como los metodos se marcan @Async tanto en la interfaz como en la implementacion y aunque esto no es estrictamente requerido, es una buena practica, cuando lo que se pretende es que el funcionamiento sea siempre asincrono de manera que se indica al resto de consumidores acerca de esto.

...

public interface ClockAlarmService

{

@Async
void sendClockAlarm(String subject, String message, Date date, Collection recipients);


}

@Service
public class FakeClockAlarmService implements ClockAlarmService

{

private static final Logger log = LogManager.getLogger();

@Override

@Async

public void sendClockAlarm(String subject, String message, Date date, Collection recipients)

{

log.info("Envio de Alarma  a los recipients {}.", recipients);

try {

Thread.sleep(5_000L);

} catch (InterruptedException ignore) { }

log.info("Fin envio alarma a recipients.");

}

}

El servicio DefaultReplyService recoge una instancia @Inject de ClockAlarmService y, en pocas lineas de codigo, llama al metodo asincrono saveReply si se trata de una nueva reply .

...
Set recipients = new HashSet<>(hilo.getSubscribedUsers());

recipients.remove(reply.getUser()); 
Date d = new Date();
this.clockAlarmService.sendClockAlarm("Reply posted", "Someone replied to \"" + hilo.getSubject()+ ".\"", d , recipients);

4.1. Crear y usar metodos @Scheduled

Crear metodos de tipo @Scheduled no cambia mucho respecto de metodos tipo @Async. Lo que necesitamos hacer es escribir el metodo y anotarlo de esta manera. La parte mas importante respecto de anotarlo @Scheduled es que dicho metodo no puede contener parametros en su signatura, (como puede determinar Spring que argumentos usar?), esto no implica que no podamos realizar una llamada a un metodo @Scheduled directa.

Es posible realizar dicha llamada directamente, aunque no deberiamos, incluso es posible anotar un metodo @Scheduled tambien con @Async de manera que se ejecute de manera asincrona si es llamado directamente.

La ejecucion planificada, del ejemplo, borra aquellas conversaciones almacenadas que no se han modificado en mas de un año. Para esto, necesitamos realizar algunos trucos respecto de los “repositorios”, de manera que permitan el borrado. Dentro de “ReplyRepostory” y su implementacion, añadimos el metodo “deleteHiloById”

martes, 14 de junio de 2016

Introduccion a WebSockets

Introduccion a los WebSockets

1. Ajax y WebSockets

Cuando a principio de los 90 el contenido de la web era principalmente estatico, se decidio mejorar la interaccion entre el usuario y el contenido mostrado. Para ello, la solucion pasaba por JavaScript en el navegador, los primeros navegadores ofrecian distintas implementaciones y JavaScript era lento podia provocar ataques a la seguridad. A lo largo de los años se ha mejorado con diferentes frameworks (Dojo, jQuery, node.js, Angular), que nos permiten crear aplicaciones ricas en efectos, interaccion, compatibles entre navegadores, usando poco codigo. El mayor hito reciente, llego con la aparicion de Ajax.

2. Transferir datos entre Cliente y Servidor

Ajax, esta asociado a la comunicación asincrona en la que el servidor remoto utiliza tecnologia Javascript (Json, Html, Xml, Javascript). Con AJAX los navegadores, pueden comunicar con el servidor si que tenga que actualizarse la pagina entera. La comunicación es transparente para el usuario y se usa para enviar datos de formularios, recibir datos del servidor. Esta forma de comunicación Cliente/Servidor, trae sin embargo sus problemas. El navegador, recibe los datos que se mostraran (despues de validar, calcular, transformar), desde el servidor y sin embargo el cliente no gestiona los datos que se actualizan (depende de la response del servidor ). De la misma forma que solo el navegador sabe cuando tiene nuevos datos para enviar.

Pongamos el ejemplo de un usuario A y otro B usan una aplicación de chat, solo el servidor conoce los datos de A y de B y controla que enviar a cada uno. Incluso con AJAX el problema de sincronizar y enviar la informacion era dificil de resolver (a nivel de rendimiento, trafico de datos, sincronizacion).

Entre las distintas soluciones de los ultimos 14 años algunas dependian demasiado de la implementacion del navegador.

Vamos a intentar comprender algunas de ellas.

2.1. Polling a intervalos

Es quiza una de las tecnicas que mas se utilizan, consultar en intervalos si el servidor tiene nuevos datos listos para recibir. El concepto es sencillo, a intervalos regulares (supongamos 1 por segundo), el navegador envia una peticion Ajax (con datos en la request o vacio) al servidor. El servidor responde con nuevos datos o vacio (lo que puede ser un objeto JSON vacio, o un Content-Lenght header a 0). Como vemos hay una gran cantidad de request-response en las que muchas de ellas se usan para controlar el estado si contener nuevos datos.

Browser
  GET /ajaxEndpoint
 ~100 miliseconds

Server 200 OK Content-Length: 156
Browser
 GET /ajaxEndpoint
~100 miliseconds
Server
 200 OK Content-Length: 0
Browser GET /ajaxEndpoint
       ~100 miliseconds
Server
 200 OK Content-Length: 0
Browser GET /ajaxEndpoint
~100 miliseconds
Server
 200 OK Content-Length: 241

2.2. Long Polling

Es similar a Polling por intervalos a diferencia de que el servidor no envia la respuesta hasta que contiene datos a enviar. Lo cual evita sobrecarga de recursos, sin embargo presenta los siguientes problemas. Supon que el navegador tiene datos actualizados a enviar y esta esperando que el servidor responda. El navegador, deberia poder realizar una nueva peticion con esos datos o poder cancelar (de manera que el servidor la descarte) y lanzar una nueva. El tiempo de duracion de la conexión viene especificada en cada uno de los protocolos TCP y HTTP, el cliente y el servidor deben cerrar y reconectar. Mantener la conexión durante un largo periodo de tiempo representa un problema. Existe un tope en el numero de conexiones entre C y S especificada por el protocolo HTTP/1.1. Los navegadores no pueden mantener mas de dos conexiones simultaneas a un mismo servidor (ver). Si de las conexiones al servidor, una se encuentra en espera de nuevos datos, nos reduce a la mitad el rendimiento para cargar paginas, graficos y el resto de recursos del servidor. Si tener en cuenta estos aspectos, esta aproximacion gano popularidad en el pasado, a menudo denominada Comet.

Browser GET /longPollEndpoint
200 miliseconds
Server
 200 OK Content-Length: 120

Browser GET /longPollEndpoint
95 seconds
Server
 200 OK Content-Length: 96

Browser GET /longPollEndpoint
15 seconds
Server
 200 OK Content-Length: 204

Browser GET /longPollEndpoint
47 seconds
Server 200 OK Content-Length: 191

2.3. Chunked Encoding

Es semejante a long polling, aprovecha la funcionalidad que ofrece el protocolo HTTP/1.1 que permite al servidor responder sin anunciar una cabecera con el atributo content length. En lugar de la cabecera Content-Length: n, una respuesta puede contener la cabecera Transfer-Encoding: chunked. Esto indica al cliente que la respuesta se enviara por chunks. Dentro de la respuesta cada chunk empieza con un numero, que indica su longitud, mas una serie de caracteres opcionales que indican el tipo de chunk del que se trata, a continuacion con el caracer de fin de linea CRLF. Lo que sigue son los datos del chunk enviado y terminado en CRLF. Se pueden enviar en teoria cualquier numero de chunks y pueden ir espaciados en una cantidad de tiempo cualquiera. Cuando se envia un chunk de longitud cero (un 0 seguido de CRLF), esto indica que es el final de la secuencia de la respuesta. La manera mas corriente de usar chunked encoding suele ser cuando establecemos una conexión al comienzo con la intencion de recibir eventos desde el servidor. Cada chunk del servidor es un nuevo evento que lanza el manejador de evento del “onreadystatechanged” del objeto XMLHttpRequest. Algunas veces, sin embargo no tan a menudo como sucede en long polling, la conexión tiene que actualizarse. Cuando el cliente tiene que enviar nuevos datos al servidor, lo hace con una segunda request de corta duracion. Vemos el protocolo representado en la figura a continuacion. En la parte izquierda, vemos el cliente enviando datos hacia el “endpoint de subida” cuando es necesario, usando para ello pequeñas requests. En la parte derecha, el cliente establece una sola conexión larga con el “endpoint de bajada” y el servidor usa dicha conexión para enviar al cliente datos actualizados en “chunks”. Chunked enconding resuelve la mayoria de los problemas de timeouts que aparecen en la tecnica de long polling (los clientes aceptan respuestas que toman un tiempo grande para completarse mucho mejor que que las respuestas que necesitan de un largo tiempo para empezar – la descarga de grandes ficheros es un buen ejemplo), sin embargo, la limitacion del cliente a 2 conexiones por host conectado sigue presente. Añadir ademas que con long polling y con chuked encoding, los navegadores mas antiguos solian mostrar informacion de status indicando que la pagina se encontraba cargando – sin embargo los navegadores modernos han eliminado este comportamiento.


2.4. Applets y Adobe Flash

Los intentos anteriores intentaban la manera de emular una conexión full-duplex entre navegador y servidor sobre una conexión HTTP, lo cual no puede darse mediante Ajax y su objeto XMLHttpRequest. De forma extendida, aunque no por mucho tiempo, fue (es), el uso de Applets o objetos Flash embebidos en la pagina. Con este plug-in se pueden establecer conexiones TCP mediante sockets al servidor. Lo que elimina todas las limitaciones que presenta el protocolo HTTP. Así, mientras que el servidor envia mensajes al navegador, el Applet u objeto Flash puede llamar a una funcion JavaScript con los datos de dicho mensaje. Cuando el navegador tiene nuevos datos que enviar al servidor, puede llamar un metodo Java o ActionScript (Flash), mediante una funcion Javascript que el plug-in del navegador entiende, y dicho metodo enviara la informacion al servidor. Este protocolo consigue (uso de sockets TCP), una conexión full-duplex y elimina problemas tales como timeouts y numero maximo de conexiones (incluso saltaba las restricciones en seguridad que fija el navegador para las conexiones AJAX, que deben originarse desde un elemento que se encuentra dentro del mismo nombre de dominio, “problema de crosscripting”). El precio, es sin embargo el tener que instalar un plug-in (Java o Flash), que pueden tener algun agujero en la seguridad, cargan la memoria, consumo de CPU. Aun cuando esta tecnologia se mantiene, el auge de uso del movil, donde un navegador ejecutando contenido embebido resulta extremadamente lento, hizo que se buscasen nuevas maneras de comunicación entre cliente y servidor. Requisitos como conexiones TCP, seguras, rapidas, ligeras (no necesidad de plug-ins).

3. WebSockets

La especificación HTTP/1.1. contiene los requisitos que han de cumplir las comunicaciones basadas en HTTP. Dentro de la seccion 14.42 se incluye un apartado llamado HTTP Upgrade.

HTTP/1.1 Upgrade

Un cliente HTTP (no necesariamente un navegador) puede incluir la cabecera Connection: Upgrade dentro de una request. De esta manera se indica que es lo que el cliente solicita actualizar, dicho atributo Upgrade debe indicar una lista de uno o mas protocolos, los cuales han de ser incompatibles con HTTP/1.1, como por ejemplo IRelayChat. El servidor, si acepta la peticion de Upgrade, debe devolver el codigo 101 Switching Protocols junto a cabecera response upgrade con un solo valor: el primero de los protocolos soportados de la lista que se envio en la request. Al principio, esta funcionalidad se usaba para actualizar de HTTP a HTTPS, pero resulto ser una puerta para ataques a la seguridad (man in the middle) ya que no se aseguraba la conexión desde el principio. Por esta razon, la tecnica fue reemplazada por el esquema de URI (https://), y la negociacion con Connection:Upgrade, fue quedando fuera de uso. La caracteristica principal de esta especificacion es que es posible indicar HTTP Upgrade con cualquier tipo de protocolo. Una vez que se ha establecido el acuerdo entre el cliente HTTP Upgrade y el servidor, el protocolo puede ser incluso una conexión persistente entre sockets TCP. En teoria, seria posible establecer cualquier tipo de conexión TCP entre dos endpoints con un protocolo propio. Sin embargo, los fabricantes de navegadores, no estan por la labor de dejar a los desarrolladores JavaScript, perderse en la pila TCP, asi que era necesario llegar a un acuerdo en cuanto a que parte era accesible desde JavaScript, de ahí el protocolo WebSockets.

Una nota al respecto: Si existe algun recurso de un servidor cualquiera que solo acepta peticiones HTTP Upgrade y un cliente conecta a dicho recurso sin haber enviado dicha peticion el servidor puede enviar la respuesta “426 Upgrade Required” para indicar que Upgrade es obligatorio. En este caso, la respuesta puede incluir la cabecera Connection: Upgrade que contiene la lista de protocolos que el servidor soporta. Si un cliente envia en su request Upgrade un protocolo no soportado por el servidor, el servidor puede responder con 400 Bad Request e incluir el header Upgrade con la lista soportada. Finalmente, si el servidor no acepta peticiones Upgrade, envia la respuesta 400 Bad Request

Una conexión de WebSocket, esquematizada, comienza con una peticion HTTP hacia un esquema particular. El esquema URI “ws” y “wss” se corresponden con los esquemas HTTP “http” y “https” respectivamente. La cabecera Connection:Upgrade y Upgrade:websocket se envian en la peticion indicando al servidor que se espera actualizar la conexión al protocolo WebSocket, un tipo de conexión persistente y full-duplex que se especifica en el RFC 6455 desde el año 2011. Una vez que se han realizado el handshake, se pueden realizar envios de texto y binarios en ambas direcciones, simultaneamente, sin tener que cerrar y reabrir la conexión. Llegado a este punto, no hay diferencia entre el cliente y el servidor – Ambos tienen caracteristicas de comunicación semejantes sobre la conexión establecida – semejante a conexión p2p.

Nota : Los esquemas URI “ws” y “wss”, no son exactamente parte del protocolo HTTP. Ya que la peticion HTTP no envia esquemas URI enteros sino URLs relativas al servidor al que conecta. Los esquemas especificos WebSocket se incluyen principalmente para indicar al navegador y sus implementaciones de si se intenta conectar mediante SSL/TLS o sin encriptacion.

Existen numerosas ventajas en la forma en que el protocolo WebSockets:

Las conexiones se establecen sobre los mismos puertos que en HTTP 80 ( ws ) o 443 ( wss ), no se bloquean por firewalls.

El protocolo se adapta facilmente a navegadores y servidores HTTP ya que el hadshake se realiza sobre HTTP

Los mensajes de Heartbeat  pings (cliente) y pongs (servidor) mantienen la conexion viva casi de manera infinita.

Servidor y cliente cuando empieza un mensaje y cuando se envia todo su contenido

Al cerrarse una conexion (onclose) de WebSocket se envia un mensaje especial con el  codigo y texto indicando la razon

 Una conexion WebSocket puede manejar de forma segura las conexiones cross-domain lo que elimina las restricciones que tenia Ajax 

Las restricciones de numero de conexion se eliminan ya que tras el handshake dicha conexion deja de ser de tipo HTTP

Las cabeceras de handshake en una peticion de conexión bajo WebSockets es simple. Veamos una conexión tipica de upgrade filtrada por Wireshark:

GET /webSocketEndpoint HTTP/1.1
Host: www.example.org
Connection: Upgrade
Upgrade: websocket
Origin: http://example.com
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13
Sec-WebSocket-Protocol: game

Una vez indicado el preludio HTTP( GET /webSocketEndpoint HTTP/1.1 ) vemos la cabecera de Host. Ademas las cabeceras de Connection y Upgrade que se explicaron. A continuación la cabecera Origin es un mecanismo de seguridad indicando el nombre del host origen hacia el que se inicio la conexión, para impedir que se realicen peticiones “crossdomain”. El navegador establece este valor y el servidor verifica que dicho valor se encuentra dentro de los nombres de dominio aceptados.

La cabecera “Sec-WebSocket-Key” es un valor de verificacion dentro de la especificacion, de manera que el navegador genera una clave aleatoria en base64 encoding y la añade a la request. El servidor anexa a dicho valor de la request, otra clave, se cifra con SHA-1, de manera que se devuelve el valor cifrado en base64 en la cabecera de la response dentro del atributo Sec-WebSocket-Accept. Sec-WebSocket-Version indica la version del protocolo que el cliente soporta y Sec-WebSocket-Protocol es una cabecera opcional para indicar cual es el protocolo que encapsula el protocolo WebSocket.

La respuesta a la peticion previa podria ser esta:

HTTP/1.1 101 Switching Protocols
Server: Apache 2.4
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: game

Una vez alcanzado este punto, la conexión HTTP se sustituye por una conexión basada en WebSocket, que usa la misma conexión subyacente TCP. El mayor problema que tiene este tipo de conexión es el pasar a traves de HTTP proxies, los cuales historicamente no soportan las peticiones con cabeceras HTTP Upgrade muy bien. Cuando el navegador detecta que va a pasar por un Proxy envian la cabecera HTTP CONNECT antes, pero este truco no funciona siempre. Asi que la forma mas fiable de poder conectar mediante WebSockets es usando SSL/TLS ( wss ) ya que los proxies suelen permitir dichas conexiones realizar su tarea, con lo que con esta estrategia las conexiones WebSocket funcionan casi siempre y son ademas seguras ya que el trafico va cifrado en ambos sentidos como lo hace bajo HTTPS.

Existen numerosas APIs que encapsulan la mayoria de tareas complicadas del protocolo. La unica advertencia es de que al tratarse de una tecnologia bastante nueva, necesitamos versiones acutalizadas de navegador, para soportar las aplicaciones basadas en WebSockets.

3.1. Aplicaciones basadas en WebSockets

El protocolo WebSocket se usa en multitud de aplicaciones, entre las que se incluyen aplicaciones web. Algunas de ellas existen ya fuera de un navegador, veamos algunos ejemplos.

 Un  Chat  basado en JavaScript
 Juego Online multijugado (un  MMORPG de Mozilla, llamadoBrowserQuest esta escrito en HTML 5 y JavaScript usa WebSockets.)
 Una tira informativa de valores de bolsa en tiempo real
 Una tira informativa de noticias en tiempo real
 Streaming de video en HD (!!)
 Comunicar nodos (compartir un contexto) en un cluster de aplicación.
 Envio  transactional  de gran cantidad de datos a traves de la red.
 Monitorizacion de recursos o rendimiento de software de forma remota.

3.2. API WebSocket HTML5

Es importante tener en cuenta que el uso de WebSockets no se basa unicamente en comunicar el navegador con un servidor. Dos aplicaciones desarrolladas en cualquier framework que soporta WebSockets pueden, en teoria, conectar entre ellas. Por lo tanto, la mayoria de las implementaciones de WebSocket soportan tanto endpoints cliente y servidor. Por ejemplo, en Java y .NET. Sin embargo, en JavaScript, esta enfocado a utilizarse como endpoint cliente de una conexión WebSocket. Veremos por lo tanto como trabajar con un endpoint cliente en JavaScript, para a continuacion, ver el funcionamiento de un endpoint cliente en Java y para terminar un endpoint servidor Java.

Nota En el libro hablamos de las capacidades Js, hacemos referencia al soportado por el navegador. Ya que algunos frameworks JavaScript como Node.js, pueden ejecutarse fuera del contexto del navegador y aportar caracteristicas adicionales (incluso un servidor basado en WebSockets).

API cliente HTML5 (JavaScript)

al como se indico previamente, todo navegador moderno soporta el API WebSocket que es estandar en aquellos navegadores que la sopotan. W3C establece la interfaz WebSocket como una extension de la especificacion de HTML5.

/*Crear un Objeto WebSocket
*/
var
 connection = new WebSocket('ws://www.servidor1.net/stocks/stream');
var
 connection = new WebSocket('wss://sec.servidor1.net/games/chess');
var
 connection = new WebSocket('ws://www.servidor2.com/chat', 'chat');
var
 connection = new WebSocket('ws://www.servidor2.com/chat', {'chat.v1','chat.v2'});
/**/

El primer parametro del constructor es la URL (required), del servidor WebSocket al que deseamos conectar. El segundo parametro (optional), puede ser una cadena o un array de cadenas que indican el o los protocolos propuestos por el cliente que se aceptarian. Recordemos que estos protocolos son nuestros, no los que implementa la tecnologia WebSocket. Esto nos permite enviar información propia que deseamos manejar en las cabeceras de la conexión.

Manejar un Objeto WebSocket

Existen varias propiedades en la interfaz WebSocket. La primera, readyState, indica es estado acutal de la conexión ws. Su valor es siempre CONNECTING (0), OPEN (1), CLOSING(2), CLOSED(3).

/**/
if(connection.readyState == WebSocket.OPEN) { /* do something */ }
/* */

Principalmente se usa de forma interna; sin embargo, a veces es util para asegurarnos de que no se intenta enviar cuando la conexión no esta aun abierta. A diferencia del objeto XMLHttpRequest, WebSocket no contiene un evento “onreadystatechange” que se lance cada vez que el objeto cambia, lo que nos fuerza a comprobar “readyState” para verificar el estado de una accion. En su lugar, WebSocket tiene cuatro eventos que representan cuatro cambios que pueden suceder en un WebSocket:

/**/
connection.onopen = function(event) { }
connection.onclose = function(event) { }
connection.onerror = function(event) { }
connection.onmessage = function(event) { }
/**/

Los nombres indican claramente cuando se lanza dicho evento. Es importante, el evento “onclose” que se lanza cuando la propiedad “readyState” cambia de CLOSING a CLOSED. Cuando termina el handshake y se llama a “onopen” ( “readyState” cambia de CONNECTING a OPEN), la url de solo lectura, las extensiones enviadas desde el servidor y el protocolo que ha seleccionado dicho servidor, se asignan al objeto WebSocket. El objeto de tipo evento que se asigna a “onopen” es un objeto Event de JavaScript con ninguna propiedad adicional. El objeto Event que se asigna a “onclose”, contiene sin embargo tres propiedades interesantes: 1-wasClean , 2- code , y 3-reason. Podemos comprobar estos valores para informar de comportamientos impropios al usuario:

/**/
connection.onclose = function(event) {
if(!event.wasClean)
alert(event.code + ': ' + event.reason);
}
/**/

Los codigos de cada atributo se especifican en el RFC 6455 Seccion 7.4 ( http://tools.ietf.org/html/ rfc6455#section-7.4 ). El valor 1000 indica comportamiento normal el resto indica alguna anomalia. El evento “onerror” contiene el objeto error que puede ser de cualquier tipo (normalmente es una cadena). Este evento se lanza en errores del lado del cliente; los errores de protocolo terminan por un cierre en la conexión. El manejador de evento “onmessage” es de los eventos que debemos manejar mas cuidadosamente. Su evento contiene ademas una propiedad “data”. Se trata de un string si el mensaje es texto, un Blob si el mensaje es binario y por defecto la propiedad “binaryType” de WebSocket es “blob”, o un ArrayBuffer si el mensaje es de tipo binary y la propiedad “binaryType” es “arraybuffer”. Es recomendable asignar el valor de la propiedad “binaryType” de un WebSocket inmediatamente despues de instanciarlo y dejar este valor hasta el final de la conexión; aunque es posible cambiarlo (rw) cuando fuese necesario.

/**/
var connection = new WebSocket('ws://www.example.net/chat');
connection.binaryType = 'arraybuffer';
...
/**/

El objeto WebSocket contiene dos metodos: “send” and “close” . Close() acepta un argumento opcional como argumento (que es por defecto 1000) y un string indicando la razon (por defecto vacio). El metodo send(), que acepta como unico argumento un string, Blog, ArrayBuffer o ArrayBufferView, es el unico lugar en el que probablemente tengamos que usar la propiedad “bufferedAmount” de nuestro WebSocket. “bufferedAmount” indica la cantidad de datos desde la ultima llamada a send() queda por enviar al servidor. Aunque podriamos seguir enviando aun cuando los datos estan todavia esperando ser enviados, a veces es posible que queramos enviar unicamente datos hacia el servidor, cuando no existen datos pendientes de enviar:

/**/
connection.onopen = function() {
var intervalId = window.setInterval(function() {
if(connection.readyState != WebSocket.OPEN) {
	window.clearInterval(intervalId);
return;
}
if(connection.bufferedAmount == 0)
connection.send(updatedModelData);
}, 50);
}

/**/

En el codigo anterior, enviamos nuevos datos hacia el servidor, como maximo cada 50 mills, unicamente cuando el buffer de envio esta vacio. Si la conexión esta cerrada, se para de enviar y se reinicia el intervalo del timeout.

3.3. API WebSocket de Java

La especificacion WebSocket de Java aparece en JCP como JSR 356 y esta incluida en la version Java EE 7. Implementa el API cliente y servidor. La base se encuentra en el API cliente: se especifican un conjunto de clases e interfaces dentro del paquete “javax.websocket” que incluyen toda la funcionalidad basica para un peer WebSocket. El API servidor, contenida dentro de “javax.websocket.server” incluye clases e interfaces que se basan en las clases cliente de manera que se añade funcionalidad. De esta manera, existen dos artifacts para el API: client-only y full. Ambos APIs contienen gran cantidad de clases e interfaces que no vamos a explicar aquí.

El API WebSocket Client

Se basa en la clase ContainerProvider y los interfaces WebSocketContainer ,RemoteEndpoint , y Session. WebSocketContainer permite acceder a todas las funcionalidades de un cliente WebSocket, y la clase ContainerProvider contiene un metodo static getWebSocketContainer, para acceder a la implementancion de cliente WebSocket subyacente. WebSocketContainer contiene cuatro metodos sobrecargados de “connectToServer”, los cuales aceptan una URI como parametro, para conectar al endpoint remoto e iniciar un handshake. Estos metodos, aceptan o bien una instancia de POJO de cualquier tipo que haya sido anotada con @ClientEndpoint , una Class<?> que representa un POJO y anotado con @ClientEndpoint, una instancia de una Endpoint, o una clase Class<? extends Endpoint>. Cualquiera de las maneras de declarar un Endpoint, la clase ha de contener un constructor sin argumentos y debe ser creada por nosotros. Si usamos los metodos de Endpoint o Class<? extends Endpoint>, debemos incluir una ClientEndpointConfig. Cuando se realice el handshake, el metodo “connectToServer” devolvera una Session. Es posible realizar varias operaciones con el objeto Session, la mas destacable es cerrar la Session (lo que cierra la conexión WebSocket) o enviar mensajes hacia el endpoint remoto.

Nota El API Java para WebSocket no especifica como ha de ser la implementacion. Es posible desarrollar con ella pero es preciso incluir un paquete con la implementacion. Si nuestras aplicaciones se ejecutan en un contenedor J2EE o en un Application Server, las implementaciones servidor y cliente se encuentran añadidas. Sin embargo si lo ejecutamos de forma standalone, es necesario incluir la implementacion apropiada para desplegar nuestra aplicación.

Los Endpoint de tipo WebSocket contiene los metodos onOpen , onClose , and onError, por otro lado las clases anotadas con @ClientEndpoint pueden tener sus metodos anotados con @OnOpen , @OnClose , y @OnError . Una clase que extiende de @ClientEndpoint o de Endpoint puede indicar uno o mas metodos anotados con @OnMessage para manejar los mensaje que se reciben desde otro endpoint remoto. El uso de clases y metodos anotados, nos aporta flexibilidad respecto a los parametros que podemos necesitar.

@OnOpen puede tener los siguientes parametros: Session (optional) EndpointConfig (optional)

@OnClose: Session (optional) CloseReason (optional)

@OnError: Session (optional) Throwable (required)

Los metodos anotados con @OnMessage son mas complejos. Ademas del parametro optional Session, han de contener exactamente una de las siguentes combinaciones de parametros:

 Un parametro String para recibir la totalidad del mensaje
 Un String  mas un boolean para recibir un mensaje de texto en partes, con el valor del boolean a “true” en la ultima parte
 Una tipo o clase  Java,  para recibir el mensaje de texto recibido convertido a dicho tipo
 Un java.io.Reader para recibir un mensaje de texto como stream bloqueante
 Un array byte[] o un “java.nio.ByteBuffer” para recibir el mensaje binario completo
 Un array byte[] o un “ByteBuffer”, mas un boolean para recibir un mensaje binario en partes
 Un “java.io.InputStream” para recibir un mensaje binario como stream bloqueante
 Un  “PongMessage” (ping enviado como respuesta desde el servidor), para manejar respuestas   de control del servidor
 Cualquier Objeto Java si el endpoint tiene un “Decoder.Text” , “Decoder.Binary” , “Decoder
.TextStream” , o un  “Decoder.BinaryStream” registrado para transformar dicho tipo de Objeto. El mensje de tipo de texto o binario debe corresponderse con el decoder registrado.

Un endpoint puede tener un solo metodo para manejar los eventos open, close y error; sin embargo podria tener mas de tres metodos para manejar mensajes: no mas de uno para los mensajes de texto, no mas de uno para mensajes binarios, y no mas de uno para respuestas de control del servidor (pongMessages).

Como nota final, acerca del cliente, se incluye el codigo de la dependencia Maven para el API client.




javax.websocket
javax.websocket-client-api
1.0
provided


El API WebSocket Server

Se basa en toda el API cliente y añade un conjunto de clases e interfaces utiles. ServerContainer extends WebSocketContainer añade metodos para registrar instancias de “ServerEndpointConfig” o clases anotadas con @ServerEndpoint . Dentro de un contexto de servlets, se obtiene una instancia de ServerContainer invocando a “ServletContext .getAttribute( " javax.websocket.server.ServerContainer " )” . En una aplicación “standalone” necesitamos seguir las especificacion de la implementacion WebSocket que usamos para obtener una instancia de ServerContainer.

Sin embargo en casi todos los casos (incluido dentro de un contenedor J2EE), no es necesario obtener una referencia a ServerContainer. Basta con anotar la clase endpoint de servidor con “@ServerEndpoint”; de esta manera, la implementacion WebSocket buscara entre las clases la clase anotada de esta manera para registrar los server endpoints.

Cuando usamos la anotacion “@ServerEndpoint”, debemos indicar al menos el atributo “value”, el cual indica la URL relativa al recurso desplegado, al que dicho endpoint escuchara. La URL relativa ha de comenzar con “/”, y puede contener parametros. Por ejemplo, veamos la siguiente anotacion:

@ServerEndpoint("/game/{gameType}")

Si nuestra aplicación estuviese desplegada en la siguiente direccion: http[s]://www.example.org/app , el server endpoint responderia a las llamadas: ws[s]://www.example.org/app/game/chess , ws[s]://www.example.org/ app/game/checkers, y asi sucesivamente. De esta manera, los metodos anotados con @OnOpen , @OnClose , @OnError , or @OnMessage dentro de este server endpoint tendrian un parametro opcional indicado con la siguiente anotacion:

@PathParam( " gameType")

, y el container lo remplazaria por “chess” , “checkers” respectivamente. El evento que maneja los metodos en el servidor, funciona de la misma manera en los client endpoints. La diferencia entre cliente y servidor solo se produce durante el handshake. Una vez que termina el handshake y se establece la conexión, es cliente y el servidor son ambos endpoints equivalentes con las mismas funcionalidades y caracteristicas.

Orientacion a Objetos en JavaScript

Concpetos basicos de POO en Javascript

Terminologia OO

ECMA-262 por definicion define un objeto como "una coleccion desordenada de propiedades cada una de las cuales contiene un valor primitivo, un objeto o una funcion.". Esto significa que un objeto es un array de valores sin un orden establecido. Aunque esta es la definicion ECMAScript, un objeto se define de manera generica como una representacion basada en codigo de una entidad a la que podemos aplicarle un conjunto de atributos, su estado y un conjunto de metodos, sus comportamiento, siendo ambos, de ambito privado, publico o protegido.

Cada objeto se crea a traves de su clase (su representacion estatica) de la cual los objetos son instancias, dicha clase define la interfaz del objeto (lo que se hereda,lo que puede ser invocado desde el objeto y que permanecera estatico para todas los objetos de dicha clase, y la implementacion de sus metodos siendo posible modificar segun el ambito dicha implementacion mediante herencia. El numero maximo de instancias de objetos de una clase viene limitada por la memoria reservada para dicho empeño.

En ECMAScript no existen clases en su definicion formal, sino mas bien prototipos de objeto. Esto es una restriccion de ECMAScript, ya que las mismas declaraciones son objetos al mismo tiempo. Queda comprensible su uso como clase y el funcionamiento es similar.

La declaracion de un objeto (declaracion de su clase), esta contenida dentro de una sola funcion llamada constructor. No se trata de ningun tipo especial de funcion, sino una funcion que se usa para crear el objeto mediante el operador new.

 Requisitos de los leguajes OO

Un lenguaje considerado OO debe poseer las siguientes caracteristicas:

1. Encapsulacion — contener la informacion asociada a dicho objeto en la forma de atributos o metodos

2. Herencia - una clase puede depender de una o varias classes de las que hereda sus atributos y metodos

3. Composicion — un objeto puede estar compuesto de otros objetos

4. Polimorfismo — una funcion o metodo puede tener distintas implementaciones

ECMAScript cumple todos estos requisitos por lo que puede ser considerado un lenguaje OO Los objetos estan compuestos de atributos los cuales pueden ser valores primitivos del lenguaje o referencias.

Trabajar con Objetos JavaScript

Declarar e instanciar un Objeto

Para crear un Objeto se utiliza el operador new seguido del nombre de la clase que queremos instanciar:

var oObject = new Object();
var oStringObject = new String();

En la primera linea creamos una nueva instancia del objeto que se almacena en la variable. Cuando la funcion constructor no requiere parametros es posible instanciar la clase sin parentesis.

var oObject = new Object;
var oStringObject = new String;

Referencias a Object

ECMAScript, no permite acceder a la representacion fisica de un objeto; unicamente podemos acceder a su referencia. Cada vez que creamos un objeto, la referencia se almacena en la variable, no el objeto en si mismo.

Destruir un Objeto

Para la destruccion ECMAScript posee un recolector de basura, lo que nos evita de tener que ocuparnos de la destruccion de objetos para liberar memoria. En el momento que un objeto no contiene ninguna referencia hacia el, recolector de basura se encarga de destruir dicho objeto. El recolector de basura se ejecuta cada vez que una funcion termina liberando todas sus variables ademas de ejecutarse en momentos no tan predecibles. La manera de forzar la destruccion de un objeto es hacer todas sus referencias igual a null. Por ejemplo:

var oObject = new Object;
//do something with the object here
oObject = null;

En este caso oObject es igual a null, no existes mas referencias hacia el objeto creado. Esto implica que cuando se ejecute el recolector de basura, se destruira el objeto. Es una buena practica, una vez que no vayamos a usar mas un objeto creado, igualar su referencia a null. Esto nos evitara referencias indeseadas y liberara memoria. Ademas en antiguos navegadores, el funcionamiento

Hay que ser cauteloso a la hora de quitar todas las referencias a un objeto, supongamos que tenemos mas de una, ambas deberian ser igualadas a "null" para que dicho objeto sea destruido.

Early y late binding

Por "binding" entendemos la manera en la que el codigo de la interfaz de un objeto (metodos y propiedades) se asocian a una instancia. Early binding las propiedades y metodos de se declaran en su clase antes de que se realice una instanciacion, de esta manera el compilador/interprete puede preparar el codigo bytecode con anterioridad. Esto es lo que sucede en leguajes como Java. ECMAScript no es fuertemente tipado por lo que no soporta early binding. Late binding, implica que el compilador/interprete no conoce con anticipacion el tipo de objeto que contiene una variable hasta que no esta en runtime, por lo que no se realiza ninguna verificacion del tipo de objeto, sino si soporta o no una determinada propiedad o metodo.

En ECMAScript se usa "late binding".

En ECMAScript, los objetos no se crean de la misma manera. Existen objetos propios del lenguaje los cuales pueden ser usados directamente o creados a partir de su constructor.

ECMA-262 se definen los objetos nativos como "cualquier objeto que incorpora ECMAScript independientemente del cliente o framework".

Dicho claramente, los objetos nativos son las clases entre las que se incluyen los siguientes:

Object,Boolean,Error,SyntaxError,Function,Number,EvalError,TypeError,Array,Date,RangeError,URIError,String,RegExp,ReferenceError

La clase Array

ECMAScript, al contrario de Java, tiene una clase Array.
var aValues = new Array();
//o bien
var aValues = [];
Si conocemos el numero de elementos del Array podemos indicar el tamaño como parametro.
var aValues = new Array(20);

//acceder a los elementos o asignarlos

var aColors = new Array();
aColors[0] = “red”;
aColors[1] = “green”;
aColors[2] = “blue”;
var elem = aColors[0];
Ademas si sabes los valores que el array deberia contener, pueden establecerse directamente.
var aColors = new Array(“red”, “green”, “blue”);

//En este caso como strings, primer elemento en posicion 0

alert(aColors[1]);
//devuelve “green”

var aColors = new Array(“red”, “green”, “blue”);
alert(aColors.length);
//devuelve “3”

//Como indicamos anteriormente, crece dinamicamente. Si queremos añadir un elemento al final:

var aColors = new Array(“red”, “green”, “blue”);
alert(aColors.length);
//outputs “3”

//Este codigo cambia la longitud del array de 3 a 4. 
aColors[3] = “purple”;

alert(aColors.length);
//outputs “4”
//en otro lenguaje tendriamos un error Array OutOfBounds 

aColors[20] = "color20"

// automaticamente se rellenan las posiciones 4-19 con null
//lenght es ahora 21

alert(aColors.length);
//outputs “21”

El numero maximo de elementos de un array es "4 294 967 295" elementos. Mas alla de este numero nos devolveria una excepcion.

Es posible declarar un objeto Array mediante su representacion literal.

var aColors = [“red”, “green”, “blue”];
alert(aColors.length);

En la clase Array se sobrecarga el metodo toString() y valueOf() para devolver un string formateado. El string se formatea de manera que cada elemento del array es de la forma siguiente:

“red,green,blue”
//Array.valueOf y Array.toString

var aColors = [“soda”, “fanta”, “cola”];
alert(aColors.toString());
//outputs “soda,fanta,cola”

var aColors = [“soda”, “fanta”, “cola”];
alert(aColors.toString());
//outputs “soda,fanta,cola”

var aColors = [“soda”, “fanta”, “cola”];
alert(aColors.toString());
//outputs “soda,fanta,cola”

var aColors = [“soda”, “fanta”, “cola”];
alert(aColors.toString());
//outputs “soda,fanta,cola”

var aColors = [“soda”, “fanta”, “cola”];
alert(aColors.toString());
//outputs “soda,fanta,cola”

var aColors = [“soda”, “fanta”, “cola”];
alert(aColors.toString());
//outputs “soda,fanta,cola”
var aColors = [“soda”, “fanta”, “cola”];
alert(aColors.toString());
//outputs “soda,fanta,cola”

De la misma forma, el metodo toLocaleString() devuelve un string formateado con sus elementos. La diferencia aqui es que cada uno de sus elementos se formatea teniendo en cuenta los requisitos de formateo de idioma.

var aColors = [“red”, “green”, “blue”];
alert(aColors.toLocaleString());
//outputs “red,green,blue”

Cuando queremos crear dichos valores fuera de los arrays, ECMAScript contiene el metodo join() , su funcion es crear string concatenados. join() acepta el argumento que es el string a utilizar para separar los elementos del array.


//metodo join
var aColors = [“red”, “green”, “blue”];
alert(aColors.join(“,”));
//outputs “red,green,blue”
alert(aColors.join(“-SEP-”));
//outputs “red-SEP-green-SEP-blue”

alert(aColors.join(“][“));
//outputs “red][green][blue”

Vemos que cualquier elemento string puede ser usado como separador.

La forma de realizar la operacion inversa es mediante split(). Este metodo recibe un unico parametro que es el string que debe ser considerado como separador.

//metodo split
var sColors = “red,green,blue”;
var aColors = sColors.split(“,”);
//Si ponemos un nuevo separador con una cadena vacia, el metodo split() devuelve cada item con el
//separador por defecto.

var sColors = “green”;
var aColors = sColors.split(“”);
alert(aColors.toString());
//outputs “g,r,e,e,n”

Aqui el, string “green” se transforma en el array de strings “g” , “r” , “e” , “e” , “n” . Esta funcionalidad puede ser util si necesitamos parsear strings en sus caracteres. El objeto Array tiene un par de metodos que tiene su equivalente en la clase String, llamado concat() y slice(). El metodo concat() funciona exactamente de la misma forma que lo ha works almost exactly the same as it does with strings: The arguments are appended to the end of the array, and a new Array object (one containing both the items in the original array and the new items) is returned as the function value.

var aColors = [“red”, “green”, “blue”];
var aColors2 = aColors.concat(“yellow”, “purple”);
alert(aColors2.toString());
//outputs “red,green,blue,yellow,purple”
alert(aColors.toString());
//outputs “red,green,blue”

En este ejemplo el string “yellow” y “purple” se añade al array aColors, mediante concat() y el resultado se asigna a aColors2 que contiene el resultado. aColors2 array contiene los 5 valores, aColors contiene los valores inciales. Esto se puede demostrar usando el metodo toString(). El metodo slice() similar al String de la clase que devuelve un nuevo array con los items indicados.

var aColors = [“red”, “green”, “blue”, “yellow”, “purple”];
var aColors2 = aColors.slice(1);
var aColors3 = aColors.slice(1, 4);
alert(aColors2.toString());
//outputs “green,blue,yellow,purple”
alert(aColors3.toString());
//outputs “green,blue,yellow”

Una caracteristica interesante de la clase Array en ECMAScript es que contiene metodos que permiten comportarse como otro tipo de estructrura de dato.

1- Array como Stack, metodos push() y pop().

// un array manejado como pila
var stack = new Array;
stack.push(“red”);
stack.push(“green”);
stack.push(“yellow”);
alert(stack.toString());
var vItem = stack.pop();
alert(vItem);
alert(stack.toString());
//outputs “red,green,yellow”
//outputs “yellow”
//outputs “red,green”
///
var stack = new Array;
stack[0] = “red”;
stack[1] = “green”;
stack[2] = “yellow”;
alert(stack.toString());
var vItem = stack.pop();
alert(vItem);
alert(stack.toString());
//outputs “red,green,yellow”
//outputs “yellow”
//outputs “red,green”

2- Array y los metodos shift(), unshift()

var aColors = [“red”, “green”, “yellow”];
var vItem = aColors.shift();
alert(aColors.toString());
//outputs “green,yellow”
alert(vItem);
//outputs “red”
aColors.unshift(“black”);
alert(aColors.toString());
//outputs “black,green,yellow”

3- Array como Cola FIFO, metodos push() y unshift().

var queue = [“red”, “green”, “yellow”];
queue.push(“black”);
alert(queue.toString());
//outputs “red,green,yellow,black”
var sNextColor = queue.shift();
alert(sNextColor);
//outputs “red”
alert(queue.toString());
//outputs “green,yellow,black”

4- Array ordenado, metodos reverse() y sort() methods.

//reverse()

var aColors = [“red”, “green”, “blue”];
aColors.reverse();
alert(aColors.toString());
//outputs “blue,green,red”

El metodo sort(), por otro lado, organiza los items en el array ordenandolos de manera ascendente segun los valores que contiene

var aColors = [“red”, “green”, “blue”, “yellow”];
aColors.sort();
alert(aColors.toString());
//outputs “blue,green,red,yellow”

//sort()
var aColors = [3, 32, 2, 5]
aColors.sort();
alert(aColors.toString());
//outputs “2,3,32,5”
//!! Ordenacion de tipos string

El metodo splice() , es realmente sencillo, permite insertar elementos en medio del Array, aunque ademas se usa para:

1- Borrar — Es posible borrar un numero determinado de elementos de un array indicando unicamente 2 paramtros, la posicion inicial y el numero de elementos a eliminar

//ejemplo : array.splice(0, 2) elimina los dos primeros elementos
var tab = ['sea','monkey','browser'];
tab.splice(0,2);
// ['browser']

Insertar valores — reemplazamos los valores de un array indicando la posicion inicial, el numero de elementos a eliminar y el elemento a insertar, podemos añadir un cuarto parametro, quinto, ...N, que son los valores a insertar a partir de dicha posicion.

//por ejemplo:  array.splice(2, 0, “red”, “green”)
// añade los strings “red” and “green” 
//en el array a partir de la posicion  2.

Reemplazar valores:

//array.splice(2, 1, “red”, “green”) 
//borra un elemento a partir de la posicion 2 e inserta uno.

La clase Date

La clase "Date" en ECMAScript se basa en antiguas versiones de "java.util.Date" de Java. ECMAScript, almacena la fecha como el numero de milisegundos desde las 12 AM on January 1, 1970 UTC. UniversalTimeCocde (Greenwich Mean Time), es la fecha estandar de referencia. Almacenar la fecha en milisegundos garantizaria que no afectase el efecto 2000.

var d = new Date();
//crea un objeto date con la fecha y hora del dia actual

//Para crear un valor lo podemos indicar como parametro el numero de milisegundos que han transcurrido desde la fecha de referencia:

var d = new Date(0);
//equivalente a new Date()

Date y los metodos parse() y UTC() .

ECMA-262 no especifica cuales son los formatos string de fecha que parse() maneja, asi que es especifico de la implementacion o especifico de la locale, por ejemplo los siguientes formatos:

"mm/dd/yyyy" (6/13/2004) "mmmm dd, yyyy" (January 12, 2004)

Si intentamos crear un objeto date a partir de la cadena "May 25, 2004", podemos usar el metodo parse() para obtener su representacion en milisegundos y a continuacion pasar dicho valor a un constructor Date(millis)

var d0 = Date.parse(“May 25, 2004”)
// verificar d0 instanceof Date 
// o bien isNan(d0)
var d = new Date(d0);
//si parse falla devuelve NaN

El metodo UTC() devuelve la representacion en milisegundos de una fecha, pero con diferentes argumentos: año, mes, dia del mes, horas, minutos, segundos, and milisegundos. Cuando usamos UTC(), tenemos que especificar el año y mes, pero el resto de informacion es opcional. Atencion cuando establecemos el rango de valores ya que numero de mes va de 0 (Enero) a 11(Diciembre).

// "Feb/5/2003"
var d = new Date(Date.UTC(2003, 1, 5));

//Para el caso de las horas van de 0 a 23.
//"February 5, 2004 at 1:05 PM"
var d = new Date(Date.UTC(2003, 1, 5, 13, 5));

Otra forma de crear una fecha es pasar los parametros que el metodo UTC() acepta directamente:

var d = new Date(2003, 1, 5);

Los argumentos se especifican en el mismo orden, y no tienen que aparecer todos (excepto para año y mes).

La sobrecarga de los metodos toString() y valueOf() de la clase Date es distinta. El metodo valueOf() siempre devuelve los milisegundos mientras que el metodo toString() devuelve un string dependiente de la implementacion y en formato legible.

Metodos de la clase Date

Metodo Descripcion
toDateString() devuelve la parte de fecha( mes, dia, año ) en formato plataforma.
toTimeString() devuelve la parte de tiempo de fecha (horas, minutos, segundos)
toLocaleString() devuelve la fecha hora en formato de la locale
toLocaleDateString() devuelve la parte de fecha en formato de la locale
toLocaleTimeString() devuelve la parte de tiempo en formato de la locale
toUTCString() devuelve los valores UTC de la fecha en formato legible

El metodo de la clase Date getTimezoneOffset(). Devuelve el numero de minutos que la current timezone que sobrepasa la hora UTC. Para U.S. Eastern Daylight Saving Time, que es 5 horas( 300 minutes) anterior a UTC.

//hora de verano; si son iguales
var d1 = new Date(2004, 0, 1);
var d2 = new Date(2004, 6, 1);
var bSupportsDaylightSavingTime = d1.getTimezoneOffset() != d2.getTimezoneOffset();

El resto de metodos de la clase Date se usan como getters/setters

Date 
Metodo Descripcion
getTime() Returns the milliseconds representation of the date.
setTime(milliseconds) Sets the milliseconds representation of the date.
getFullYear() Returns the year of the date, represented by four digits (such as 2004 instead of just 04).
getUTCFullYear() Returns the year of the UTC date, represented by four 
digits.
setFullYear(year) Sets the year of the date, which must be given as a 
four-digit year.
setUTCFullYear(year) Sets the year of the UTC date, which must be given 
as a four-digit year.
getMonth() Returns the month of the date, represented by the numbers 0 
(for January) through 11 (for December).
getUTCMonth() Returns the month of the UTC date, represented by the 
numbers 0 (for January) through 11 (for December).
setMonth(month) Sets the month of the date, which is any number 0 or 
greater. Numbers greater than 11 begin to add years.
setUTCMonth(month) Sets the month of the UTC date, which is any number 0
 or greater. Numbers greater than 11 begin to add years.
getDate() Returns the date, which is the day of the month, of the date 
value.
getUTCDate() Returns the date, which is the day of the month, of the UTC
 date value.
setDate(date) Sets the day of the month of the date.
setUTCDate(date) Sets the day of the month of the UTC date.
getDay() Returns the day of the week of the date.
getUTCDay() Returns the day of the week of the UTC date.
setDay(day) Sets the day of the week of the date.
setUTCDay(day) Sets the day of the week of the UTC date.
getHours() Returns the hours of the date time.
getUTCHours() Returns the hours of the UTC date time.
setHours(hours) Sets the hours of the date time.
setUTCHours(hours) Sets the hours of the UTC date time.
getMinutes() Returns the minutes of the date time.
getUTCMinutes() Returns the minutes of the UTC date time.
setMinutes(minutes) Sets the minutes of the date time.
setUTCMinutes(minutes) Sets the minutes of the UTC date time.
getSeconds() Returns the seconds of the date time.
getUTCSeconds() Returns the seconds of the UTC date time.
setSeconds(seconds) Sets the seconds of the date time.Object Basics
setUTCSeconds(seconds) Sets the seconds of the UTC date time.
getMilliseconds() Returns the milliseconds of the date time. Note that 
this does not refer to the milliseconds since January 1,1970, but rather
 the number of milliseconds in the current time, such as 4:55:34.20, 
where 20 is the number of milliseconds of the time.
getUTCMilliseconds () Returns the milliseconds of the UTC date time.
setMilliseconds(milliseconds) Sets the milliseconds of the date time.
setUTCMilliseconds(millseconds) Sets the milliseconds of the UTC date time.

Objetos implicitos de ECMAScript

ECMA-262 define built-in object (BOM) como "cualquier objeto de la implementacion independientemente del entorno en el que se encuentra, que se encuentra presente en la ejecucion de un programa ECMAScript" Esto implica que un desarrollador no tiene por que instanciar directamente un objeto de este tipo ya que se encuentra presente en el entorno. ECMA-262: define dos objetos: "Global" y "Math".

El objeto Global

Un objeto exclusivo de ECMAScript es el objeto Global, ya que a efectos de desarrollador no existe, por ejemplo, si queremos hacer una referencia a Global, devolveria error:

//intentar crear una referencia a Global
var pointer = Global;

El error indicaria que no existe dicho objeto. ECMAScript no contiene funciones independientes, pertenecen a un objeto que existe, por ejemplo a Global. esta manera las propiedades por defecto y metodos de ECMAScript tales eval(), isNan(), parseInt(), en realidad son metodos del objeto Global. Veamos algunas de ellas:

//ECMAScript  metodos de Global
var sUri = “http://www.wrox.com/jsprog value.htm#start”;
// tiene en cuenta que se trata de una URI por lo que encode se aplica a la parte que sigue a http://

alert(encodeURI(sUri));

// devuelve http://www.wrox.com/jsprog%20value.htm#start

// no tiene en cuenta que se trata de una URI, toma todo el  string  para aplicar encode

alert(encodeURIComponent(sUri));

//deveuelve http%3A%2F%2Fwww.wrox.com%2Fjsprog%20value.htm%23start

// la transformacion inversa seria con decodeURI
var sUri = “http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start”;
alert(decodeURI(sUri));
// devuele http%3A%2F%2Fwww.wrox.com%2Fillegal value.htm%23start

alert(decodeURIComponent(sUri));
// devuelve http://www.wrox.com/illegal value.htm#start

Una buena practica para evitar sorpresas en cuanto a la codificacion es usar encondeURI, decodeURI en lugar de escape, unescape, ya que estos ultimos no tienen en cuenta la codificacion Unicode sino ASCII, por lo que podemos obtener caracteres indeseados

Metodo eval():

Quiza uno de los mas importantes ya que trabaja como un interprete de ECMAScript. Un ejemplo:

var str = "( 1 && 1)";
eval(str);
//devolveria true
str = "( 1 && 0)";
eval(str);
//devolveria false

Declarar una variable fuera de eval e invocarla dentro de la cadena, sustituye la variable por su valor:

var msg = “hello world”;
eval(“alert(msg)”);

Declarar funciones mediante eval() u otro tipo de propiedad.Existe riesgo en su uso, ocurre cuando en una aplicacion en las que se introducen datos, entre ellos, un campo que declara un trozo de codigo malintencionado, puede dar lugar a un problema de seguridad (denominado inyeccion de codigo).

//evaluar codigo js en una cadena, en este caso carga la funcion
var input = "";
input = “function sayHi() { alert(‘hi’); }”;
eval(input);
sayHi();

Propiedades del objeto Global:

Global

Propiedad Descripccion
undefined The literal for the Undefined type.
NaN The special Number value for Not a Number.
Infinity The special Number value for an infinite value.
Object Constructor for Object
Array Constructor for Array .
Function Constructor for Function .
Boolean Constructor for Boolean .
String Constructor for String .
Number Constructor for Number .
Date Constructor for Date .
RegExp Constructor for RegExp .
Error Constructor for Error .
EvalError Constructor for EvalError .
RangeError Constructor for RangeError .
ReferenceError Constructor for ReferenceError .
SyntaxError Constructor for SyntaxError .
TypeError Constructor for TypeError .
URIError Constructor for URIError .

El objeto "Math"

El objeto implicito Math, esta destinado a operaciones de calculo. Veamos algunas de sus propiedades:

Math 
Propiedad Descripccion
E The value of e, the base of the natural logarithms.
LN10 The natural logarithm of 10.
LN2 The natural logarithm of 2.
LOG2E The base 2 logarithm of E .
LOG10E The base 1 logarithm of E .
PI The value of π.
SQRT1_2 The square root of 1 ⁄ 2.
SQRT2 The square root of 2.

Metodos del objeto Math:

Usados con frecuencia los metodos min(),max():

var iMax = Math.max(3, 54, 32, 16);
alert(iMax);
//devuelve “54”
var iMin = Math.min(3, 54, 32, 16);
alert(iMin);
//devuelve “3”

Metodo abs() , valor absoluto de un numero:

var iNegOne = Math.abs(-5);
alert(iNegOne);
//outputs “5”
var iPosOne = Math.abs(5);
alert(iPosOne);
//outputs “5”

Para el redondeo tenemos : ceil() , floor() , and round()

ceil() redondea decimales hacia el valor más cercano.
floor() redondea al valor inferior mas cercano.
round() el redondeo clasico, lo realiza hacia el valor más proximo a partir de 0.5.

Veamos un ejemplo de redondeo:

var a = 25.5;
var ceil = Math.ceil(a);
var round = Math.round(a);
var floor = Math.floor(a);
alert(ceil);
//devuelve “26”
alert(round);
//devuelve “26”
alert(floor);
//devuelve “25”

En funciones de redondeo es necesario tener muy encuenta cual es el tipo que necesitamos aun cuando el resultado sea el mismo y no intercambiar de una a otra si no queremos obtener resultados indeseados.

Methods de calculo exponencial:

exp() eleva Math.E (E exp x) a la potencia indicada
log() devuelve el logaritmo natural de un numero
pow() eleva un determinado numero a una potencia
sqrt() calcula la raiz cuadrada de un numero

Los metodos exp() y log() realizan cada uno la transformacion inversa con Math.E

var number = 2;
var resultado = Math.log(Math.exp(number));
alert(resultado);
// resultado = number = 2
var iNum = Math.pow(2, 10);
var iNum = Math.sqrt(4);
alert(iNum);
//outputs “2”

Resto de metodos para calcular que ofrece el objeto implicito Math:

Method Description
acos(x) Returns the arc cosine of x.
asin(x) Returns the arc sine of x.
atan(x) Returns the arc tangent of x.
atan2(y, x) Returns the arc cosine of y/x.
cos(x) Returns the cosine of x.
sin(x) Returns the sine of x.
tan(x) Returns the tangent of x.

Metodo random() Nos devuelve un numero aleatorio entre 0 y 1, distinto de 0 o 1

//En este ejemplo de redondeo de un resultado aleatorio entre una serie de prim a Total elementos
var prim = 2;
var Total = 10;
var aleat = Math.floor(Math.random() * Total  + prim) % Total;

Objetos Host

Scope de objetos, objetos static y uso de "this"

Public, protected y private

En la implementacion ECMAScript, el unico ambito que existe es el de publico, un factor a tener en cuenta, por convencion es se usa la notacion underscore para indicar que una propiedad o metodo es privado. En general se añaden __ antes de cada elemento.

obj.__color__ = “red”;
obj._radius = 0.3;

Static no es static

El ambito "static" indica que la propiedad o metodo es definido a nivel de clase y es accesible para todos las instancias y declarado publico como ocurren en ECMAScript, accesible a todo el resto de elementos. Es similar al caso del metodo java, java.util.Date.parse() que es estatico.

//Ejemplo que muestra añadir un metodo
//en el ambito publico, no estatico ya que no 
//esta declarado dentro del contexto de la funcion  de sayHi

function sayHi() {
alert(“hi”);
}
sayHi.alternate = function() {
alert(“hola”);
};
sayHi();
sayHi.alternate();
//outputs “hi”
//outputs “hola”

Uso de this

var oCar = new Object;
oCar.color = “red”;
//añade el metodo showColor no estatico
oCar.showColor = function () {
alert(this.color); //this aqui hace referencia a oCar
//outputs “red”
};

var oCar = new Object;
oCar.color = “red”;
oCar.showColor = function () {
alert(oCar.color);
//outputs “red”
};

//this en este caso nos permite apuntar al objeto que contiene el metodo
 
//y evita tener que referenciarlo  directamente
function showColor() {
alert(this.color);
}
var oCar1 = new Object;
oCar1.color = “red”;
oCar1.showColor = showColor;

var oCar2 = new Object;
oCar2.color = “blue”;
oCar2.showColor = showColor;

oCar1.showColor();
oCar2.showColor();
//outputs “red”
//outputs “blue”

Es importante tener en cuenta que debemos usar this "cuando hacemos referencia a propiedades de un objeto".

// si queremos hacer referencia a la propiedad color del objeto 
contenedor
// this se busca en el ambito de variables locales al metodo y en el 
ambito global
// por lo que al no encontrarlo mostraria null.
function showColor() {
alert(color);
}

Subsection 2.12

Declarar Clases y Objectos

Factory paradigm

Para crear un Objeto se utiliza el operador new seguido del nombre de la clase que queremos instanciar:

var oObject = new Object();
var oStringObject = new String();

En la primera linea creamos una nueva instancia del objeto que se almacena en la variable. Cuando la funcion constructor no requiere parametros es posible instanciar la clase sin parentesis.

var oObject = new Object;
var oStringObject = new String;

Constructor paradigm

ECMAScript, no permite acceder a la representacion fisica de un objeto; unicamente podemos acceder a su referencia. Cada vez que creamos un objeto, la referencia se almacena en la variable, no el objeto en si mismo.

Prototype paradigm

Para la destruccion ECMAScript posee un recolector de basura, lo que nos evita de tener que ocuparnos de la destruccion de objetos para liberar memoria. En el momento que un objeto no contiene ninguna referencia hacia el, recolector de basura se encarga de destruir dicho objeto. El recolector de basura se ejecuta cada vez que una funcion termina liberando todas sus variables ademas de ejecutarse en momentos no tan predecibles. La manera de forzar la destruccion de un objeto es hacer todas sus referencias igual a null. Por ejemplo:

var oObject = new Object;
//do something with the object here
oObject = null;

En este caso oObject es igual a null, no existes mas referencias hacia el objeto creado. Esto implica que cuando se ejecute el recolector de basura, se destruira el objeto. Es una buena practica, una vez que no vayamos a usar mas un objeto creado, igualar su referencia a null. Esto nos evitara referencias indeseadas y liberara memoria. Ademas en antiguos navegadores, el funcionamiento

Hay que ser cauteloso a la hora de quitar todas las referencias a un objeto, supongamos que tenemos mas de una, ambas deberian ser igualadas a "null" para que dicho objeto sea destruido.

Hybrid constructor/prototype paradigm

Por binding entendemos la manera en la que el codigo de la interfaz de un objeto (metodos y propiedades) se asocian a una instancia. Early binding las propiedades y metodos de se declaran en su clase antes de que se realice una instanciacion, de esta manera el compilador/interprete puede preparar el codigo bytecode con anterioridad. Esto es lo que sucede en leguajes como Java. ECMAScript no es fuertemente tipado por lo que no soporta early binding. Late binding, implica que el compilador/interprete no conoce con anticipacion el tipo de objeto que contiene una variable hasta que no esta en runtime, por lo que no se realiza ninguna verificacion del tipo de objeto, sino si soporta o no una determinada propiedad o metodo.

En ECMAScript se usa late binding.

Hybrid factory paradigm

Que patron de construccion usar