domingo, 10 de septiembre de 2023

Home Assistant con Docker

Home Assistant Logo

Chuleta de comandos útiles para trabajar con la versión Docker de Home Assistant.

 

 

Para actualizar a la última versión estable de Home Assistant realizar las siguientes acciones (ver comandos más abajo):

  1. Parar el contenedor de docker si estuviera en marcha
  2. Eliminar el contenedor de docker
  3. Descargar última versión estable
  4. Arrancar contenedor con la última versión

 

Listado de comandos

Consultar imágenes de docker en el equipo:

docker images

Eliminar imagen de docker (indicando el id de imagen):

docker rmi dcd2b777e7a4 

Consultar contenedores en ejecución:

docker ps -a

Arrancar contenedor ya existente:

docker start homeassistant

Parar contenedor:

docker stop homeassistant 

Eliminar contenedor:

docker rm homeassistant

Descargar última versión estable:

docker pull homeassistant/home-assistant:stable

Arrancar contenedor a partir de la última versión estable de la imagen:

docker run -d  --name homeassistant  --privileged  --restart=unless-stopped  -e TZ=Europe/Madrid  -v $HOME/Development/homeassistant:/config  --network=host homeassistant/home-assistant:stable

miércoles, 28 de enero de 2015

Control de excepciones en peticiones AJAX en JSF 2

Durante la ejecución de una aplicación se pueden producir excepciones en el servidor por diversas causas, un problema de acceso a la base de datos, un error de programación, etc. En el caso de JSF 2, durante las peticiones HTTP, se delega en el sistema que ofrece el contenedor de servlets para el tratamiento de las excepciones. Mediante la definición de reglas del tipo <error-page> en el web.xml de la aplicación podemos conseguir que ante determinadas excepciones del servidor se redirija la petición a una página de error concreta.

JSF 2 además nos ofrece la posibilidad de hilar más fino mediante un ExceptionHandler. La extensión de las clases ExceptionHandlerWrapper y ExceptionHandlerFactory nos permite capturar las excepciones que salten durante la ejecución del ciclo de vida de JSF y hacer un tratamiento concreto dependiendo de la excepción producida.

Este mecanismo es muy útil para el tratamiento de excepciones dentro de llamadas AJAX en una aplicación JSF, puesto que tanto Mojarra como MyFaces ignoran por defecto este tipo de excepciones con las configuraciones de producción, con lo que el usuario no es consciente de que ha ocurrido un error grave en la aplicación.

Vamos a ver como podríamos solucionar este problema con un ejemplo sencillo en el que vamos a redirigir a una página determinada en caso de encontrarnos con una excepción durante una petición AJAX.

Por un lado declaramos nuestra factoría de ExceptionHandler:

public class AjaxExceptionHandlerFactory extends ExceptionHandlerFactory {

 
    /**
     * wrapped
     */
    private ExceptionHandlerFactory wrapped;
 
    /**
     * Constructor de una factoria para el manejo de excepciones AJAX.
     *
     * @param wrapped La factoría que se encapsula.
     */
    public AjaxExceptionHandlerFactory(ExceptionHandlerFactory wrapped) {
        this.wrapped = wrapped;
    }

    /**
     * Devuelve una nueva instancia de AjaxExceptionHandler que
     * envuelve el exception handler original.
     * @return ExceptionHandler ExceptionHandler
     */
    @Override
    public ExceptionHandler getExceptionHandler() {
        return new AjaxExceptionHandler(
            getWrapped().getExceptionHandler());
    }
 
    /**
     * Devuelve la factoría encapsulada.
     * @return ExceptionHandlerFactory ExceptionHandlerFactory
     */
    @Override
    public ExceptionHandlerFactory getWrapped() {
        return wrapped;
    }
}


A continuación nuestro ExceptionHandler:

public class AjaxExceptionHandler extends ExceptionHandlerWrapper {
    /**
     * Logger.
     */
    public static final Log LOG =
        LogFactory.getLog(AjaxExceptionHandler.class);
    /**
     *  Exception handler encapsulado
     */
    private ExceptionHandler wrapped;
    /**
     * Constructos de un nuevo exception handler para peticiones
     * ajax encapsulando el exception handler indicado.
     *
     * @param wrapped El exception handler encapsulado.
     */
    public AjaxExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }
    /**
     * Maneja las excepciones en peticiones ajax de la siguiente manera,
     * sólo y sólo si la actual petición es una petición ajax cuya
     * respuesta aún no ha sido enviada y existe al menos una excepción
     * que no ha sido tratada.
     *
     * Las demás excepciones pendientes serán ignoradas, primero hay que
     * corregir la primera.
     */
    @Override
    public void handle() {
        handleAjaxException(getContext());
        wrapped.handle();
    }
    @Override
    public ExceptionHandler getWrapped() {
        return wrapped;
    }
  
    /**
     * Metodo que devuelve el contexto JSF
     * @return Contexto JSF actual
     */
    private static FacesContext getContext() {
        return FacesContext.getCurrentInstance();
    }
  
    /**
     * Método que se encarga de tratar las excepciones encontradas
     * durante una petición JSF. Sólo se van a tratar las excepciones en
     * peticiones ajax. Si la excepción es en una petición HTTP normal ya
     * se encarga el web.xml de redirigir a la página de error.
     *
     * @param context Contexto JSF actual.
     */
    private void handleAjaxException(FacesContext context) {
        if (context == null
                || !context.getPartialViewContext().isAjaxRequest()) {
            return; // No es una request ajax
        }
        Iterator<ExceptionQueuedEvent> unhandledExcQueuedEvents =
            getUnhandledExceptionQueuedEvents()
                .iterator();
        if (!unhandledExcQueuedEvents.hasNext()) {
            return; // No hay excepciones pendientes.
        }
        Throwable exception = unhandledExcQueuedEvents.next()
            .getContext().getException();
        if (exception instanceof AbortProcessingException) {
            return; // Let JSF handle it itself.
        }
        exception = findExceptionRootCause(exception);
        String errorPageLocation = "/errorPage.xhtml";
        unhandledExcQueuedEvents.remove();
        ExternalContext externalContext = context.getExternalContext();
        LOG.error(String.format(
            "Ocurrio un error no esperado, redirigiendo a %s",
            errorPageLocation), exception);
        // Añadimos información sobre la excepcion al request HTTP para
        //que pueda ser mostrada en la pagina de error
        HttpServletRequest request =
            (HttpServletRequest) externalContext.getRequest();
        request.setAttribute(ERROR_EXCEPTION, exception);
        request.setAttribute(ERROR_EXCEPTION_TYPE, exception.getClass());
        request.setAttribute(ERROR_MESSAGE, exception.getMessage());
        request.setAttribute(ERROR_REQUEST_URI, request.getRequestURI());
        request.setAttribute(ERROR_STATUS_CODE,
            HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        try {
            renderErrorPageView(context, request, errorPageLocation);
        } catch (IOException e) {
            throw new FacesException(e);
        }
        while (unhandledExcQueuedEvents.hasNext()) {
            // No nos interesan el resto de excepciones, sólo la primera.
            unhandledExcQueuedEvents.next();
            unhandledExcQueuedEvents.remove();
        }
    }
    /**
     * Determina la raiz de la causa de una excepción.
     *
     * @param exception La excepción de la que se quiere encontrar
     * la raiz de la causa.
     * @return La excepción raiz de la causa de la excepción primera.
     */
    private Throwable findExceptionRootCause(Throwable exception) {
        return unwrap(exception);
    }
    /**
     * Desenvuelve las causas anidadas de una determinada excepción
     * mientras no se encuentre una instancia del tipo indicado,
     * entonces se devuelve dicha instancia.
     *
     * @param <T> El tipo genérico throwable.
     * @param exception La excepción a desenvolver.
     * @param type El tipo de excepción que tiene que ser devuelto.
     * @return La raiz de la causa de la excepción inicial.
     */
    private static <T extends Throwable> Throwable unwrap(
            Throwable exception, Class<T> type) {
        while (type.isInstance(exception)
                && exception.getCause() != null) {
            exception = exception.getCause();
        }
        return exception;
    }
    /**
     * Devuelve las causas anidadas de una excepción dada mientras no
     * sean instancias de FacesException (Mojarra) o
     * ELException (MyFaces).
     *
     * @param exception La excepción de la que se quiere quitar el
     * anidamiento con FacesException y ELException.
     * @return La causa de la excepción.
     */
    private static Throwable unwrap(Throwable exception) {
        return unwrap(
            unwrap(exception, FacesException.class),
                   ELException.class);
    }
     
    /**
     * Muestra la página de error indicada.
     *
     * @param context Contexto JSF actual
     * @param request Request de la petición actual
     * @param errorPageLocation Localización de la página
     * de error a mostrar.
     * @throws IOException En caso de que ocurra un error 
     * mostrando la página de error, y no se
     * pueda mostrar la página de error de emergencia.
     */
    private void renderErrorPageView(FacesContext context,  
            final HttpServletRequest request,
            String errorPageLocation) throws IOException {
        String viewId = errorPageLocation;
        ViewHandler viewHandler = context
          .getApplication().getViewHandler();
        UIViewRoot viewRoot = viewHandler.createView(context, viewId);
        context.setViewRoot(viewRoot);
        context.getPartialViewContext().setRenderAll(true);
        try {
            ViewDeclarationLanguage vdl = 
                viewHandler.getViewDeclarationLanguage(context, viewId);
            vdl.buildView(context, viewRoot);
            context.getApplication().publishEvent(
                    context,PreRenderViewEvent.class, viewRoot);
            vdl.renderView(context, viewRoot);
            context.responseComplete();
        } catch (Exception e) {
            // Aqui podríamos mostrar una página de error 
            // estática si todo ha ido mal
            throw new FacesException(e);
        } finally {
            // Evitamos que el contenedor de la aplicación 
            // trate de manejar esta excepción.
            request.removeAttribute(ERROR_EXCEPTION);
        }
    }
}


Por último declaramos nuestra factoría en el faces-config.xml de nuestra aplicación:

<factory>
  <exception-handler-factory>
    org.exceptionhandler.AjaxExceptionHandlerFactory
  </exception-handler-factory>
</factory>


Esta solución está basada en la propuesta por la librería Omnifaces. Consutar en las referencias la documentación del FullAjaxExceptionHandler de Omnifaces para una implementación más completa y con ajustes para una mejor integración con distintos frameworks JSF.

Más información:
https://docs.oracle.com/javaee/6/api/javax/faces/context/ExceptionHandler.html
http://showcase.omnifaces.org/exceptionhandlers/FullAjaxExceptionHandler
http://balusc.blogspot.com.es/2012/03/full-ajax-exception-handler.html
https://weblogs.java.net/blog/edburns/archive/2009/09/03/dealing-gracefully-viewexpiredexception-jsf2
http://www.beyondjava.net/blog/jsf-2-0-hides-exceptions-ajax/

sábado, 20 de julio de 2013

Redirigir un dominio propio a tu aplicación en OpenShift

OpenShift de Red Hat nos permite configurar un servidor web en el que podemos instalar nuestras propias aplicaciones. Cuando creas tu cuenta en OpenShift has de indicar el nombre del namespace que van a utilizar tus aplicaciones, con lo que la URL para acceder a ellas tendrá el formato nombreaplicacion-nombrenamespace.rhcloud.com. Esta URL puede estar bien para hacer pruebas o algo poco serio, pero si quieres, puedes asociar un dominio que ya tengas adquirido para que te redirija a tu servidor OpenShift.

Veamos un ejemplo práctico de como he configurado OpenShift para alojar la web, blog y foro de Ikaro Games y usar el dominio ikarogames.com que ya tenía registrado.

El blog y el foro de Ikaro Games son una instalación de Serendipity y phpBB respectivamente, por lo que vamos a necesitar crear un servidor PHP, con los cartridges de MySQL y phpMyAdmin dentro de OpenShift. La creación del servidor es un proceso muy simple, pero recomiendo que cada vez que hacemos un paso nos apuntemos los parametros de configuración y comandos que nos indican en pantalla, por si en algún momento nos hacen falta. De todas formas accediendo mediante SSH al servidor y ejecutando el comando env podremos ver muchos de estos parámetros de configuración y otros que nos pueden ser útiles a la hora de configurar nuestras aplicaciones.

Una vez tengamos la web funcionando sobre OpenShit, por ejemplo, la de Ikaro Games está en http://web-ikarogames.rhcloud.com/, podremos configurar la redirección de nuestro dominio a dicha URL. Para que todo esto funcione son necesarios 3 elementos:


  1. El servidor web donde está alojada la aplicación. En este caso el servidor OpenShift que acabamos de crear.
  2. El dominio que hayamos adquirido, en este caso ikarogames.com.
  3. Un servidor de DNS que nos redirija nuestro dominio a la dirección de nuestro servidor web.
Los puntos 2 y 3 dependen un poco de si el proveedor donde has comprado el dominio te ofrece también el servidor DNS o no. En mi caso no lo ofrecía gratuitamente, por lo que he utilizado para el tercer punto CloudFlare, que por el momento tiene un servicio gratuito de redirección DNS.

Añadimos nuestro dominio a la cuenta de CloudFlare y configuramos la redirección DNS de la siguiente manera:


Al realizar esta configuración en CloudFlare, nos indicará las direcciones de los DNS primario y secundario que tendremos que utilizar para configurar nuestro dominio. En mi caso han sido iris.ns.cloudflare.com y walt.ns.cloudflare.com. Vamos ahora a la web de nuestro proveedor del dominio, y en la configuración del dominio debe haber una sección donde nos permita indicar dichas direcciones DNS.

Una vez tengamos configurado el servidor de DNS y el dominio en la web de nuestro proveedor, nos vamos a la configuración de nuestro servidor en OpenShift y pulsamos sobre la opción Add Alias, indicamos el campo Domain name el nombre de nuestro la URL con la que queramos acceder al servidor, en este caso www.ikarogames.com.

Con esto ya tendremos todo listo para que al acceder a www.ikarogames.com se nos redireccione al servidor OpenShift. El proceso de actualizar las DNS puede tardar hasta 48 horas según nos indican en CloudFlare, pero a mi me tardó apenas un par de horas.

jueves, 18 de julio de 2013

Desplegar una aplicación Java en OpenShift

OpenShift
OpenShift es un servicio de Red Hat que nos ofrece una plataforma de fácil configuración en la nube, lo que se viene a llamar Platform as a Service o PaaS, en la que podremos desplegar nuestras aplicaciones o páginas web, blogs, servidores de pruebas, etc. Entre las opciones disponibles podemos montar servidores JBoss, Tomcat, PHP, Node.js, Ruby, usar bases de datos MySQL, MongoDB, o directamente configurar un blog Wordpress sin ningún esfuerzo.

Una vez registrados, nos ofrece la posibilidad de utilizar hasta 3 Gears gratuitamente. Con estos 3 Gears podremos montar hasta 3 pequeños servidores para poco tráfico, o usar los Gears en un sólo servidor para darle más capacidad de carga de trabajo. Si necesitamos montar servidores que requieran más carga de trabajo, podemos pagar por Gears adicionales.

La interfaz web nos permitirá crear, configurar y eliminar fácilmente los servidores con pocos clicks de ratón así como acceder a la documentación oficial de OpenShift. A parte de la interfaz web, tenemos una aplicación de línea de comandos llamada rhc con la que poder estas y otras operaciones.

Esta es una pequeña chuleta con las operaciones más útiles. Para utilizar los comandos abajo indicados tenemos que tener instaladas previamente las herramientas git y rhc en nuestro sistema.

  1. Creamos una aplicación Java con Tomcat 7:
    rhc app create -a nombreaplicacion -t jbossews-2.0
  2. Borramos el contenido por defecto de la aplicación:
    cd nombreaplicacion 
    git rm -rf src/ pom.xml 
    git commit -am 'removing default files'
  3. Añadimos el fichero WAR al directorio webapps y ejecutamos los siguientes comandos:
    git add . 
    git commit -am 'commit nombreaplicacion.war' 
    git push


Para reiniciar una aplicación tenemos varias opciones:
  1. Desde la interfaz web, vamos a la sección My Applications, seleccionamos la aplicación, y arriba a la derecha hay una opción que nos permite reiniciar la aplicación.
  2. Reiniciar la aplicación desde la consola de comandos:
    rhc app restart -a $your_app
  3. Si lo anterior no funciona, parar y arrancar la aplicación con:
    rhc app stop -a $your_app
    rhc app start -a $your_app
  4. Si la aplicación se ha quedado sin memoria y no funciona todo lo anterior, probar con:
    rhc app force-stop -a $your_app 

jueves, 21 de febrero de 2013

Entorno de desarrollo para JSF 2

Vamos a describir un posible conjunto herramientas de desarrollo para la creación de un proyecto web Java. Este artículo es simplemente una guía de ejemplo y estas no son las únicas ni mejores herramientas, simplemente utilizaremos esta base para los siguientes artículos sobre JSF (Java Server Faces).

Como entorno de desarrollo vamos a utilizar Eclipse con sus plugins para Maven, Git, y TestNG. Como servidor web vamos a utilizar Apache Tomcat y por supuesto el JDK de Java.

Seguiremos los siguientes pasos:

  1. Asegurarnos de tener instalada la última versión de Java en el equipo, este paso depende de en qué sistema operativo estemos, pero suele reducirse a descargar e instalar Java desde la web oficial si estamos en Windows o instalarlo mediante el sistema de paquetes de nuestra distibución Linux.
  2. Descargar el último JDK de Java de la página oficial de Oracle para nuestro sistema operativo. Una vez descargado lo descomprimimos en algún directorio a nuestra elección. Por ejemplo, voy a descargar de dicha página el fichero jdk-7u25-linux-x64.tar.gz y descomprimirlo en mi directorio ~/Programas/Java/jdk1.7.0_25/, puesto que estoy en una máquina Linux de 64 bits.
  3. Descargar la última versión de Eclipse para nuestro sistema y descomprimirlo en un dirección a nuestra elección. Voy a descargar eclipse-jee-kepler-R-linux-gtk-x86_64.tar.gz y descomprimirlo en ~/Pogramas/eclipse_kepler_web/.
  4. Descargar la última versión de Apache Maven y Apache Tomcat y descomprimirlos en un directorio a nuestra elección. Descargaré los ficheros apache-maven-3.0.5-bin.tar.gz y apache-tomcat-7.0.41.tar.gz respectivamente, y los descomprimiré en ~/Programas/Apache/apache-maven-3.0.5/ y en ~/Programas/Apache/apache-tomcat-7.0.41/.
Personalmente prefiero descargar las aplicaciones de sus páginas oficiales y tener un directorio de instalación para cada una de ellas, así podemos tener en un momento dado distintas versiones de una determinada herramienta. Por ejemplo un Eclipse para desarrollo web en Java y otro para desarrollo de aplicaciones en C++.

Ahora abriremos Eclipse, le instalaremos los plugins necesarios y lo configuraremos para empezar a trabajar:
  • Abrimos el directorio de Eclipse que creamos anteriormente y lanzamos el ejecutable que encontraremos allí. Aparecerá una pantalla donde nos pedirá que seleccionemos el workspace. Aquí dejamos la opción por defecto o indicamos un directorio a nuestro gusto, yo prefiero tener workspaces separados según los tipos de proyectos que tengo.
  • Los plugins EGit, Maven Integration for Eclipse WTP (m2e-wtp) están ya integrados en Eclipse a partir de Eclipse Kepler, por lo que no es necesario instalarlos si hemos descargado Eclipse en su edición JEE. Vamos a Help->Eclipse Marketplace e instalamos el plugin TestNG for Eclipse. Estos son los plugins para trabajar desde Eclipse con el sistema de control de versiones Git, Apache Maven, y TestNG respectivamente. Al instalar cada plugin aceptamos las opciones por defecto y nos pedirá que reiniciemos Eclipse.
 Ahora vamos a configurar el workspace para trabajar, esto se hace desde la opción Window->Preferences:
  • Lo primero de todo configuramos la codificación de caracteres para nuestro workspace para ponerla en UTF-8 en General->Workspace, dentro de Text file encoding seleccionamos Other y UTF-8 en el desplegable. Esto es importante para que no haya problemas para que los proyectos funcionen desde distintos sistemas operativos.

  • Vamos a Java->Installed JREs y añadimos como instalación por defecto el directorio del JDK que nos habíamos descargado previamente.
  • Entramos en Maven->Installations y añadimos como instalación por defecto el directorio en el que habíamos descromprimido Apache Maven previamente.
  •  Vamos ahora a Server->Runtime Enviromment y añadimos el servidor Apache Tomcat que habíamos descargado antes.
  • Por último, vamos a la opción TestNG y en la casilla Output Directory escribimos /target/test-output.


Con esto ya tendríamos nuestro entorno de desarrollo Eclipse completamente configurado para comenzar a trabajar en nuestros proyectos.


La configuración del plugin EGit la dejaremos para cuando veamos como trabajar con el sistema de control de versiones Git.

Actualización: Actualizo el artículo para usar Eclipse Kepler edición JEE, que ya trae integrados varios de los plugins que antes había que instalar manualmente.

martes, 12 de junio de 2012

Introducción a JSF 2

JavaServer Faces (JSF) es una especificación para el desarrollo de aplicaciones web mediante Java que lleva varios años en el mercado y forma parte de la plataforma Java EE (Java Enterprise Edition).

La especificación de JSF va actualmente por la versión 2.1 y de ella existen implementaciones como Mojarra, la implementación de referencia desarrollada por Oracle, o MyFaces, la implementación de la Fundación Apache.

Llevo unos años trabajando con JSF 1.2, pero ahora que parece que la nueva versión de la especificación y el ecosistema de librerías existentes alrededor es estable, me he decidido a ponerme las pilas con JSF 2.

Las principales mejoras que trae JSF 2 respecto a JSF 1.2 son:
  • Facelets se integra en JSF como la tecnología a utilizar para la parte de la vista de las aplicaciones. Esto simplifica mucho el desarrollo de la interfaz de usuario y la creación de componentes reutilizables.
  • Integración de llamadas Ajax dentro de la especificación. Antes había que utilizar librerías externas.
  • Capacidad de enviar y recibir parámetros GET dentro de las URLs.
  • Nuevos ámbitos para los beans, como el View Scope que mantiene un bean en memoria mientras se esté utilizando la misma vista que lo utiliza.
  • Simplificación de la configuración de la aplicación mediante el uso de anotaciones.

En resumen JSF 2 es una evolución a mejor de lo que era JSF 1.2, integrando en el estándar varias de las cosas que aportaban librerías externas como RichFaces o PrimeFaces, como el soporte Ajax o el View Scope.

Hola mundo!

Que mejor empezar para un blog sobre programación que con un "Hola Mundo".

Mi nombre es David Ballesteros Mayo, trabajo como desarrollador de aplicaciones y desde aquí voy a ir apuntando las cosas que voy aprendiendo y desarrollando.

En un principio el blog estará enfocado principalmente al desarrollo Java, JSF 2, Hibernate, etc, pero no descarto artículos sobre otros lenguajes como C++ o Python, tecnologías que también me interesan como Ogre3D, o alguna cosa sobre inteligencia artificial.

Espero que os guste.