Archivos por Etiqueta: java

Java: Upgrade log4j 1.2

Si usas log4j 1.2 y estas leyendo este articulo seguramente te planteas actualizar, vayamos al grano…

Escenario 1: codigo que usa directamente log4j 1.2, no puedes tocarlo y necesitas 100% retrocompatibilidad.

Si necesitas reemplazar sin tocar codigo o sin compilar (tienes un entorno antiguo del que no tienes acceso al codigo o es un proyecto que funciona bien y meterse a cambiar codigo es poco viable, por poner un par de ejemplos), existen opciones, una es reemplazar el log4j-1.2.17.jar por reload4j-1.2.20.jar, directamente en el filesystem o bien cambiando las dependencias en el pom.xml, haciendo algun exclude y haciendo el package de nuevo. Este escenario es 100% retro-compatible (reload4j es un fork/parches sobre el log4j original). Este es de los pocos metodos que usaria en un entorno productivo «legacy» sin opcion de pruebas.

<!-- Log4j 1.2 replacement -->
<dependency>
	<groupId>ch.qos.reload4j</groupId>
	<artifactId>reload4j</artifactId>
	<version>1.2.20</version>
</dependency>

Escenario 2: usas slf4j con el backend de log4j 1.2 y necesitas mantenerlo por algun motivo.

Si estabas usando slf4j-api y slf4j-log4j12, este es practicamente como el escenario anterior, con un par de matices, puedes usar reload4j pero te recomendaria actualizar a la ultima version de slf4j (1.7.36) y cambiar slf4j-log4j12 por slf4j-reload4j (aqui hay que vigilar las dependencias finales/excludes).

<!-- Log4j 1.2 replacement -->
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-reload4j</artifactId>
  <version>1.7.36</version>
</dependency>

Escenario 3: tienes log4j 1.2 pero quieres pasar a log4j 2.x con pocos cambios.

Otra opcion interesante, es mediante log4j-1.2-api, con esto emularas el log4j 1.2 pero usando el backend de log4j 2.x, no requiere tocar codigo, aunque tendras que cambiar el pom.xml (asegurarte de borrar las referencias o hacer los excludes de «log4j:log4j:1.2.17») y hacer el package, la magia corre de cuenta de log4j2. Este escenario diria que cubre el 80-90% de los casos de uso. Aqui no me la jugaria sin un entorno de pruebas.

<!-- Log4j 1.x bridge -->
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-1.2-api</artifactId>
  <version>2.17.2</version>
</dependency>

Hay otros escenarios / combinaciones, pero diria que la mayoria rondaran slf4j, reload4j o log4j2.

Mi recomendación es que si no necesitas ninguna funcionalidad especifica del framework de logging (como por ejemplo NDC), uses slf4j-api, por debajo ya es cuestion de gustos (mi preferencia siempre será el más sencillo o en su defecto, log4j*).

Referencias:
https://reload4j.qos.ch/
https://reload4j.qos.ch/manual.html
https://www.slf4j.org/legacy.html
https://logging.apache.org/log4j/2.x/manual/migration.html
https://logging.apache.org/log4j/1.2/
https://technobcn.wordpress.com/2013/02/04/java-logs-de-aplicaciones-la-senda-del-guerrero/

Java: Browser using Eclipse SWT and Edge WebView2

Mostrar contenido web (HTML, CSS y JavaScript) en una aplicación Java con Microsoft Edge WebView2.

import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

// ...

final Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("Edge Browser in SWT");
shell.setLayout(new FillLayout());

Browser browser = new Browser(shell, SWT.EDGE);
System.out.println("Browser: " + browser.getBrowserType()); // edge
browser.setUrl("https://www.google.com/");

shell.pack();
shell.setMaximized(true);
shell.open();

while (!shell.isDisposed()) {
	if (!display.readAndDispatch())
		display.sleep();
}
display.dispose();

Aqui las dependencias de Maven:

<dependency>
	<groupId>org.eclipse.platform</groupId>
	<artifactId>org.eclipse.swt</artifactId>
	<version>3.118.0</version>
</dependency>
<dependency>
	<groupId>org.eclipse.platform</groupId>
	<artifactId>org.eclipse.swt.win32.win32.x86_64</artifactId>
	<version>3.118.0</version>
</dependency>

Para que funcione, vas a necesitar el «Microsoft Edge WebView2», lo puedes descargar de la web:

https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section

La opcion que yo he usado es: «Evergreen Standalone Installer (x64)«

Referencias:
https://docs.microsoft.com/microsoft-edge/webview2/
https://www.eclipse.org/swt/snippets/#browser
https://www.eclipse.org/windowbuilder/

Java: Getting Memory Usage with MemoryMXBean

Estoy madurando una idea y me he encontrado con una de las muchas perlas de JMX de Java, la MemoryMXBean:

MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
System.out.println("HeapUsage: " + mbean.getHeapMemoryUsage());
System.out.println("NonHeapUsage: " + mbean.getNonHeapMemoryUsage());

El resultado:

HeapUsage: init = 16777216(16384K) used = 7772720(7590K) 
           committed = 16252928(15872K) max = 1037959168(1013632K)

NonHeapUsage: init = 2359296(2304K) used = 15099032(14745K) 
              committed = 15327232(14968K) max = -1(-1K)

Referencias:
java.lang.management.ManagementFactory

Java: Skeleton for Workers / Batch processing

Un pequeño esqueleto que persigue:

  1. Que no se coma la CPU.
  2. Que no se coma el espacio el disco soltando trazas de fallo.
  3. Que ante una excepcion «extraña» no se muera el worker.
@Override
public void run() {
	int c = 0;
	while (!isShutdown()) {
		if ((++c % 10000) == 0) { // Anti cpu eater
			intrSleep(1);
		}
		try {
			// ... do things
		} catch (ControlledException e) {
			// ... do things
			log.error("ControlledException: " + e.toString(), e);
			intrSleep(100); // Anti disk space eater
		} catch (Exception e) {
			// ... last resort
			log.error("Unknown Exception: " + e.toString(), e);
			intrSleep(100); // Anti disk space eater
		}
	}
}
private static void intrSleep(final long millis) {
	try {
		Thread.sleep(millis);
	} catch (InterruptedException e) {
		Thread.currentThread().interrupt();
	}
}

Java: JavaStack artifacts Available in Maven Central

Ya se han liberado los primeros artefactos (librerías de proposito general) de JavaStack en Maven Central:

  • packer:1.1.1 > Libreria de Serializacion de datos (compresion, encriptacion,…). Similar a Kryo.
  • mapexpression:1.0.2 > Evaluador de Expresiones para usar en placeholders como ${name}.
  • stringproperties:1.0.1 > Properties con Features extra (${placeholders}).
  • kvstore:1.0.0 > Un NoSQL / Map Key-Value (disco y memoria).
  • standalone-preferences:1.0.4 > Implementacion del API de Preferences en Filesystem.
  • figaro:1.0.0 > Sistema de mensajes asincronos In-process / EventBus / ActorModel. Similar a Kilim, µJavaActors, Akka.

Todos estos artefactos siguen la misma filosofía: Zen, KiSS

Maven Central: org.javastack

Java: Generating CIDR InetAddress

Una pequeña chuleta para generar una «NetMask» desde un CIDR en Java:

import java.net.InetAddress;

public static InetAddress getAddressByCIDR(final int bits, final boolean ipv6) {
	final int totalBits = (ipv6 ? 128 : 32);
	if (bits < 0 || bits > totalBits)
		throw new IllegalArgumentException("Illegal CIDR prefix");
	final byte[] bytes = new byte[totalBits >> 3];
	for (int offset = 0; offset < bits; offset++) {
		bytes[offset >> 3] |= (1 << (7 - (offset & 7)));
	}
	try {
		return InetAddress.getByAddress(bytes);
	} catch (UnknownHostException e) {
		throw new RuntimeException(e);
	}
}

Referencias:
CIDR

Java: Could not generate DH keypair

Si te aparece este error, sigue leyendo…

javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:190)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1762)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1723)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1706)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1237)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1214)
        at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)

Leer más de esta entrada

Network: Latency benchmark

Las pruebas han sido muy basicas (pero dan una idea/orden de magnitud), las maquinas dst tienen un Servidor ECHO-TCP y las maquinas src tiene un Cliente ECHO-TCP. El cliente se conecta al servidor, envia un byte, lee el byte de vuelta, asi una y otra vez en un bucle de 10mil iteraciones, calcula la latencia minima, maxima y la media de las 10mil iteraciones.

Los resultados:

+--------+--------+------------+-------------+------------+----------+
| src    | dst    |    min     |     max     |    avg     | medium   |
+--------+--------+------------+-------------+------------+----------+
| linux1 | win7   | 2137.421µs | 24779.393µs | 3471.736µs | plc      |
| linux2 | win7   | 2035.887µs | 36111.414µs | 3040.004µs | plc      |
| linux3 | win7   | 1889.267µs | 10737.868µs | 2689.145µs | plc      |
| linux1 | win7   | 1031.974µs |  6943.338µs | 1371.043µs | wifi-11n |
| linux2 | win7   |  786.553µs |  4445.808µs | 1153.319µs | wifi-11n |
| linux3 | win7   |  621.457µs | 40078.223µs |  964.037µs | wifi-11n |
| linux1 | win7   |  380.495µs | 69546.800µs |  732.009µs | gbe      |
| linux1 | linux3 |  101.130µs | 10486.523µs |  314.863µs | vm       |
| linux2 | linux1 |  159.140µs |  9334.732µs |  308.808µs | vm       |
| linux2 | win7   |  165.534µs | 11921.050µs |  307.096µs | gbe      |
| linux3 | win7   |   79.133µs |  2289.499µs |  150.973µs | gbe      |
| linux2 | linux3 |   54.764µs |  5447.378µs |   86.460µs | vm       |
| linux1 | linux1 |   54.197µs |   299.199µs |   85.713µs | loopback |
| linux2 | linux2 |   41.505µs |   372.127µs |   72.765µs | loopback |
| linux3 | linux3 |   15.805µs |   500.069µs |   48.219µs | loopback |
| win7   | win7   |   17.675µs |    76.399µs |   22.927µs | loopback |
+--------+--------+------------+-------------+------------+----------+

Las maquinas son:

  • linux1: Ubuntu 14.04 32bits (virtual)
  • linux2: Ubuntu 14.04 64bits (virtual)
  • linux3: Ubuntu 12.04 64bits (fisica)
  • win7: Windows 7 Pro 64bits (fisica)

Los medios de transmision son:

  • plc: enlace PLC HomePlug-AV (aunque el PLC se conecta a la red por Ethernet a 100Mb)
  • wifi: enlace wifi 802.11n (aunque el AP-Wifi se conecta a la red por Ethernet a 100Mb)
  • vm: comunicacion entre dos maquinas dentro de un mismo hypervisor/host (linux3)
  • gbe: enlace Ethernet a 1Gb
  • loopback: comunicacion dentro de la misma maquina (127.0.0.1)

Sourcecode on GitHub:
EchoServer.java
EchoClient.java

Java: Agnostic Cache with Dynamic Proxies and Reflection

Hace tiempo usé un modulo de Perl muy interesante, Memoize. La idea era muy sencilla, tienes una funcion X, si para una entrada A, hay una salida B constantes y ese cálculo es lento, puede usar un caché.

La idea es esa, calcular una vez, usar muchas; sin tener que tener una implementación con cache de cada implementación original.

Aquí está la implementación en Java usando Reflexión:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

public class ReflectMemoizer implements InvocationHandler {
  private final Object object;
  private final HashMap<Method, ConcurrentHashMap<List<Object>, Object>> caches;

  /**
   * Memoize object
   * @param object source
   * @return proxied object
   */
  public static Object memoize(final Object object) 
        throws InstantiationException, IllegalAccessException {
    final Class<?> clazz = object.getClass();
    final ReflectMemoizer memoizer = new ReflectMemoizer(object);
    return Proxy.newProxyInstance(clazz.getClassLoader(), 
        clazz.getInterfaces(), memoizer);
  }

  private ReflectMemoizer(final Object object) {
    this.object = object;
    this.caches = new HashMap<Method, ConcurrentHashMap<List<Object>, Object>>();
  }

  public Object invoke(final Object proxy, final Method method, 
        final Object[] args) throws Throwable {
    if (method.getReturnType().equals(Void.TYPE)) {
      // Don't cache void methods
      return invoke(method, args);
    } else {
      final Map<List<Object>, Object> cache = getCache(method);
      final List<Object> key = Arrays.asList(args);
      Object value = cache.get(key);
      if ((value == null) && !cache.containsKey(key)) {
        value = invoke(method, args);
        cache.put(key, value);
      }
      return value;
    }
  }

  private synchronized Map<List<Object>, Object> getCache(final Method m) {
    ConcurrentHashMap<List<Object>, Object> cache = caches.get(m);
    if (cache == null) {
      cache = new ConcurrentHashMap<List<Object>, Object>();
      caches.put(m, cache);
    }
    return cache;
  }

  private Object invoke(final Method method, final Object[] args) 
        throws Throwable {
    try {
      return method.invoke(object, args);
    } catch (InvocationTargetException e) {
      throw e.getTargetException();
    }
  }
}

Leer más de esta entrada