Utilizar GMail como SmartHost desde Linux Debian 5

Introducción.

Un servidor que utilizo frecuentemente para el desarrollo de aplicaciones web que se encuentra basado en Debian 5 no estaba enviando los correos de las aplicaciones ni de un par de scripts que había escrito hace un tiempo para la creación de copias de seguridad.

Al revisar los logs encontré este mensaje: Mailing to remote domains not supported.

La solución es realizar la configuración del Exim 4, sin embargo tenía un detalle adicional que lo hacía interesante.  Para la empresa propietaria del servidor estoy utilizando Google Apps para gestionar su correo electrónico, así que el SmartHost tenía que ser con GMail, SSL (el puerto indicado) y autenticación.

Procedimiento.

Para este procedimiento se supone que el nombre del servidor es desarrollo.dominio.com.

1. Crear una cuenta de correo en GMail/Google Apps para el relay del servidor de correo.

Nombre de usuario: desarrollo_relay
Contraseña: password_relay

2. Realizar la configuración de Exim.

$ su –

$ dpkg-reconfigure exim4-config

  • General type of mail configuration: mail sent by smarthost; received via SMTP or fetchmail
  • System mail name: localhost
  • Ip Address to listen on: 127.0.0.1
  • Other destinations~: desarrollo.dominio.com
  • Machines to Relay for: <vacío>
  • IP address or hostname of the outgoing smarthost: smtp.gmail.com::587
  • Hide local mail name in outgoing mail: No
  • Keep number of DNS queries minimal: No
  • Delivery method for local mail: mbox format in /var/mail/
  • Split configuration into small files: Yes

3. Configurar la información del cliente de acceso.

$ vi /etc/exim4/passwd.client

gmail-smtp.l.google.com:desarrollo_relay@dominio.com:password_relay
*.google.com:desarrollo_relay@dominio.com:password_relay
smtp.gmail.com:desarrollo_relay@dominio.com:password_relay

$ chmod 640 /etc/exim4/passwd.client

$ chown root:Debian-exim /etc/exim4/passwd.client

4. Actualizar la lista de correspondencias de direcciones de correo.

$ vi /etc/exim4/email-addresses

root@localhost:    desarrollo_relay@dominio.com

$ chmod 640 /etc/exim4/email-addresses

5. Verifique la configuración actual del Exim.

$ vi /etc/exim4/update-exim4.conf

dc_eximconfig_configtype=’smarthost
dc_other_hostnames=’desarrollo.dominio.com
dc_local_interfaces=’127.0.0.1
dc_readhost=’desarrollo.dominio.com
dc_relay_domains=”
dc_minimaldns=’false
dc_relay_nets=”
dc_smarthost=’smtp.gmail.com::587
CFILEMODE=’644
dc_use_split_config=’true
dc_hide_mailname=’false
dc_mailname_in_oh=’true
dc_localdelivery=’mail_spool

6. Reiniciar el servicio del MTA.

$ /etc/init.d/exim4 restart

Enlaces.

Instalación de Icecast2 en Linux Ubuntu 9.04

Introducción.

Icecast es una herramienta libre desarrollada por la Fundación Xiph para generar contenidos de audio a través de la red utilizando la técnica de streaming.  La versión 2 se basa en el formato libre Ogg Vorbis mientras que la versión anterior permite utilizar archivos MP3 los cuales según entiendo, requieren de un pago de licenciamiento al tener estos un formato propietario.

Una de las mayores ventajas de la herramienta es su flexibilidad, permitendo diferentes orígenes del sonido a reproducirse como fuentes de reproducción (playlists) predefinidas o la salida de una tarjeta de audio específica (como el caso de un micrófono).  Su arquitectura cliente servidor permite que se originen contenidos desde múltiples ubicaciones que serán distribuidos a los usuarios finales a través de un único servidor de Icecast.

Instalación.

$ sudo aptitude install icecast2

Configuración.

$ sudo vi /etc/icecast2/icecast.xml

Actualizar las contraseñas de administración.

<authentication>
<!– Sources log in with username ‘source’ –>
<source-password>MySecretSourcesPassword</source-password>
<!– Relays log in username ‘relay’ –>
<relay-password>MySecretRelayPassword</relay-password>

<!– Admin logs in with the username given below –>
<admin-user>admin</admin-user>
<admin-password>MySecretAdminPassword</admin-password>
</authentication>

Modifique los valores resaltados en rojo según su conveniencia.

Actualizar la información de conexión.

<hostname>jimezam-laptop</hostname>

<!– You may have multiple <listener> elements –>
<listen-socket>
<port>8000</port>
</listen-socket>

El hostname deberá corresponder con el valor del servidor de Icecast2 que se está instalando.  El port se utilizará para publicar el servicio.

Actualizar las ubicaciones base.

<logdir>/var/log/icecast2</logdir>
<webroot>/usr/share/icecast2/web</webroot>
<adminroot>/usr/share/icecast2/admin</adminroot>

logdir hace referencia al directorio donde se almacenarán los registros del servicio (access.log y error.log), webroot hace referencia al directorio donde se publicará el contenido estático a publicarse (archivos de audio) y adminroot almacenará los archivos de administración.

Actualizar el inicio a través de init.d.

$ sudo vi /etc/default/icecast2

ENABLE=true

Iniciar el servidor.

Modo de pruebas.

$ sudo -u icecast2 /usr/bin/icecast2 -c /etc/icecast2/icecast.xml

Modo de producción (background).

$ sudo -u icecast2 /usr/bin/icecast2 -b -c /etc/icecast2/icecast.xml

Estilo Ubuntu.

Iniciar el servicio.

$ sudo /etc/init.d/icecast2 start

Detener el servicio.

$ sudo /etc/init.d/icecast2 stop

Verificar su funcionamiento.

Verificar la ejecución del proceso.

$ ps -fea | grep icecast

icecast2  7674  6254  0 23:21 pts/0    00:00:00 /usr/bin/icecast2 -c /etc/icecast2/icecast.xml

Verificar las estadísticas del servicio desde web.

Visitar el siguiente URL con un navegador web.

http://localhost:8000/admin/stats.xsl

La autenticación se debe realizar utilizando el admin-user y el admin-password especificados durante la etapa de configuración en el archivo icecast2.xml.

Reemplace localhost por el nombre del servidor o su correspondiente dirección IP si desea acceder a este remotamente.  Modifique también el puerto según el elegido en la sección listen-socket del mismo archivo de configuración.

Enlaces.

Descubriendo dispositivos Bluetooth con Java y BlueCove

Introducción.

Después de la fallida búsqueda de una librería para acceder al protocolo Bluetooth desde Mono vuelvo entonces a Java buscando la opción mas portable posible.  Esta vez voy a probar BlueCove que soporta Mac OSX, WIDCOMM, BlueSolei, Windows nativo y Linux con BlueZ.

Instalación.

Descargar las últimas versiones disponibles desde la siguiente ubicación: http://sourceforge.net/project/showfiles.php?group_id=114020

  1. bluecove-*.jar: módulo principal, incluye el soporte para las pilas de Mac OS X, WIDCOMM, BlueSoleil and Microsoft Bluetooth.
  2. bluecove-gpl-*.jar: adiciona el soporte para la pila en Linux.

Descargar estos archivos JAR en una ubicación conocida.

Descubriendo dispositivos Bluetooth.

Para esto se parte de un objeto que implementa DiscoveryListener, él define que se debe hacer cuando cuando se encuentra un nuevo dispostivo y cuando se termina la búsqueda.

        /**
         * The DiscoveryListener interface allows an application to
         * receive device discovery and service discovery events.
         */

        DiscoveryListener listener = new DiscoveryListener()
        {
            /**
             * Called when a device is found during an inquiry.
             */

            public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod)
            {
                System.out.println("Device " + btDevice.getBluetoothAddress() + " found");

                devicesDiscovered.addElement(btDevice);

                try
                {
                    System.out.println("     name " + btDevice.getFriendlyName(false));
                }
                catch (IOException cantGetDeviceName) {}
            }

            /**
             * Called when an inquiry is completed.
             */

            public void inquiryCompleted(int discType)
            {
                System.out.println("Device Inquiry completed!");

                synchronized(inquiryCompletedEvent)
                {
                    inquiryCompletedEvent.notifyAll();
                }
            }
            // Not used in this example.

            public void serviceSearchCompleted(int transID, int respCode) {}
            public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {}
        };

En este ejemplo, cuando se identifica a un nuevo dispositivo Bluetooth (ver deviceDiscovered) se obtiene su dirección, de ser posible su nombre y se agrega en la lista de dispositivos encontrados.

public static final Vector<RemoteDevice> devicesDiscovered = new Vector<RemoteDevice>();

Para ejecutar finalmente la búsqueda de dispositivos de acuerdo con el comportamiento definido anteriormente, se crea un objeto sobre el cual se sincronizarán las próximas acciones.

final Object inquiryCompletedEvent = new Object();

synchronized(inquiryCompletedEvent)
{
         // The search code ...
}

Con él se inicia la búsqueda de dispositivos accediendo al Agente Descubridor del Dispositivo Local.

boolean started = LocalDevice.getLocalDevice().getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, listener);

Finalmente se verifica que la búsqueda haya comenzado exitosamente y se espera para garantizar su ejecución.

     if (started)
     {
          System.out.println("Starting Device Discovery process ...");

          /**
           * Wait for Discovery Process end
           */

          inquiryCompletedEvent.wait();

          System.out.println("There was " + devicesDiscovered.size() +  " device(s) found");
     }

Compilación & ejecución.

Para compilar y posteriormente ejecutar el programa de demostración es necesario garantizar que el JAR de bluecove, descargado inicialmente, se encuentre en el CLASSPATH.  También es necesario recordar que si la plataforma objetivo es Linux, es necesario incluír además el JAR de bluecove-gpl.

Para compilar se utiliza un comando preparado de la siguiente manera.

javac -cp ../lib/current/bluecove-2.1.0.jar:../lib/current/bluecove-gpl-2.1.0.jar RemoteDeviceDiscovery.java

Debe tenerse en cuenta que para la compilación se está suponiendo que los archivos JAR se encuentran en el directorio ../lib/current y que corresponden con la versión 2.1.0.   Además se está realizando en Linux, motivo por el cual el separador de directorios es : en lugar del ; utilizado por Windows.  Es necesario que adapte el comando según sus características específicas.

Para interpretar se utiliza un comando similar, preparado de la siguiente manera.

java -cp ../lib/current/bluecove-2.1.0.jar:../lib/current/bluecove-gpl-2.1.0.jar RemoteDeviceDiscovery

La salida de la aplicación.

La aplicación de demostración deberá imprimir por salida estándar la información de los dispositivos Bluetooth que se encuentren cerca durante el tiempo que dure la búsqueda.  Algo similar a lo siguiente.

BlueCove version 2.1.0 on bluez
Starting Device Discovery process …
Device 001ADE8BF510 found
name Jimezam Phone
Device 0017AE39DCB0 found
name Nintendo RVL-CNT-01

Device Inquiry completed!
There was 2 device(s) found
BlueCove stack shutdown completed

En la respuesta anterior se puede apreciar que la aplicación detectó exitosamente a mi teléfono celular y a un Wiimote que pasaba por allí.

Enlaces.

Instalación del servidor SSHd en Linux Debian 5

Instalación del servicio.

# apt-get install ssh

Este paquete incluye las aplicaciones servidor y cliente para reemplazar las herramientas inseguras rlogin/rsh/rcp.

Configuración básica del servicio.

# vi /etc/ssh/sshd_config

Port 22
Protocol 2
UsePrivilegeSeparation yes
PermitRootLogin no
StrictModes yes
PermitEmptyPasswords no
Subsystem sftp /usr/lib/openssh/sftp-server

Opciones de configuración adicionales.

Agregar soporte para el transporte de aplicaciones X11 a través de SSH.

X11Forwarding yes

Si se presentan problemas de desconexión de las sesiones SSH, incluyendo las SSHFS, debido a timeouts modificar la siguiente opción de /etc/ssh/ssh_config.

ServerAliveInterval  120   # seconds.

Reiniciar el servicio.

# /etc/init.d/ssh restart

Como borrar los directorios .SVN

Si alguna vez, por una extraña razón, necesita remover los directorios de SVN sólo es necesario seguir estos dos pasos.

$ find RUTA -type d -name .svn

Verifique que efectivamente sean las carpetas que desea eliminar bajo la ubicación RUTA y proceda con el siguiente comando.

$ rm -rf `find RUTA -type d -name .svn`

Tenga en cuenta que las comillas que recubren a la instrucción find son invertidas: estas ( ` ), no estas  ( ‘ ).

Transfiriendo un proyecto a Dreamhost

Introducción.

Este mes realice la transferencia de un proyecto que estaba albergado en un hosting un tanto incómodo (poco espacio, no acceso al shell, bases de datos limitadas, no acceso por SFTP, …) hacia Dreamhost donde están hospedados los demás proyectos.  Este proceso incluyó la transferencia del dominio desde el Registrar anterior, la copia de archivos y la copia de las bases de datos.  Pensé que la parte de actualización de los dominios iba a ser mas tortuosa pero en realidad no fue nada difícil, sin embargo amerita su documentación para futuras referencias.

Transferencia del dominio.

Para transferir el dominio al Registrar de Dreamhost se debe contar con las siguientes condiciones obligatorias.

  • Ser un dominio .com, .net, .org o .info.
  • Tener una cuenta (Web ID) con Dreamhost.
  • El dominio a transferirse debe tener mas de 60 dias de adquirido/renovado.
  • Tampoco debe estar a punto de vencerse ya que el proceso toma algunos días y es abortado si este se vence durante la transacción.  Un rango de tiempo mínimo es de 2 semanas antes de su vencimiento.
  • No debe estar asegurado (locked) o retenido (on-hold) por el Registrar actual.
  • Se debe contar con el código de transferencia del dominio provisto por el Registrar.
  • Se debe contar con acceso a la cuenta de correo del administrador del dominio registrada con él ya que a esta se envía un correo de confirmación.

Para iniciar la transferencia se accede al panel de control de Dreamhost (http://panel.dreamhost.com/) a través de los menúes Domains > Reg. Transfer.  En el campo Transfer a registration to us se debe especificar el nombre del dominio que va a ser trasladado.  Posteriormente el sistema solicita el código de transferencia (Transfer Auth Code) que lo entrega el Registrar de orígen y la información del Whois que puede ser la de Dreamhost si se desea privacidad o sus datos propios.

En este momento se envía un correo de confirmación a quien aparezca como administrador del dominio, este correo contiene una autorización que debe ser activada en un plazo máximo de 7 días o la transacción se terminará automáticamente.  Esta información se puede consultar a través de Whois.  Este proceso puede tomar algunos días.

Para formalizar la transferencia del dominio es obligatorio que se renueve el dominio por un año mas.  Este tiempo se suma al que tenga ya contratado el dominio en ese momento.

Después de realizada la transferencia del registro se especifican los servidores DNS (Whois nameservers) que manejaran el nombre, ya sean los del hosting orígen si se desea que se siga utilizando (útil si no se ha hecho aún la copia de archivos) o a los siguientes servidores de Dreamhost para que se utilicen los archivos almacenados allí.

  • ns1.dreamhost.com
  • ns2.dreamhost.com
  • ns3.dreamhost.com

Para verificar el cambio del dominio utilice un navegador web o la herramienta ping junto con el nombre del dominio en cuestión.  En éxito deberá aparecer el nuevo sitio o la nueva dirección IP respectivamente, a la cual apunta el dominio.

Si utiliza Windows Vista como sistema operativo, probablemente necesite renovar el caché del DNS ya que este habrá almacenado el valor inicial y se demorará cierto tiempo en solicitar el nuevo, impidiéndo que sea tomado en cuenta el cambio en el DNS ya propagado.  Para hacer esto realice los siguientes pasos.

  1. Haga click sobre el menú de inicio desplegándolo.
  2. En el campo de texto ubicado en la parte inferior donde dice “Iniciar la búsqueda” escriba cmd.
  3. Presione las teclas CTRL + SHIFT + ENTER.
  4. Presione el botón Continuar para aceptar la ejecución del Símbolo del sistema con permisos de administrador.
  5. Ejecute el comando: ipconfig /flushdns

Copia de seguridad de la base de datos.

Mientras se realiza la transferencia del registro es necesario continuar con el proceso de la copia de seguridad de la base de datos.  Como mencioné, el hosting orígen no me daba acceso a la línea de comando así que no podía utilizar mysqldump así que la copia de seguridad se realiza a través de PHPMyAdmin.  El procedimiento es muy sencillo.

  1. Ingrese al PHPMyAdmin del servicio de hosting con el nombre de usuario y contraseña de la base de datos que se va a exportar.
  2. En la parte izquierda seleccione la base de datos que se va a exportar (es posible que aparezcan varias).
  3. En la parte media superior elija la etiqueta Exportar.
  4. Seleccione las tablas (por defecto todas) que desea exportar y el formato (por defecto SQL).
  5. Elija la casilla Deshabilitar la revisión de las llaves extranjeras para evitar futuros problemas con la restauración de las tablas en desórden.
  6. Seleccione las casillas Estructura y Datos para que sean incluídos en la copia de seguridad.
  7. En la parte inferior seleccione Enviar (genera un archivo descargable) y presione el botón Continuar.
  8. Almacene este archivo para posteriormente trasladarlo al nuevo hosting.

Creación de la base de datos y restauración de la copia de seguridad.

El primer paso es crear la nueva base de datos en la cuenta de Dreamhost, para esto realice los siguientes pasos.

  1. Acceda al Panel de Dreamhost.
  2. Navegue a través de los menúes Goodies > Manage MySQL.
  3. Ubique la sección Create a New MySQL Database.
  4. Ingrese la información de la nueva base de datos.
  5. Presione el botón Add new database now!.
  6. Tome atenta nota de la información suministrada en este punto.

El segundo paso corresponde a la restauración de la copia de seguridad realizada anteriormente.  Para hacerlo siga los pasos dispuestos a continuación.

  1. Acceda al PHPMyAdmin asociado a la cuenta.  Esto se hace accediendo al host (corresponde al valor del campo Use Hostname del paso anterior) de la base de datos desde un navegador web.
  2. Ingrese utilizando el nombre de usuario y contraseña especificados durante el paso anterior.
  3. Seleccione en la parte media superior la etiqueta Importar.
  4. En la sección Archivo a importar presione el botón Examinar y seleccione el archivo donde almacenó la copia de seguridad de la base de datos.
  5. Presione el botón Continuar para terminar el proceso.

Copia de los archivos al nuevo hosting.

Para este momento la transferencia del dominio ya ha sido realizada y la base de datos se encuentra lista, el problema es que el sitio aún está vacío.  El único acceso al hosting de orígen es a través de FTP motivo por el cual se siguen estos pasos para realizar la copia de lo archivos del proyecto.

  1. Inicie una sesión SSH con su cuenta de Dreamhost.  Para esto utilice un cliente SSH como Putty (Windows).
    • Como Host name escriba su nombre de dominio, el cual ya debe ser accesible desde su ubicación.
    • Como Connection type elija SSH.
    • Presione el botón Open.
  2. En los campos Login as y Password ingrese los datos correspondientes al usuario propietario de la cuenta asociada al dominio, que de paso, es diferente al usuario administrador de su cuenta de Dreamhost.
  3. Acceda al directorio donde se almacenarán los archivos de su sitio web.  Dreamhost crea en las cuentas de los usuarios, un directorio por cada dominio asociado.  Estos directorios tienen como nombre el mismo nombre del dominio.

    $ cd midomino.com

  4. Utilice wget para realizar la copia de los archivos del hosting original hacia la cuenta en Dreamhost.

    $ wget –mirror ftp://USUARIO:CONTRASEÑA@HOSTING_ORIGEN/RUTA

    Modifique los valores de USUARIO (usuario FTP del hosting orígen), CONTRASEÑA (contraseña del usuario FTP del hosting orígen), HOSTING_ORÍGEN (nombre o dirección IP) y RUTA (ubicación de los archivos a copiar).

Ajustes finales.

Realice los ajustes finales que requiera su proyecto como configurar la nueva ubicación y autenticación de las bases de datos, asegurarse que los enlaces funcionen correctamente, etc.

Enlaces.

Mis plugins de Firefox preferidos

Traducciones desde GTalk bots

Este año Google habilitó el servicio de traducción asistida a través de bots del servicio de GTalk.  Para utilizarlos se debe agregar como contacto la dirección del bot y posteriormente aceptarlo como contacto.

Las direcciones de los bots tienen el siguiente formato.

[lenguaje orígen] 2 [lenguaje destino]@bot.talk.google.com

Esto quiere decir que el bot que traduce de español a inglés es es2en@bot.talk.google.com y el que realiza el proceso contrario es en2es@bot.talk.google.com.

Las combinaciones de idiomas disponibles son las siguientes.

  1. Arabic – English:      ar2en      en2ar
  2. Bulgarian – English:     bg2en     en2bg
  3. Czech – English:     cs2en     en2cs
  4. Danish – English:     da2en     en2da
  5. German – English:     de2en     en2de
  6. German – French:     de2fr     fr2de
  7. Greek – English:     el2en     en2el
  8. Spanish – English:     es2en     en2es
  9. Finnish – English:     fi2en     en2fi
  10. French – English:     fr2en     en2fr
  11. Hindi – English:     hi2en     en2hi
  12. Croatian – English:     hr2en     en2hr
  13. Italian – English:     it2en     en2it
  14. Japanese – English:     ja2en     en2ja
  15. Korean – English:     ko2en     en2ko
  16. Dutch – English:     nl2en     en2nl
  17. Norwegian – English:     no2en     en2no
  18. Polish – English:     pl2en     en2pl
  19. Portuguese – English:     pt2en     en2pt
  20. Romanian – English:     ro2en     en2ro
  21. Russian – English:     ru2en     en2ru
  22. Swedish – English:     sv2en     en2sv
  23. Chinese – English:     zh2en     en2zh
  24. Traditional Chinese – English:     zh-hant2en     en2zh-hant
  25. Traditional Chinese – Chinese:     zh-hant2zh     zh2zh-hant

Este servicio se encuentra basado en el servicio de traducción de Google.

Enlaces:

Demostración de georreferenciación al estilo web 2.0

La demostración de georreferenciación al estilo web 2.0 que permite visualizar el mapa de cualquier ubicación del mundo y ubicar sobre él marcadores georreferenciados.

Para esto utiliza los servicios de Google Maps para la generación de las imágenes y GeoNames para la georreferenciación, es decir, para convertir las ubicaciones (Manizales, Caldas, Colombia) en sus respectivas duplas latitud/longitud para poder ser relacionadas geográficamente.

En la parte izquierda se aprecia la lista con las ubicaciones seleccionadas que corresponden con las marcas rojas en el mapa, en la parte derecha está el mapa junto con tres barras de desplazamiento que regulan su presentación y en la parte inferior se encuentran los botones de opciones.

El demo le permite al usuario Agregar y Remover ubicaciones como puntos seleccionados.  Como se mencionó, estas se ingresan con los nombres de las ubicaciones y el sistema obtiene su ubicación geográfica a través de la consulta de un servicio web.  Es posible en cualquier momento, Centrar el mapa al rededor de cualquiera de los puntos seleccionados almacendos.

La manipulación del mapa se realiza con las barras de desplazamiento.  La naranja (derecha) corresponde con el zoom: hacia abajo aumenta, haciendo mayor el acercamiento del mapa.  La horizontal, azul, corresponde con la longitud y la vertical, verde, corresponde con la latitud.  Cuando se modifica cualquiera de estos valores se deberá solicitar la actualización del mapa presionando el botón Refrescar.

La aplicación ha sido desarrollada en Java por lo que su código es muy claro y modular.  En términos de la implementación, el acceso al webservice de GeoNames utiliza su propio API para el cual se descargaron dos archivos: geonames-1.0-java5.jar y jdom-1.0.jar.

La georrefernciación no podría ser más fácil.

    public static GeoLocation locate(String location) throws Exception
    {
        GeoLocation result = new GeoLocation();

        // Creates the toponym searcher

        ToponymSearchCriteria searchCriteria = new ToponymSearchCriteria();

        // Sets the criteria based on the specified location

        searchCriteria.setQ(location);

        // Request the geolocalization to the webserver

        ToponymSearchResult searchResult = WebService.search(searchCriteria);

        // Gets the results

        List toponyms = searchResult.getToponyms();

        // Checks if there were results

        if(toponyms == null || toponyms.size() == 0)
            return null;

        // Gets the first result of all (could be many)

        Toponym first = toponyms.get(0);

        // Prepares the result with its information

        result.put("geoNameId",   first.getGeoNameId()   + "");
        result.put("name",        first.getName()        + "");
        result.put("latitude",    first.getLatitude()    + "");
        result.put("longitude",   first.getLongitude()   + "");
        result.put("countryCode", first.getCountryCode() + "");
        result.put("countryName", first.getCountryName() + "");

        return result;
    }

La clase GeoLocation que utilizo para manejar el resultado no es mas que un Hashtable<String, String> con algunos adendos para facilitar su uso.

Por otro lado, la generación del mapa requiere aún menos ciencia aunque la realizo en dos pasos discretos que en general no incluyen nada extraño.

    public String prepareUrl()
    {
		String markers = "";

		// Walks thru all the points to create its markers

		for(int i=0; i

En el primer paso preparo el URL del consulta al servicio basado en información como la coordenada centro del mapa, el nivel de zoom, el tamaño de la imagen, los puntos seleccionados (marcadores) y la llave del API que debe ser privada y es única para cada sitio web (FQDN), aunque para el caso específico de aplicaciones de escritorio no es muy relevante a pesar de ser obligatoria.  La llave del API puede ser obtenida de manera gratuita por cualquier desarrollador desde esta dirección.

    public Image prepareImage(String url) throws Exception
    {
        Image image = ImageIO.read(new URL(url));

        return image;
    }

El segundo paso se relaciona con consultar el servicio de Google utilizando el URL recién generado, leer los bytes que conforman la imagen y crear con ellos un objeto Image para ser mostrado posteriormente en la interfaz de usuario.  Con Java, este procedimiento es extremadamente sencillo: 1 línea de código.

Para su uso se deberá tener cuidado en el manejo de las posibles excepciones que pueda lanzar el requerimiento como por ejemplo, producto de un fallo de red.

        // Gets the map image

        Image imageMap = mapService.getMap();

        // Checks if was received

        if(imageMap == null)
        {
            JOptionPane.showMessageDialog(this, "El mapa no se pudo recuperar.",
                    "Error recuperando mapa", JOptionPane.ERROR_MESSAGE);
            return;
        }

        // Puts the map on the gui

        map.setIcon(new ImageIcon(imageMap));

Teniendo el objeto Image lo podemos poner en cualquier componente de AWT/Swing.  Por facilidad, yo utilizo un JLabel que incluye el soporte de íconos (ImageIcon) los cuales se basan en objetos de imagen.

Como se puede apreciar, la complejidad de la aplicación es muy baja por lo que reitero: la imaginación es el límite.

Es posible acceder a la aplicación desde web sin instalar ningún archivo local desde el siguiente enlace o ejecutando el siguiente comando en una consola/símbolo del sistema operativo:

   $ javaws http://demo.jorgeivanmeza.com/Java/DemoGeoReferenceMap/0.1/DemoGeoReferenceMap.jnlp

Enlace: