Cómo cambiar el timeout por defecto de un socket en Java  

Cuando se crea un socket de ésta forma:

Socket socket = new Socket(IP, puerto);

Puede darse que el timeout por defecto usado (el del sistema operativo) sea demasiado larga. Para poder controlarlo es mejor inicializar el socket de ésta forma:

Socket socket = new Socket();
socket.connect(new InetAddress(IP, puerto), timeout);

Que nos permite especificar un timeout en milisegundos.

Espero que os sea de utilidad. ¡Happy coding!

Resolviendo excepciones: Permission Denial, broadcasting Intent XXXX requires null due to receiver YYYY  

NOTA: Léelo también en Diario de un Androide.

Mientras desarrollas tu aplicación que gestione notificaciones puedes recibir una excepción como esta (Siendo XXXX una actividad que reciba intents e YYYY un intent concreto (personalizado, en mi caso)):

W/ActivityManager: Permission denied: checkComponentPermission() reqUid=10060
W/ActivityManager: Permission Denial: broadcasting Intent { act=YYYY cmp=XXXX bnds=[0,395][480,491] } from XXXX (pid=-1, uid=10073) requires null due to receiver XXXX

Hay varias interpretaciones de éste error por internet, pero en mi caso se debría a una visibilidad entre componentes, que se solucionó añadiendo android:exported="true" en las actividades o servicios del manifest de tu aplicación.

Espero que os ayude. ¡Happy coding!

Como permitir que un applet firmado capture audio desde el micrófono  

Si al ejecutar una lectura de audio desde el canal del micrófono a través de nuestro applet firmado obtenemos la excepción siguiente:

java.security.AccessControlException: access denied (javax.sound.sampled.AudioPermission record)
at java.security.AccessControlContext.checkPermission (AccessControlContext.java:323)
at java.security.AccessController.checkPermission(Acc essController.java:546)
at java.lang.SecurityManager.checkPermission(Security Manager.java:532)
...

Habrá que buscar (o crear si no existe) el archivo java.policy (a nivel de sistema) o el archivo .java.policy (a nivel de usuario), y editarlo escribiendo algo como lo siguiente:

grant
{
	permission javax.sound.sampled.AudioPermission "record";
};

Y si estáis bajo un Linux (Ubuntu Desktop, en mi caso) y os surge una nueva excepción que dice lo siguiente:

java.security.AccessControlException: access denied (java.lang.RuntimePermission loadLibrary.pulse-java)

Habrá que rellenar el archivo .java.policy con lo siguiente:

grant
{
	permission javax.sound.sampled.AudioPermission "record";
	permission java.lang.RuntimePermission "loadLibrary.pulse-java";
    permission java.io.FilePermission "<<ALL FILES>>", "read";
};

¡Espero que os sirva de ayuda! ¡Happy coding!

Cómo capturar, codificar, decodificar y reproducir audio en formato ALAW para sesiones RTP usando Peers  

Vamos a ver cómo utilizar la librería del softphone Peers para realizar las tareas de captura y reproducción de audio, además de la codificación y decodificación desde audio linear a ALAW y viceversa.

¿Qué es cada cosa de las que hemos hablado ahora? He aquí las definiciones:

  • Peers es un softphone funcional y portable totalmente desarrollado en Java.
  • ALAW es un codec de compresión de audio usado principalmente para la transmisión de voz en llamadas VoIP.

Para usar la librería de Peers basta con bajar el paquete del softphone desde Sourceforge e importar el JAR de la aplicación (peers.jar) dentro de nuestro proyecto Eclipse o Netbeans, así de facil. Con ésto ya tendremos toda la potencia de Peers disponible para nuestra aplicación.

Y ahora vamos ahora a lo interesante, el código (es bastante autoexplicativo):

Inicializando el sistema

Para inicializar el sistema de audio de Peers haremos lo siguiente:

// Logger para Peers
// Se ha de crear el directorio "./logs" o fallará
(new File("logs")).mkdir();
Logger loggerInterno = new Logger(null);

// Inicializamos el audio
soundManager = new SoundManager(false, this.loggerInterno, ".");
soundManager.openAndStartLines();

Decodificando y reproduciendo audio RTP

Para decodificar y reproducir los datos RTP que hayamos recibido a través de nuestra sesión RTP haremos lo siguiente:

while(recibimosPaquetesRTP)
{
	// Recibimos el paquete desde la fuente RTP
	byte[] paquete = null;

	// ...
	// NOTA: Fuera del ámbito de éste post, deberás escribir tú éste fragmento de código
	// ...

	// Procesamos el paquete
	RtpParser rtpParser = new RtpParser(loggerInterno);
	RtpPacket rtpPacket = rtpParser.decode(paquete);

	// Decodificamos los datos
	Decoder decoder = null;

	switch (rtpPacket.getPayloadType())
	{
		case RFC3551.PAYLOAD_TYPE_PCMU:
		{
			decoder = new PcmuDecoder();
			break;
		}

		case RFC3551.PAYLOAD_TYPE_PCMA:
		{
			decoder = new PcmaDecoder();
			break;
		}
	}

	byte[] rawBuf = decoder.process(rtpPacket.getData());
	soundManager.writeData(rawBuf, 0, rawBuf.length);
}

Capturando desde el micro y codificando audio antes de enviar

Para recibir datos del micrófono y codificar el audio en ALAW para enviar a través de nuestra sesión RTP haremos lo siguiente:

Encoder encoder = new PcmaEncoder(null, null, false, this.padre.loggerInterno, ".", new CountDownLatch(3));

while(queremosLeerDesdeElMicro)
{
	// Leemos del micro
	byte[] paquete = this.padre.soundManager.readData();

	// Codificamos
	byte[] codificado = encoder.process(paquete);

	// Enviamos el paquete por la sesión RTP

	// ...
	// NOTA: Fuera del ámbito de éste post, deberás escribir tú éste fragmento de código
	// ...
}

¡Espero que os sirva de ayuda! ¡Happy coding!

Resolviendo problemas de Hibernate en Beans con Managed Transactions bajo JBoss  

Si tienes una Bean etiquetada con @TransactionManagement(TransactionManagementType.BEAN) y recibes excepciones como éstas:

javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: Cannot open connection
   at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
   at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
   at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:255)
   ...
   at java.lang.Thread.run(Unknown Source)
 Caused by: org.hibernate.exception.GenericJDBCException: Cannot open connection
   at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140)
   at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128)
   at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
   at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52)
   at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:449)
   at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
   at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:161)
   at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1700)
   at org.hibernate.loader.Loader.doQuery(Loader.java:801)
   at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
   at org.hibernate.loader.Loader.doList(Loader.java:2533)
   at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276)
   at org.hibernate.loader.Loader.list(Loader.java:2271)
   at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:452)
   at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:363)
   at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
   at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1268)
   at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
   at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:246)
   ... 32 more
 Caused by: org.jboss.util.NestedSQLException: Transaction is not active: tx=TransactionImple < ac, BasicAction: 0:ffff0a021e29:126a:4f6095ab:c1 status: ActionStatus.ABORT_ONLY >; -
not active: tx=TransactionImple < ac, BasicAction: 0:ffff0a021e29:126a:4f6095ab:c1 status: ActionStatus.ABORT_ONLY >)
   at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:95)
   at org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider.getConnection(InjectedDataSourceConnectionProvider.java:71)
   at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
   ... 46 more
 Caused by: javax.resource.ResourceException: Transaction is not active: tx=TransactionImple < ac, BasicAction: 0:ffff0a021e29:126a:4f6095ab:c1 status: ActionStatus.ABORT_ONLY >
   at org.jboss.resource.connectionmanager.TxConnectionManager.getManagedConnection(TxConnectionManager.java:403)
   at org.jboss.resource.connectionmanager.BaseConnectionManager2.allocateConnection(BaseConnectionManager2.java:496)
   at org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy.allocateConnection(BaseConnectionManager2.java:941)
   at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:89)
   ... 48 more

El problema se debe a la forma en que se manejan las transacciones. En ocasiones se resuelve con éstos dos consejos:

  • Añadiendo un verificador al especificador de Datasource (explicación):
    <valid-connection-checker-class-name> com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker </valid-connection-checker-class-name>
  • Seguir el patrón de uso de las transacciones que se puede leer aquí

A mi me ha ayudado mucho, ¡espero que os ayude a vosotros!

Happy coding!

Solucionando la excepción java.lang.OutOfMemoryError  

Si al desplegar tu aplicación en Tomcat/JBoss te sale ésta famosa excepción:

java.lang.OutOfMemoryError: PermGen space

Ésta web y ésta otra lo explican bastante bien, pero resumiendo, el problema viene de que el ClassLoader del anterior de ploy de la aplicación no ha sido descargado y recolectado como basura, por lo que se lanza ésa excepción.

Las posibles causas son:

  • Cualquier referencia desde fuera de la aplicación a un objeto de la aplicación en la cual haya sido cargada la clase por el cargador de clases de la aplicación, causará una fuga de memoria en el cargador de clases. Habrá que vigilar las referencias.
  • A veces se produce cuando la aplicación se reinstala en el servidor sin reiniciar el servidor. La forma de reinstalar las aplicaciones es eliminando el classloader que cargó la aplicación por primera vez y creando un nuevo classloader para la nueva instancia de la aplicación.

Espero que ésto os ayude como me ha ayudado a mi icon smile Solucionando la excepción java.lang.OutOfMemoryError

¡Happy coding!

Etiquetas: , , ,
Comentarios: No hay comentarios aún

Enviando emails desde una aplicación Android  

Hoy vamos a enviar un correo electrónico desde nuestra aplicación. Ésto puede ser de mucha utilidad. Por ejemplo, para permitir que nuestros usuarios se pongan en contacto con nostros o nos puedan enviar un log de la aplicación para reportar fallos.

Hacerlo es muy sencillo, éste snippet de código lo explica a la perfección:

Intent email = new Intent(android.content.Intent.ACTION_SEND);
email.setType("plain/text");

email.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{"email@email.com"});
email.putExtra(android.content.Intent.EXTRA_SUBJECT, "Asunto de mi correo");
email.putExtra(android.content.Intent.EXTRA_TEXT, "Texto de mi correo");

email.putExtra(Intent.EXTRA_STREAM,
	Uri.parse("file://"+Environment.getExternalStorageDirectory()+"/archivo.txt"));

startActivity(Intent.createChooser(email, "Enviar correo electrónico"));

Facil, ¿eh? ¡Happy coding!

hi 256 4 f4f3667dfb66514a859a216284211dd72f820799 Enviando emails desde una aplicación Android

Etiquetas: , , ,
Comentarios: No hay comentarios aún

Exploded deploy en JBoss 6 sobre Windows  

Cuando intento deployar un archivo EAR sobre un JBoss 6 bajo windows, recibo el siguiente error:

Failed to create Resource EJEMPLO.ear - cause: java.lang.Exception:Failed to distribute 'file:/XXXX/EJEMPLO.ear' to 'EJEMPLO.ear' - cause: java.lang.RuntimeException:java.io.FileNotFoundException: C:\XXXX\EJEMPLO.ear\META-INF\jboss-app.xml (El sistema no puede encontrar la ruta especificada)

Leemos aquí lo siguiente: “Every EAR application should specify a unique string name for the class loader”. Así que nos pondremos manos a la obra haciendo lo siguiente:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-app>
	<loader-repository>
		EJEMPLO:archive=EJEMPLO.ear
	</loader-repository>
</jboss-app>

El deploy a través de la Admin Console de JBoss sigue fallando. Así que tras otro rato de investigación (Google, qué haría sin ti…), siguiendo pistas de algunos de los foros de JBoss, probaremos a hacer lo siguiente:

  • Detener JBoss
  • Descomprimir el archivo ear en el directorio deploy de JBoss, añadiendo la extensión al directorio (es decir, descomprimiremos EJEMPLO.ear al directorio deploy/EJEMPLO.ear/).
  • Descomprimir dentro de ése directorio los archivos de los EBJ y el WAR en directorios con sus respectivas extensiones.
  • Volver a arrancar JBoss

Viendo los logs al iniciar JBoss, vemos que por fin todo se deploya correctamente. Y si modificamos algún recurso, éste se actualiza correctamente sin necesidad de un redeploy icon smile Exploded deploy en JBoss 6 sobre Windows

¡Espero que os sirva de ayuda! ¡Happy coding!

Solucionando problemas durante el desarrollo: Unable to open sync connection  

Tras un rato de desarrollo en ocasiones el ADB se vuelve un poco loco, y al subir un APK al móvil desde Eclipse recibimos éste error:

Unable to open sync connection!

La solución es sencilla:

  1. Quitar el cable USB
  2. Desactivar la depuración USB en el móvil y volverla a activar
  3. Conectar el cable USB de nuevo

Espero que os sirva de ayuda. ¡Happy coding icon smile Solucionando problemas durante el desarrollo: Unable to open sync connection !

Como hacer que una aplicación solicite permisos de superusuario  

Si tenemos el terminal rooteado podemos hacer muchas tareas interesantes desde nuestras aplicaciones. Pero antes de hacer nada, tenemos que solicitar al usuario los permisos de superusuario.

Haremos un método estático par ayudarnos en las tareas de ejecutar cosas como Root:

/**
 * Ejecuta un comando como Root
 */
public static boolean ejecutarComoRoot(String comando)
{
	Process p = null;

	try
	{
		// Ejecutamos como SU
		p = Runtime.getRuntime().exec("su -c "+comando);

		try
		{
			p.waitFor();

			// Comprobamos si somos root
			if (p.exitValue() != 255)
			{
				Log.i("Serone", "Comando '"+comando+"' ejecutado como root correctamente icon smile Como hacer que una aplicación solicite permisos de superusuario ");
				return true;
			}
			else
			{
				Log.e("Serone", "No somos root, no se puede ejecutar '"+comando+"'...");
			}
		}
		catch (InterruptedException e)
		{
			Log.e("Serone", "No somos root, no se puede ejecutar '"+comando+"'...", e);
		}
	}
	catch (IOException e)
	{
		Log.e("Serone", "No somos root, no se puede ejecutar '"+comando+"'...", e);
	}

	return false;
}

Luego, para solicitar root basta ejecutar cualquier comando, por ejemplo:

// Pedimos root (ejecutando un programa cualquiera como superusuario)
Utils.ejecutarComoRoot("ls");

Inspirado en el código de ésta web.

¡Happy coding!


Disclaimer: Las imágenes mostradas en ésta página web se utilizan sólamente con propósitos ilustrativos, y son propiedad de sus respectivos autores (cuando es aplicable).
Hijo de Blog es un producto del Dr. SeROne

Los contenidos se ofrecen bajo una licencia de Creative Commons
Attribution-NonCommercial-NoDerivs 3.0 Unported

salvo que se indique lo contrario

Licencia de Creative Commons