Otros tipos de inyección de dependencias

No es la primera vez que hablo en este blog sobre inyección de dependencias, el patrón que nos permite pasar todas las dependencias que una clase necesita en el constructor en vez de como argumentos en métodos o utilizar clases estáticas.

En el caso de Java, donde últimamente paso la mayoría de mi tiempo, contamos con Spring y Guice como las maneras más conocidas de inyectar dependencias, veamos un ejemplo de Spring.

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ClassWithDependencies {
    private final DependentClass dependentInstance;

    public void doSomethingWithDependency(){
        dependentInstance.doSomething();
    }
}

@Component
public class DependentClass {
    public void doSomething(){
        System.out.println("Doing something")
    }
}

En este ejemplo, con las anotaciones @Component de Spring y @RequiredArgsConstructor de Lombok (un pre-procesador que nos permite agregar setters, getters y constructores a Java) podemos definir ClassWithDependencies como una clase que recibe DependentClass como parámetro del constructor, y luego operar sobre ella.

En artículos anteriores hemos hablado de otros sistemas como el de ASP.net vNext o incluso crear el nuestro propio. Creando un motor de inyección de dependencias con C#

Es importante destacar que en este ejemplo concreto, la inyección construye una nueva instancia de la clase cada vez que se inyecta, siendo la más sencilla de las opciones de inyección.

Una instancia por ejecución (Singleton)

Sin embargo, podemos personalizar aún más el tipo de inyección que hacemos. Volviendo a nuestro ejemplo anterior, supongamos que DependentClass contiene información de la máquina (memoria, procesador, etc) en la que se ejecuta, y por tanto no cambiará a lo largo de la vida de nuestra aplicación.

En este caso, una nueva instancia de cada clase sería innecesario o incluso costoso, dependiendo del tipo de inyección, para lo cual, en la definición del componente, especificamos qué tipo de inyección queremos

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ClassWithDependencies {
    private final MachineContext machineContext;

    public void doSomethingWithDependency(){
        machineContext.getProcessor();
    }
}

@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class MachineContext {
    public String getProcessor() {
        return "Intel";
    }
}

Comparemos esto con definir un patrón singleton de manera manual:

public class ClassWithDependencies {
    private final MachineContext dependentInstance;

    public void doSomethingWithDependency(){
        MachineContext.getInstance().getProcessor();
    }
}

public class MachineContext {
    private static MachineContext instance;

    public String getProcessor() {
        return "Intel";
    }

    private MachineContext() {
    }

    public static MachineContext getInstance(){
        if(instance == null){
            instance = new MachineContext();
        }
        return instance;
    }
}

La principal diferencia de usar Singleton en inyección respecto al singleton estándar que podemos ver en el ejemplo anterior es con inyección de dependencias tenemos las ventajas de singleton y mantenemos la capacidad de probar nuestro sistema, ya que en una prueba de ClassWithDependencies podríamos simular o utilizar un mock de MachineContext (por ejemplo si queremos probar cómo se comporta nuestra aplicación en distintos contextos).

Una instancia por petición (Request)

Una variante de Singleton especialmente para web, ocurre cuando el contexto depende de la petición o la sesión. Para este ejemplo, tenemos una función que se dedica a llevar un registro de las excepciones, y queremos, para cada excepción, registrar además el Id del usuario al que le ocurrió la excepción.

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GlobalExceptionHandler {
    private final Request request;

    public void handleException(Exception ex){
        logger.error(request.getUserId(), ex.getStacktrace())
        machineContext.getProcessor();
    }
}

@Component
@Getter
@Setter
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class Request {
    private String userId;
}

Este formato nos permite rellenar la clase Request en la capa del controlador de de nuestra aplicación, y en la otra directamente preguntar por el estado, sin necesidad de tener que pasar el objeto request a lo largo de toda la cadena de llamadas hasta la captura de esta excepción.

Con ello, evitamos que nuestras clases tengan una referencia al objeto únicamente por tener que pasarlo a la siguiente capa, se simplifica el número de parámetros que manejamos y podemos referirnos al contexto siempre que lo necesitemos.

Conclusiones

En este artículo hemos repasado inyección de dependencias de manera tradicional y además hemos visto las ventajas de utilizar construcciones como Singleton y Request.

Y tú, usas estas construcciones cuando desarrollas aplicaciones?

Autenticación con Visual Studio Online desde Java usando OAuth

El protocolo OAuth nos proporciona una manera muy fiable de autenticación, así como la posibilidad de interconectar sistemas sin tener que ceder nuestras credenciales a un tercero.

Visual Studio Online es uno de los proveedores que lo soporta, aunque con ciertas peculiaridades. En este artículo veremos cómo podemos utilizar OAuth con Java para conectarnos y autenticarnos, así las peculiaridades de VSO.

Cómo funciona OAuth2.0

Oauth se basa en dos conjuntos de clave, conocidos como key y secret, que el cliente (Aplicación A) proporciona al sistema al que se quiere conectar (Aplicación B). Veamos un ejemplo del ciclo de vida de una petición OAuth:

  1. El usuario desde Aplicación A solicita autenticar con Aplicación B
  2. Aplicación A redirige a la página de Aplicación B con la Api_Key, la url de retorno y otros parámetros como parte de la redirección.
  3. El usuario introduce sus credenciales y autoriza (o no) la cesión de datos desde la Aplicación B a la Aplicación A.
  4. La Aplicación B redirige de vuelta a la Aplicación A con la url de retorno especificada anteriormente con un código de autenticación.
  5. De lado de servidor, la Aplicación A le envía a la Aplicación B el código de autenticación, el secret, y otros parámetros.
  6. La Aplicación B devuelve un Token a la Aplicación A que identifica al usuario y que se puede empezar a utilizar para realizar peticiones.

Cliente Oauth

Vamos a crear un ejemplo de Aplicación A, es decir, un cliente OAuth. Para ello utilizaremos scribe, un componente OAuth para Java muy sencillo y muy fácil de extender para adaptar a nuestras necesidades:

OAuthService service = new ServiceBuilder()
                                  .provider(LinkedInApi.class)
                                  .apiKey(YOUR_API_KEY)
                                  .apiSecret(YOUR_API_SECRET)
                                  .build();

A partir de ese código podemos generar la URL de redirección o capturar el Token. Como Visual Studio Online no forma parte de los proveedores por defecto, crearemos nuestro propio proveedor:

@Override
public class VSOnlineApi extends DefaultApi20 {

    @Override
    public String getAccessTokenEndpoint() {
        return "https://app.vssps.visualstudio.com/oauth2/token";
    }

    @Override
    public String getAuthorizationUrl(OAuthConfig oac) {
        return String.format("https://app.vssps.visualstudio.com/oauth2/authorize?mkt=es&client_id=%s&response_type=Assertion&state=sample&scope=vso.profile&redirect_uri=%s", 
                oac.getApiKey(), oac.getCallback());
    }

    @Override
    public Verb getAccessTokenVerb() {
        return Verb.POST;
    }

    
    @Override
    public OAuthService createService(OAuthConfig config) {
        return new VSOOauthService(this, config);
    }

    @Override
    public AccessTokenExtractor getAccessTokenExtractor() {
        return new VSOTokenExtractor();
    }
}

Este proveedor consta de dos urls, la de token y la de autorización, el verbo que utilizaremos para solicitar el access token, y dos componentes, un servicio que crearemos a continuación y el extractor para procesar el código resultado de la autenticación. Con este proveedor podemos generar la URL para realizar la redirección:


 OAuthService service = new ServiceBuilder()
                           .provider(VSOnlineApi.class)
                           .apiKey("KEY")
                           .apiSecret("SECRET)
                           .callback("https://rlbisbe.dev:4567/callback")
                           .signatureType(SignatureType.QueryString)
                           .build();

Por otra parte, para poder hacer la llamada del lado de servidor y validar el token necesitaremos implementar el servicio VSOOauthService, ya que la implementación OAuth de Visual Studio Online tiene ciertas peculiaridades.

public class VSOOauthService extends OAuth20ServiceImpl {

    private final DefaultApi20 api;
    private final OAuthConfig config;
    
    public VSOOauthService(DefaultApi20 api, OAuthConfig config) {
        super(api, config);
        
        this.api = api;
        this.config = config;
    }
    
    @Override
    public Token getAccessToken(Token requestToken, Verifier verifier)
    {
      OAuthRequest request = new OAuthRequest(api.getAccessTokenVerb(), api.getAccessTokenEndpoint());
      request.addBodyParameter(VSOConstants.CLIENT_ASSERTION_TYPE, "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
      request.addBodyParameter(VSOConstants.GRANT_TYPE, "urn:ietf:params:oauth:grant-type:jwt-bearer");
      request.addBodyParameter(VSOConstants.CLIENT_ASSERTION, config.getApiSecret());
      request.addBodyParameter(VSOConstants.ASSERTION, verifier.getValue());
      request.addBodyParameter(OAuthConstants.REDIRECT_URI, config.getCallback());
      request.addHeader("Content-type", "application/x-www-form-urlencoded");
      config.log(request.getCompleteUrl());
      Response response = request.send();
      return api.getAccessTokenExtractor().extract(response.getBody());
    }
}

Esta clase nos permite construir una petición POST (que hemos visto antes en que nos permitirá validar el código que hemos recibido desde Visual Studio Online utilizando el secret de nuestra aplicación y las claves específicas que nos solicita la aplicación, enviar la petición y convertir el resultado en un Token para futuras peticiones.

Creando la web para conectarnos al servicio

Una vez que tenemos el servicio creado para obtener el token, vamos a crear una pequeña página para poder hacer el proceso completo. Para ello utilizaremos spark, un proyecto inspirado en Sinatra que nos permite crear aplicaciones web de una manera rápida y sencilla:


        OAuthService service = new ServiceBuilder()
                           .provider(VSOnlineApi.class)
                           .apiKey("KEY")
                           .apiSecret("SECRET")
                           .callback("https://rlbisbe.dev:4567/callback")
                           .signatureType(SignatureType.QueryString)
                           .debugStream(System.out)
                           .debug()
                           .build();
        
        get("/auth", (req, res) -> {
            res.redirect(service.getAuthorizationUrl(EMPTY_TOKEN));
            return null;
        });
        
         get("/callback", (req, res) -> {

             String code = req.queryParams("code");
             Verifier verifier = new Verifier(code);
             Token token = service.getAccessToken(EMPTY_TOKEN, verifier);
             return token;
        });

Con el sódigo anterior podemos ver dos puntos de entrada, /auth, que realiza la redirección al servicio, y /callback, que recoge el resultado de la redirección, parsea el código del resultado, solicita el token utilizando el servicio que hemos creado anteriormente y muestra el token como resultado:

Token[CODIFICADOENHEXADECIMAL, ]

Consideraciones adicionales: SSL

Visual Studio Online requiere que la url de retorno esté bajo el protocolo SSL y no admite localhost, con lo cual para pruebas lo que podemos hacer es crear un certificado autofirmado utilizando la utilidad Keytool de Java:

keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048

Además deberemos importar dicha keytool dentro de nuestro proyecto para poder utilizar HTTPS:

        SparkBase.setSecure("C:\\Users\\Roberto\\Documents\\NetBeansProjects\\OauthClientTest\\keystore.jks", "password", null, null);

Finalmente, como no admite localhost, una solución puede ser utilizar el nombre DNS de nuestro ordenador de pruebas, o bien mediante el fichero hosts crear una entrada para 127.0.0.1, en mi caso rlbisbe.dev

Documentación

Desarrollando The Time Box, mi primera aplicación para Android

El ecosistema Android ha ido madurando de manera muy acelerada en los últimos años, y lo que comenzó como un proyecto piloto se ha convertido en el segundo jugador (o primero según el mercado) móvil a nivel mundial, y aprender a desarrollar para él de manera nativa puede ser una opción interesante, sobre todo si ya hemos trabajado en plataformas como Windows Phone o iOS.

Esto me llevó a hacer el año pasado un curso de Coursera sobre Desarrollo de aplicaciones para Android, y, con lo aprendido, hacer mi primera aplicación. En este artículo cuento mi experiencia desarrollando la misma, así como las herramientas y los recursos utilizados en este primer viaje por el ecosistema Android.

Descarga The Time Box desde Google Play

La aplicación

The Time Box es una mezcla entre lista de tareas y cronómetro, con opción de poder agregar manualmente las horas y minutos transcurridos de la actividad deseadas. Este es el aspecto que ha tenido desde la primera vez que tuve algo «depurable» hasta la versión actualmente disponible en la tienda:

Presentation1

Tras la primera versión, Sergio Moya, compañero de aventuras, me sugirió utilizar material design, y gracias a las guías disponibles y a las opciones de compatibilidad con terminales antiguos, pude adaptar la mayor parte del diseño sin demasiados problemas.

Lenguaje

Para programar en android podemos utilizar Java, o desde algunas versiones C++ para trabajo intensivo de procesador, como juegos. También podemos utilizar otros lenguajes que compilen a la VM como es el caso de Clojure, Scala o Kotlin de Jetbrains, siendo este último una alternativa interesante, ya que se trata de un lenguaje de más alto nivel, orientado a objetos y dinámico. Tras probarlo durante un par de iteraciones volví a Java, aunque no descarto utilizarlo en un futuro.

Arquitectura

architecture_app

La aplicación cuenta con tres vistas (actividades como se denominan en Android), un controlador de tabs, dos fragmentos personalizados y varias clases auxiliares para el manejo de los datos.

Componentes externos

La aplicación emplea dos componentes adicionales:

  • Joda-time: Aporta una mejor gestión de fechas y horas a las clases existentes de Java
  • SugarORM: Un mapper relacional muy sencillo que permite tener una pequeña base de datos sqlite donde almacenar los datos, que además cuenta con soporte para migraciones.

Testing

Actualmente el proyecto cuenta con algunos tests unitarios, y la idea es que los tests vayan aumentando a medida que se necesite más funcionalidad para evitar pruebas manuales, que al final son las que más tiempo consumen.

Herramientas

Las herramientas para el desarrollo Android también han mejorado mucho últimamente, podemos utilizar Eclipse con el plugin ADT, o también podemos emplear Android Studio, basado en InteliJ IDEA y soportado oficialmente por Google.

Para poder depurar nuestra aplicación, lo mejor y más rápido es contar con un dispositivo físico, o varios, ya que hemos de probar con diferentes versiones. Podemos además recurrir a emuladores como Genymotion, que al estar basado en VirtualBox, nos proporciona una máquina virtual muy rápida y fluida, lejos del pobre rendimiento que proporciona el emulador oficial.

Publicación y subida

Para poder publicar en Google Play (de momento no he considerado otros marketplaces como el de Amazon, aunque están en mi lista) necesitamos pagar la cuota de inscripción, que son $25 y que nos dan acceso permanente, sin necesidad de renovar. Como la aplicación es gratuita y (de momento) no usa publicidad, el proceso de registro es bastante simple. Una vez que tenemos la aplicación lista, basta con generar el APK desde nuestro editor, subirlo a la plataforma y llenar la información relativa al título, descripción, así como algunas imágenes.

Una de las cosas más interesantes que ofrece la plataforma son las opciones de Alpha y Beta, ya que podemos tener hasta tres versiones subidas de la aplicación al mismo tiempo para tres grupos distintos de usuarios sin tener que recurrir a servicios externos.

Conclusiones

Esta pequeña utilidad que espero seguir mejorando con el tiempo me ha permitido tener un primer contacto con la plataforma y reencontrarme con Java después de varios años. Es una experiencia muy interesante y aporta una visión adicional si trabajas con varias plataformas.

Descarga The Time Box desde Google Play

Recursos

Material Design

Recuperar la clase a la que pertenece un objeto en Java y C#

Una acción bastante común en programación orientada a objetos es poder conocer si un objeto pertenece a una clase concreta. Se suele usar al reimplementar métodos para agregar funcionalidad a la ya existente usando herencia.

En este artículo se verá cómo conocer si un objeto pertenece a una clase concreta usando Java y C#. Para el ejemplo se usará una clase que se podrá comparar con otra.

Supongamos que tenemos una clase Persona con los siguientes parámetros:

  • DNI
  • Nombre
  • Apellidos

El objetivo es conseguir implementar la funcionalidad necesaria para poder comparar personas por DNI.

Implementación en Java

En Java, el código a escribir sería el siguiente:

public class Persona {

    private String DNI;
    private String Nombre;
    private String Apellidos;

    public String getDNI()
    {
        return DNI;
    }

    @Override
    public boolean equals(Object o) {
        if(o instanceof Persona && ((Persona)o).getDNI().equals(getDNI()))
            return true;
        return false;
    }
}

Las primeras líneas contienen la definición de la clase, los tres valores usados y el método getDNI para poder acceder al valor DNI, que será solo lectura.

Para comparar lo que se ha hecho es reemplazar (override) el método equals, que se hereda de la clase Object y de la que heredan todas las clases en Java. Esta comparación primeramente comprueba que el objeto sea de tipo Persona, y si el DNI coincide, en caso contrario devuelve false. Si no se hubiese hecho este reemplazo, se llamaría al método existente en la clase Object que se limita a comparar la dirección de memoria del objeto.

Implementación en C#

C# y Java son dos lenguajes de programación que comparten bastantes elementos en su sintaxis, y en este caso tampoco existe una gran diferencia. La definición de la clase en C# sería la siguiente:

    public class Persona
    {
        private string dni;
        private string nombre;
        private string apellidos;

        public string DNI
        {
            get { return dni; }
            set { dni = value; }
        }

        public override bool Equals(object obj)
        {
            if (obj.GetType() == typeof(Persona))
            {
                if ((obj as Persona).DNI == DNI)
                {
                    return true;
                }
            }
            return false;
        }
    }

Como se aprecia, el código es bastante similar. El acceso a las variables en C# se produce mediante el uso de Propiedades que se emplean de manera similar a las funciones que se han visto anteriormente en Java.

Para poder obtener la clase a la que pertenece el objeto del objeto, se obtiene el tipo con la sentencia getType, que devuelve un AssemblyQualifiedName, un nombre de tipo completo que incluye tipos anidados, el nombre de ensamblado y argumentos de tipo genérico.

Por ejemplo, el nombre completo de una clase podría ser similar al siguiente:

TopNamespace.SubNameSpace.ContainingClass+NestedClass,MyAssembly

Este nombre se compara con el que devuelve el operador typeof, lo que permite saber el nombre completo de la clase.

Resumen

En este artículo se ha visto cómo se puede obtener el tipo al que pertenece un objeto usando C# y Java, así como un escenario concreto en el cual puede resultar de gran utilidad.

Más información

Cargando información de archivos de texto en Java

Como seguramente sabreis, cuando se compila en Java, no se genera un programa ejecutable, sino que se compila en un código intermedio llamado bytecode, que es el que la máquina virtual de Java (JVM) se encarga de interpretar en tiempo de ejecución.

Este código se guarda en unos archivos .class que a su vez se empaquetan en un archivo .jar, junto con información de la clase principal y otros archivos, como los archivos de recursos, que es de lo que trata este artículo.

Continuar leyendo «Cargando información de archivos de texto en Java»

Look & Feel nativo en Windows con Swing

Una de las ventajas que tiene Java respecto a otros sistemas es la capacidad de adaptarse a los diferentes sistemas operativos, y de adaptarse a las diferentes interfaces usando Swing, aunque si bien es cierto que la aplicación funciona, no lo hace todo lo «bonito» que queremos, al menos eso me ocurrió a mí, sin embargo sí que podemos conseguir una aplicación que «de el pego» haciendo lo siguiente:

  • Detectar qué sistema operativo estamos ejecutando.
  • Aplicar el tema correspondiente a nuestra aplicación.

Lo que en código se traduce a:

String os = System.getProperty("os.name").toLowerCase();
String name = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
if (os.indexOf("win") >= 0) {
     try {
          UIManager.setLookAndFeel(name);
     }
     catch (Exception e) {}
}

Lo que hemos hecho ha sido, obtener el identificador del sistema operativo y transformarlo a minúsculas:

String os = System.getProperty("os.name").toLowerCase();

Una vez hecho esto, lo comparamos con el identificador deseado (en este caso, «win»):

if (os.indexOf("win") >= 0) {}

Finalmente, en caso de ser correcto, aplicamos el tema del sistema:

try {
     UIManager.setLookAndFeel(name);
}
catch (Exception e) {}

Es importante destacar que esta última sentencia ha de ir rodeada por un try … catch, ya que en caso contrario el compilador nos devolverá un error.

Espero que os haya sido tan útil o más de lo que me fue encontrar esto en su momento

Para más información: Documentación de Java (en inglés)