martes, 31 de diciembre de 2013

¡FELIZ AÑO NUEVO!

Parece mentira que ya ha pasado otro año más el blog. Este año ha sido muy interesante y ha tenidos algunas anécdotas:

  • Durante el año pasado y parte de este, el post de Lorem Ipsum era el más visitado , jajaja. Incluso recibí algún que otro email dándome las gracias. No sé porqué se posicionó bastante bien en algún buscador y la gente entraba aquí a copiarlo. Por supuesto a los que me escribieron sobre el post les remití a la página es.lipsum.com
  • El perfil de usuarios que visitan el blog sigue siendo en su mayoría de curritos que tienen un problema, visitan el blog y me escriben un email para que les eche una mano. Yo encantado si puedo ayudar.

Este año he tenido más de 3500 visitas, son 3000 más que el año pasado. La verdad es que estoy muy contento con el crecimiento de las visitas e emails recibidos, aunque no me dejéis muchos comentarios.


Incremento de visitas al blog este año.

España y México siguen siendo los países que más visitan el blog, mientras que Argentina ha cedido este año la tercera posición a Colombia.


Los 10 primeros países con más visitas al blog.


Si a un lugar quieres viajar... me debes consultar... soy el mapa... el mapa el mapa el mapa...

Bueno, no os entretengo más. Os deseo a todos Feliz Navidad y año nuevo. ¡Nos leeremos en el 2014!

Saludos.

lunes, 16 de diciembre de 2013

Primera semana de CProject en Google Play

  • Eres un encanto Walker.
  • Este lugar… de lo único que hablamos aquí es de sexo, y de sentimientos…

Estaba viendo el capítulo “Sin Límite de Tiempo” de la octava temporada de Colombo, cuando me he acordado de que hoy se cumplía una semana de la publicación de CProject. Así que me ha dado por conectarme al Dashboard de Google y sacar unos cuantos datos, a ver que tal iba la cosa.

Os pongo dos gráficas bastante simplonas, las que salen por defecto:



No se la ha bajado ni el tato.


Gente que tiene buen gusto y quiere ser productiva, por países

En resumen, según las estadísticas ha habido 8 instalaciones de la aplicación. Aunque me acabo de volver a conectar después de escribir el post y ya me aparecen más de 10, pero para el caso es lo mismo.

Pero tranquilos, que Roma no se conquistó en un día, y además hay buenas noticias. Resulta que cuando publiqué la aplicación el día 10 no aparecía ni en el buscador de Google Play, ni en la parte de las novedades, ni nada. Había que seguir el enlace directo que puse en mi anterior post. A lo largo de esta semana la aplicación ha ido apareciendo e indizándose en el sistema, y ahora los usuarios la pueden localizar. Así que espero que las cifras de descargas aumenten un poquito.

En fin, veremos como acaba este experimento.

Saludos.

martes, 10 de diciembre de 2013

CProject en Google Play


CProject listo para descarga en Google Play

Buenas a todos. Tal como os comentaba en mi anterior post acabo de publicar la aplicación CProject en Google Play en https://play.google.com/store/apps/details?id=com.charlicode.cproject

Os pongo algunas capturas más de la misma:


Vista analítica. No hace falta hacer cábalas para saber que tarea va mal.

Edición de tareas.

Exportación de datos. Puedes exportar toda la información de la aplicación en formato .xls y aplicar un ETL para migrar :D

Vista gannt, con scroll vertical y horizontal.

Ahora mismo la aplicación no está preparada para móviles, sólo para tablets. Durante el año que viene le iré añadiendo más características.

Por ahora tengo pensado:

  • Compatibilidad con móviles.
  • Contextos.
  • Más diagramas.
  • Una nueva vista GTD.
  • Exportación a XML.
  • Y otras cosas chulas que ya os iré comentando.

Por supuesto si alguien quiere algo en concreto que lo comente y lo estudiaré.

Saludos.

sábado, 7 de diciembre de 2013

Avance de CProject, gestión de proyectos en Android. Próximamente en Android Market

Hace más de un año escribía este post en el que os comentaba que estaba realizando una pequeña aplicación que permitía gestionar tareas y sincronizarlas con OpenERP. A finales de 2012 aún no tenía pensado como iba a evolucionar el desarrollo, puesto que en realidad fue un proyecto rápido de cuatro días que preparé para una entrevista.

Aquí os pongo unas capturas de la primera versión. Como se puede comprobar usa por defecto el estilo visual de android. Simplemente le añadí un degradado a los títulos que encontré haciendo una búsqueda por internet (lo siento, no tengo la página).


CProject 2012. Vista de gestión de proyectos

CProject 2012. Vista kanban de tareas. Siento no tener una captura con tareas, no la hice en su momento.

Durante todo un año he ido añadiendo funcionalidades nuevas, ya que el proyecto inicial sólo constaba de una vista para la gestión de proyectos y otra vista kanban para la gestión de tareas. No sólo me enfrenté a retos de programación, sino a decisiones difíciles, como por ejemplo quedarme en casa trabajando mientras el resto de la peña se divertía en la piscina (sólo un rato, después fui, tranquilos :D )


Diseñando características de la nueva versión

Haciendo pruebas con la interfaz de usuario

Además de crear un estilo visual mucho más amigable, actualmente la aplicación tiene una serie de características bastante interesantes, como por ejemplo:

  • Vista gannt: Clásico diagrama Gantt con scroll vertical y horizontal.
  • Vista analítica: Facilita la interpretación de los datos y el estado del proyecto al usuario.
  • Exportación de datos en formato Excel.
  • Etc

Os presento las nuevas pantallas para que las podáis comparar con las anteriores. Como se puede ver, no hay color.


CProject 2013. Vista de gestión de proyectos. Estado actual.

CProject 2013. Vista kanban. Como se puede ver no hay color, literalmente

¿Y por qué os cuento todo esto? Pues porque acabo de empezar el proceso de publicación en Android Market. Actualmente me encuentro en proceso de verificación de datos, fee, etc. y espero que en 2 ó 3 días esté disponible para su libre descarga.

En cuanto esté publicada la aplicación os escribiré unos cuantos post más sobre ella para que podáis conocer las características de primera mano.

Saludos.

domingo, 1 de diciembre de 2013

¿Dónde nació la web?


Placa indicando el nacimiento de la web

Rebuscando en youtube he dado con un curioso vídeo Birthplace of the World Wide Web - Computerphile de Computerphile en el que realizan un tour por el CERN. En el vídeo comentan y enseñan muchas cosas curiosas, como por ejemplo el primer servidor que usaron, lo tétrico que pueden ser algunos pasillos de ese lugar, etc.


Primer servidor usado. NEXT.

Lo que más me ha llamado la atención es que la web se diseñó usando una estructura compleja de tubos anclados en el techo, siendo posible el apagado completo de las webs si fuera necesario :D

Os dejo con el vídeo.


Vídeo cortito pero interensante.

Saludos.

miércoles, 13 de noviembre de 2013

XML to XSD, y más utilidades geniales vía online

Actualmente me encuentro desarrollando una aplicación en Android que debe generar unos xml muy complejos. Para ello dispongo de varios xml de ejemplo. El problema principal radica en que no tengo los xsd, así que me estoy montando mis propios xsd a mano o con tareas ant.

Hacer esto es bastante tedioso, y no sé porqué no se me ocurrió antes buscar en internet si alguien había programado ya una herramienta que lo hiciera. De hecho he encontrado esta web. Desde esta web no sólo se pueden obtener xsd, sino base64, limpiar html, etc. Como suelo hacer cuando encuentro alguna web que me gusta, acabo de añadirla al pie de mi blog :D

Saludos.

martes, 5 de noviembre de 2013

Coaching, pensamiento positivo y cafés

Los lunes ando muy liado, y es que en mi empresa estamos haciendo un curso de coaching grupal… vamos, una serie de ejercicios, tareas y reflexiones tanto a nivel individual como cooperativo. En teoría todo esto nos va a ayudar a conocernos mejor, ser mejores personas, tener un objetivo común, etc. La Wikipedia lo explica muy bien :)

Evidentemente el curso está dirigido por un equipo de profesionales que nos guían y nos ponen los deberes. Certificados en coaching todos ellos.

La verdad es que mola. Mola mucho. Mola tanto que si hacemos una búsqueda en internet con términos como coaching grupal, coaching de equipo, etc, hay un montón de gente feliz.


¡La gente que hace coaching es super feliz!

¿Y de verdad funciona el coaching? Pues no lo sé, porque acabamos de empezar. El primer día fue rápido, y el segundo se me hizo un poco largo, pero muy interesante. El coaching sirve sobre todo para enterarte de qué opinan tus compañeros, ver cómo afrontan las situaciones, conocer sus opiniones y sacar a relucir la verdadera personalidad de cada uno.

Enterarme de que la empresa había contratado un curso de coaching me hizo gracia. Desde hace meses escucho el podcast de Jorge Fernandez, Pensamiento positivo. A mí me van estos rollos. Así que me llevé una grata sorpresa. Y es que el coaching desde mi punto de vista sirve para aprender a ver el lado bueno a todo y de todos.

Actualmente estoy en un equipo muy bueno. Tenemos gente de mucho talento, y estamos haciendo buenos productos. Creo que todos somos muy buenos profesionales, pero diferentes. Tenemos una buena visión, y creo que los clientes se benefician de ello.

Evidentemente todo en esta vida se puede mejorar, y espero que dentro de unas semanas seamos un equipo mejor. Si el coaching sirve para esto, bienvenido sea. Yo por mi parte le voy a dar una oportunidad.

Saludos.

domingo, 3 de noviembre de 2013

Mi relación con Nokia y Symbian S60 (parte 2)

Una vez un amigo me digo que nunca escribiera “continuará”, “parte 1 “ o similar en un post, ya que según él lo normal es no tener tiempo para escribir la continuación. Cuando escribía para xnoccio me pasó, y aquí he intentado estirar el tiempo para continuar con la historia Mi relación con Nokia y Symbian S60.

Tal como os comentaba, tenía un plan de negocio, preparé un viejo ordenador Pentium 120 con os2 warp, y me puse a currar. Al principio fue bastante duro, ya que partía de cero. Nunca había trabajado en un proyecto similar, no tenía experiencia ni nadie que me ayudara.

El primer paso fue decidir qué tipo de juego quería hacer. Personalmente me apasionan las aventuras tipo Myst, así que la elección fue fácil. Desarrollé un motor gráfico que permitía meter imágenes de fondo, sprites encima y diálogos. Además permitía meter lógica condicional para poder acceder (o no) a ciertas partes del mapa. En unos meses tuve lista una versión beta. La cual he recuperado y subido a youtube.


Versión beta de las chronicas de Ludwig s60. Disculpad la calidad de la imagen, pero fue grabada con una “creative webcam video blaster” hace más de 8 años :D

También he recuperado un trozo del código en c++ , el relacionado con el vídeo.


/*
* ============================================================================
*  Name     : CLudwigAppUi from LudwigAppUi.cpp
*  Part of  : Ludwig
*  Created  : 01/09/2005 by Carlos G. González
*  Implementation notes:
*     Initial content was generated by Series 60 AppWizard.
*  Version  :
*  Copyright: 2005
* ============================================================================
*/

TKeyResponse CLudwigAppUi::HandleKeyEventL(
    const TKeyEvent& aKeyEvent,TEventCode aType)
    {

	TInt iavanzado = 0;
	if(aType != EEventKeyDown)
       return EKeyWasNotConsumed;
    


     switch(aKeyEvent.iScanCode){

		case EStdKeyUpArrow:


				// Para el control del habla múltiple
				if (iAppContainer->ihabla == 1)	
				{
					if (iAppContainer->iEscenaa == 3) // Cabaña
					{
						if (iAppContainer->iguion[0] == 0)
						{
							iAppContainer->iguion[0] = 1;
							break;
						}else
						{
							iAppContainer->iguion[0] = 2;
							iAppContainer->ihabla = 0;
							iAppContainer->imapaactivo = 1; // Activo el mapa al empezar.
							break;
						}
					}  // Fin de la cabaña
						
					else if (iAppContainer->iEscenaa == 4) // Bosque
					{
						if ((iAppContainer->iPosicion.iX == 2) && 
							(iAppContainer->iPosicion.iY == 8) &&
							(iAppContainer->iBa == iAppContainer->iBs))

						{

							if (iAppContainer->ife[0] == 0)
							{
							if (iAppContainer->iguion[1] == 0)
							{
								iAppContainer->iguion[1] = 1;
								break;
							}else
							{
								iAppContainer->iguion[1] = 0; // Por si quiero repetir
								iAppContainer->ihabla = 0;	
								if (iAppContainer->imapacondi == 1)				
									iAppContainer->imapaactivo = 1;	
								break;
							}

							}


						} // Fin de la posición de Ludóvico
					}  // Fin del bosque 

					else if (iAppContainer->iEscenaa == 5) // Ciudad
					{
						if ((iAppContainer->iPosicion.iX == 5) && 
							(iAppContainer->iPosicion.iY == 1) &&
							(iAppContainer->iBa == iAppContainer->iBw))

						{

							
							if (iAppContainer->iguion[3] == 0)
							{
								iAppContainer->iguion[3] = 1;
								break;
							}else
							{
								iAppContainer->iguion[3] = 0; // Por si quiero repetir
								iAppContainer->ihabla = 0;	
								if (iAppContainer->imapacondi == 1)				
									iAppContainer->imapaactivo = 1;	

								iAppContainer->ife[3] = 1;
								break;
							}

							


						} // Fin de la posición de Baldovino


Los meses pasaron y al final obtuve un juego bastante decentillo. En esa época, no había plataformas de pago como itunes, android market, etc. Así que para distribuirlo me uní a la comunidad developer de Handango. No recuerdo a qué precio salió a la venta, pero sí algunas de las condiciones. La más molesta era que los juegos debían llevar un código de activación, y el control debía hacerlo el desarrollador, no el vendedor.

Así que desarrollé un simple programa en c++ en el que dado un imei devolvía la clave. Cualquiera que lo lea podrá ver que es un poco tonto, pero es que ya llevaba meses y no tenía muchas más fuerzas ni ganas, lo que quería era publicarlo.

//-------------------------------------------------
// Programa creado por Carlos Gonz lez Gonz lez
//
//   Generador de claves para el juego Ludwig
//-------------------------------------------------

#include 
#include 
#include 



void main(void)
{
   int imei[18];

   clrscr();

   printf("\n*******************************************************\n");
   printf("*                                                     *\n");
   printf("*    LL      UU   UU DDDD   WW W WW  III   GGGGGGGG   *\n");
   printf("*    LL      UU   UU DD  D  WW W WW   I    GG         *\n");
   printf("*    LL      UU   UU DD   D WW W WW   I    GG         *\n");
   printf("*    LL      UU   UU DD   D WW W WW   I    GG   GGG   *\n");
   printf("*    LL      UU   UU DD  D   W W W    I    GG    GG   *\n");
   printf("*    LLLLLLL UUUUUUU DDDD     WWW    III   GGGGGGGG   *\n");
   printf("*                                                     *\n");
   printf("*******************************************************\n");


   printf("\n\n\n Introduzca n£mero IMEI a registrar: ");

   


   for (int j=0;j<18;j++)
   {
      imei[j] = getche();
      if ((j == 1)||(j == 7)||(j == 13)) printf("-");
   }

   printf("\n El n£mero de registro es: ");

   putchar(imei[13]);
   putchar(imei[8]);
   putchar(imei[9]);
   putchar(imei[12]);
   putchar(imei[11]);
   putchar(imei[10]);


   printf("\n Pulse una tecla para continuar");
   getch();


}

Una mañana me desperté y me había llegado un email de Handando. El juego estaba a la venta. Unos días más tarde me llegó otro email, había vendido una copia y el comprador se ponía en contacto conmigo para obtener la clave. Le respondí con la clave solicitada. Parecía que todo iba bien, pero… Handango decidió cambiar la política de claves. Me enviaron un email diciendo que tenía que hacer ciertos cambios a la aplicación, entre ellos para facilitar el control y que el juego dejaba de estar a la venta mientras no aplicase los cambios…

Desde hacía unos meses trabajaba en Viavansi, y no tenía tiempo para nada. Así que así terminó mi aventura como desarrollador de juegos symbian.

Como anécdota os dejo unos cuantos enlaces que acabo de buscar por la red:

Quedan muchas cosas por contar sobre este tema, pero creo que como homenaje a nokia está bastante bien. Desde hace un tiempo estoy desarrollando una aplicación en Android que espero ver a la venta en breve, y con suerte con un poco más de éxito que esta.

Saludos.

jueves, 24 de octubre de 2013

Trabajar en la nube no mola nada :(

Como está de moda, y como muchos productos están saliendo con opción de trabajar directamente en la nube (Google Docs, Office 360, etc) me propuse hace unos días intentar trabajar así. Para ello decidí escribir una entrada en mi blog, la cual estaba muy currada, directamente en modo borrador.

La entraba iba a tratar sobre un problema que me salió con Jasper Reports en java al cual me costó muchas horas encontrar solución. Ya estaba acabada, simplemente estaba releyendo todo antes de publicar cuando sucedió lo inesperado...


Soy idiota, lo sé :(

Y es que soy idiota. Trabajar en la nube no mola. Al recargar la página del borrador... ¡estaba en blanco!

En fin, esto me servirá de lección. A partir de ahora todo a Word y después al blog, nada de hacer las cosas en modo borrador.

:(

domingo, 20 de octubre de 2013

Mi relación con Nokia y Symbian S60

Hace un mes Microsoft compró la división de móviles y servicios relacionados de Nokia. Durante este tiempo se han publicado muchas noticias relacionadas con esto, como por ejemplo como se han visto afectadas las acciones de las dos empresas, que nokia dejará de dar soporte a symbian el 1 de enero de 2014, etc. También he visto por algunos blogs (lo siento, perdí los enlaces) historias de usuarios comentando lo satisfechos que fueron con algunos modelos de nokia. La más interesante para mí ha sido una que comentaba justo lo contrario, lo malo que fue un modelo E51 y lo mágico que fue el primer iPhone.

En mi caso tuve dos modelos de nokia: una ngage y un 3650. Mi historia con nokia es un tanto especial, ya que está relacionada con la programación y tiene algunas cosas divertidas. Espero disfruten conociendo esta parte de mi vida tanto como yo escribiéndola.


Corría el año 2004 ó 2005, y yo estaba terminando la carrera de informática en la Universidad de Huelva. Como muchos jóvenes en esos años, soñaba con tener una consola Xbox. La había visto funcionando en un piso de unos amigos de la facultad, y alucinaba con sus gráficos. Mi modesto K6-2 a 500 Mhz no daba la talla respecto a juegos, aunque para compilar aplicaciones, investigar y hacer la carrera iba más que sobrado. Entre semana daba clases particulares de programación a compañeros de la carrera con dificultades en las materias relacionadas, y los sábados por la mañana daba clases de física de 2º de bachiller (COU) a una vecina de mis padres. Así que poco a poco iba ahorrando.

Al contrario de la creencia popular, los informáticos también ligamos, y yo tenía novia (en el año 2006 le hice el update a esposa, aunque eso es otra historia). Mi novia trabajaba de cara al público en una empresa (no voy a dar datos), y el problema que tenía era que si un cliente o clientes entraban a cinco minutos del cierre no lo podías echar, había que atenderlos. Así que era habitual que muchos días yo estuviera en la puerta de su empresa, esperándola, hasta las 10 ó las 11 de la noche siendo su salida a las 8 de la tarde.

Un día al fin tuve el dinero suficiente, y me fui al hipercor a comprar la Xbox. Creo recordar que costaba unos 120€. El caso es que cuando iba a pagarla, se me ocurrió, ¿y si compro una portátil y así las horas de espera de mi novia, las hago más entretenidas? Así que solté la Xbox, y me fui a mirar las game boys advance que tenía expuestas. Supongo que el vendedor se dio cuenta de la situación, y se me acercó. Obviamente no recuerdo al pie de la letra la conversación, pero fue más o menos así:

- Vendedor (V): ¿Puedo ayudarte en algo?

- Yo (Y): Quería llevarme una game boy

- V: No están mal, pero yo me llevaría lo último que ha salido, una ngage

En eso momento se me vino a la cabeza el anuncio de la ngage que había visto esa semana en la tele .


(Lo siento, no encontré la version en español, pero creo que era este)

Le pedí que si me podía hacer una demo de la consola, que si me gustaba me la llevaba puesta. Estuvo como 15 minutos contándome funcionalidades, poniendo juegos, etc. Me la compré con un pack de fútbol, y me llevé el Ashen suelto. Flipé con ese juego. Con el tiempo conseguí tener muchos más juegos, aplicaciones, etc.


Mi ngage y los juegos que tengo.

Esa es la primera parte de la historia. Muy común, que podría haberle pasado a cualquiera. Ahora os contaré como se relaciona todo con la programación.

Pasados unos meses acabé la carrera. Como la mayoría de los jóvenes que acaban, lo primero que hice fue apuntarme a una bolsa de empleo en prácticas que ofrecía la universidad. Los requisitos eran ser estudiante a falta de X (no recuerdo) asignaturas para acabar, o estar en el primer año de carrera terminada. La bolsa funcionó y recibí tres ofertas, en este orden:

  1. La primera oferta fue del ayuntamiento de Mazagón o de una empresa relacionada, no recuerdo. Me ofrecieron 4 horas de trabajo al día, ganando unos 400 €. La oferta no estaba mal, pero yo vivía en Sevilla, y con el alquiler del piso perdería dinero. Tampoco quería ir y venir todos los días desde Sevilla, así que la rechacé.
  2. La segunda oferta era de una cooperativa de fresas de la provincia de Huelva. Las horas y el importe eran similares. El problema y lo que me tocó las narices fue que me dijeron que dos días en semana había que hacer horas extras, y que no me las pagarían. Así que no me pareció bien.
  3. La última oferta fue para trabajar un buffet de abogados en Huelva capital. Hablé con una persona que me dijo que estaban incorporando firma digital al buffet, y quería un ayudante para su informático. Todo iba bien, me gustaba de lo que hablaban, hasta que me dijeron que tendría que trabajar 8 horas al día, pero que el contrato sería sólo de cuatro. Les dije que no me parecía bien, que si quería que hiciera las ocho horas pues que me hicieran el contrato de ocho, pero el tío se puso bastante chulo conmigo, a soltar que había muchos deseando coger las prácticas, que yo era un privilegiado por haberme llamado, etc. Evidentemente rechacé la oferta.

A continuación llamé a la facultad, les conté lo que me habían dicho, les dije el nombre del buffet, y les pedí que me dieran de baja de la bolsa de práctica.

Me encontraba en una situación un poco jodida, porque no tenía experiencia, y buscar prácticas sin estar en la bolsa no era lo habitual. Así que se me ocurrió, ¿y si me hago yo mis propias práctica y consigo experiencia de programador? Y la segunda pregunta fue… ¿y eso como se hace?

Después de darle vueltas, busqué en la red si había información sobre como programar para móviles. Me compré un libro de J2ME y durante una semana le dí caña, pero yo quería algo más. Tenía la ngage comprada, así que busqué sobre el tema, y di con un libro. Lo compré a través de Amazon.


Libro de desarrollo de Nokia Symbian Serie 60

Mis padres fliparon un poco cuando le dije que había comprado un libro, que iba a hacer un juego, y que había rechazado las prácticas. Pero he de decir que me apoyaron en todo.

Así que me puse manos a la obra. Busqué un compilador, monté el sdk, y empecé migrando prácticas de turbo pascal a c++ con symbian.

Justo tras acabar los primeros “Hola mundo” hice un parón de una semana. En esa semana me informé sobre donde vender el juego, que papeleo me implicaba, hice un plan de desarrollo de unos 9 meses, monté un viejo Pentium 120 con osdos warp 3 para ayudarme en algunas tareas y volví a programar.

Todo estaba en marcha.

Continuará…

domingo, 22 de septiembre de 2013

Madrid 2020 in the world :D

Después de la derrota de la candidatura de España como sede de los juegos 2020, mi fuentes RSS se están inundando de parodias sobre el tema. Ayer vi un vídeo que me hizo mucha gracia, sobretodo el comentario final de Mariano.



Ana Botella - In The World (Botella's Mix) from Javi Fer

Y es que aquí nos tomamos las derrotas con mucho humor. Y si no que se lo comenten a los del Mundo Today, con el genial artículo Madrid 2020 se celebrará en Tokio.

Saludos.

jueves, 19 de septiembre de 2013

Quick Fix en eclipse... Unsupported IClasspathEntry kind=4

Hoy me ha pasado una de esas cosas que dan un poco por saco, sólo un poco, aunque en teoría no afectan al proyecto en el que estoy trabajando. El caso es que tengo un proyecto maven y eclipse me está indicando que tiene un problema en el pom.xml y que debo realizar un quick fix.

Hasta ahí todo correcto, nada nuevo. Lo que me molesta es que después ejecutar dicho quick fix eclipse muestra un error Unsupported IClasspathEntry kind=4 y aunque el aviso de error desaparece, vuelve a aparecer si reinicio eclipse. Como siempre hago, he buscado por internet y he dado con varias soluciones (1 y 2 ) que no me han funcionado y una explicación con algo más de detalle del problema.

Después de varias pruebas he dado con una solución que a mí me funciona :D

Consiste en crear una configuración en maven con los parámetros eclipse:clean eclipse:eclipse y ejecutarla. Por supuesto no he tenido que quitar naturaleza de maven, ni reimportar, etc. Y al reiniciar eclipse… sigue funcionando :D

Saludos

viernes, 13 de septiembre de 2013

OpenCms Days 2013


OpenCms Days 2013 logo.

Todos los años se realiza un evento llamado OpenCms Days en el que se reúnen profesionales del sector tecnológico para hablar de OpenCms y temas relacionados.

Lo interesante de esta reunión, aparte de que Alkacon de la mano de Alexander Kandzior presenta las novedades de la futura versión de OpenCms (este año será la novena), es que distintos profesionales de diferentes empresas explican en conferencias sus casos de éxito, integraciones con otras tecnologías, etc.

Este año hay dos ponencias que me llaman mucho la atención:

Gradle based OpenCms build and automatic setup

Esta conferencia sera impartida por Tobias Herrmann, desarrollador de Alkacon. Y lo que presenta es la nueva forma de construir los módulos y el propio OpenCms usando Gradle en lugar de Ant. He de confesar que no conocía Gradle hasta hace muy poco, pero una vez echado un vistazo parece un buen cambio.

Social Connect for OpenCms Portal

Esta segunda conferencias será impartida por Helmut Manck, CEO de eonas: IT-Beratung und Entwicklung. En principio esta conferencia no me llamó mucho la atención, ya que la descripción es algo tan machacado como incorporar contenidos sociales a OpenCms. Lo que me ha hecho cambiar de opinión ha sido que al final de la descripción de la conferencia se da a entender que dichas integraciones las hacen usando JSR 286: Portlet Specification 2.0. ¿Y qué es un portlet? En la wikipedia vemos que se lo han currado mucho escribiendo todo este tocho, pero yo voy a hacer un mini resumen: Es una aplicación independiente dentro de otra aplicación. Vamos, que mola mucho.

En fin, estoy ansioso porque publiquen las conferencias, espero que no me decepcionen.

Enlaces de interés:

OpenCms Days.

Conferencias.

Saludos.

domingo, 8 de septiembre de 2013

Menú contextual en ListView no funciona... Desactivar el foco de los items del ListView

Hace casi un año escribí una entrada en la que ponía como hacer un menú contextual para elementos de un ListView. El otro día intenté realizar mi propio ejemplo, y no funcionaba en la nueva aplicación que estoy desarrollando. No obstante la miniaplicación que usé de ejemplo para sicha entrada funcionaba correctamente.

Después de mucho comerme la cabeza, y de muchísimas búsquedas en san google, dí con esta entrada.

Lo que comenta el autor, es que si los items del ListView tienen elementos con "foco activo", en mi caso botones, hay que desactivar dicho foco para que funcione el menú contextual. En resumen, que a cada botón le he tenido que añadir el código:

android:focusable="false"

Esta tontería me ha tenido varios días liado :( . Menos mal que el personal comparte las cosas, y que existe http://stackoverflow.com.

Saludos.

miércoles, 21 de agosto de 2013

Eclipse Juno a pantalla completa.

Buscando por internet como poner eclipse Juno a pantalla completa, me encuentro con este interesante post de stackoverflow en el comentan que hay un plugin de eclipse para hacer eso. Una vez instalado usando Crtl + F11 eclipse estará a pantalla completa, pero no es multimonitor. Saludos.

martes, 23 de julio de 2013

Tonterías varias que mejoran la usabilidad de una aplicación android

Este post lo iré actualizando con pequeños tips rápidos que voy usando en las aplicaciones.

Hacer que por defecto no salga el teclado en una vista con campos de edición:

// Se pone dentro del método onCreate:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

Volver a atrás pulsando el icono principal de la actividad (el superior izquierdo)


@Override
 public boolean onOptionsItemSelected(MenuItem item) {
  super.onOptionsItemSelected(item);
  switch(item.getItemId()){
      
   case android.R.id.home: 
    this.finish(); 
   break; 
   
  }
  return true;
 }

Bloquear el tipo de pantalla (horizontal vs vertical)

En el archivo AndroidManifest.xml, en la declaración de la actividad que queramos forzar:

android:screenOrientation="landscape"  // En este caso la pantalla siempre será horizontal

Fuentes:

Aquí encontré como fijar el giro de pantalla. Aunque tiene más explicaciones interesantes.


jueves, 18 de julio de 2013

Lista select con spinner en android

Acabo de necesitar hacer una lista de selección para mi aplicación en android. Como en otras ocasiones, encontré la respuesta en un blog conocido.

El primer paso consiste en crear los valores que se mostrarán. Dichos valores se almacenan en un fichero arrays.xml situado en la carpeta values.

En mi caso los valores los he referenciado a través del fichero string.xml


 

   
       @string/kanbanlist1
       @string/kanbanlist2
       @string/kanbanlist3
   
    

Después en el layout de la actividad pertinente, escribimos un "spinner" que referencia a los valores sabiendo que "entries" son las entradas del select, y "prompt" el título que muestra el popup.




Sólo nos queda recuperar el valor desde la actividad. A continuación el resultado final.


Lista select.

Popup que sale al pulsar sobre el select

Recuperación del valor:

// Recupera el valor:
Spinner spinnerKanban = (Spinner) findViewById(R.id.editTaskListNumber);
long valueSpinter = spinnerKanban.getSelectedItemId();
valueSpinter++;  // El spinner comienza en 0, pero mis comparaciones de valores en 1 :D
// Operación a realizar con el valor.

Saludos.

sábado, 13 de julio de 2013

Popup de confirmación en android, usando la clase AlertDialog

A veces necesitamos que se muestre un menú de confirmación antes de realizar una determinada acción (a menudo borrar). En android esto se hace con la clase AlertDialog.

En mi caso en concreto tengo mucho listados (ListView) en los cuales muestro una determinada información y varios botones de acción.


Listado de proyectos de aplicación. Cada ítem tiene varios botones con acciones asociadas.

Cada botón tiene asociada un método usando el valor onclick:

android:onClick="deleteProyect"

Dentro dentro de ese método se encuentra el código que muestro a continuación:


import android.app.AlertDialog;
import android.content.DialogInterface;

...

          AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
          // set title
          String alert_title = getResources().getString(R.string.alert_project_delete_title);
          String alert_description = getResources().getString(R.string.alert_project_delete_description);
    alertDialogBuilder.setTitle(alert_title);

    // set dialog message
    alertDialogBuilder
     .setMessage(alert_description)
     .setCancelable(false)
     .setPositiveButton("Yes",new DialogInterface.OnClickListener() {
      // Lo que sucede si se pulsa yes
      public void onClick(DialogInterface dialog,int id) {
       // Código propio del método borrado para ejemplo
      }
      
      
       })
     .setNegativeButton("No",new DialogInterface.OnClickListener() {
      public void onClick(DialogInterface dialog,int id) {
       // Si se pulsa no no hace nada
       dialog.cancel();
      }
     });
  
     // create alert dialog
     AlertDialog alertDialog = alertDialogBuilder.create();
  
     // show it
     alertDialog.show();

Y este es el resultado final:


Diálogo de confirmación antes de borrar.

Saludos

domingo, 7 de julio de 2013

Desactivando el foco (onFocus) en las vistas de android

Unas de las cosas que más me molesta de las aplicaciones android es que al cambiar de actividad, si la nueva actividad tiene campos de edición como (EditText) el foco se sitúa sobre ellos, mostrando el teclado virtual.

Navegando encontré un buen post en el que se indica como desactivar el autofocus.

Sencillo, simplemente 2 líneas en el elemento padre de la vista:

android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"

En mi opinión este detallido puede parecer una tontería, pero mejora la usabilidad de la aplicación.

Saludos.

viernes, 31 de mayo de 2013

Introducción a los servicios web

La primera vez que un programador se enfrenta a la tarea de tener que realizar un servicio web (en adelante WS, Web Service) se suele encontrar un poco perdido. Normalmente se recurre a internet o a algún libro especializado. El problema es que son tantas las tecnologías con las que se puede desarrollar un WS, y son tantos los tipos de WS que existen, protocolos y demás, que a no ser que alguien ayude pueden pasar horas hasta que el programador obtenga el resultado deseado.

En mi caso he desarrollado muchos WS en distintos lenguajes como java, python y php; y distintas tecnologías, como XMLRPC, SOAP, MAVEN, AXIS, AXIS2… y os comento que me he encontrado con muchos problemas, siendo algunos de ellos de solución muy compleja.

Desde hace un tiempo sigo mi propia metodología para realizar WS. En realidad lo que os voy a contar no es de mi propia cosecha, sino que fue una gran aportación de un amigo (JT). Evidentemente yo hice mis cambios y lo adapté a mi forma de trabajar, pero sirvan estos posts como agradecimiento.

Durante cuatro posts, este inclusive, voy a contar lo que es un WS. No voy a hacer como muchos libros que profundizan tanto en los detalles que no se sabe por donde cogerlos, sino que voy a ir al grano. La estructura a seguir será la siguiente:

  • En este primer post, daré una explicación light de lo que es un WS y comentaré el ejemplo que realizaré.
  • En el segundo post programaré una aplicación “productor”.
  • El tercer post será un ejemplo de manejo de la interfaz de eclipse para obtener datos del “productor”.
  • El cuarto y último post lo usaré para crear un “cliente” y una aplicación que use dicho “cliente”.

Así pues, que comience el espectáculo:

¿Qué es un Web Service?

Para responder a esta pregunta, me remito a la descripción dada en la Wikipedia: Un servicio web (en inglés, Web services) es una tecnología que utiliza un conjunto de protocolos y estándares que sirven para intercambiar datos entre aplicaciones. Distintas aplicaciones de software desarrolladas en lenguajes de programación diferentes, y ejecutadas sobre cualquier plataforma, pueden utilizar los servicios web para intercambiar datos en redes de ordenadores como Internet. La interoperabilidad se consigue mediante la adopción de estándares abiertos. Las organizaciones OASIS y W3C son los comités responsables de la arquitectura y reglamentación de los servicios Web. Para mejorar la interoperabilidad entre distintas implementaciones de servicios Web se ha creado el organismo WS-I, encargado de desarrollar diversos perfiles para definir de manera más exhaustiva estos estándares. Es una máquina que atiende las peticiones de los clientes web y les envía los recursos solicitados.

¿Y esto que significa?

Imaginemos la siguiente situación: Tenemos una aplicación (llamada A) que almacena datos de películas. Dicha aplicación sólo está accesible vía web, y queremos que otra aplicación distinta (llamémosla B) muestre los datos de la aplicación A. En este ejemplo la aplicación A se llama productor, ya que produce los datos, y la aplicación B se llama consumidor o cliente.

Para que la aplicación A pueda compartir los datos, es necesario que publique un archivo de descripción del servicio. Dicho archivo debe estar bien formado y contiene una descripción de los métodos que acepta el WS, y de los datos que utiliza tanto si son de llamada como de retorno. Además si dichos datos son clases propias de la aplicación, también deben estar descritas en el archivo. A dicho archivo se le denomina WSDL (Web Services Description Language). En realidad esto es una verdad a medias, puesto que los tipos de datos no son necesarios que estén. Lo que pasa es que si el WSDL está completo el cliente se puede generar de forma automática, ya sea con maven, con eclipse o con cualquier otra aplicación que lo permita. Si no lo estuviera es requisito indispensable que el programador que va a realizar el cliente conozca a la perfección los tipos de datos, etc.

Como podéis imaginar realizar este archivo a mano resulta una tarea tediosa, ya que cualquier error en el mismo hace que no funcione, y para colmo estos errores son difíciles de localizar. Ahora pensad, si hacer un simple xsd es complicado, imaginad un super xsd, es decir, un WSDL.

Sigamos con la teoría. Tenemos una aplicación productora que además de producir datos, publica un archivo que describe que operaciones se pueden realizar con ella. Pues lo que nos quedaría sería leer dicho archivo, y generar una aplicación que sea capaz de usar los métodos y los datos definidos en el WSDL. La aplicación productora a su vez publica una url a la que conectaremos el cliente, y así las dos aplicaciones se comunicarán y pasarán información entre ellas.


Diagrama de funcionamiento de un WS

En resumen:

El productor publica un archivo WSDL que describe como interactuar con él, y además dispone de una url para poder realizar dicha interacción.

El cliente interactúa con el productor y muestra los datos en su aplicación. El WSDL sirve para generar las clases y llamadas a métodos que usará el cliente.

En el próximo post realizaremos una aplicación que será el productor del WS.

Saludos.

sábado, 25 de mayo de 2013

Red no identificada tras hibernar o suspender windows 7

Estaba escribiendo un post sobre servicios webs que voy a publicar en breve, y me encuentro con un problemilla que tengo desde que instalé la última versión de Panda Antivirus 2013.

Mi problema consiste en que después de reanudar la actividad con el ordenador, tras haber hibernado o suspendido el equipo, pierdo la conectividad de red.


Red no identificada.

Si trato de realizar un ping obtengo el mensaje “PING: error en la transmisión. Error general.”. Si miro la wifi, aunque se conecta a la red me pone “Red no identificada” y al hacer un ipconfig me asigna la ip 169.254.70.112.


Error al hacer ping

Tras muchas pruebas vi por casualidad que en la configuración del adaptador wifi tengo una entrada de filtro llamada “PANDA NDIS IM Filter v 1.6.0.44”. Desmarcando dicha entrada la red vuelve a funcionar correctamente.


Configuración de dispositivo de red.

Por supuesto tras reiniciar el equipo el problema se soluciona y vuelve a conectar bien, pero esto es una lata.

En los foros del servicio técnico de panda he encontrado una entrada en la que un usuario comenta el mismo problema, pero para la edición 2012. He probado a instalarme el hot fix de esa versión, pero el instalador no me deja por no ser un hot fix de la edición 2013.

Acabo de enviar un email al servicio técnico, por si hubiera un hot fix disponible para esta versión. Mientras creo interesante publicar esta solución aquí, aunque conociendo al equipo técnico de panda no creo que tarden en darme una respuesta satisfactoria, y es que otro problemilla que tuve hace unos meses me lo solucionaron casi al instante.

Saludos.

Actualización 26/5/13

Después de varias horas de pruebas me he dado cuenta de que el filtro dne lightweight filter también me está dando problemas con la conexión. Además parece ser incompatible con el de Panda, puesto que si desactivo este filtro y no el de Panda, la conexión se ha recuperado varias veces (aunque no todas).

domingo, 19 de mayo de 2013

Giga tv hd620t, convierte tu televisión en una smart tv, si te atreves

Ayer se me estropeó el tdt, y como sin televisión no se puede vivir, fui a comprar uno nuevo. En Carrefour encontré una interesante opción, un Giga tv hd 620t. Después de leer las características me entero que este aparato es un dispositivo android 4.0.3, con entrada de televisión y descodificador tdt, wifi, varios puertos usb, hdmi, etc. Hablo con un dependiente y me comenta que se vende mucho, que a la gente no les está dando ningún problema. Así que convencido me lo llevo a casa.

La primera sorpresa que me llevo es que para usarlo es necesario arrancar el miniordenador. Y es que pequé de novato. Yo creía que funcionaría como tdt por hardware y que para usar el smart tv es cuando arrancaría, pero no. Pequé de novato con este tipo de dispositivos. Pero no importa, al fin y al cabo en realidad no es un problema, ya que el arranque es menor a un minuto.

Una vez arrancado lo que se muestra es una Shell de android, con aplicaciones. No se muestra la típica pantalla de android 4, sino una adaptada por el fabricante. El menú de configuración del dispositivo es accesible mediante una aplicación de wizards o mediante la aplicación de configuración estándar de android.

El primer problema con el que me encuentro es que el dispositivo trae un mando, por llamarlo de alguna forma, al cual le han puesto demasiados botones y no es para nada intuitivo. El simple hecho de navegar entre pantallas se convierte en una tarea desesperante, sin saber que botón es el correcto. Además las “instrucciones” que trae es una típica hoja para conectar cables, explicando las conexiones, y poco más.


Shell de entrada del dispositivo.

Después de maldecir al equipo de diseño de esta empresa, lo configuro correctamente, entro en la aplicación de televisión, realizo una búsqueda de canales, y para mi sorpresa, la televisión se ve pixelada, con una calidad que ni de coña es hd, con ligeros saltos y una imagen de menú android fantasma que siempre se queda detrás. ¿Pero qué mierda es esto?

Pienso que el problema está en que la señal de tdt es interpretada por la mierda aplicación de tv que trae. No hay problema, decido entrar en la tienda android a ver si tienen alguna aplicación tdt que sea mejor… pero me llevo otra sorpresa, no hay tienda android. El dispositivo viene capado, o la aplicación no viene instalada...

Pero vamos a ver, ¿este dispositivo no se supone que es para ver la televisión? ¿y por qué la principal característica que tenía que hacer la hace mal?

A estas alturas ya estoy bastante desesperado. He debido perder 4 puntos de carisma y 6 de autoestima. Envío un email al servicio técnico del aparatito y decido acostarme y volver a al ataque al día siguiente.


Mando por detrás. Teclado pequeñito.

Mando por delante. Muy intuitivo.

Tras horas de sueño me levanto, enciendo la tele, pulso el botón “tv/radio” del mando para ir más rápido, pero este botón no hace nada. Miro a ver si hay algún otro acceso directo a la tele en el mando, pero no, eso sería demasiado fácil. Busco el icono de la aplicación, entro en la tele y busco opciones de configuración. A continuación descubro otro problema de smart tv, en algunos canales el sonido no va sincronizado con las bocas. Me vienen recuerdos de mi época de estudiante en la facultad, cuando algún colega me prestaba una película mal ripeada en un cd. Que bonitos recuerdos, me hacen sentir más joven.

Se me ocurre que si en vez de usar la salida hdmi uso la de componentes, a lo mejor la televisión se ve como debería ser. Después de esto la tele se ve igual que antes, con los mismos problemas, pero la resolución del android ya no me permite usar la 1080, eso es sólo para machos, eso es sólo de salidas hdmi.

Bueno, no pasa nada, voy a hacer un zapping por los canales. Pulso subir canal, no hace nada. Vuelvo a pulsar y espero, no hace nada. A los 3 ó 4 segundos vuelvo a pulsar, entonces sube tres canales de golpe. Ahhh, vale, que tiene un ligero retraso. Decido ordenar la lista de canales, algo super intuitivo, sobretodo porque las instrucciones para hacerlo salen cortadas en pantalla. Menos mal que en la web han puesto un pdf sobre esto. Me desmoraliza un poco tener que buscar en internet para hacer algo que he sabido hacer desde que era pequeño, pero la edad no perdona. Debí suponer que la tecla “0” sirve para hacer aparecer un menú emergente que permite ordenar. Torpe que me estoy volviendo.

Vuelvo al salón y me pongo a ello. Elijo un canal, me siento a verlo. Poco a poco me voy cabreando. La imagen fantasma sigue ahí, los cortes siguen, y mi cabreo aumenta. Creo que no es un buen dispositivo, esto no está bien conseguido. Ya sé que podría intentar meter más aplicaciones vía usb u otras opciones, pero si para ver la tele no sirve, ¿para qué lo quiero?.


Aplicaciones que trae el dispositivo.

Hoy es domingo, el lunes lo pondré en su caja y lo descambiaré, compraré un simple tdt grabador, y esperaré unos años a ver si la tecnología avanza un poco.

Actualización 01

Buscando en google he encontrado este post en el que comentan que el sonido se arregla con la actualización, y que se crea el acceso a la tienda. Efectivamente después de actualizar el firmware el problema de sincronismo de audio ya no ocurre, y la imagen fantasma ha desaparecido.

Aún así el tdt sigue sin ser hd,viéndose muy pixelado y sufriendo algunas ralentizaciones, ¿quizás otra actualización lo arregle?. Acabo de enviar otro email al servicio técnico. A ver si se ponen las pilas y corrigen los problemas. Mientras voy a buscar alguna otra aplicación tdt en el market, a ver que tal. Como curiosidad el market no me reconoce el dispositivo como android hd, y muchas de las aplicaciones etiquetadas hd que me aparecen como primer resultado en el Tablet, no aparecen en este dispositivo.

Actualización 02

Por fin he descubierto lo que pasa, o por lo menos tengo una teoría. He cogido un viejo tdt que no reproduce hd, y la imagen se ve exactamente igual de pixelada que con este tdt. Mi teoría es que el hd620 es capaz de interpretar la señal hd que le llega, pero a la hora de reproducirla, en vez de enviarla en hd, la envía como si no fuera hd. Yo desde hace un par de años tenía el tdt hd y me había acostumbrado a su calidad de imagen, y este tdt aunque ponga hd no envía la señal hd (o la aplicación android no la envía), sino que la transforma a señal normal y corriente :(

Otras pruebas que he hecho a sido intentar reproducir un .divx, un .avi, y un .mkv (h.264). En los tres casos el sistema se ha bloqueado sin empezar el vídeo y ha mostrado el mensaje de forzar el cierre de la aplicación.

La verdad es que todo esto me decepciona bastante. Estoy seguro de que el dispositivo es capaz de reproducirlos, pero no sé si es por actualización o porque faltan codecs, o que sé yo.

Conclusión

Yo buscaba un tdt hd grabador, algo que enchufara y funcionara, y este dispositivo no cumple. Este dispositivo en mi opinión no está enfocado a usuarios domésticos, sino a geeks de la tecnología. Como experimento está bien, pero si en la caja pone "TDT FULL HD 1080p", lo que yo como usuario espero es poder ver con calidad hd la imagen; si en la caja pone que reproduce MKV (h.264) yo lo que espero es poder ver vídeos con ese códec. Si la caja "teclado querty" yo como usuario me imagino que el teclado que trae va a funcionar optimizado para el dispositivo, que no es el caso. He pasado más de un día probando y hay cosas que aún no funcionan, y las que funcionan no dan el rendimiento adecuado.

De todas formas aunque yo lo vaya a descambiar, me gusta mucho el enfoque que Sebastian Rubio le ha dado en su blog. Para trastear sí parece un cacharro divertido. Si uno tiene tiempo está bien tener un android en la tele, conectarte por ssh y jugar con él.

Para terminar, si quieres ver la tele con calidad pasa de este dispositivo, si quieres cacharrear cómpralo, pero que sepas que no es tan bonito como lo ponen en la caja.

Saludos.

Última actualización 19/5/13

El servicio técnico me ha respondido a primera hora de la mañana, con indicaciones sobre como actualizar el aparato. Aún así no se han arreglado los problemas y me han indicado que ese comportamiento no era normal y que lo llevase al punto de venta. Me quedo con la duda sobre el aparato, supongo que he tenido mala suerte.

miércoles, 15 de mayo de 2013

Reseteando formularios con inputs file

Ayer ocurrió lo impensable, el código js de una aplicación web no era compatible con internet explorer... ¿cómo?... ¿por qué?... si eso nunca me había pasado, es la primera vez...

Así que me puse a buscar por internet y encontré la inspiración y explicación en este post.

En la aplicación estamos usando Foundation, y mi problema en concreto era que tras hacer ajaxSubmit en un formulario con inputs, que estaba dentro de un modal (reveal), el modal se cerraba impidiendo volver a usarlo.

Tal como indican en el enlace, la solución fue fácil, clonar el formulario tras el success de la petición ajax:

if($.browser.msie || $.browser.webkit){
  $('#idForm').after($('#idForm').clone(true)).remove();  
}

Lo difícil fue encontrar dicho post :D , que perdí varias horas probando soluciones alternativas.

Saludos.

domingo, 12 de mayo de 2013

Getting Things Done. Comparando herramientas de productividad.

Desde hace un tiempo me he visto con la necesidad de usar herramientas GTD. El mayor problema que estoy encontrando es que si quiero obtener sincronización entre dispositivos hay que pagar una cuota mensual o anual y las que veo no cumplen con todas mis necesidades.

Habitualmente uso un Tablet Sony S de primera generación, un móvil Sony Ericson con android 2.3, varios pc y un mac.

Entre mis necesidades principales se encuentran: Permitir el uso de etiquetas y contexto, organización de tareas por fechas, recordatorios y posibilidad de adjuntar documentos a las tareas.

En principio la herramienta que más me ha gustado ha sido conqu, de asfusion. Cumple con casi todos mis requitos, y además el que falta (poder adjuntar documentos) está en el roadmap de la aplicación. Así que esta herramienta permite hacer casi todo lo que me planteo como usuario. El mayor problema es que funciona sobre adobe air y en el móvil me va muy lenta. Vamos, que no voy a pagar una cuota mensual para que no funcione bien. Supongo que cuando cambie de dispositivo será la opción adecuada, pero mientras tanto me es imposible elegirla.



Diagrama de sincronización de Conqu

La otra opción que he encontrado, y que es con la que me he quedado a sido wunderlist , que en sí misma (o por lo menos en mi opinión) no es una herramienta GTD, ya que no permite etiquetas ni contextos. No obstante la sincronización es muy buena y gratuita. Y en su roadmap también tiene puesto que en el futuro se podrán adjuntar documntos. El problema que he encontrado es que siempre trabaja online, y si desconectas la wifi /3G del móvil se pierde la sesión y el widget deja de mostrar datos y en su lugar pone un mensaje advirtiendo que no estás logado.


Logotipo de Wunderlist

Así que me quedo un poco a medias. Aunque Wunderlist está bien, el hecho de no tener etiquetas o contextos y poder filtrar por ellas hace que tenga información redundante en varias listas, y esto no mola.

¿Conocéis alguna otra herramienta similar?

sábado, 4 de mayo de 2013

Escritura de archivos XML con JAXB

En un post anterior presenté el proceso que hay que seguir para leer archivos XML usando JAXB. En dicho post generé las clases necesarias y las usé de ejemplo.

Para cerrar el círculo adecuadamente, usando el mismo ejemplo, presento ahora una clase que permite escribir un archivo XML en disco.


import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import org.example.personas.Persona;
import org.example.personas.Personas;


public class SaveXMLwithJAXB {

 public static void main(String[] args) {

  JAXBContext ctx;
  
  Personas p = new Personas();
  Persona pItem = new Persona();
  pItem.setCiudad("Madrid");
  pItem.setEdad("20");
  pItem.setId("1");
  pItem.setNombre("Carlos");
  
  p.getPersona().add(pItem);
  
  try {
   ctx = JAXBContext.newInstance(Personas.class);
   Marshaller m = ctx.createMarshaller();
   
   File f = new File("C:/destino.xml");
   m.marshal(p, f);
   
  } catch (JAXBException e) {
   e.printStackTrace();
  }  
 }
}


Saludos.

sábado, 27 de abril de 2013

Bases de datos y Groovy.

El tratamiento de bases de datos en cualquier lenguaje es algo básico. A continuación presento un ejemplo sencillo realizado con Groovy. Hay que destacar que el manejo de bases de datos en java está muy conseguido gracias a frameworks como hibernate, jpa, etc. No obstante creo que conocer esta opción no está de más :D


Pasos previos

He creado un proyecto en Eclipse con el plugin comentado en el anterior post.

En postgres he creado una base de datos vacía. Le he dado acceso al usuario postgres/postgres para que pueda interactuar con la bd.

Como en cualquier programa, lo primero que tenemos que hacer es establer la conexión con la base de datos. El paquete groovy.sql contiene la clase Sql, que es la que nos permite operar contra bases de datos.

En concreto para obtener un conexión nos hace falta el método newInstance. Entre las implementaciones disponibles, la más cómoda en mi opinión es newInstance(url,user,password,driverClassName) throws SQLException, ClassNotFoundException

Los parámetros son evidentes:

url:
Es la url a la bd a la que nos vamos a conectar, en formato jdbc:subprotocol:subname
user:
Usuario de la base de datos con los permisos necesarios.
password:
La contraseña del usuario.
driverClassName:
Nombre del driver.

Esta clase devuelve una instancia de la conexión, con la que ya podremos comunicarnos. Lanza dos tipos de excepciones:

SQLException:
Cualquier tipo de error al interactuar con la base de datos, por ejemplo si el usuario no existe, o no tiene permisos, etc.
ClassNotFoundException:
Si no se ha podido obtener la clase del driver de conexión. Vamos, que no hemos incluido la librería necesaria o que no hemos puesto bien el nombre de la misma.

Obteniendo la conexión

Mi ejemplo va a ser muy sencillo. Voy a crear una clase llamada OperacionesBD.groovy. La cual en el constructor realiza la conexión, y mediante el resto de métodos interactúa con la base de datos.

De esta forma el constructor queda:


public OperacionesBD(String urljdbc, String usuario, String password) {
  super();
  this.connection = Sql.newInstance(urljdbc,usuario,password,Constantes.JDBC_DRIVER);
 }

siendo connection un atributo:

private Sql connection;

Insertando datos

Para ejecutar instrucciones la clase Sql dispone del método execute. Los dos siguientes métodos crean una tabla y insertan valores en ella:


 public void createTablePersons(){
  connection.execute(Constantes.TABLE);
 }



 public void insertValueTest(){
  connection.execute(Constantes.INSERT,[1,'Carlos','M']);
  connection.execute(Constantes.INSERT,[2,'Juan','M']);
  connection.execute(Constantes.INSERT,[3,'María','F']);
  connection.execute(Constantes.INSERT,[4,'Elena','F']);
  connection.execute(Constantes.INSERT,[5,'Pedro','M']);
  connection.execute(Constantes.INSERT,[6,'Rosa','M']);
 }


Mostrando u obteniendo datos

Con el método eachRow se puede iterar sobre los resultados de la consulta sql. El método showFemales imprime en consola todas las mujeres de la tabla person.

 public void showFemales(){
  connection.eachRow(Constantes.FEMALES, {
   println "id: ${it.id}, Nombre: ${it.name}"
   } );
 }

Por consola obtenemos:

 id: 3, Nombre: María
 id: 4, Nombre: Elena
 id: 6, Nombre: Rosa

El método getFemales devuelve una lista de maps con la consulta para realizar un tratamiento posterior.

 public List < Map < Integer,String > > getFemales(){
  List < Map > l = new LinkedList< Map >();
  connection.eachRow(Constantes.FEMALES, {
      Map < Integer,String > m = new HashMap < Integer,String >();
      m.put(it.id.toInteger(), it.name.toString());
      l.add(m);
      } );
  return l;
 }

Actualizando datos

La actualización de datos es bastante sencilla con executeUpdate:

 
public void update(int id, String newName){
  connection.executeUpdate(Constantes.UPDATE, [newName,id]);
 }

Pues esto es todo para este post. A continuación pongo las clases completas del ejemplo.

Fichero de constantes - Constantes.java


package es.test;

public class Constantes {

 protected static String JDBC_DRIVER = "org.postgresql.Driver";
 
 protected static String JDBC_URL = "jdbc:postgresql://localhost:5432/GroovyTest";
 
 protected static String DROP =  "DROP TABLE IF EXISTS  person";
 
 protected static String TABLE = "CREATE TABLE \"person\" "+
       "("+
        " id integer NOT NULL,"+
        " \"name\" character varying(30),"+
        " gender character(1),"+
        " CONSTRAINT pk PRIMARY KEY (id) "+
        ")";

 protected static String INSERT = "INSERT INTO person(id,name,gender)  VALUES (?,?,?)";

 protected static String FEMALES = "SELECT * FROM person WHERE gender = 'F'";
 
 protected static String UPDATE = "UPDATE person SET name=? WHERE id=?";
}

Lógica Groovy - OperacionesBD.groovy


package es.test

import groovy.sql.Sql;

public class OperacionesBD {

 
 private Sql connection;

 
 public OperacionesBD(String urljdbc, String usuario, String password) {
  super();
  
  this.connection = Sql.newInstance(urljdbc,usuario,password,Constantes.JDBC_DRIVER);
  connection.execute(Constantes.DROP);
 }
 

 
 public void createTablePersons(){
  connection.execute(Constantes.TABLE);
 }
  
 public void insertValueTest(){
  connection.execute(Constantes.INSERT,[1,'Carlos','M']);
  connection.execute(Constantes.INSERT,[2,'Juan','M']);
  connection.execute(Constantes.INSERT,[3,'María','F']);
  connection.execute(Constantes.INSERT,[4,'Elena','F']);
  connection.execute(Constantes.INSERT,[5,'Pedro','M']);
  connection.execute(Constantes.INSERT,[6,'Rosa','F']);
 }
 
 
 public void showFemales(){
  connection.eachRow(Constantes.FEMALES, {
      println "id: ${it.id}, Nombre: ${it.name}"
      } );
 }
 
 
 public List < Map < Integer,String > > getFemales(){
  List < Map > l = new LinkedList< Map >();
  connection.eachRow(Constantes.FEMALES, {
     Map < Integer,String > m = new HashMap < Integer,String >();
     m.put(it.id.toInteger(), it.name.toString());
     l.add(m);
     } );
  return l;
 }
 
 
 public void update(int id, String newName){
  connection.executeUpdate(Constantes.UPDATE, [newName,id]);
 }
 

}

Clase principal para probar el ejemplo - Main.java

package es.test;

import java.util.List;
import java.util.Map;

public class Main {

 /**
  * @param args
  */
 public static void main(String[] args) {

  OperacionesBD obd = new OperacionesBD(Constantes.JDBC_URL, "postgres", "postgres");
  
  obd.createTablePersons();
  
  obd.insertValueTest();
  
  obd.showFemales();
  
  List < Map < Integer,String > > l = obd.getFemales();
  
  for(Map < Integer,String > item:l){
   System.out.println(item.toString());
  }
  
  obd.update(6, "Rosa Rosae");
  
  obd.showFemales();  
 }
}

Y por último os comento que el código fuente completo se puede bajar de mi repositorio público de Git.


Referencias

La idea de este post surgió por un problemilla con Groovy, que solucioné gracias a este enlace.

Saludos.

domingo, 21 de abril de 2013

Qttabbar, pestañas en el explorador de windows

Si hay algo que echo de menos en el explorador de archivos de windows son las pestañas.

Durante años he probado muchas soluciones, pero ninguna terminaba de gustarme... hasta ahora.

Qttabbar es un addon para el explorador de archivos. Muy fácil de instalar, con licencia GNU, y muy estable.


Licencia GNU.

Lo puedes descargar desde aquí.

El uso es muy sencillo, puesto que usa la típica combinación de teclas:

  • Ctrl + N : Nueva pestaña.
  • Ctrl + W : Cerrar pestaña.

Y el aspecto del explorador (por lo menos al ocultar la horrible barra de iconos) es elegante :)


¡Pero que elegancia de pestañas!

Saludos.

martes, 26 de marzo de 2013

Lectura de archivos XML en Java. Uso de JaxB.

En mi anterior post sobre Groovy realicé un ejemplo que leía un archivo xml. En este post voy a leer casi el mismo archivo xml usando JAXB.

Archivo personas.xml (modificado), la diferencia es que a la etiqueta persona le voy a añadir un namespace, quedando el archivo así:


 

  
   1
   Carlos G. González
   Sin ley
   
  
  
   2
   M. Rajoy
   
   Mamoncete
  
  
   3
   ZP
   
   Engañabobos
  


JAXB son las siglas de Java API for XML Binding. Con JAXB podemos serializar objetos java y archivos xml. ¿Y esto qué significa? Pues que podemos tener una clase java con atributos y relacionar esa clase con un archivo xml. También podemos cargar los valores del archivo xml en dicha clase, con lo cual facilitamos mucho la lectura del mismo. En realidad la unión de la clase java no se va a realizar con el archivo xml que contiene los datos que queremos leer, sino con el archivo de definición del mismo, es decir, con el XSD (XML Schema Definition).

Ejecutando xjc

Como personas.xml fue un ejemplo creado a mano para el post mencionado, no tengo su archivo xsd. Eclipse permite crear este tipo de archivos de forma rápida, autocompletando, etc. Tras un par de minutos mi xsd quedaría:







 
  
 



 
  
  
  
  
 
 




Aunque yo para este ejemplo he picado el xsd a mano, existen herramientas que lo pueden generar a partir de clases java (eclipse) o de archivos xml (Microsoft tiene una que mola mucho). El libro Profesional Java JDK 6 de Anaya multimedia dedica varias páginas a este tema, por lo que lo recomiendo si alguien quiere profundizar más.

Ahora lo que vamos a hacer es crear las clases java asociadas al xsd. Hasta la versión 5 del jdk había que bajarse el paquete JWSDP, el cual contenía el ejecutable que nos hace falta para esta tarea. A partir de la versión 6 del jdk, dicho paquete se incluyó en el jdk, por lo que ya no es necesario bajarse nada independiente.

El ejecutable xjc es el que nos permite generar las clases a partir del archivo xsd. La opción –d permite indicar el directorio en el que queremos generar las clases, en mi caso “.\src “. El otro directorio escrito es la ruta hacia el archivo xsd.

En mi caso la sentencia es:

c:\Java(x86)\jdk1.6.0_21\bin\xjc.exe -d .\src src\xml\Personas.xsd

Existen otros parámetros para indicar el nombre de los paquetes a generar… pero no los he usado para no complicar el ejemplo.

Tras ejecutar la sentencia, en el paquete org.example.personas he obtenido cuatro clases:

  • ObjectFactory.java
  • package-info.java
  • Persona.java
  • Personas.java

Aún falta un paso para que la unión entre el xsd y las clases esté finalizada, y es que a veces el elemento raíz del xsd no queda marcado en las clases java. En mi caso hay que añadir la anotación @XmlRootElement a la clase Personas.java, quedando así:

@XmlRootElement (name="personas")
public class Personas {…}

El problema parece estar relacionado con información incompleta en los xsd o en los xml. Si se quiere obtener más información sobre este problema, en los siguientes links comentan la jugada:

Enlace a magicmonster.com.

Enlace a weblogs.java.net.

Usando las clases obtenidas

La siguiente clase es muy sencilla y muestra como se realizaría la lectura del xml:

import java.io.FileInputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

import org.example.personas.Persona;
import org.example.personas.Personas;


public class ReadXMLwithJAXB {

 public static void main(String[] args) {

  JAXBContext ctx;
  try {
   ctx = JAXBContext.newInstance(Personas.class);
   Unmarshaller u = ctx.createUnmarshaller();
   
   Personas root = (Personas) u.unmarshal(new FileInputStream("C:/Users/Carlos/workspace/ReadXML/src/xml/personas.xml"));
   for(Persona p:root.getPersona()){
    System.out.println(p.getNombre());
   }
   
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

El resultado obtenido es:

Carlos G. González
M. Rajoy
ZP

Y una vez montado todo este tinglado, sinceramente, ¿no mola mucho más Groovy?

Saludos.

jueves, 7 de marzo de 2013

Api Reflection en Java. Ejemplo de uso

El otro día necesité usar reflection en java. Es el típico api que no uso muy a menudo, por lo que siempre tiro de documentación. Personalmente suelo recurrir al documento Introducción al API Reflection (Reflexión) de Java por Eneko González Benito (Keko) , alojado en JavaHispano. Antes tiraba de google, pero este documento está bastante bien para ser una introducción.

Aún así, pongo aquí un ejemplo rápido de uso, el cual es bastante intuitivo.


Código

Clase que vamos a usar de ejemplo.

class Persona{
  private String nombre;
  private String apellido;
  
  public String getNombre() {
   return nombre;
  }
  public void setNombre(String nombre) {
   this.nombre = nombre;
  }
  public String getApellido() {
   return apellido;
  }
  public void setApellido(String apellido) {
   this.apellido = apellido;
  }
  @Override
  public String toString() {
   return "Persona [nombre=" + nombre + ", apellido=" + apellido + "]";
  }
}

Clase que va a instanciar a la anterior usando el API Reflection. Responde a la pregunta... ¿Cómo coño se hacía...? :D

public class ReflectionTest {
 
 public static void main(String[] args) {
  try {
   Class p = Class.forName("Persona");
   
   try {
    Persona pp = (Persona) p.newInstance();
    
    pp.setNombre("Carlos");
    pp.setApellido("G. González");
    
    System.out.println(pp.toString());
    
   } catch (InstantiationException e) {
    e.printStackTrace();
   } catch (IllegalAccessException e) {
    e.printStackTrace();
   }
   
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  }
 }
}

Y el resultado:

Persona [nombre=Carlos, apellido=G. González]

Documentación relacionada

martes, 5 de marzo de 2013

Pasar en Solr de query en string a query en CmsSolrQuery


String solrQuery = "fq=type:MyType&sort=MyOtherField asc&rows=15";

Map < String, String[] > pm = CmsRequestUtil.createParameterMap(solrQuery);

CmsSolrQuery cmsSolrQuery = new CmsSolrQuery(getCmsObject(),pm);

String SOLR_INDICE_ONLINE = "Solr Online";
CmsSearchManager manager = OpenCms.getSearchManager();
CmsSolrIndex index = manager.getIndexSolr(SOLR_INDICE_ONLINE);
index.setRequireViewPermission(false);


CmsSolrResultList results = index.search(adminCmsObject, cmsSolrQuery,true);
 for (CmsSearchResource item: results){
  // TODO tratamiento
 }
    
   

viernes, 22 de febrero de 2013

Enviando emails con Java 6 y tomcat 7. DCH for MIME type multipart/mixed

Si la aplicación no puede enviar emails, mostrando un error tal como

Caused by: javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed; 
 boundary="----=_Part_4_26855300.1361447126169"
 at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:877)
 at javax.activation.DataHandler.writeTo(DataHandler.java:302)
 at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1403)
 at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1745)
 at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:636)
 ... 50 more

La solución es copiar las librerías activation-1.1.1.jar y mail-1.4.1.jar a la carpeta lib de tomcat. Unos post de stackoverflow me ayudaron a dar con la solución, pero dando pistas sobre el error, sin dar solución concreta.

sábado, 9 de febrero de 2013

Hola mundo con Groovy

Tanto oir hablar de Groovy, y yo aún no había podido trabajar con él. Así que me he puesto manos a la obra a ver si hacía un hola mundo en condiciones.

¿Y Groovy que puñetas es? pues es un lenguaje de scripting para java que está disponible en la especificación JSR 241: The Groovy Programming Language.

Para poder usar Groovy con eclipse, hay que bajarse el plugin que se encuentra aquí.

La instalación se realiza como en todos los plugins de eclipse.

Instalación del plugin de Groovy en eclipse.

Lo primero que me ha tocado las narices de esta instalación es que después de instalar el plugin, tras reiniciar eclipse, he obtenido un bonito error Could not create the Java virtual machine.

Could not create the Java virtual machine. Después de instalar el plugin de Groovy en eclipse.

El problema es que tras la instalación del plugin, el eclipse.ini fue modificado. Concretamente se afectaron las líneas de la versión de java y las que referencian al directorio de java. ¡WTF!.

-Dosgi.requiredJavaVersion=1.6

La solución la encontré en este post.

Y mi pregunta, ¿por qué hizo esto el plugin?. A ver si alguien me lo aclara.

Pasado el susto, es hora de seguir con cosas más interesantes. Una vez instalado el plugin y corregido el error, voy a realizar un HolaMundo en groovy que leerá un archivo XML y mostrará en consola varios valores.

El Xml a leer:



  
   1
   Carlos G. González
   Sin ley
   
  
  
   2
   M. Rajoy
   
   Mamoncete
  
  
   3
   ZP
   
   Engañabobos
  

El primer paso será crear un proyecto groovy con una única clase de ejemplo (ReadXmlPersons.groovy).

package es.test

class ReadXmlPersons {

 static main(args) {
 
   
  def personas = new XmlSlurper().parse(new File("C:/compartido/personas.xml"))
  
  personas.persona.nombre.each( 
         { println it }
         )
 }

}

Si ejecutamos esta clase vemos que se muestra en consola lo que queremos.

Esto ha molado bastante, ya que la lectura del XML se ha simplificado mucho, por lo menos si lo comparamos con JAXB. ¿Y si lo adaptamos a nuestras necesidades?

Si modificamos la clase groovy anterior, podemos encapsular los valores en una lista. Después podemos hacer una clase java que lea esa lista y los muestre por consola.

La clase groovy quedaría:

package es.test

class ReadXmlPersons {

 public static List < String > getNombres(){
  
  List < String > l = new LinkedList< String >();
  
  def personas = new XmlSlurper().parse(new File("C:/compartido/personas.xml"))
  
  personas.persona.nombre.each(
         { l.add(it) }
         )
  
  return l;
  
 }
 
 static main(args) {
 }

}

Y la clase java:

package es.test;

import java.util.List;

public class Main {

 /**
  * @param args
  */
 public static void main(String[] args) {

  List< String > l =  ReadXmlPersons.getNombres();
  
  System.out.println(l);
  
 }

}

Bueno, pues yo creo que como HolaMundo está bastante bien. A ver si tengo un poco más de tiempo para darle caña a Groovy y hacer cosas más interesantes.

Saludos.

domingo, 3 de febrero de 2013

Configurando un nuevo catálogo (XSD) en eclipse

Al crear nuevos contenidos estructurados de opencms desde eclipse, los tipos propios de OpenCms son subrayados en rojo. Para que eclipse conozca esos tipos de contenidos, simplemente hay qe configurar un nuevo catálogo de datos XML con las definiciones de los mismos.

¿Y dónde obtenemos el catálogo de tipos? El propio Alexander Kandzior nos daba la solución en la lista de correos de OpenCms.

org.opencms.xml.CmsXmlEntityResolver resolver = new org.opencms.xml.CmsXmlEntityResolver(null); 
org.xml.sax.InputSource source = resolver.resolveEntity(null,org.opencms.xml.CmsXmlContentDefinition.XSD_INCLUDE_OPENCMS); 
byte[] bytes = org.opencms.util.CmsFileUtil.readFully(source.getByteStream()); 
String string = org.opencms.i18n.CmsEncoder.createString(bytes,"UTF-8"); 
System.out.println(string); 

Una vez obtenido el fichero opencms-xmlcontent.xsd simplemente hay que darlo de alta en eclipse, en XML\XML Catalog.

Captura de Catálogo XML en eclipse con valores de configuración.

Saludos.

sábado, 19 de enero de 2013

Inicializando un hashmap en una clase de constantes

Esta semana he necesitado instanciar un Map en un fichero constantes. El truco no es mio, sino de esta fuente.


public static final Map < Integer, String >  MAPA= Collections.unmodifiableMap(
              new HashMap< Integer, String >(){
                   {
                    put(0,"");
                    put(1,"");
                   }
               });

martes, 8 de enero de 2013

Reiniciando el pool de conexiones de Oracle 11g a lo bestia

La semana pasada me encontré con un problema en el entorno de desarrollo, el pool de conexiones de Oracle. El problema en concreto es que el pool se llena demasiado rápido y hay que estar reiniciando Oracle constantemente. Por defecto Oracle admite 20 conexiones de pool, aunque este valor se puede incrementar.

¿Pero que pasa si hay varias máquinas de desarrollo (tomcat + eclipse) apuntando al mismo oracle? Pues que aunque subamos el pool al final del día vuelve a estar lleno y es necesario vaciarlo.

La forma bonita sería entrar como SYSDBA y ejecutar:

SYS as SYSDBA:
SQL> EXEC DBMS_CONNECTION_POOL.stop_pool;
SQL> EXEC DBMS_CONNECTION_POOL.start_pool;

Pero claro, ¿qué ocurre si no tenemos el password del usuario? ¿ o si no están los listener necesarios configurados? ¿o simplemente si queremos hacerlo "de otra forma" pero que sea más rápida?.

Mi solución ha sido un poco bestia, como matar moscas a cañonazos, pero efectiva.

Viendo los procesos del sistema

ps aux|grep oracle

me di cuenta de había procesos con la nomenclatura oracle+SID, en mi caso oracleorcl.

ps aux|grep oraceorcl

Por tanto se pueden matar procesos a mano (kill -9) para liberar pool. Pero claro, 20 ó 30 procesos a mano es un poco pesado. Googleando un poco y combinando post nos sacamos de la manga el comando:

ps aux|grep oracleorcl| awk '{print $2}' |xargs kill –KILL

y matamos a todos de golpe :D

Lo malo es que tiramos las conexiones activas (vamos, que podemos joder al personal), así que hay que avisar a los compañeros antes, pero es un mal menor.

Y la pregunta clave, ¿todo esto para qué? Pues simplemente ganamos un poco te tiempo y ya no es necesario reiniciar Oracle, y porque me divirtió investigar este tema, por supuesto ;D

Por cierto que este problema de pools al parecer sólo se da en java, ya que el driver de oracle no libera las conexiones pilladas.

saludos

Related Posts Plugin for WordPress, Blogger...