martes, 14 de junio de 2016

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

lunes, 11 de abril de 2016

AJAX Basico

Introduccion a AJAX

AJAX Basico

Introduccion a AJAX

AJAX = Asynchronous JavaScript and XML Aparece en 2005, no se trata de una nueva tecnología, como veremos mas adelante, sino de un conjunto de tecnologias que permite el funcionamiento asincrono de peticiones dentro de una pagina web. El concepto esta intimamente ligado a WEB 2.0, y RIA.

 RIA y Web 2.0

AJAX = Asynchronous JavaScript and XML

Aparece en 2005, no se trata de una nueva tecnología, como veremos mas adelante, sino de un conjunto de tecnologias que permite el funcionamiento asincrono de peticiones dentro de una pagina web. El concepto esta intimamente ligado a WEB 2.0, y RIA.

Como funciona AJAX

Primero lo descompondremos en cada una de sus tecnologias, veremos que se basa principalmente en el objeto XMLHttpRequest, el cual nos permite el funcionamiento de peticiones asincronas dentro de un objeto DOM.

En AJAX interviene

Tecnologia Cliente

Web Browser
DOM  
CSS  (manejo de la presentacion)
JavaScript (ECMAScript standard 1.2)
XMLHttpRequest
JSON

Tecnologia Servidor

Servidor/Contendor Web por ejemplo LAMP, Apache Tomcat

En una aplicacion Web no Ajax, el contenido de la vista que muestra nuestro navegador, se actualiza entero tras realizar, una peticion ya sea GET o POST a cada respuesta. Sin embargo perdemos dinamismo y rendimiento a cada recarga del documento. Ajax nos permite que las peticiones correspondan a fragmentos del documento las cuales pueden ser manejadas de forma separada.


El Objeto XMLHttpRequest

1-Se lanza un evento en el navegador.
2- Se crea el objeto XHR.
3- Se configura el objeto XHR creado.
4- Se ejecuta la peticion XHR de manera asincrona.
5- El servidor devuelve un documento del Mime/Type indicado como respuesta.
6- El objeto XHR ejecuta la funcion  CallBack  y procesa el resultado.
7- El cliente se actualiza con el resultado (HTML, DOM).

Estados de XMLHttpRequest

0 – sin inicializar, el método open() no se ha ejecutado.
1 – inicializado, el método open() se ha ejecutado.
2 – cargado, el método send() se ha ejecutado.
3 – interactivo, el servidor está enviando datos.
4 – completada, el servidor a terminado de enviar los datos.

sábado, 20 de febrero de 2016

Mantener el estado en una aplicación web

Doc template

Básico


Mantener el estado en una aplicación web

Sessions y Cookie


Navegador, Servidor, Cookies y HTTP

Una manera de mantener el estado de una conexion en el protocolo HTTP 1.1 se consigue mediante el envio de IDs de sesion entre el navegador y el servidor al que conecta.  De esta manera el navegador conserva dicho ID para futuras conexiones. Se trata de un mecanismo, mediante el que se envía reciben un conjunto arbitrario de datos en conexiones HTTP a través de la cabecera de respuesta "Set-cookie", y que el cliente almacena localmente y re-envía en cada nueva conexion al servidor a través de la cabecera "Cookie" de la request. Entre los atributos que contiene una Cookie, puede ser casi cualquier dato string, establecido por el servidor, solemos encontrar el nombre del dominio, una ruta dentro de dicho servidor,y un tiempo de expiración o duración máxima, un flag que indica si se trata de una cookie de seguridad y un flag para indicar si se trata de HTTP-only.

Cada vez que el navegador realiza una petición, busca en su almacen de cookies que se corresponden con el nombre de dominio y la ruta  y envía la cookie junto con los datos de la request. El atributo Expires nos da un valor absoluto de fecha de caducidad mientras que Max-Age, ambos mutuamente exclusivos, indica el numero de segundos que han de pasar hasta que la cookie expire.  Si el navegador al leer la Cookie comprueba que ha caducado
la borra automaticamente, por otro lado si dicha cookie no contiene alguno de estos atributos, se borra  cuando cerramos el navegador.

Una cookie puede contener el atributo Secure, entonces, el navegador la enviará unicamente  a través del protocolo HTTPS, lo cual asegura que se enviara cifrada.  El atributo HTTP-only restringe el envío a peticiones de navegador (solo a través de la request GET-POST), otros plugins no tendrian acceso a enviar dicha cookie. Servidores Web y de aplicaciones, usan las cookies para almacenar el estado de las conexiones cliente (session). En los servidores de aplicaciones JEE, el nombre por defecto es  JSESSIONID. Si analizamos las cabeceras de request-response
encontrariamos algo parecido a lo siguiente:

Request 1
GET /users/home HTTP/1.1
Host: www.servidor.com
Response 1
HTTP/1.1 302 Moved Temporarily
Location: https://www.servidor.com/access/login
Set-Cookie: JSESSIONID=NRxclGg2vG7MdlLn; Domain=.servidor.com; Path=/; HttpOnly

Request 2
GET /access/login HTTP/1.1
Host: www.servidor.com
Cookie: JSESSIONID=NRxclGg2vG7MdlLn
Response 2
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 21765

Request 3
POST /access/login HTTP/1.1
Host: www.servidor.com
Cookie: JSESSIONID=NRxclGg2vG7MdlLn
Response 3
HTTP/1.1 302 Moved Temporarily
Location: http://www.servidor.com/users/home
Set-Cookie: username=Jose; Expires=Wed, 02-Jun-2021 12:15:47 GMT;
Domain=.servidor.com; Path=/; HttpOnly

Request 4
GET /users/home HTTP/1.1
Host: www.servidor.com
Cookie: JSESSIONID=NRxclGg2vG7MdlLn; username=Jose
Response 4
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 2653380 

De la misma forma que las cabeceras Set-Cookie en la respuesta se usan para enviar cookies a los clientes en response, de manera que se almacenen en el cliente si este lo permite; las cabeceras Cookie en la peticion se usan para enviarlas de vuelta al servidor. En el caso imaginario descrito arriba, el usuario intenta acceder a la direccion /users/home y se le redirige a la pagina de login. Cuando accede a pagina el servidor  incluye un ID de session,
mediante Set-Cookie. Cada vez que el navegador conecta con el servidor, se incluye la cookie JSESSIONID.

Una vez que el usuario se autentifica, el servidor reenvia una cookie con la clave username.

Uno de los problemas que presenta el uso de cookies es que los usuarios pueden desactivar que el navegador las acepte, de esta manera
impedir que se envie el ID de sesion, la manera de pasar por alto esta situacione, es incluirla en la URL. Se trata de una forma comun
de transmitir la sesion. Una aplicación web o un servidor de aplicaciones, busca un patron reconocible en la uri y extrae de ahí los datos
de la sesion. Un ejemplo en PHP:

http://www.servidor.com/usuarios?PHPSESSID=NRxclGg2vG7kI4MdlLn&foo=bar&lang=es

Las aplicaciones JEE usan una tecnica distinta. El session ID se coloca en la última parte de la URI, lo que
no sobrecarga  query string, de esta manera no hay conflictos con otros parametros de la request.

http://www.servidor.com/usuarios;JSESSIONID=NRxclGg2vG7kI4MdlLn?foo=bar&lang=es

Cualquiera de las tecnicas usadas el resultado es el mísmo: Incluir el session ID en la URL para evitar la necesidad de almacenar Cookies,

Deberíamos preguntarnos, de que manera entonces como recoge el navegador el session ID la primera vez,
Una  request URL es unicamente para convenir el session ID desde el navegador al servidor al que conecta.
De donde se obtiene entonces la primera vez? Dicho  session ID  se incluye en cada URL que la aplicacion envia su response,
incluidos los enlaces, actions y redirects.

Para incluir session ID en cada URL,  HttpServletResponse  contiene dos metodos que incluyen el ID de session si es necesario: : encodeURL  y encodeRedirectURL . Para cada  salida de la response que escriba
una URL,  se usa el metodo encodeURL  el cual devuelve la URL correcta. De la misma manera una URL  para una response
de tipo sendRedirect, llamariamos al metodo  encodeRedirectURL, de manera que se incluya el  JSESSIONID, esto sucedera si se da alguno
 de los siguientes casos:

Una session activa en la request en curso. (Bien se realizo una peticion que contenía session ID o bien la
aplicacion creo uno nuevo).

 No  contenia la cookie  JSESSIONID.

La  URL es relativa a la aplicacion.

El descriptor de la aplicacion tiene configurado URL rewriting.

El caso segundo es el mas problematico. La unica forma de detectar si un navegador acepta cookies, es enviar una y comprobar
si es devuelta en la siguiente peticion. Sin embargo, es necesario crear una session para asociar una request con otra; sino, como
podemos saber si la request era la primera que envia otro usuario o es una segunda request del mismo? Asi que de esta manera,
se asume que cuando no exista JSESSIONID en la request, esto nos indica que el navegador no acepta cookies. Lo cual no tiene por que
ser siempre cierto.


domingo, 27 de diciembre de 2015

Configurar PovRay en Ubuntu

Configurar PovRay en Ubuntu

Una configuracion

Vamos a probar una configuracion por defecto, a partir de la instalacion mediante APT,

 sudo apt-get install povray* 
, instala los paquetes "povray-include, povray-examples, povray" version 3.7

 

Configurar el perfil y añadir variables de entorno

En el directorio $HOME se creara ".povray/{version}/" alli incluiremos el fichero povray.conf,que se encuentra en "/etc/povray/" , vemos que necesita la variable INSTALLDIR por defecto apunta a "/usr/share/povray-{version}/" tambien indicamos los directorios de Lectura/Escritura.

"/usr/share/povray/3.7/scripts", se encuentran scripts que permiten renderizar los ficheros .pov de una forma mas sencilla.

  
povray -h
povray: /home/david/.povray/3.7/povray.conf: 57: the user setting 'allowed' for [Shellout Security] is less restrictive than the system 'forbidden' setting in '/etc/povray/3.7/povray.conf': using system setting
Persistence of Vision(tm) Ray Tracer Version 3.7.0.unofficial (g++ 4.8 @
 i686-pc-linux-gnu)
export PATH=$PATH:/usr/share/povray-3.7/scripts  //añadir a .bashrc
cp /etc/povray/3.7/povray.conf ~/.povray/3.7/
 geany ~/.povray/3.7/povray.conf &
 mkdir .povray/3.7/in      
 cp /usr/share/doc/povray/examples/objects/* ~./povray/3.7/in/
 mkdir .povray/3.7/out
 sudo render_scene.sh  .povray/3.7/out   .povray/3.7/in/primitiv.pov  
 ll ~/.povray/3.7/out
 okular ~/.povray/3.7/out/primitiv.png &

En out obtenemos:

// This work is licensed under the Creative Commons Attribution 3.0 Unported License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/
// or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View,
// California, 94041, USA.

// Persistence Of Vision raytracer version 3.5 sample file.
//
// -w320 -h240
// -w800 -h600 +a0.3
#version 3.7;
global_settings { assumed_gamma 1.0 }
#default{ finish{ ambient 0.1 diffuse 0.9 }} 

#include "colors.inc"

#declare Radius =2.5;
#declare RowSpace=1.0;
#declare ColSpace=1.0;
#declare Dist=-1.25;
#declare Row3= 2;
#declare Row2=Row3+Radius*RowSpace*2;
#declare Row1=Row2+Radius*RowSpace*2;
#declare Col1= -Radius*ColSpace*3;
#declare Col2= Col1+Radius*ColSpace*2;
#declare Col3= Col2+Radius*ColSpace*2;
#declare Col4= Col3+Radius*ColSpace*2;
#declare Col5= Col4+Radius*ColSpace*2;

// perspective (default) camera
camera {
  location  <0.0, 5.0, -17.5>
  look_at   <0.0, 7.0,  0.0>
  right     x*image_width/image_height
  angle 65 
}
// create a regular point light source
light_source {
  0*x                  // light's position (translated below)
  color rgb <1,1,1>    // light's color
  translate <200, 500, -500>
}
 
//otro punto de luz
light_source {
  100*x                  // light's position 
  color rgb <1,0.5,0.2>    // light's color
  translate <25, 200, 200> //desplazamiento 
  
}

background { 
color rgb<0.1,0.1,0.1>
 
 } 

#declare ThisBlue = color rgb<0.1,0.5,0.8>; 

#declare Fade=
texture {
   pigment {
      gradient <1,1,0>
      color_map {
         [0.0 color ThisBlue]
         [0.3 color ThisBlue]
         [0.5 color Clear]
         [1.0 color Clear]
      }
      rotate z*45
   }
   finish {phong 1}
   scale 5
}

#declare Solid=
texture {
   pigment {ThisBlue}
   finish {phong 1}
}

bicubic_patch {
   type 1 flatness 0.01 u_steps 4 v_steps 4,
   <0, -1.5, 2>, <1, -1.5, 0>, <2, -1.5, 0>, <3, -1.5, -2>,
   <0, -0.5, 0>, <1, -0.5, 0>, <2, -0.5, 0>, <3, -0.5,  0>,
   <0,  0.5, 0>, <1,  0.5, 0>, <2,  0.5, 0>, <3,  0.5,  0>,
   <0,  1.5, 2>, <1,  1.5, 0>, <2,  1.5, 0>, <3,  1.5, -2>
   texture {Solid}
   rotate    -45*y
   translate 
}

blob {
   threshold 0.6
   component 1.0, 1.0, < 0.75,   0,       0>
   component 1.0, 1.0, <-0.375,  0.64952, 0>
   component 1.0, 1.0, <-0.375, -0.64952, 0>
   texture {Solid}
   translate 
}

box {
   <-1, -1, -1>, <1, 1, 1>
   texture {Solid}
   rotate <-25, 15, 0>
   translate 
}

cone {
   x,0.5,
   -x,1.0
   rotate  y*30
   texture {Solid}
   translate 
}

cylinder {
   x,-x,1.0
   rotate  y*30
   texture {Solid}
   translate 
}

...

plane {
   z, 0
   hollow on
   texture {Fade}
   clipped_by{box{<-1,-1,-1>,<1,1,1> scale 3}}
   translate 
}
...

quartic {
   //xxxx         xxyy    xxzz  -2(rr+RR)xx
   <1, 0, 0, 0, 2, 0, 0, 2, 0, -2.5,
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

   //yyyy     yyzz  -2(rr-RR)yy
   1, 0, 0, 2, 0    1.5,     0, 0, 0,  0,

   //zzzz   -2(rr+RR)zz    (rr-RR)(rr-RR)
   1, 0,    -2.5,       0, 0.5625>
   texture {Solid}
   rotate -45*x
   translate 
}


 

viernes, 18 de septiembre de 2015

Asociaciones "many-to-many" en Hibernate

Asociaciones en Hibernate

Mapeo de asociaciones

En los ejemplos anteriores se ha realizado el mapeo de una sola entidad hacia una única tabla. A continuación ampliaremos los ejemplos teniendo en cuenta los distintos tipos de asociaciones entre clases. Tomaremos como ejemplo Personas que participan una serie de Eventos.

1.2.1. Mapeo de la clase Person

Una primera implementación de la clase  Person.java seria la siguiente:

	  package org.hibernate.tutorial.domain;

		public class Person {
		private Long id;
		private int age;
		private String firstname;
		private String lastname;

		public Person() {} // Accessor methods for all properties, private setter for 'id'

	}

Person.hbm.xml

<hibernate-mapping package="org.hibernate.tutorial.domain">
<class name="Person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="native" />
</id>
<property name="age" />
<property name="firstname" />
<property name="lastname" />
</class>
</hibernate-mapping>

Dentro de hibernate.xml:

<mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml" />
<mapping resource="org/hibernate/tutorial/domain/Person.hbm.xml" />

De esta manera hemos configurado la asociación bi-direccional entre ambas entidades. Los principios de diseño importantes a tener en cuenta son la direccionalidad, cardinalidad y el tipo de Collection que necesitamos.

1.2.2. Asociación uni-direccional basada en Set

Al añadir la collection de eventos a la clase  Person , es posible acceder a cada uno de los eventos para una instancia de persona, sin tener que ejecutar de forma explícita la consulta - llamada a  Person#getEvents. Hibernate mapea las asociaciones multi-valuadas a traves de una de las distintas implementaciones de Java Collection Framework; en este caso escogemos java.util.Set ya que no deseamos tener en cuenta elementos repetidos, ni su ordenación, en los ejemplos:

 public class Person {
	private Set events = new HashSet();

	public Set getEvents() {
		return events;
	}

	public void setEvents(Set events) {
		this.events = events;
	}
}
 

Antes de realizar el mapeo de la asociación, vemos que es posible permitir la bi-direccionalidad, creando otra colección de Person dentro de  Event. Esto no tiene por qué estar especificado desde el punto de vista funcional. Es posible implementar una consulta que de forma explicita obtenga todos los participantes dado un evento. Esta parte corresponde al diseño, de momento uni-direccional. Lo que ha de quedar claro, es que la asociación configurada implica una multiplicidad de muchos-a-muchos. Como vemos en el mapping Hibernate siguiente:

<class name="Person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="native" />
</id>
<property name="age" />
<property name="firstname" />
<property name="lastname" />
<set name="events" table="PERSON_EVENT">
<key column="PERSON_ID" />
<many-to-many column="EVENT_ID" class="Event" />
</set>
</class>

Dentro del rango de mapeo a Collection,  set suele ser el más utilizado. Para las asociaciones muchos-a-muchos, y relaciones  n:m entre entidades, es necesaria la existencia de la tabla de asociacion. Dicha tabla se crea usando el nombre del atributo table del elemento set . La clave primaria en la tabla de asociación, se indica mediante el atributo key , los nombres de cada columna que se crean a partir de la entidad Event mediante el atributo column  de la configuración many-to-many. Hibernate acepta tambien que la declaracion de dicha collection sea tipada.

El esquema resultante del mapping sería el siguiente:

   _____________        __________________     |             |      |                  |       _____________   
     |EVENTS    |      |   PERSON_EVENT   |      |             |     |_____________|      |__________________|      
	 |PERSON   |     |             |      |                  |      |_____________|     | *EVENT_ID   |
   <--> 
   | *EVENT_ID        |      |             |     |  EVENT_DATE |      | *PERSON_ID       | 
   <--> 
   | *PERSON_ID  |     |  TITLE      |      |__________________|      |  AGE        |     |_____________|                                |  FIRSTNAME |                                                    |  LASTNAME   |                                                    |_____________|   
 

1.2.3. Trabajando sobre la asociation many-to-many

Creamos una clase EventManager que nos permita realizar ciertas operaciones sobre las entidades:

  	private void addPersonToEvent(Long personId, Long eventId) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();
		Person aPerson = (Person) session.load(Person.class, personId);
		Event anEvent = (Event) session.load(Event.class, eventId);
		aPerson.getEvents().add(anEvent);
		session.getTransaction().commit();
	}
   

Actualizaremos los valores de la colección a través de los métodos que ofrece. Como vemos, no existe una llamada explicita a los métodos  update() o save(); el framework Hibernate detecta automaticamente que la colección se ha modificado y necesita actualizarse (update). A ésto se le llama "automatic dirty checking". Pasar a "dirty" es posible, por ejemplo, modificando cualquier atributo (name, date...) de cualquiera de los objetos entidad. Mientras esten en su estado persistent, reflejado en la session una Hibernate org.hibernate.Session correspondiente, el framework Hibernate controla cualquier cambio y ejecuta sentencias SQL de escritura en segundo plano. El proceso de sincronización del estado de la memoria con la base de datos, que normalmente se ejecuta al final de cada unidad de operación, se denomina flushing. En el código, la finalización de la unidad de operación, se corresponde con la llamada a commit, o ejecución de rollback, dentro de una transacción.

Es posible realizar la carga de los datos de una entidad person y sus events multiples unidades de operación. Además es posible actualizar un objeto fuera de su org.hibernate.Session , cuando no se encuentra en un estado "persistent" (si se encontraba en el estado persistent antes, este nuevo estado se denomina " detached"). En el estado "detached" es posible además modificar los datos de una colección (ej. Events):


  private void addPersonToEvent(Long personId, Long eventId) { 
  Session session = HibernateUtil.getSessionFactory().getCurrentSession(); 		              session.beginTransaction(); //
Person aPerson = (Person)  session
.createQuery("select p from Person p left join fetch p.events where p.id = :pid")
.setParameter("pid", personId).uniqueResult();// Eager fetch the collection so we can use it detached  
   Event anEvent = (Event) session.load(Event.class, eventId); 		      session.getTransaction().commit();  // End of first unit of work        
    aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
    // Begin second unit of work            
     Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();       
     session2.beginTransaction(); 
	 sesion2.update(aPerson); // Reattachment of aPerson         
	 session2.getTransaction().commit();
}
	 	
   

La llamada al método update hace que el objeto pase de "detached" a "persistent" de nuevo, asociándolo a una nueva unidad de operación, de esta forma cualquier modificación que hubiesemos realizado cuando estaba en "detached", se guarda en la base de datos. Esto afecta a cualquier tipo modificación que se hubiese realizado (inserciones/borrados) a la colección (ej. events) de dicha entidad (ej. person).

Aunque no es de mucha utilidad en nuestro ejemplo, se trata de un concepto muy importante que debe ser tenido en cuenta a la hora del diseño. Completaremos el tutorial, añadirendo una nueva acción a la clase manager EventManager y realizaremos una llamada desde la linea de comandos. Para recuperar los identificadores de una persona y de un evento - el método save() devuelve el id:

   else if (args[0].equals("addpersontoevent")) { 
		Long eventId = mgr.createAndStoreEvent("My Event", new Date());
		Long personId = mgr.createAndStorePerson("Foo", "Bar"); 
		mgr.addPersonToEvent(personId, eventId);
		System.out.println("Added person " + personId + " to event " + eventId);       
		}

Este es un ejemplo de asociación entre dos clases de igual relevancia (es decir dos entidades). Como mencionabamos anteriormente, existen otros tipos de clases y tipos, dentro de un modelo, normalmente de menor relevancia en el diseño. Por ejemplo, podriamos tener una clase Address dentro de Person, o un tipo de valor long para Event indicando el timestamp en el que ocurre. Ambos valores dependen de su entidad.

En el diseño puede aparecer una entidad independiente como colección de valores estáticos. Lo cual es conceptualmente distinto a una collection referenciada entre entidades aunque parezca lo mísmo en código.

1.2.4. Añadir una colection de valores

Añadiremos la colección de direcciones email a la entidad  Person. Para ello usaremos java.util.Set de java.lang.String :

private Set emailAddresses = new HashSet();

	public Set getEmailAddresses() {
		return emailAddresses;
	}

	public void setEmailAddresses(Set emailAddresses) {
		this.emailAddresses = emailAddresses;
	}

El mapeo de la colección se realiza de la siguiente manera:

private Set emailAddresses = new HashSet();

	public Set getEmailAddresses() {
		return emailAddresses;
	}

	public void setEmailAddresses(Set emailAddresses) {
		this.emailAddresses = emailAddresses;
	}
	

La diferencia entre el mapeo anterior es la utilización de element lo que indica a Hibernate que dicha colección no referencia otra entidad sino que se trata de un conjunto de valores (en este caso de tipo string), mediante type=string indicamos el conversor de tipo. De igual manera el atributo table del elemento  set se corrresponde con el nombre de la tabla.  key indica el nombre de la columna que se usara como foreign-key en dicha tabal. El atributo column de  element nos indica el nombre de la columna en la que se almacenan los valores en base de datos.

Vemos el esquema resultante:

  _____________        __________________   |             |      |                  |       _____________   |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________   |_____________|      |__________________|      |    PERSON   |      |                   |   |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |   | *EVENT_ID   | 
   <-->
    | *EVENT_ID        |      |             |      |___________________|   |  EVENT_DATE |      | *PERSON_ID       | 
	<-->
	 | *PERSON_ID  | 
	 <--> 
	|  *PERSON_ID       |   |  TITLE      |      
	|__________________|      |  AGE        |      |  *EMAIL_ADDR      |   |_____________| 
	                               |  FIRSTNAME  |    
	  |___________________| |  LASTNAME   |                                         
	  |_____________|  
	   

Se puede ver que la primary key de la tabla de valores correspondiente a la colección es una clave compuesta de ambas columnas. Lo que implica que no pueden existir valores duplicados de email para una persona. Esto es lo que funcionalmente se deseaba y se indico con la Collection java.util.Set en Java.

Vemos la implementación de un método para añadir elementos a la colección, como se hizo anteriormente.

	private void addEmailToPerson(Long personId, String emailAddress) {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();
		Person aPerson = (Person) session.load(Person.class, personId); 
		aPerson.getEmailAddresses().add(emailAddress);
		session.getTransaction().commit();
	}
  

Esta vez no se ha utilizado  fetch query para initializar la colección. Viendo el log de la consulta, intentaremos optimizarlo mediante eager fetch.

1.2.5. Asociación bi-directional

A continuación realizaremos el mapping de una asociación bi-direccional. El esquema creado, no cambia, ya que necesitamos la multiplicidad many-to-many.

Importante

Tener en cuenta que en la navegabilidad es más flexible desde el punto de vista de acceso a una base de datos relacional que el caso de acceso de forma remota; en estos casos seria necesario tener en cuenta la navegabilidad, desde el punto de vista de rendimiento.

Añadimos, la colección de participants a la clase Event :

       private Set participants = new HashSet();

	public Set getParticipants() {
		return participants;
	}

	public void setParticipants(Set participants) {
		this.participants = participants;
	}
	   

Creamos el mapping para la asociación,  Event.hbm.xml

   <set name="participants" table="PERSON_EVENT" inverse="true">
<key column="EVENT_ID" />
<many-to-many column="PERSON_ID" class="Person" />
</set>

Realizamos dicho mapping a través de set en ambos ficheros. Como vemos, los nombres de las columnas dentro de  key y many-to-many, estan intercambiados en ambos documentos .hbm.xml. Lo más importante a tener en cuenta es el atributo inverse="true" dentro del elemento set para el mapping de Event.

Esto indica a Hibernate que ha de acceder a la clase Person , cada vez que necesite información acerca de la relación entre el Event en curso y los participantes.

1.2.6. Trabajando con asociaciones bi-directionales

Tengamos en cuenta que Hibernate no modifica la semantica de Java. Entonces, cómo se enlazan las clases Person y Event en el ejemplo de navegabilidad unidireccional? Al añadir una instancia de  Event a la colección events, dentro de una instancia Person. Si queremos que dicho enlace sea bi-directional, lo que debemos hacer es añadir en una referencia a una collection Person dentro de Event. "Crear un enlace en ambos lados" es absolutamente necesario si queremos que dicho enlace sea bi-direccional.

Su acceso bi-direccional en  Person:

 	protected Set getEvents() {
			return events;
			}

	protected void setEvents(Set events) {
		this.events = events;
	}

	public void addToEvent(Event event) {
		this.getEvents().add(event);
		event.getParticipants().add(this);
	}

	public void removeFromEvent(Event event) {
		this.getEvents().remove(event);
		event.getParticipants().remove(this);
	}
	   

Vemos que los métodos get y set para el manejo de la coleccion son protected. Esto permite que las clases del mismo paquete y sus subclases puedan acceder, evitando que clases fuera del paquete puedan modificarla. Esto se aplica tambien al otro lado (Event).

Respecto al atributo  inverse , en el caso de un enlace bi-directional se trata únicamente de establecer las referencias en ambos lados. Sin embargo, Hibernate necesita más información para realizar las operaciones de INSERT y UPDATE  (y así evitar constraint violations). Si establecemos uno de los lados como inverse  Hibernate lo considerará como  mirror (copia exacta del otro lado). Una vez indicado esto, Hibernate es capaz de resolver la transformación direccional de los objetos enlazados al esquema SQL. Esta configuración es fija: Toda asociación bi-direccional a de tener uno de los lados inverse.

domingo, 19 de abril de 2015

Interceptores en Struts2

Introduccion

Los interceptores procesan una invocacion a Action antes y despues de cada llamada. La mayor parte de la funcionalidad del framework esta implementada mediante interceptores. De esta manera se aplican los filtros ante multiples submits, conversion de tipos, propagacion de objetos, la validacion, el upload de ficheros, la preparacion de pagina y más. Es posible aplicar una pila especifica de ellos de manera que establezcamos que caracteristicas necesita soportar una Action.

Ciclo de vida de una Action

schema

 

Las clases de interceptor se declaran tambien en el fichero de configuración struts.xml utilizando un par clave valor. Los nombres especificados más abajo vienen predeclarados en el fichero struts-default.xml. Es posible declarar nuestros propios interceptores creados para lo cual indicamos el nombre y la clase dentro de la etiqueta.

Lista de Interceptores:

Interceptor

Name

Description

Alias Interceptor

alias

Transforma el nombre de parametros que se envían con distinto nombre en las distintas request.

Chaining Interceptor

chain

Hace que las propiedades de la Action anterior esten disponibles en la Action en curso. Se usa comúnmente con el <result type="chain"> (de la acción precedente).

Checkbox Interceptor

checkbox

Añade un código automático para gestionar los checkbox no inicializados y los añade como parámetros en la request con un valor por defecto (generamente "false"). Utiliza campos hidden para detectar campos que no se han marcado. Se puede modificar el valor que inicia al principio.

Cookie Interceptor

cookie

Inyecta una cookie con un par nombre-valor configurable en la accion (Since 2.0.7.)

CookieProvider Interceptor

cookieProvider

Inyecta cookies desde la acción hacia la response (Since 2.3.15.)

Conversion Error Interceptor

conversionError

Inyecta errores de tipo conversion errors from the ActionContext to the Action's field errors

Create Session Interceptor

createSession

Crea una sesión HttpSession automaticamente, útil con ciertos interceptores, por ejemplo para funcionar correctamente con el el interceptor de tipo TokenInterceptor

DebuggingInterceptor

debugging

Aporta varias plantillas de depuración para entender lo que ocurre detrás de la página.

DeprecationInterceptor

deprecation

Cuand devMode está activado, marca toda configuración desconocida o desestimada (deprecated) settings

Execute and Wait Interceptor

execAndWait

Ejecuta la Action en segundo plano y a continuación reenvia una respuesta hacia una página intermedia de espera.

Exception Interceptor

exception

Mapea las excepciones hacia un <result ...>

File Upload Interceptor

fileUpload

Un Interceptor que facilita el upload de ficheros.

I18n Interceptor

i18n

Guarda la configuración de locale guardada para una user's session.

Logger Interceptor

logger

Escribe el nombre de la Action hacia un <result...>.

Message Store Interceptor

store

Guarda y recupera mensajes de tipo "action messages / errors / field errors" para una acción que implemente la interfaz ValidationAware, dentro de la sesion.

Model Driven Interceptor

modelDriven

Si la Action implementa ModelDriven, apila el resultado de  getModel dentro del Value Stack.

Scoped Model Driven Interceptor

scopedModelDriven

Si la Action implementa ScopedModelDriven, el interceptor recupera ell modelo de la sesion, request, y lo copia en la Action en curso con la llamada setModel.

Parameters Interceptor

params

Establece los parametros de la request en la Action.

Prepare Interceptor

prepare

Si la Action implementa la interfaz Preparable, se realiza la llamada al método prepare.

Scope Interceptor

scope

Es un sencillo mecanismo para almacenar los parametros de la Action en distintos scopes.

Servlet Config Interceptor

servletConfig

Permite acceder a HttpServletRequest and HttpServletResponse.

Static Parameters Interceptor

staticParams

Establece los parametros declarados en struts.xml dentro de la Action. Estos se corresponden con <param> dentro de <action>.

Roles Interceptor

roles

Una Action solo se ejecutara si el usuario tiene el role de JAAS correcto.

Timer Interceptor

timer

Devuelve el tiempo que lleva la Action ejecutandose (incluido sus interceptores anidados y la vista)

Token Interceptor

token

Verifica la presencia de un token dentro de la Action, lo que previene de request con el mismo contenido (multiple submission).

Token Session Interceptor

tokenSession

Lo mísmo que el Interceptor de tipo Token, pero almacena los datos almacenados en la sesion cuando se ha interceptado un token invalido.

Validation Interceptor

validation

Realiza la validacion a partir de los validators declarados en  action-validation.xml

Default Workflow Interceptor

workflow

Llama el método validate en nuestra clase de tipo Action. Si los errores de tipo Action se crean entonces se devuelve la vista INPUT.

Parameter Filter Interceptor

N/A

Elimina parametros de la lista de parametros accesibles a la Action.

Profiling Interceptor

profiling

Activa el profiling entre parametros

Multiselect Interceptor

multiselect

Como el interceptor de tipo checkbox, detecta que no hay valores seleccionados para un campo con muchos valores (al igual que vimos en el Interceptor de tipo Checkbox).

Desde la version 2.0.7, los nombres de Interceptors y Results pasaron a camelCase. (El modelo principal model-driven es ahora modelDriven.) Los nombre antiguos se guardan como "alias" hasta la verion Struts 2.1.0. Las versiones que utilizan la notación hyphen no se listan aqui, pero pueden encontrarse en documentaciones anteriores.