17-agosto-2017
admin

Agrupaciones en consultas con javax.persistence.criteria.CriteriaBuilder

Vamos a poner un par de ejemplos de uso del CriteriaBuilder en JPA para poder hacer consultas usando JpaSpecificationExecutor e incluso usar agrupaciones con groupBy.

Se van a ir poniendo las diferentes clases desde el Entity hasta el Service:

Entity de la tabla cuenta con un par de campos.

@Entity(name="cuentaEntity")
@Table(name="CUENTA")
public class CuentaEntity implements Serializable {
     @Id
     private Integer id;
     @Column(name="balance")
     private Integer balance;
     @Column(name="empresa")
     private String empresa;
     @Column(name="fecha")
     @Temporal(TemporalType.TIMESTAMP)
     private Date fecha;

     //getter setter
}

Su correspondiente JPAMetalModelEntityProcessor, la vamos a utilizar para las consultas.

@Generated(value = "org.hibernate.jpamodelgen.JPAMetalModelEntityProcessor")
@StaticMetamodel(CuentaEntity.class)
public abstract class CuentaEntity_ {
	public static volatile SingularAttribute< CuentaEntity, Integer> id;
	public static volatile SingularAttribute< CuentaEntity, Integer> balance;
	public static volatile SingularAttribute< CuentaEntity, String> empresa;
	public static volatile SingularAttribute< CuentaEntity, Date> fecha;
}

Un clase repositorio. Hay que hacer que herede tanto de la JpaRepository como del JpaSpecificationExecutor.

@Repository
public interface CuentaRepository extends JpaRepository< CuentaEntity, Integer>, 
                                         JpaSpecificationExecutor< CuentaEntity> {
	
}

Creamos nuestra clase criteria donde meteremos las especificaciones de las querys. Se añaden unos ejemplos de condicionales

public class CuentaCriteria implements Serializable{
     private Integer id;
     private Integer balance;
     private String empresa;
     private Date fecha;

     ......

     public static Specification< CuentaEntity> search(final CuentaCriteria cri){
	return new Specification< CuentaEntity>(){

	        @Override
		public Predicate toPredicate(Root< CuentaEntity> root, 
                                 CriteriaQuery< ?> criQuery, CriteriaBuilder criBuilder) {
				
			List< Predicate> predicates = new ArrayList< Predicate>();

			//el nombre de la empresa sea igual al que se pasa en CuentaCriteria. Si no está vacia.
			if( !StringUtils.isEmpty( cri.getEmpresa())){
				predicates.add( criBuilder.like(root.get(CuentaEntity_.empresa), cri.getEmpresa()) );
			}

			//la fecha debe ser igual a la que se pasa en CuentaCriteria. Si no está vacia.
			if( !StringUtils.isEmpty( cri.getFecha())){
				predicates.add( criBuilder.equal(root.get(StatementEntity_.fecha),cri.getFecha()) );
			}

			//podemos añadir tambien una condicion de tipo OR ( id = 0 OR id = 1). 
			List< Predicate> predOr = new ArrayList< Predicate>();
			predOr.add( criBuilder.equal(root.get(CuentaEntity_.id), 0) );
			predOr.add( criBuilder.equal(root.get(CuentaEntity_.id), 1) );
			predicates.add( criBuilder.or(predOr.toArray(new Predicate[predOr.size()]) ) );
	
			//Si tubieramos un objeto Embeddable u otro tipo de objeto podriamos acceder 
			//a las propiedades de ese objeto
			//predicates.add( criBuilder.like(root.get("OBJETO").get("CAMPO_OBJETO"), "qqqqqq") );
				
			..............

		        //Concatenamos todos los predicados como ands
			return criBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
		}
	};
     }
}

Interfaz con nuestro servicio con unos métodos de prueba.

public interface CuentaService{
	public Page< CuentaEntity> find(CuentaCriteria criteria, Pageable pageable);
	public List< Object[]> findGroupBy(CuentaCriteria criteria);
	public Long count(CuentaCriteria criteria);
        .........
}

Y su implementación:

@Component("cuentaService")
@Transactional
public class CuentaServiceImpl implements CuentaService {

	@PersistenceContext
        EntityManager em; 
		
	@Autowired
	private CuentaRepository cuentaRepository;
	
	//En este método permite realizar una consulta que devuelve el listado de todas las cuentas que
	//lo cumplen. Las condiciones de la consulta se le pasan con CuentaCriteria.search(criteria).
	//No devolverá todos los elementos al pasarle un objeto Pageable para paginación.
	public Page< CuentaEntity> find(CuentaCriteria criteria, Pageable pageable){
		return cuentaRepository.findAll( CuentaCriteria.search(criteria), pageable);
	}

	//En este método deveulve la cuenta de la consulta anterior. Las condiciones de la consulta
	//se le pasan con CuentaCriteria.search(criteria).
	public Long count(StatementCriteria criteria){
		return this.statementRepository.count( StatementCriteria.search(criteria) );
	}
	
	//El groupBy no funciona bien si se mete en StatementCriteria.search(criteria), eso es porque
	//aunque hagas un multiselect() con sólo los elementos que quieres sacar en la consulta te lo va 
	//a sobreescribir por el select().
	//Una posible solución sería hacerlo como se hace en este método.
	public List< Object[]> findGroupBy(CuentaCriteria criteria){
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery cq = cb.createQuery();
		Root root = cq.from(StatementEntity.class);
				
		//declaramos el multiselect con las columnas a devolver
		cq.multiselect(
                       //fecha mayor
                       cb.greatest( root.get(CuentaEntity_.fecha).as(java.util.Date.class) ),
                       //fecha menor
                       cb.least( root.get(CuentaEntity_.fecha).as(java.util.Date.class) ),
                       //balance mayor
                       cb.max( root.get(CuentaEntity_.balance) ),
                       //balance menor
                       cb.min( root.get(CuentaEntity_.balance) ),
                       //media del balance
                       cb.avg( root.get(CuentaEntity_.balance) ),
                       //suma del balance total
                       cb.sum( root.get(CuentaEntity_.balance).as(java.lang.Integer.class) ),
                       //suma del balance siempre que sea mayor de cero, es decir, positivo
                       cb.sum( cb.selectCase()  
				.when(cb.greaterThan(root.get(CuentaEntity_.balance), 0), 
                                           root.get(CuentaEntity_.balance)    ).otherwise(0)),
     
                       //contador con todas las filas agrupadas
                       cb.count( root.get(CuentaEntity_.id) )
		);
                //aplicamos todas la condiciones de consulta al where
		cq.where(  CuentaCriteria.search(criteria).toPredicate(root, cq, cb)  );

                //le decimos que agrupe por el nombre de las empresas
		cq.groupBy( root.get( CuentaEntity_.empresa) );
		  
		Query query = em.createQuery(cq);

                //Por último lo podemos retornar como una lista de objetos
		return (List< Object[]>)query.getResultList();
	}	
}
2-agosto-2017
admin

Logrotate

Logrotate permite rotar a los archivos de LOG de nuestras aplicaciones. El logrotate se trata de un servicio que se ejecuta de forma autónoma, si queremos comprobar su funcionamiento basta con ejecutar la siguiente instrucción:

    logrotate -vf /etc/logrotate.conf

Es en ese fichero donde se establece la configuración base para cualquier log que deseemos rotar. Vamos a poner un ejemplo de configuración para un aplicación de Node.js donde se utiliza Forever. Para ello:

Añadimos en /etc/logrotate.conf la configuración

/home/admin/.forever/*.log {
     daily       # how often to rotate
     rotate 10     # max num of log files to keep
     missingok     # don’t panic if the log file doesn’t exist
     notifempty    # ignore empty files
     compress      # compress rotated log file with gzip
     sharedscripts # no idea what it does, but it’s in all examples
     copytruncate  # needed for forever to work properly
     dateext       # adds date to filename
     dateformat %Y-%m-%d.
}

Tras añadirlo iniciamos el logrotate

     sudo logrotate -s /var/log/logstatus /etc/logrotate.conf

Podeis comprobar que los logs se están tratando asi:

     tail -f /var/log/logstatus



Documentación logrotate

14-julio-2017
admin

Objeto JSON en javascript: JSON.stringify vs JSON.parse

El objeto JSON contiene los métodos necesarios para analizar el JavaScript Object Notation (JSON) y, a su vez, convertir valores a JSON. A continuación se esponen los métodos de los que consta:

JSON.parse(text[, reviver])
Convierte una cadena de texto en un objeto de javascript.

Parámetros
text: La cadena que convertirá a JSON. Vea el objeto JSON para una descripción de la sintaxis JSON.
reviver (Opcional): Función que sobreescribe cómo se transforma el valor producido por el parsing.

Retorna el objeto que se corresponde con el texto JSON entregado.

JSON.parse('{"p": 5}', function (key, value) {
    if(key === "") return value;     
    return value * 2;             
});                           
// { p: 10 }



JSON.stringify(valor[, remplazo [, espacio]])
Convierte un valor dado en javascript a una cadena JSON.

Parámetros
valor: El valor que será convertido a una cadena JSON.
función de remplazo (Opcional): Es una función que altera el comportamiento del proceso de conversión a cadena de texto, o un array de objetos String o Number que representan una lista de elementos validos que se incluyen en la cadena JSON.
espacio (Opcional): Es un objeto de tipo String o Number que es usado para insertar un espacio en blanco dentro de la cadena de salida JSON para su mejor comprensión. Si es un número, se entiende que representa el numero de espacios a agregar; este numero tiene un limite de 10 espacios; numeros menores que 1 inplican que no se utiliza espacio alguno. Si es un cadena (sólo los 10 primeros caracteres son tomados en cuenta), esta es usada como espacios en blanco. Si este parámetro no se define o este es nulo no se agrega ningun espacio.

Retorna un string JSON representando el valor dado.

function replacer(key, value) {
  // Filtrando propiedades 
  if (typeof value === "string") {
    return undefined;
  }
  return value;
}

var foo = {foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7}; 
var jsonString = JSON.stringify(foo, replacer);
// '{"week":45, "month":7}'

Fuente Json

1-julio-2017
admin

HTTP Status Codes

1×× Informational
100 Continue
101 Switching Protocols
102 Processing

2×× Success
200 OK
201 Created
202 Accepted
203 Non-authoritative Information
204 No Content
205 Reset Content
206 Partial Content
207 Multi-Status
208 Already Reported
226 IM Used

3×× Redirection
300 Multiple Choices
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
305 Use Proxy
307 Temporary Redirect
308 Permanent Redirect

4×× Client Error
400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Timeout
409 Conflict
410 Gone
411 Length Required
412 Precondition Failed
413 Payload Too Large
414 Request-URI Too Long
415 Unsupported Media Type
416 Requested Range Not Satisfiable
417 Expectation Failed
418 I’m a teapot
421 Misdirected Request
422 Unprocessable Entity
423 Locked
424 Failed Dependency
426 Upgrade Required
428 Precondition Required
429 Too Many Requests
431 Request Header Fields Too Large
444 Connection Closed Without Response
451 Unavailable For Legal Reasons
499 Client Closed Request

5×× Server Error
500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
505 HTTP Version Not Supported
506 Variant Also Negotiates
507 Insufficient Storage
508 Loop Detected
510 Not Extended
511 Network Authentication Required
599 Network Connect Timeout Error

21-junio-2017
admin

JSON Viewer

El JSON Viewer se trata de una herramienta que te permite visualizar los ficheros *.json.

Capturas de pantalla del visor:

JSON Viewer

Main View


JSON Viewer

Text View


JSON Viewer

Fiddler Plugin


JSON Viewer

Custom Visualizer showing data as a grid


Enlace de la aplicación.

1-junio-2017
admin

Instalación RabbitMQ en Ubuntu

RabbitMQ se trata de un software de código abierto para la negociación de mensajes. Implementa el estándar Advanced Message Queuing Protocol (AMQP).

Nota: AMQP es un protocolo binario que destaca por su interoperabilidad y fiabilidad. Ofrece un amplio conjunto de funcionalidades como colas fiables basadas en mensajería P/S, enrutamiento flexible, seguridad, además de permitir un control en profundidad de colas, cabeceras,…

Para instalarlo en ubuntu se pueden seguir los siguientes pasos:

1 – Añadir el repositorio de rabbitmq al ubuntu

	echo 'deb http://www.rabbitmq.com/debian/ testing main' |
        sudo tee /etc/apt/sources.list.d/rabbitmq.list

2 – Instalarlo

	sudo apt-get update
	sudo apt-get install rabbitmq-server

3 – Comandos para iniciar, parar,…

	//inicio el servicio rabbitmq
	sudo service rabbitmq-server start

	//parar el servicio rabbitmq
	sudo service rabbitmq-server stop

	//reiniciar el servicio rabbitmq
	sudo service rabbitmq-server restart

	//ver el estado del servicio rabbitmq
	sudo service rabbitmq-server status

3 – Configuración
Por defecto trae creado el usuario: guest (la contraseña es la misma). Podriamos cambiar esa contraseña pero vamos a explicar como sería crear un usuario nuevo para luego borrar el de por defecto:

	//creamos el usuario admin con la contraseña 123
	sudo rabbitmqctl add_user admin 123

	//al usuario admin le asignamos el rol de administrator
	sudo rabbitmqctl set_user_tags admin administrator

	//eliminamos el usuario por defecto (guest)
	sudo rabbitmqctl  delete_user guest

Podemos crear ahora un virtual host con el nombre DISASTER. Un Virtual Host viene a ser el namespace sobre el que luego crearemos los distintos objetos que vamos a utilizar para el intercambio de mensajes (p.e. colas)

	//se crear el virtual host
	sudo rabbitmqctl add_vhost DISASTER

	//asignamos permisos de configuración/lectura/escritura al usuario admin
	sudo rabbitmqctl set_permissions -p DISASTER admin ".*" ".*" ".*"

Una vez creado el virtual host ya podriamos crear en él los canales para realizar el intercambio de mensajes.

Todo esto lo podriamos haber hecho desde la consola que nos provee el propio rabbitmq. Para ello, tendriamos que habilitarla

	sudo rabbitmq-plugins enable rabbitmq_management

Una vez habilitada podriamos acceder a ella así: http://localhost:15672/
Por defecto solo se puede acceder a la web desde localhost, por lo tanto tenemos dos opciones: o bien se cambia la configuracion o bien accedemos desde un tunel.

Para la configuración se debe abrir el fichero /etc/rabbitmq/rabbitmq.config y añadir los accesos que se deseen:

		{tcp_listeners, [5672]},
		{loopback_users, []}

4 – Logs
Por defecto en /var/log/rabbitmq

Documentación oficial

14-mayo-2017
admin

@ElementCollection vs @OneToMany

Estas dos anotaciones nos permiten elaborar relaciones 1 a N entre dos objetos con JPA. A continuación se va a exponer su funcionamiento:

@ElementCollection
Te permite de una forma muy simple definir una relación de una entidad con otros objetos. Se puede por ejemplo, dado un empleado, definir una lista de strings que se corresponden con los telefonos del empleado. Sería así:

@Entity(name="Employee")
@Table(name="EMPLOYEE")
public class Employee {

	@Id
	@Column(name = "_id")
	private String id;

	@Column(name="name")
	private String name;

	@ElementCollection
	@CollectionTable(name="PHONE", joinColumns=@JoinColumn(name="phone_id"))
	@Column(name="phone_number")
	private List< String> phones;
        .....
}

Teniendo en cuenta este ejemplo tendremos en BD:
– Una tabla EMPLOYEE con las columnas -> _id y name.
– Una tabla PHONE con las columnas -> phone_id y phone_number. (el campo phone_id hara de foreign key, mientras que phone_number contendrá el String del número de teléfono)

En el ejemplo anterior usábamos una lista de String pero podríamos usar un objeto @Embeddable, tal que así:

@Entity
public class Employee {
	@Id
	@Column(name = "_id")
	private String id;

	@Column(name="name")
	private String name;

	@ElementCollection
	@CollectionTable(name="PHONE",joinColumns=@JoinColumn(name="phone_id"))
        private List< Phone> phones;
        ...
}

@Embeddable
public class Phone {
        @Column(name="phone_number")
        private String number;
        ...
}

El resultado de hacerlo así en la base de datos sería exactamente el mismo pero nos va a permitir añadir mas campos en el objeto PHONE.

@OneToMany
Te permite relacionar dos objetos Entity.

@Entity
public class Employee {
	@Id
	@Column(name = "_id")
	private String id;

	@Column(name="name")
	private String name;

	@OneToMany(cascade={CascadeType.ALL}, mappedBy="empl", 
                   fetch=FetchType.LAZY, targetEntity = Phone.class)
	@OnDelete(action = OnDeleteAction.CASCADE)
	private List< Phone> phones;
  ...
}

@Entity
public class Phone {
	@Id
	private long id;

	@Column(name="phone_number")
	private String number;

	@ManyToOne
	@JoinColumn(name="phone_id")
	private Employee empl;
	...
}

Como se puede ver hay que marcar la relacion OneToMany en la entidad Employee, marcándole el campo donde debe apuntar (en este caso «empl»). En ese campo de la entidad Phone se debe marcar la ManyToOne indicandole el nombre de la columna (phone_id) que hará de foreign key.

Además, se ha añadido la anotación @OnDelete para indicarle que haga un borrado en cascada de la lista de teléfonos al eliminar al empleado. Esto es significativo por el hecho de que en el caso del ElementCollection no se permite indicar el tipo de borrado.
Nota: Hay que decir que en el borrado en cascada se eliminan de golpe todos los relacionados mientras que sin él, va haciendo un borrado de cada uno de sus relacionados (es decir, si un empleado tiene 10 teléfonos al hacerlo en cascada se lanzaría un único delete mientras que en el otro caso se lanzan 10 sentencias delete).

Resumen final
BD: el esquema de tablas y relaciones que va a construir JPA en nuestra BD va a ser muy similar en ambos casos.
Código: Se puede decir que es mucho más cómodo utilizar @ElementCollection al simplificar el código.
Potencia: Si queremos poder utilizar toda la potencia de las relaciones optimizando nuestros recursos es mejor decantarse por @OneToMany.


Fuente
@ElementCollection
@OneToMany

7-mayo-2017
admin

Configuración de host y dominio (DNS)

Cuando se quiere publicar una aplicación web tenemos dos opciones:
– Contratar el host y el dominio con el mismo proveedor
– Contratar el host con un proveedor y el dominio con otro distinto

En el primer caso no hay que hacer nada ya que el proveedor nos va a dar todo configurado. En cambio en el segundo caso debemos cambiar las DNS del dominio para que apunten a las del host.

DNS
«El sistema de nombres de dominio (DNS, por sus siglas en inglés, Domain Name System) es un sistema de nomenclatura jerárquico descentralizado para dispositivos conectados a redes IP como Internet o una red privada. Este sistema asocia información variada con nombre de dominio asignado a cada uno de los participantes. Su función más importante es «traducir» nombres inteligibles para las personas en identificadores binarios asociados con los equipos conectados a la red, esto con el propósito de poder localizar y direccionar estos equipos mundialmente.» Wikipedia DNS


Resumen pasos configuración DNS

1 – Si no sabes cuáles son (te las suelen dar cuando contratas el host) debes pedir al proveedor del host sus DNS.

2 – Una vez dispongas de ellas ya puedes ir al panel de control de tu proveedor de dominio. En él tienes que buscar la zona donde se te permite configurar las DNS asociadas a cada dominio que le hayas contratado.

3 – Finalmente, introduces las DNS del host y das a guardar.

4 – Ahora ya sólo te queda esperar. Ya que al realizar el cambio te suelen indicar que tienes que esperar entre 24 y 48 horas para que se propaguen los DNS y se haga efectivo el cambio (normalmente en menos de 24 horas ya lo tienes activado).

28-diciembre-2016
admin

Integrar Facebook en Unity para apps Android

Paso 1:
Registrarse en https://developers.facebook.com/ para lo que es necesario tener una cuenta de facebook.

Paso 2:
Crear una aplicación en la web anterior en Apps > Add new app. De esta forma obtendremos un App ID.

Paso 3:
Descargar e importar al proyecto de unity el SDK de facebook. Aquí. En mi caso para un windows 64bits instalé openssl-0.9.8k_X64.
Tras importarlo, en la plataforma unity nos aparecera una nueva opcion en el menu llamada Facebook.

Paso 4:
En ese menu nuevo vamos a la opción Edit Settings y rellenamos el App ID que habiamos obtenido en el paso 2.
Así ya tendriamos la configuración básica para poder usar facebook en unity.
Para probarlo podemos añadir un botón en nuestro proyecto que haga una llamada al login de facebook (FB.login(….)). Al pulsar en Login aparecerá una ventana pidiéndonos un User Access Token. Podemos obtenerlo pulsando en esa misma venta en Find Access Token, que nos llevará al Access Token Tool de Facebook, donde podremos generarlo y copiarlo a Unity.


A partir de aquí para Android
Paso 5:
Si en el apartado Android Build Facebook Settings vemos que sale la alerta “OpenSSL not found. Make sure that OpenSSL is installed, and that it is in your path“ es porque debemos instalar OpenSSL en nuestro equipo.
Podemos descargarlo de aquí.
Para instalarlo basta con descomprimirlo en una carpeta de nuestro equipo y modificar la variable de entorno Path, añadiéndole la ruta a la carpeta bin de OpenSSL. También podemos añadir una nueva variable de entorno llamada OpenSSL.

Paso 6:
Si la alerta que sale es “Keytool not found. Make sure that Java is installed, and that Java tools are in your path“ debes instalar la JDK o JRE de java añadiendo la ruta a la variable de entorno del sistema como antes.

Paso 7:
Debajo de esas alertas podemos ver debajo el Package Name, el Class Name y la Debug android key hash.
Estos datos deben introducirse en el apartado Settings de la app de Facebook creada al principio. Tendremos que añadir una nueva plataforma android pulsando en Add Platform e introducir los 3 valores y guardar. Haciendo esto ya podremos probar a compilar y desplegar la aplicación en el dispositivo android.

Paso 8:
En el dispositivo android no se nos pedirá un User Token al hacer login pero puede que se produzca el siguiente error: “Invalid key hash. The key hash ***** does not match any stored key hashes…“ Y es que la key hash que proporciona el SDK de Facebook en sus settings es la de debug, mientras que al desplegar la app en el dispositivo se usa otra, que es la que muestra el mensaje de error. Tendremos que añadir esta key hash en la página de Settings de la app de Facebook, a continuación de la que introdujimos previamente.

15-diciembre-2016
admin

Kill Wasp

Se trata de un juego realizado mediante la plataforma Unity y que ha sido exportado a WebGL y a Android. Se integra con facebook para poder publicar tus resultados en tu muro.

Kill Wasp

Kill Wasp

El juego consiste en hacer que tu colmenar aguante el mayor tiempo posible. Para ello tendrás que enfrentarte a dos poderosos enemigos:
– Por un lado a las avistas asiáticas cuyo principal alimento serán tus abejas. La unica solución de mantenerlas a raya es mediante el trampeo.
– Por otro lado tendrás que enfrentarte a los osos, que su aspecto no te engañe. No dudarán matarte y comerse la miel de las abejas.

Versión Web
Versión Android

Páginas:«1234567...25»

Categorias

Linkedin