Diferencias entre null y undefined

En javascript existen cinco tipos primitivos de datos: undefined, null, boolean, number y string.
A primera vista no se aprecia la diferencia entre los tipos undefined y null.

El tipo undefined corresponde a las variables que han sido definidas y todavía no se les ha asignado un valor.
El tipo null se suele utilizar para representar objetos que en ese momento no existen.

Sin embargo aunque son conceptos distintos el operando de igualdad los considera iguales. No así el operando typeof o el operador de igualdad estricta ===.

<br />
(undefined == null) //--> true<br />
(undefined === null) //--> false<br />
(typeof undefined == typeof undefined null) //--> false<br />

Si intentamos operar con una variable que tiene valor null, según el contexto devolverá los siguientes resultados.

Boolean: false<br />
Numeric: 0<br />
String: “null

Si intentamos operar con una variable que tiene valor undefined, según el contexto devolverá los siguientes resultados.

Boolean: false<br />
Numeric: NaN<br />
String: “undefined”

Leave a Comment

Añadir logging a un cliente SOAP de web services

Cuando trabajamos con web services en java, a la hora de depurar nos sería muy útil el poder ver el xml (protocolo SOAP) que se envían cliente y servidor.
Sin embargo no existe una forma 'sencilla' de hacerlo.

La idea consiste en hacer una clase que implemente el interface javax.xml.rpc.handler.Handler, capaz de interceptar los mensajes SOAP antes de su envío del cliente al servidor y antes de la recepción por parte del cliente de los mensajes enviados por el servidor.
Pueden añadirse varios handlers en serie para procesar las llamadas (handler chains). Este comportamiento es idéntico al de un ServletFilter en una cadena de filtros.
Desde esta clase tenemos acceso al contenido del mensaje SOAP, por lo que somos capaces de leerlo y escribirlo en un fichero de texto o similar.

En el caso de un cliente hecho con apache axis, podemos obtener la lista de Handlers asociados a un nombre de puerto (javax.xml.namespace.QName) y a un punto de destino a través de la clase org.apache.axis.client.Service. Una vez obtenida la lista, solo nos resta añadir nuestro Handler.

Vamos a ello. En primer lugar implementamos el interfaz javax.xml.rpc.handler.Handler para interceptar la llamada soap:

package com.madeinxpain.seamcity.ws;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.rpc.handler.Handler;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.handler.soap.SOAPMessageContext;

public class SoapLoggingHandler implements Handler{

private HandlerInfo handlerInfo;
private List streams;

public SoapLoggingHandler() {
streams = new ArrayList();
try {
this.addOutputStreamLog(System.out);
this.addFileLog("soap.xml");
} catch (Exception e) {
e.printStackTrace();
}
}

public void addOutputStreamLog(OutputStream os) {
this.streams.add(os);
}

public void addFileLog(String rute) throws FileNotFoundException {
FileOutputStream fos = new FileOutputStream(new File(rute));
this.addOutputStreamLog(fos);
}

public boolean handleRequest(MessageContext arg0) {
SOAPMessageContext messageContext = (SOAPMessageContext) arg0;
try {
for (OutputStream os : streams) {
os.write(new String("\n\n<!-- REQUEST -->\n").getBytes());
messageContext.getMessage().writeTo(os);
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}

public boolean handleResponse(MessageContext arg0) {
SOAPMessageContext messageContext = (SOAPMessageContext) arg0;
try {
for (OutputStream os : streams) {
os.write(new String("\n\n<!-- RESPONSE -->\n").getBytes());
messageContext.getMessage().writeTo(os);
}
} catch (Exception e) {
}
return true;
}

public boolean handleFault(MessageContext arg0) {
SOAPMessageContext messageContext = (SOAPMessageContext) arg0;
try {
for (OutputStream os : streams) {
os.write(new String("\n\n<!-- FAULT -->\n").getBytes());
messageContext.getMessage().writeTo(os);
}
} catch (Exception e) {
}
return true;
}

public void init(HandlerInfo arg0) {
this.handlerInfo = arg0;
}

public void destroy() {
}

public QName[] getHeaders() {
return handlerInfo.getHeaders();
}
}

Esta clase implementa una serie de métodos extra aparte de los obligatorios definidos por el interface. Estos métodos permiten definir una lista de Streams por los que escribir el mensaje.
Estos métodos de logging deben ser invocado desde el constructor, ya que al añadir el Handler a la cadena (como veremos más adelante) no se añade una instancia de un objeto, si no una clase, y es el framework axis el encargado de crear la instancia mediante el método Class.new Instance(), por lo que no es posible definir las formas de logging si no es en el constructor por defecto del handler.

Un a vez codificada la clase, vamos a proceder a añadirla a la cadena. Cada handler debe estar asociado
Tomaremos como ejemplo un cliente WebService para Microsoft Exchange 2007, creado en un post anterior
En primer lugar buscamos la clase que extiende de org.apache.axis.client.Stub, en nuestro caso llamada ExchangeServiceBindingStub, y le añadimos dos campos para almacenar el port por el que se va a realizar la petición soap y el punto de destino.
Estos campos se van a utilizar en el metodo createCall() a la hora de crear la petición soap.
Por simplicidad crearemos los campos como públicos.

public class ExchangeServiceBindingStub extends org.apache.axis.client.Stub implements com.microsoft.schemas.exchange.services._2006.messages.ExchangeServicePortType {

public javax.xml.namespace.QName portName;
public String endPoint;

// resto del código original de la clase

// metodo a modificar
protected org.apache.axis.client.Call createCall() throws java.rmi.RemoteException {
// codigo anterior
if (super.cachedPortName != null) {
_call.setPortName(super.cachedPortName);
}

// Tenemos que añadir estas dos lineas
_call.setPortName(this.portName);
_call.setTargetEndpointAddress(this.endPoint);

// codigo posterior
java.util.Enumeration keys = super.cachedProperties.keys();

}

Cuando instanciamos el objeto org.apache.axis.client.Stub le añadimos el handler:

public class ExchangeWebServiceClient {
private ExchangeServiceBindingStub esb;
private ExchangeServicesLocator locator;

public ExchangeWebServiceClient() {
this.locator = new ExchangeServicesLocator();
this.esb = (ExchangeServiceBindingStub) locator.getExchangeServicePort(new URL(locator.getExchangeServicePortAddress()));

// Añadimos el handler
QName portName = new QName("http://www.neodoo.es/", locator.getExchangeServicePortWSDDServiceName());
List list = locator.getHandlerRegistry().getHandlerChain(portName);
HandlerInfo handlerInfo = new HandlerInfo();
handlerInfo.setHandlerClass(com.madeinxpain.seamcity.ws.SoapLoggingHandler.class);
list.add(handlerInfo);
this.esb.portName = portName;
this.esb.endPoint = locator.getExchangeServicePortAddress();
}
}

Y con esto y un bizcocho, ya tenemos una forma de depurar las llamadas soap a un webservice desde un cliente hecho con axis.
La optimización del código queda a cargo del desarrollador final ;)

Leave a Comment

Como inyectar un EntityManager en Seam

Con la llegada de EJB 3 y JPA nace la figura del EntityManager para simplificar la persistencia de objetos.
Y gracias a las anotaciones, el EntityManager puede ser inyectado por el contenedor de EJBs.
Vamos a ver diferentes formas de obtener un EntityManager en Seam a través de anotaciones.

  • @PersistenceContext
    EntityManager entityManager;

    El EntityManager es inyectado directamente por el EJB container. El ciclo de vida del EntityManager inyectado de esta forma terminará cuando la transacción sea completada.
    Tras el cierre de la transacción, las entidades son desacopladas del contexto de persistencia, lo que puede dar lugar a una LazyLoadException.

  • @PersistenceContext(type=PersistenceContextType.EXTENDED)
    EntityManager entityManager;

    El EntityManager es inyectado directamente por el EJB container, y estará disponible aún después de que la transacción haya sido completa.
    Las entidades pueden seguir asociadas al contexto de persistencia durante varias interacciones.

  • @In
    EntityManager entityManager;

    De esta forma, el EntityManager es inyectado por Seam y asociado al contexto de conversación, con las mismmas características que un EntityManager de tipo extendido.

  • @PersistenceUnit
    EntityManagerFactory;

    public void getNewEmInstance() {
    return emf.createEntityManager();
    }

    Esta anotacion inyecta un EntityManagerFactory, que permite crear objetos EntityManager mediante el método EntityManagerFactory.createEntityManager();

Leave a Comment

Extendiendo el objeto Array

Una de las mejores características de javascript es que se pueden añadir funciones a las 'clases' en cualquier momento a traves de la propiedad prototype.
Aprovechando esta capacidad podemos extender el objeto Array para añadirle funcionalidades de búsqueda y eliminación.

array.indexOf
Devuelve el indice del array en el que se encuentra el elemento. Devuelve -1 si no encuentra el elemento

Array.prototype.indexOf = function(element) {
  for (var i = 0; i &lt;this.length; i++) {
    if(this[i] == element) return i;
  }
  return -1;
};


array.exists

Devuelve true si el elemento se encuentra en el array, haciendo uso de la funcion indexOf

Array.prototype.exists = function(element) {
  return this.indoexOf(element) != -1;
};

array.filter
Devuelve un array que contiene solo los elementos para los que la función pasada como argumento devuelve true

Array.prototype.filter = function(fn) {
  var array = [];
  for (var i = 0; i &lt;this.length; i++) if(fn(this[i])) array.push(this[i]);
  return array;
};

array.removeIndex
Elimina todos los elementos del array que están entre los índices from y to. Si solo se especifica valor para from, se elimina solo el elemento que se encuentra en ese índice.

Array.prototype.removeIndex = function(from, to) {
  if (from &lt;0) return;
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from &lt;0 ? this.length + from : from;
  return this.push.apply(this, rest);
};

array.remove
Elimina un elemento del array, usando las funciones removeIndex e indexOf

Array.prototype.remove = function(e) {
  return this.removeIndex(this.indexOf(e));
};

array.execute
Ejecuta la función fn pasandole como argumento cada elemento del array
si le pasamos el argument obj, se ejecutara la funcion fn como si perteneciese al objeto obj

Array.prototype.execute = function(fn, owner) {
  for (var i=0; i<;this.length; i++){
    if (owner) fn.call(owner, this[i]);
    else if (typeof this[i] != 'function') fn(this[i]);
  }
}

array.foreach
Ejecuta la función fn en cada elemento del array, pasandole como argumentos los elementos contenidos en el array args
si le pasamos el argument obj, se ejecutara la funcion fn como si perteneciese al objeto obj

Array.prototype.foreach = function(fn, args) {
  for (var i=0; i<this.length; i++) {
    fn.apply(this[i], args);
  }
}

Leave a Comment

Seam y Ajax con Seam Remoting

Realizar peticiones Ajax a tus componentes en Seam es increíblemente fácil gracias al framework Seam Remoting.
Con solo añadir un par de lineas de javascript, tu componente escrito en Java se convierte en un componente javascript, pudiendo acceder a sus campos y ejecutar sus métodos asíncronamente.
En simplemente tres pasos podemos invocar a un componente y manejar la respuesta.

1) Indica los métodos que van a invocarse vía Ajax
Simplemente marca con la anotación @WebRemote los métodos que quieras invocar por Ajax.

@Name("calculadora")
public class Calculadora {

   private float pi = 3.14;
   private float n = 10;

    @WebRemote
    public int suma(float a, float b) {
        return a+b
    }

    @WebRemote
    public int sumaConstante(float a) {
        return this.n + a;
    }

    // Este metodo no está marcado con @WebRemote, por lo que no se puede invocar desde javascript
    public void metodoNoAjax() {
    }
 
    public float getPi() { return this.pi;}
}

Si quisieses invocar un EJB en lugar de un POJO, las anotaciones @WebRemote deberán estar en la declaración los métodos de la interface del EJB.

2) Importa los scripts necesarios
Primero debes importar el script que contiene el código que permite las llamadas remotas:

<script type="text/javascript" src="seam/resource/remoting/resource/remote.js"></script>

Ahora por cada componente que contenga métodos que quieras invocar vía Ajax debes importar otro script en el que indicas el nombre del componente (el que has definido en la anotacion @Name).
Este script contiene el stub del componente, que indica los métodos a los que puedes llamar y la definición de sus tipos.
Por ejemplo, si tienes un componente anotado con @Name("calculadora") deberás incluir la siguiente linea

<script type="text/javascript" src="seam/resource/remoting/interface.js?calculadora"></script>

Si quisieses acceder a más de un componente en la misma página puedes especificar varios componentes:

<script type="text/javascript" src="seam/resource/remoting/interface.js?calculadora&componente2&componente3"></script>

También puedes importar el javascript de los componentes usando el tag s:remote.

<s :remote include="calculadora,componente2,componente3"/>

3) Invoca el método y maneja la respuesta
Ahora podemos invocar los métodos de nuestra calculadora marcados con @WebRemote.
Para obtener los objetos javascript que representan nuestros componentes debemos hacerlo a través de Seam.Component.
En la llamada le pasamos los parámetros que tenga el método al que estemos invocando (admite sobrecarga) y un último parámetro que será la función a la que se invocará con el resultado de la invocación

<script type="text/javascript">
  //<![CDATA[

  function suma() {
    Seam.Component.getInstance("calculadora").suma(1, 5, muestraResultado);
  }

  function muestraResultado(result) {
    alert(result); // --> mostrará un 6
  }

   // ]]>
</script>

También puedes acceder a los campos del componente que tengan un getter asignar un valor a los que tengan un setter.

<script type="text/javascript">
  //<![CDATA[

  var calc = Seam.Component.getInstance("calculadora");
  function suma() {
    calc.n = 25;
    calc.sumaConstante(5, muestraResultado)
  }

  function muestraResultado(result) {
    alert(result);   // --> mostrará 30
    alert(calc.pi); // --> mostrará 3.14
  }

   // ]]>
</script>

Seam Remoting también permite evaluar EL Expressions, trabajar con Collections, hacer debug de las llamadas enviadas y recibidas, suscribirse a una cola JMS.
Toda esta información y más se encuentra disponible en la documentación en inglés

Leave a Comment

Obtener un EntityManager sin inyección de dependencias

Para obtener un EntityManager en un componente Seam, la vía más fácil es usar la anotación @In y disfrutar de las ventajas del mecanismo de inyección de dependencias de Seam.

@In
EntityManager entityManager;

Pero estas ventajas solo están disponibles dentro de los componentes, es decir, en aquellas clases anotadas con @Name.
Si en una clase normal quisiésemos obtener el EntityManager, deberíamos hacerlo manualmente.

// PERSISTENCE_UNIT_NAME es el nombre del persistence-unit definido en el archivo persistence.xml
EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = emf.createEntityManager();

Leave a Comment

Incluir código javascript en un documento XHTML

Si estás trabajando con Seam, muy probablemente estés utilizando Facelets para la vista y páginas xhtml.
Si intentas incluir código javascript en un documento XHTML directamente puede que de algunos problemas con los símbolos < ("menor que",&lt;) y & (amperstand), ya que el navegador los intentará interpretar como partes de etiquetas xhtml y dará algún error de sintaxis.

Para evitar ésto podemos escribir nuestro javascript entre etiquetas CDATA. Ésta etiqueta lo que hace es indicarle al validador de XHTML que ignore todo lo que se encuentre en su interior. El problema es que algunos navegadores no entienden la etiqueta CDATA, por lo que deberemos comentar la etiqueta CDATA. De esta forma, si el navegador no la sabe interpretar, la ignorará.

<script type="text/javascript">
//<![CDATA[

 alert("<Ésto & y ésto <<  es compatible con XHTML>");

//]]>
</script>

Leave a Comment

Bloquear la pantalla con javascript

Hay ocasiones en las aplicaciones web que nos interesa bloquear la pantalla del navegador para impedir al usuario interactuar con la aplicación.
Un ejemplo es durante una llamada ajax que tarda un cierto tiempo y queremos mostrar el típico mensaje "loading" y poner el fondo con un tono oscuro, o para pedir nombre de usuario y contraseña.

Una solución simple para este problema consiste en poner un div que ocupe toda la pantalla y se sitúe por encima del resto de componentes. Así todos los clicks del ratón se realizarán sobre nuestro div en vez de sobre el botón que se ve debajo.
Después, mediante javascript muestras el div bloqueador. No te olvides de proporcionar alguna forma para quitar este elemento.
Estas propiedades del div se pueden especificar en una clase css

.blocker {
position: absolute;
top: 0px;
left: 0px;
height:100%;
width:100%;        /* hacemos que ocupe toda la pantalla a cualquier resolución*/
z-index: 50;        /* lo colocamos por encima del resto de componentes*/
background: url(b.png) repeat/*Color de fondo semitransparente*/
}

Si queremos añadir algun mensaje o una ventana con la que se desee interactuar, solo tenemos que colocar un div que quede por encima del anterior.

.popup{
z-index: 100;                     /* un z-index mayor al del blocker */
background-color: white/* Un color de fondo para que se vea sobre la capa anterior*/
}

Ver ejemplo de bloqueo de pantalla

Si usas jQuery (o librerias similares) dispondrás de buenos plugins (como facebox) para hacer esto mismo con muchas mas opciones y efectos.

Leave a Comment

Crear un cliente java de Web Services para Exchange 2007

Para crear el cliente he usado el IDE eclipse-Red Hat Developer Studio, pero el procedimiento será similar para cualquier IDE.
Supondremos que la dirección del servidor es "my.exchange.com".

El primer paso es bajarse del servidor exchange estos 3 archivos y guardarlos en local:
* https://my.exchange.com/ews/Services.wsdl
* https://my.exchange.com/ews/messages.xsd
* https://my.exchange.com/ews/types.xsd
Después hay que modificar el archivo "Services.wsdl" para añadir el servicio y su url.

Debes añadir al final del archivo (antes de cerrar la etiqueta <wsdl:definitions>) las siguientes lineas:

<wsdl :service name="ExchangeServices">
     </wsdl><wsdl :port name="ExchangeServicePort" binding="tns:ExchangeServiceBinding">
       <soap :address location="https://my.exchange.com/EWS/Exchange.asmx"/>
     </wsdl>

Ahora tendrás que modificar los archivos "types.xsd" y "messages.xsd" para que maneje correctamente los arrays, mapeandolos a colecciones.
Para cada tipo llamado "ArrayOf..." o "NonEmpyArrayOf..." tendrás que añadirle el atributo maxOccurs="unbounded"
Ejemplo:

<xs :complexType name="ArrayOfFoldersType">
    </xs><xs :choice minOccurs="0" maxOccurs="unbounded">
      <xs :element name="Folder" type="t:FolderType" maxOccurs="unbounded"/>
      <xs :element name="CalendarFolder" type="t:CalendarFolderType" maxOccurs="unbounded"/>
      <xs :element name="ContactsFolder" type="t:ContactsFolderType" maxOccurs="unbounded"/>
      <xs :element name="SearchFolder" type="t:SearchFolderType" maxOccurs="unbounded"/>
      <xs :element name="TasksFolder" type="t:TasksFolderType" maxOccurs="unbounded"/>
    </xs>

Si ya has generado el cliente y sin haber cambiado esto, las clases "ArrayOf..." y "NonEmpyArrayOf..." y generadas serán incapaces de manejar arrays.
Pero aún tiene solución. Deber añadir a cada clase un campo de tipo List (cualquier Collection vale), y en cada método setXXX añadir el objeto pasado como parámetro al array.
Por ejemplo, en la clase ArrayOfRealItemsType:

// declaras la lista:
private List&lt;ItemType&gt; items = new ArrayList&lt;ItemType&gt;();

//sobreescribes los setters para añadir los parametros a la lista:
public void setPostItem(com.microsoft.schemas.exchange.services._2006.types.PostItemType postItem) {
    this.items.add(postItem);
    this.postItem = postItem;
}

public void setMessage(com.microsoft.schemas.exchange.services._2006.types.MessageType message) {
    this.items.add(message);
    this.message = message;
}

// etc..

Una vez que has generado el cliente verás que te da algunos fallos de compilación.
Esto es porque por algún motivo los constructores no se generan bien.
Tras arreglar los fallos podemos continuar.

La clase principal para realizar las llamadas al Web Service es ExchangeServiceBindingStub.
Creamos el objeto y le ponemos los parametros de usuario, password y servidor.

ExchangeServiceBindingStub esb = (ExchangeServiceBindingStub) new ExchangeServicesLocator().getExchangeServicePort(new  URL(locator.getExchangeServicePortAddress()));
esb.setUsername("usuario");
esb.setPassword("password");
esb._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, "https://my.exchange.com/EWS/Exchange.asmx");

Antes de continuar debes asegurarte que el servidor tiene activada la autentificación básica, si no te saldrá un error HTTP 402.2 "acceso denegado debido a la configuración del servidor"

Ahora solo queda invocar al método del Web Service que quieras y rellenar los parámetros requeridos.

Comments (1)

Acción por defecto de un form JSF

Al rellenar un formulario, si le das al enter cuando el foco está en uno de los input, el fomulario se envía.

En la mayoría de los casos esto está bien, ¿pero qué ocurre si queremos modificar ese comportamiento?
Concretamente, ¿como podemos modificar ese comportamiento si trabajamos con JSF? Lamentablemente, la especificación no contempla este caso.

Si estás utilizando Seam, esto lo puedes hacer con la etiqueta <s:defaultAction>, que permite cambiar la acción que se ejecuta por defecto al presionar el enter. Si no estás utilizando Seam, puedes usar la libreria javascript4jsf , y su tag <j4j:defaultAction>, que tiene el mismo comportamiento.

Pero si quieres algo rápido, lo más sencillo es incluir un h:commandButton oculto y desactivado. Así al presionar el enter, lanzará la acción del commandButton en vez de enviar el form.

<h :commandButton action="#{mi.accion}" style="display:none;" disabled="true" />

Comments (2)