Artículos en Tutoriales

Cómo saber si le hace falta más memoria a tu Mac

PostedEn Tutoriales     Comentarios Comments Off
Aug
7

¿Tu Mac no va todo lo suave que te gustaría? ¿Notas que tienes que cerrar aplicaciones para que te vaya más rápido? Es posible que te falte memoria RAM, pero ¿como lo averiguo?

Lo primero que tenemos que hacer es usar nuestro Mac durante un tiempo, cuanto más mejor. Después de tener “trabajando” al ordenador, abrimos el monitor de actividad, que está en Aplicaciones -> Utilidades -> Monitor de actividad. Una vez abierto, buscamos las pestañas de abajo y pinchamos en la segunda, la que pone “Memoria del sistema”.

En mi caso, lo he dejado cinco días encendido con un alto uso. Vale que no soy diseñador gráfico que necesite renderizar 3D, pero si tengo funcionando varios servidores Java a la vez, una base de datos, máquinas virtuales, dos IDEs, dos navegadores, Spotify, Skype y muchas cosas más. Bueno, pues después de cinco días esta es la información de memoria que da mi Monitor de actividad.

  • Libre: es la memoria que está todavía sin usar y disponible para cualquier aplicación que la necesite.
  • “Wired”: es la memoria usada por el sistema y que no puede ser paginada (más adelante veremos lo que es la paginación)
  • Activo: memoria actualmente usada por las aplicaciones abiertas y que es susceptible de ser paginada si el sistema lo necesita.
  • Inactivo: memoria que ha sido usada por aplicaciones que han sido cerradas y que ya no la necesitan. Si una de estas aplicaciones es abierta de nuevo, puede recuperar la memoria usada anteriormente de esta región y cargar más rápido. Si el sistema necesita memoria, usará primero este espacio inactivo.
  • En uso: es la memoria real usada de tu sistema. Yo tengo 4GB, pero nunca llegará a ese consume y siempre marcará algo menos porque la memoria es compartida con la tarjeta gráfica, tal y como explican en este post.
  • Espacio de intercambio usado: es el tamaño de la memoria virtual que estamos realmente usando.

Para saber cuanta memoria RAM tenemos disponible, es necesario saber primero como se obtiene cuando se necesita. Supongamos que arrancamos la aplicación X y que esta necesita para ejecutarse y abrir algunos datos un total de 300Mb. Esto es lo que hace, más o menos (ojo, no soy un experto ni me dedico a programar el kernel de MacOS, así que esta información la he obtenido de diferentes artículos de internet):

  1. Primero se busca si la aplicación ya había sido abierta con anterioridad, y si la memoria usada entonces esta todavía intacta en la region inactiva. Si es así, se recupera esa región de memoria y se usa.
  2. En caso de que necesite más memoria, o si no estuviera en la región inactiva, o estuviera en la región inactiva pero de manera incompleta (porque ha sido usada por otra aplicación), entonces se usa la memoria libre.
  3. Si no queda memoria libre o se necesita más, se utilizará memoria inactiva de otras aplicaciones (recodemos que la memoria inactiva es como un caché para que las aplicaciones que acaban de cerrar carguen más rápido si se vuelven a abrir, pero esta memoria en realidad no está siendo usada y se puede utilizar).
  4. Si todavía se necesita más memoria, se obtiene de otro proceso activo. Pero como ese proceso la necesitará en algún momento, pues todavía sigue activo, no se le puede quitar sin más, así que es necesario guardar esa información en disco en el “espacio de intercambio usado”, lo que se conoce como paginación.

Entonces, la verdadera memoria RAM que tenemos disponible = memoria libre + memoria inactiva. Pero el sistema nunca se va a quedar sin memoria, porque si necesita más, la usará de otros procesos activos usando el archivo de paginación, es decir, copiará la memoria usada por otros procesos en el archivo de paginación, y dejará ese nuevo espacio libre a la aplicación que la necesita. A costa de no quedarnos nunca sin memoria, tenemos un sistema más lento, ya que escribir y leer de disco siempre toma más tiempo que hacerlo desde la memoria RAM.

Para más información podéis consultar la documentación oficial de Apple sobre como interpretar la información de memoria del Monitor de actividad/ Memory Usage Performance, y también este post.

Cómo saber si realmente te hace falta memoria

Con la paginación. Cuando una aplicación X necesita memoria y al sistema no le queda libre más RAM, lo que hace es coger una porción de memoria de otra aplicación que está inactiva (aplicación Y), la escribe a disco, y la libera para que la aplicación X pueda usarla. A eso se le llama swap out o paginación de salida. Ahora el caso contrario, cuando una aplicación Y vuelve a necesitar ese porción de memoria que está en disco (en vez de en la memoria RAM), el sistema la lee y la vuelve a cargar en memoria para que pueda ser usada de nuevo (swap in o paginación de entrada). Claro que si el sistema tampoco tiene espacio libre, tendrá que coger otra aplicación inactiva y repetir el proceso una y otra vez. Es posible que esto pase de vez en cuando, no pasa nada. Pero si tu Mac está siempre escaso de memoria, se pasará mucho tiempo paginando y dará como resultado un rendimiento peor, ya que el acceso a disco y la propia paginación tienen un alto coste.

En mi caso vemos que tengo 17Gb de paginación de salida. Es decir, que desde el último inicio del sistema operativo, se han escrito a disco 75GB de la memoria RAM en diferentes ocasiones porque no ha habido espacio suficiente. Y de estos 75GB escritos, se han vuelto a recuperar 17GB que han sido leídos del disco y vueltos a poner en memoria. Es decir, entrada = 75GB y salida = 17GB. Por lo que he podido investigar en blogs especializados, el ratio entre swap in/out debe ser del 10% o menos. En mi caso, 17 / 75 = 0.22 es mayor que 0.10, luego necesito más RAM.

Cómo saber qué tipo de memoria necesito y dónde la compro

Para los últimos Macbooks Pro podéis comprar estas memorias en Amazon. La diferencia es que los Macbooks del 2010 tienen memoria DD3 a 1066Mhz y los del 2011 a 1333Mhz. El precio es parecido (he cogido las más baratas de la marca Corsair).

Si tenéis otro Mac y no sabéis que memoria necesitáis, la mejor manera es descargar el scanner de Crucial: nos detectará el ordenador que tenemos, la memoria que necesita y nos llevará a la página donde comprar esa memoria en su tienda, aunque podemos usar la información para comprarla en otro sitio claro (como Alternate, Amazon, etc). Podéis obtenerlo en esta dirección: http://www.crucial.com/systemscanner.

Y para buscar donde comprar Ram, lo mejor es usar Ramseeker, que es como la cotización diaria de la memoria Ram en las tiendas más importantes, como si de la bolsa se tratara.

Como instalar la memoria

Si te da miedo meter mano en las tripas de tu Mac, no te preocupes, aquí tienes las guías oficiales de Apple. Es muy fácil:

Autenticación de usuarios con Twitter/OAuth en Grails

NOTA: Para ver el video tutorial (HD 1920×1080, 7:28 min) o para descargar la aplicación con el código fuente y librerías ya funcionando, ver la sección “Resolución de problemas” al final del post.

Introducción a OAuth

El api de Twitter nos permite acceder a los datos públicos de los usuarios, hacer búsquedas, leer twits y muchas cosas más. Gracias a la implementación del protocolo OAuth por parte de Twitter podemos crear aplicaciones que acceden a los datos privados de usuarios y manejar sus datos como si fueran ellos mismos, mandando twits y DM, gestionar sus listas o seguir/dejar de seguir a otros usuarios. La principal ventaja de OAuth es que los usuarios pueden dar o quitar los permisos de acceso a su cuenta a las aplicaciones en cualquier momento, sin comprometer su password.

Para entender esto vamos a poner un ejemplo práctico imaginario:

  1. Un amigo nos recomienda un nuevo cliente de Twitter con una interfaz increíble y decidimos probarlo. Para poder usar nuestra cuenta desde este nuevo cliente, se nos solicita el login y password de nuestra cuenta de Twitter. Entonces es cuando un sudor frío nos recorrer por la espalda y dudamos en dar nuestras credenciales a un tercero, por mucha confianza que nos de. Como somos precavidos y no queremos dar nuestra password a nadie, cerramos la aplicación y no la usamos. Fin de la historia.
  2. El mismo amigo nos recomienda otra vez la aplicación y nos dice “hey, ahora ya no hay que introducir el login y password, al parecer han implementado el protocolo OAuth”. Así que decidimos darle una segunda oportunidad. Al iniciar la aplicación, el nuevo cliente de Twitter nos pide permiso para usar nuestra cuenta. Para ello, nos redirige a la página de Twitter, nos autenticamos (si no lo estuviéramos antes) con la tranquilidad de que introducimos nuestro login y password en la página de Twitter, y no en la de un desconocido. Una vez autenticados, Twitter nos pregunta si deseamos dar permiso al nuevo cliente que estamos usando a nuestra cuenta. Aceptamos, Twitter nos redirige a la aplicación inicial y ya podemos usar nuestra cuenta desde el nuevo cliente.

¿Qué os parece? Como veis, el segundo caso es mucho mejor: el login y password nunca se dan a un desconocido y, en cualquier momento, podemos revocar el acceso del nuevo cliente a nuestra cuenta de Twitter.

Autenticando con OAuth

Una ventaja colateral de este sistema es que podemos aprovechar el mecanismo de aceptación de privilegios del api OAuth de Twitter para iniciar sesión en nuestra aplicación. Supón que tenemos una aplicación web con una parte privada que requiere autenticación. Es decir, que para que un usuario pueda iniciar sesión deberá registrarse (solo la primera vez, creando su propio usuario en el sistema, con su login/password, etc) y después introducir sus credenciales cada vez que quiera entrar. Pero es posible que el usuario ya tenga cuenta en Twitter y que, además, ya esté identificado en su navegador en otra pestaña, por ejemplo (aunque no es necesario). Así que sería estupendo que para usar nuestra aplicación solo tuviera que darle a un botón “Sign in with Twitter” y que el usuario ya se encontrara registrado y autenticado inmediatamente en nuestra aplicación.

¿Parece interesante no? Recordemos que los usuarios son vagos por naturaleza y que, a veces, por pereza no llegan a utilizar nuestra aplicación por el simple hecho de tener que rellenar un nuevo formulario de registro. Con este sistema de autenticación ahorramos a los usuarios a tener que crearse una cuenta en nuestro site, pensar en un nuevo login, una nueva password, etc. La primera vez que entren hacen click, aceptan el acceso a su cuenta de Twitter desde nuestra aplicación, y ya están registrados. Y la segunda vez, hacen click e inmediatamente han iniciado sesión.

Un ejemplo muy, muy simple de uso es la página de firmas de No me hagas robar, donde el botón “Firmar” simplemente recoge el avatar del usuario y lo añade a la lista de firmantes. Y un ejemplo real de una página que solo admite autenticación mediante Twitter es Twittercounter. Todas ellas usan el mismo mecanismo, así que vamos a hacerlo.

Empezamos a programar

Para ello vamos a necesitar lo siguiente (puedes hacerlo siguiendo a la vez el vídeo al final del post):

  1. Un proyecto Grails creado (cualquier versión). Si no lo tenemos, podemos crearlo con el comando grails create-app NombreProyecto (en los ejemplos, mi proyecto se llama Deleteme)
  2. El “consumer key” y el “consumer secret” de una aplicación Twitter creada por nosotros. Para esto necesitamos logarnos en http://dev.twitter.com con nuestro usuario y pinchar en “create app”.
  3. La librería Twitter4J. Es un único jar que se descarga desde http://twitter4j.org La versión utilizada en este tutorial es la 2.2.3. La copiamos dentro de la carpeta lib de nuestro proyecto Grails.

La configuración

Antes de empezar, añadimos nuestro consumer key y consumer secret en el fichero grails-app/conf/Config.groovy:

consumerKey = "m9TdD8QLJas8998gwp96AHZaw" // No usar esta valor, cambiadlo!
consumerSecret = "4G2RDJCoiYgjn7a98sduui2190Og125m1Pdk0"  // No usar este valor!

Clase de dominio Usuario

Creamos la clase de dominio Usuario, que será la que usaremos para persistir la información del usuario que se registra en nuestro site. Usaremos el comando grails create-domain-class Usuario y este contenido (cambiar el nombre del paquete):

package deleteme
class Usuario {
    static constraints = {}

    Long twitterId
    String name
    String screenName
    String profileImg
}

Esta clase no tiene login ni password, en su lugar, tiene el twitterId, identificador numérico que obtendremos únicamente cuando el usuario se ha conectado con Twitter. También guardaremos su nombre de Twitter (screenName), login (name) y su avatar (profileImg). Por supuesto, podemos añadir a esta clase todos los campos o relaciones que queramos.

Servicio de autenticación con Twitter

Después creamos el servicio que se encargará de autenticarnos con Twitter con grails create-service TwitterService y este contenido (cambiar el nombre del paquete):

package deleteme

import org.codehaus.groovy.grails.commons.*
import twitter4j.*
import twitter4j.auth.*

class TwitterService {

    static transactional = false
    static scope = 'session'

    Twitter twitter
    RequestToken requestToken

    String authenticate(String returnUrl) {
        twitter = new TwitterFactory().getInstance()
        twitter.setOAuthConsumer(ConfigurationHolder.config.consumerKey, ConfigurationHolder.config.consumerSecret)
        requestToken = twitter.getOAuthRequestToken(returnUrl)
        return requestToken.getAuthenticationURL()
    }

    User verifyCredentials(String oauth_verifier) {
        AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, oauth_verifier)
        return twitter.verifyCredentials()
    }
}

Como veis, es un servicio de sesión, ya que los atributos que se crean en el método authenticate() se usan en verifyCredentials(). De hecho, deben llamarse en este orden siempre.

El controlador

A continuación creamos el controlador que se encargará de obtener el id de twitter cuando hace click en el botón “Sign in with Twitter”. El controlador tiene dos actions, uno invocado por el usuario y otro por Twitter para devolvernos el control. Para crearlo usamos el comando grails create-controller TwitterLogin y copiamos este código:

package deleteme

import twitter4j.*

class TwitterLoginController {

    def twitterService

    def index = {}

    def login = {
        redirect url: twitterService.authenticate("http://localhost:8080/Deleteme/twitterLogin/callback") // [1]
    }

    def callback = {
        if (params.denied){
            flash.message = "Permiso denegado"

        } else {
            Usuario usuario = checkTwitterUser(twitterService.verifyCredentials(params.oauth_verifier))

            session.user = usuario
        }
        redirect action: index
    }

    private checkTwitterUser(User twitterUser) {
        Usuario user = Usuario.findByTwitterId(twitterUser.id)

        if (!user) {
            user = new Usuario(twitterId: twitterUser.id)
        }

        user.name = twitterUser.name
        user.screenName = twitterUser.screenName
        user.profileImg = twitterUser.profileImageURL.toString()

        user.save()
    }

    def logout = {
        session.invalidate()
        redirect action: index
    }
}

La url de [1] debe ser accesible desde el navegador del usuario y se debe corresponder con el action callback de este mismo controlador, por lo que el host, puerto y contexto de la aplicación pueden cambiar: en mi caso es Deleteme, pero en el vuestro es el nombre del proyecto Grails que habéis usado durante su creación. El host y puerto localhost:8080 son los que usa por defecto Grails en modo desarrollo, en producción debería ser un dominio accesible desde internet válido.
El método checkTwitterUser() es el que se encarga de buscar, o si no existe de crear, el usuario en nuestra base de datos. Para ello utiliza el id del usuario de Twitter, que es simplemente un número único que nunca cambia (no como su nick, que si puede cambiar). Exista o no exista el usuario en nuestra base de datos, escribimos de nuevo los datos del perfil, pues estos pueden haber cambiado desde la última vez, y queremos tener siempre su nombre y su avatar actualizados. Este método es el que permite registrar automáticamente al usuario la primera vez que hace click.

La vista

Para acabar, creamos la vista del action index en grails-app/views/twitterLogin/index.gsp

<html>
  <body>

  <p style="color:red">${flash.message}</p>

  <div>
      <g:if test="${session.user}">
          <img src="${session.user.profileImg}"> Bienvenido <strong>${session.user.name}</strong> |
          <g:link controller="twitterLogin" action="logout">Logout</g:link>
      </g:if>
      <g:else>
            <g:link controller="twitterLogin" action="login">Signin with Twitter</g:link>
      </g:else>
  </div>
  </body>
</html>

Simplemente verifica que no haya en la sesión el usuario (se guarda en session.user) para mostrar el enlace “Signin with Twitter”. Si el usuario estuviera en la sesión, se mostraría su nombre, su avatar de Twitter y un enlace “logout” para cerrar la sesión.

Y para que nada más arrancar se muestre nuestra página de login, modificamos el mapeo de “/” en el fichero grails-app/conf/UrlMappings.groovy así:

"/"(controller:"twitterLogin", action: "index")

Probando la aplicación

Y arrancamos la aplicación con grails run-app. Hacemos click en el enlace “Signin with Twitter”, nos llevará a Twitter, aceptaremos la petición y nos devolverá el control a la aplicación. Si ahora pinchamos en logout y volvemos a repetir el proceso, veremos que es inmediato.

¿Qué hacemos a partir de aquí? pues ya sabemos que con este login tenemos una entidad de la clase Usuario en la sesión (en concreto, en session.user) y que guarda tanto el nombre como el avatar. Seguramente esta no sea la mejor práctica para guardar los datos del usuario en la sesión, pero es una manera rápida y clara de ver la aplicación funcionando. El reto más importante será permitir un login dual: que el usuario pueda autenticarse con su usuario de Twitter, como acabamos de hacer, pero que también pueda hacerlo manualmente, rellenando sus datos en un formulario de registro. Esto es útil, sobre todo, si el usuario no tiene cuenta de Twitter para no obligarle a crearse una. La autenticación dual es interesante porque puede producirse en cualquier orden, pero eso lo veremos otro día.

Espero que os haya gustado y que os sirva para vuestras aplicaciones.

Resolución de problemas

Puedes ver el screencast de 7:28 minutos en HD siguiendo este tutorial paso a paso aquí:

Enlace directo al vídeo en Vimeo en el Groovy TV channel.

Y también puedes descargarte la aplicación ya finalizada y completamente funcional. Incluye el código fuente y la librería Twitter4J 2.2.3. Las instrucciones de instalación son:

  1. Descargar y decomprimir el archivo TwitterOAuth.zip (452Kb)
  2. Añadir el “consumer key” y el “consumer secret” de una aplicación Twitter creada por nosotros en el fichero grails-app/conf/Config.groovy (al final del todo). Para esto necesitamos logarnos en http://dev.twitter.com con nuestro usuario y pinchar en “create app” (ver el vídeo).
  3. Arrancar la aplicación con grails run-app.

Profundizando en Javascript, parte 2: objetos, prototipos, herencia y namespaces

Tras un tiempo de descanso continuamos con la serie “Profundizando en Javascript”. En el post anterior explicaba todas las maneras de definir y usar funciones: con nombre/sin nombre, como expresión/como declaración, anónimas autoejecutables y anidadas (aunque no es obligatorio, es recomendable haber leído antes de continuar).

Hoy vamos a ver como se trabaja con objetos. En Javascript, como en cualquier lenguaje, un objeto no es más que un conjunto de atributos y funciones (sus métodos). A cada objeto podemos añadirle nuevas propiedades y funciones de diferentes maneras que iremos viendo. Sin embargo la herencia, tal y como la conocemos de otros lenguajes como Java, no existe, pues no existen las clases: para crear un nuevo objeto que tenga los mismos atributos que otro, estos deben ser copiados. A esta forma de trabajar se llama herencia basada en prototipos. Esto significa que no hay clases o interfaces como en Java o C++: solo hay objetos que copian (heredan) sus propiedades de otros objetos, llamados prototipos. Así que olvidémonos de la clásica definición de “objeto como instancia de una clase”, porque aquí no hay clases (y por esta razón, cuando hable de clases en Javascript, lo haré entre comillas así: “clases”). Pero vayamos por partes:

Creando objetos

Pare crear un nuevo objeto podemos hacerlo de cualquiera de estas dos formas:

var obj1 = new Object()
var obj2 = {}

La segunda forma se llama “objeto literal”. Es la que usamos para crear lo que en otros lenguajes se llaman diccionarios, mapas o hashtables y que sigue, afortunadamente, la misma sintaxis que JSON.

Para añadir una nueva propiedad, solo tenemos que asignársela:

var obj1 = new Object()
obj1.nombre = "mundo"

alert("hola "+obj1.nombre) // "hola mundo"

Para eliminar una propiedad, usaremos el operador delete:

var obj1 = new Object()
alert(obj1.nombre)   // undefined

obj1.nombre = "mundo"
alert(obj1.nombre)   // "mundo"

delete obj1.nombre

alert(obj1.nombre)   // undefined otra vez

Y para añadir un método, solo hay que añadirle una función como expresión, teniendo siempre en cuenta que para que un método pueda acceder a las propiedades del objeto donde reside, tenemos que usar el prefijo this.

var obj1 = new Object()
obj1.nombre = "mundo"
obj1.saluda = function() { alert("hola "+this.nombre) }
obj1.saluda()

Aquí vemos como es necesario usar this.nombre dentro de la función saluda() para acceder al atributo nombre del objeto.

Otra forma de construir objetos es como literales:

var obj1 = {nombre:"mundo",
            saluda: function() { alert("hola "+this.nombre) }
}
obj1.saluda()

En Javascript podemos acceder a las propiedades de un objeto usando la notación objeto.propiedad; o de manera indexada como un array, con objeto[prop]. En este segundo caso, prop es una variable de tipo String cuyo contenido es el nombre de la propiedad a acceder. Ejemplo:

var obj1 = new Object()
obj1.nombre = "mundo"
obj1.saluda = function() { alert("hola "+this.nombre) }

alert("hola "+obj1.nombre)       // Acceso normal
alert("hola "+obj1[ "nombre" ])  // Acceso indexado con un literal
var prop = "nombre"
alert("hola "+obj1[ prop ])      // Acceso indexado con una variable

obj1.saluda()         // Invocación normal
obj1[ "saluda" ]()    // Acceso indexado con un literal
var func = "saluda"
obj1[ func ]()        // Acceso indexado con una variable

Podemos usar esta segunda forma de acceder a las propiedades de un objeto para listarlas todas, sin importar cuantas tenga ni su nombre:

var obj1 = new Object()
obj1.nombre = "mundo"
obj1.fecha = new Date()
obj1.luckyNumbers = [4,8,15,16,23,42]
obj1.saluda = function() { alert("holas "+this.nombre) }

var name
for (name in obj1) {
	alert(name+" : "+ obj1[name])
}

Prototipos

Pero claro, con esto solo definimos un único objeto, con sus atributos y métodos. Pero, ¿qué pasa si queremos crear una “clase” de la que poder instanciar objetos? Como hemos dicho antes, en Javascript no hay clases, sino prototipos: objetos de los que se copian otros objetos. Así que lo que haremos es crear un objeto del que poder copiar sus propiedades. Para esto Javascript tiene un gran truco: hace que cualquier función pueda ser instanciada como un nuevo objeto usando la palabra clave “new”.

// Una simple función
function Saludator() {
	alert("Saludos factory!!")
}
// Y una simple llamada
Saludator()

A simple vista no es más que una función, ¡y es verdad que lo es! pues podemos llamar a Saludator() como una función de toda la vida. Pero eso no quita que sea también una factoría y que con ella podamos crear nuevos objetos:

// Una función... pero también un prototipo!
function Saludator() {
	alert("Saludos factory!!")
}
// Un nuevo objeto a partir de su "clase" prototipo
var saludo = new Saludator()

Pero claro, con este ejemplo tan sumamente sencillo no se aprecia que hemos creado un nuevo objeto. Así que vamos a añadirle un par de propiedades y métodos (recordemos que solo tenemos que declararlas con el prefijo this).

function Saludator(nom) {
	alert("Saludos factory!!")
	this.nombre = nom+"s"
	this.saluda = function() {
		alert("hola "+this.nombre)
	}
}
var obj1 = new Saludator("mundo")
var obj2 = new Saludator("gente")
obj1.saluda() // "hola mundos"
obj2.saluda() // "hola gentes"

En este ejemplo ya vemos cosas nuevas:
- Que la función Saludator() es el constructor del objeto, y podemos pasarle parámetros que posteriormente podemos usar en los atributos del objeto.
- Que dentro de la función saluda sigue siendo necesario usar this.nombre para acceder al atributo nombre.

Por cierto, podemos crear nuestros prototipos usando funciones como expresiones, y no como declaraciones. El siguiente código es completamente equivalente al anterior:

var Saludator = function(nom) {
	alert("Saludos factory!!")
	this.nombre = nom+"s"
	this.saluda = function() {
		alert("hola "+this.nombre)
	}
}

Es necesario señalar que las funciones que servirán para crear objetos se suelen nombrar con la primera letra en mayúscula. Esto es así para evitar que se confundan con funciones normales o variables.

Métodos privados

Podemos crear métodos “privados” (es decir, métodos que son solo accesibles desde dentro del objeto, nunca desde fuera), creando funciones como declaración, no como expresión. La principal desventaja es que estos tipos de métodos no tienen ligado el “this” con el objeto actual, por lo que no pueden acceder a sus datos internos. Para evitar esto, tenemos que enviar como parámetros los datos del objeto que necesiten. Además, no podemos usar el prefijo this para llamar a estos métodos:

var Saludator = function(nom) {
	this.nombre = nom
	this.saluda = function() {
		alert("hola "+plural(this.nombre))
	}
	function plural(n) {
		return n + "s"
	}
}
var obj1 = new Saludator("mundo")
obj1.saluda()
// obj1.plural()  // fallaría porque plural() es privado

La llamada al método plural() no es accesible desde fuera, por lo que fallaría (por eso está comentada). Observemos también como la llamada a plural() no se hace con this.plural(). Y que para acceder al atributo nombre hemos tenido que pasárselo como parámetro.

Los métodos privados no son dinámicos, en el sentido que no se pueden definir condicionalmente en tiempo de ejecución. Así que el siguiente código no fallará, pero no funcionará correctamente (de hecho, su funcionamiento dependerá del navegador):

// Atención, codigo erróneo a modo de ejemplo, NO USAR!
var Saludator = function(nom, enPlural) {
	this.nombre = nom
	this.saluda = function() {
		alert("hola "+quien(this.nombre))
	}
	// NO HACER ESTO NUNCA!!!!!!!
	if (enPlural) {
		function quien(n) { // Arggg!!
			return n + "s"
		}
	} else {
		function quien(n) { // Ouch!!
			return n
		}
	}
}
var obj1 = new Saludator("mundo", false)
var obj2 = new Saludator("mundo", true)
obj1.saluda() // "hola mundo"
obj2.saluda() // "hola mundo", pero es incorrecto!

En su lugar, definiendo los métodos con funciones como expresiones, si que funciona correctamente, ya que la creación del método no es más que una asignación que se produce dentro de una bifurcación condicional:

var Saludator = function(nom, enPlural) {
	this.nombre = nom
	this.saluda = function() {
		alert("hola "+this.quien())
	}
	if (enPlural) {
		this.quien = function() {
			return this.nombre + "s" // En plural
		}
	} else {
		this.quien = function() {
			return this.nombre  // En singular!!
		}
	}
}
var obj1 = new Saludator("mundo", false)
var obj2 = new Saludator("mundo", true)
obj1.saluda() // "hola mundo"
obj2.saluda() // "hola mundos", correto!

Métodos y atributos estáticos

Para crear un método estático tan solo lo tenemos que asignar a nuestra “clase” una propiedad más (recordemos que no es más que una función):

var Saludator = function(nom, enPlural) {
	this.nombre = nom
	this.enPlural = enPlural
	this.saluda = function() {
		alert("hola "+this.nombre)
	}
}
// Añadimos un método estático como atributo de la "clase" Saludator
Saludator.cloneSaludo = function(saludo) {
	return new Saludator("clonado "+saludo.nombre, saludo.enPlural)
}

var obj1 = new Saludator("mundo", false)
var obj2 = Saludator.cloneSaludo(obj1)
obj2.saluda() // "hola mundo"
obj2.saluda() // "hola clonado mundo"

Por supuesto, podemos añadir también atributos estáticos. Todas las propiedades estáticas (atributos o métodos) son siempre públicas y necesitan SIEMPRE el prefijo con el nombre de la “clase” delante siempre para acceder a ellas.

En este ejemplo, se usa la propiedad estática count de la clase Saludator para llevar la cuenta del número de objetos que se han creado:

var Saludator = function(nom) {
	// Se inicializa count a 0, si no existe
	Saludator.count = Saludator.count?Saludator.count:0
	Saludator.count ++
	this.nombre = nom
	this.saluda = function() {
		alert("hola "+this.nombre)
	}

}
Saludator.cloneSaludo = function(saludo) {
	return new Saludator("clonado "+saludo.nombre)
}

var obj1 = new Saludator("mundo", false)
var obj2 = Saludator.cloneSaludo(obj1)
obj2.saluda()

alert(Saludator.count) // "2", pues se han creado 2 objetos

Herencia

Como hemos dicho antes, la herencia basada en clases no existe en Javascript, sino que es herencia basada en prototipos. Esto significa que no hay una jerarquía de clases real (con su extends, acceso super, etc.), sino que cada “clase” tiene un objeto de referencia (como si fuera su clase padre) donde consultar atributos y métodos en caso de que nuestra clase no los encuentre. Podemos intentar simular una jerarquía (ojo, simular) usando estos objetos de referencia, llamados prototipos, con una propiedad especial que tienen todas las “clases” llamada prototype. Esta propiedad es asignable y su labor consiste en guardar un objeto. Veámoslo con un ejemplo:

var Saludator = function(nom) {
	this.nombre = nom
	this.saluda = function() {
		alert("hola "+this.nombre)
	}
}
// Añade un objeto al prototipo
Saludator.prototype = {
	apellido: "cruel",
	despide: function() {
		alert("adios "+this.nombre+" "+this.apellido)
	}
}
var obj1 = new Saludator("mundo")
obj1.despide() // "adios mundo cruel"

Con esto lo que hacemos es asignar a la variable estática prototype en la clase Saludator un simple objeto con un atributo apellido y un método despide. Cuando invocamos a obj1.despide(), Javascript primero consulta en la propia clase Saludator y busca ese método; al no encontrarlo, consulta en el objeto prototype, donde si lo encuentra, por lo que lo ejecuta. Dentro de este método, se accede a this.nombre y this.apellido y sucede lo mismo: primero Javascript mira en la clase Saludator, donde solo encuentra el atributo nombre. Sin embargo, para encontrar el atributo apellido debe consultar en el objeto prototype.

Todas las clases tienen por defecto un objeto prototype vacío, como si al crearlas se hiciera prototype = {}. Por esta razón, podemos acceder a esta variable y asignarle los atributos de uno en uno. El siguiente ejemplo es completamente equivalente al anterior:

var Saludator = function(nom) {
	this.nombre = nom
}
// Añade nuevas propiedades al prototipo
Saludator.prototype.apellido = "cruel"
Saludator.prototype.despide = function() {
	alert("adios "+this.nombre+" "+this.apellido)
}

var obj1 = new Saludator("mundo")
obj1.despide() // "adios mundo cruel"

El problema de la herencia basada en prototipos es que la “clase padre” no es una clase, sino un objeto que se crea una única vez y que sirve de referencia para todas las instancias de la clase. Además, en una herencia basada en clases como la de Java, los constructores de las clases padre se heredan automáticamente (aunque no se invocan al instanciar nuevos objetos), pero en una de prototipos no. Así que para poder heredar e invocar constructores en Javascript tenemos que hacerlo a mano. Primero debemos crear una referencia al constructor de la clase padre y después llamarlo explícitamente:

var Saludator = function(nom) {
	this.nombre = nom
	this.saluda = function() {
		alert("hola "+this.nombre)
	}
}
var SubSaludator = function(nom, ape) {
	// Primero se añade una referencia al constructor padre,
	// y después se llama explícitamente.
	this.superConstructor = Saludator
	this.superConstructor(nom)

	this.apellido = ape
	this.despide = function() {
		alert("adios "+this.nombre+" "+this.apellido)
	}
}
SubSaludator.prototype = new Saludator()

var obj1 = new SubSaludator("mundo", "cruel")
var obj2 = new SubSaludator("gente", "cruel")

obj1.saluda()  // "hola mundo"
obj2.saluda()  // "hola gente"
obj1.despide() // "adios mundo cruel"
obj2.despide() // "adios gente cruel"

Finalmente decir que podemos acceder al atributo prototype en todas clases, incluso en las clases del sistema, como String o Date. El siguiente código añade un nuevo método capitalize() a la clase de sistema String:

String.prototype.capitalize = function() {
	return this.charAt(0).toUpperCase() + this.substr(1).toLowerCase();
}

alert("hola".capitalize())

Namespaces

Una perlita para acabar. En algunos frameworks vemos como las “clases” tienen paquetes o espacio de nombres. Para empezar decir que ni son namespaces, ni packages ni nada, son solo objetos anidados unos dentro de otros. Y para acabar decir que es una muy buena practica que nosotros agrupemos nuestras funciones y objetos usando nuestro propio “espacio de nombres”.

Veámoslo con un ejemplo: es habitual tener varias funciones sueltas que nos ayuden (para manipular el Dom, validar un dato o lo que sea) junto con variables sueltas para apoyarnos así:

var dirty = false
function clickCancel() {
	var save = true
	if (dirty) {
		save = confirm("salvar antes de salir?")
	}
	if (save) clickSave()
}

function clickSave() {
	document.getElementById("myForm").submit()
}

Aquí tenemos una variable publica llamada dirty y dos métodos, también públicos, llamados clickCancel y clickSave. Pero sería mucho mejor usar nuestro propio objeto para encapsularlos:

var App = {
	dirty: false,
	clickCancel: function() {
		var save = true
		if (this.dirty) {
			save = confirm("salvar antes de salir?")
		}
		if (save) this.clickSave()
	},
	clickSave: function() {
		document.getElementById("myForm").submit()
	}
}

Ahora usaremos App.dirty, App.clickCancel() y App.clickSave(), consumiendo solo una variable pública en el ámbito global llamada App, y no tres como hacíamos antes. Si tenemos en cuenta que, generalmente, solemos crear decenas de funciones y variables públicas, está claro que la posibilidad de que usemos el mismo nombre de función o variable que ya exista en otro sitio disminuye considerablemente.

Y podemos anidar varios objetos, unos dentro de otros, hasta construir nuestro propio espacio de nombres:

var app = {util:{}}

app.util.forms = {
	dirty: false,
	clickCancel: function() {
		var save = true
		if (this.dirty) {
			save = confirm("salvar antes de salir?")
		}
		if (save) this.clickSave()
	},
	clickSave: function() {
		document.getElementById("myForm").submit()
	}
}

Ahora tenemos nuestro flamante espacio de nombres app.util.forms.dirty y podemos usar las funciones como app.util.forms.clickCancel() y app.util.forms.clickSave()

Y nada más por hoy. En el próximo post cerraremos la serie de Javascript hablando de scopes (ámbitos de visibilidad), hoisting y closures que es cuando la cosa se empieza a poner interesante de verdad. Y veremos también algunos ejemplos un poco más complejos, ¡hasta entonces!

Más información:

Profundizando en Javascript, parte 1: funciones para todo

Javascript es un lenguaje que todos los programadores web creemos dominar. Da igual si programas en Php, Java o .Net: antes o después has tenido que hacer algo con Javascript. Y encima los que programamos en Java tenemos una pequeña ventaja añadida: que Javascript y Java comparten una sintaxix extremadamente parecida, lo cual lo hace todavía más sencillo, aparentemente, claro, porque solo se parecen en la sintaxis y nada más.

Así que dado el poco alcance (también aparentemente) que tiene Javascript, limitado normalmente al navegador (aunque hay excepciones), es poco usual profundizar en este lenguaje. Digamos que no merece la pena invertir tiempo en conocerlo a fondo, si lo comparamos con la utilidad que tiene profundizar en el propio Java, Hibernate, SQL o cualquier otro lenguaje/framework que usemos para nuestra aplicación web. Y encima ahora mucho más, ya que en estos últimos años han aparecido frameworks como jQuery, Prototype, Mootools o Mochikit que nos permiten, con mínimos conocimientos de Javacript, modificar el DOM a nuestro antojo, usar Ajax, hacer efectos y controlar eventos de manera no intrusiva sin importar el navegador en el que se visualice nuestra aplicación.

Sin embargo, este lenguaje tan “sencillo y facilón” esconde algo: no hay más que ver el código fuente de jQuery, por ejemplo, para darnos cuenta de que, simplemente, no se entiende tan facilmente como se debería: es como si el Javascript que conocemos de toda la vida se transformara en algo tremendamente distinto.

Un pelín de jQuery

Veamos, por ejemplo, que esconde el fichero jquery.js de la version 1.4.4 (podeis bajarlo desde aquí):

Para empezar, toda la librería, al completo, se engloba en este código:

(function( window, undefined ) {

	// Use the correct document accordingly with window argument (sandbox)
	var document = window.document;
	var jQuery = (function() {

		// Aquí va todo el código de jQuery

	});

})(window);

Vaya, es algo un poco, como lo diría, extravagante, ¿no? Intrigado, me puse a buscar que era toda esta suerte de funciones sin nombre que se ejecutan; y he encontrado cosas bastantes interesantes que me han hecho pensar que llevo toda la vida subestimando a este lenguaje y usándolo sin conocerlo del todo bien.

Una sola palabra clave para todo: function

Para empezar, Javascript es un lenguaje dinámico, interpretado, con closures, y que permite programación orientada a objetos (aunque no como la conocemos en Java, así que olvidate de herencia, interfaces, super, etc). Sin embargo, no tiene sentencias específicas para ello: no hay manera clara de definir un closure, ni un método, ni una clase, ni un objeto, ya que todos se hacen con la misma palabra clave: function.

Así que depende de como usemos “function” estamos definiendo una simple función, un closure, una clase o un método de una clase, ¡y todo con la misma palabra clave! Por supuesto, la palabra clave “this” tiene un significado más amplio, e incluso variable en función del contexto en el que se use. Para rematar, hay maneras distintas y equivalentes de programar orientado a objetos.

Pero empecemos por el principo. Esto es una función: la definición de un bloque de código que se ejecutará más adelante. A esta forma de crear funciones se llama función como declaración:

    function saluda(quien) {
        alert("hola "+quien)
    }

Esto por si solo no hace absolutamente nada, sino que es necesario invocarlo con una llamada a nuestra función

    saluda("mundo")

Las funciones son datos

Las funciones son funciones, pero tambien datos: el hecho de definir una función con su propio nombre (en este caso “saluda” es el nombre de la función) hace que se cree una variable global llamada “saluda” que podemos leer y pasar como parámetro, por ejemplo:

    function saluda() {
        alert("hola")
    }
    function ejecuta(func) {
        func()
    }
    ejecuta(saluda)

En este ejemplo, ejecutamos la función “ejecuta” pasándole como parámetro la función “saluda” como un dato, que pasa a llamarse “func” dentro de la función ejecuta, donde es invocada simplemente con func().

Tambien podemos crear funciones como expresiones de esta manera (además, es la recomendada, luego veremos porqué):

    var saluda = function(quien) {
        alert("hola "+quien)
    }
    saluda("mundo")

Con esta sintaxis lo que estamos haciendo en realidad es crear un función anónima y asignarle un nombre inmediatamente, por lo que es equivalente a definir la función como hacíamos al principio con function saluda(quien).

Para acabar, podemos crear funciones como expresiones y con nombre a la vez, como las funciones como declaración. La utilidad de esto es hacer funciones recursivas:

    var f = function fact(x) {
        if (x <= 1) return 1;
        else return x*fact(x-1); };

Dado que f es una variable externa y ajena a la función que puede cambiar en cualquier momento, darle el nombre “fact” a la función durante su propia definición es la única manera que tiene la propia función de llamarse a sí misma.

Funciones anónimas, autoejecutables y que devuelven funciones

Una función anónima se puede definir sin que sea asiganada a ninguna variable:

function(quien) {
	alert("hola "+quien)
}

Sin embargo, hacer esto es completamente inútil: definir una función sin nombre hace que sea imposible ser ejecutada más tarde, pues sin un nombre con el que acceder a ella es imposible encontrarla.
Pero podemos ejecutarla en el mismo momento en el que la definimos. Para ello, solo tenemos que encerrar entre paréntesis, y después usar unos nuevos paréntesis con los parámetros, como hacemos con una función normal.

	(function() { alert("hola mundo") })()

Por supuesto, podemos pasarle parámetros a nuestra función autoejecutable. En el siguiente ejemplo, se pasa como parámetro “mundo” a la función:

	(function(quien) {
		alert("hola "+quien)
	})("mundo")

Puede parecer poco útil hacer esto ahora, pero más adelante veremos como es una fantástica manera de arreglar ciertos problemas.

Por supuesto, una función puede devolver una función anónima. Sera responsabilidad del programador asignarla a una variable:

    function saludator(quien) {
        return function() {
            alert("hola "+quien)
        }
    }
    var saluda = saludator("mundo")
    saluda()

O podemos ejecutar la función que se ha retornado directamente, sin asignarla a ninguna variable:

    function saludator(quien) {
        return function() {
            alert("hola "+quien)
        }
    }

    saludator("mundo")()

Claro, nadie te impide sobreescribir una función con otra.

    function saludator(quien) {
        return function() {
            alert("hola "+quien)
        }
    }

    saludator = saludator("mundo")
    saludator()

Aquí, la primera vez que ejecutamos saludator(“mundo”) nos retorna una función anónima (que muestra “hola mundo”). Esta función es asignada a la variable saludator, por lo que la segunda vez que llamemos saludator(), estamos ejecutando la nueva función anónima (la del “hola mundo”), y la función inicial original se pierde para siempre.

Funciones dentro de funciones

Sigamos. Las funciones además se pueden anidar:

    function saluda(quien) {
        function alertasaludo(quien) {
            alert("hola "+quien)
        }
        alertasaludo(quien)

    }
    saluda("mundo")

Las funciones anidadas se llaman inner-private function. Inner porque son internas, y private porque son solo accesibles desde el código de la función desde donde son definidas. En nuestro ejemplo, alertasaludo() solo se puede invocar desde dentro de saluda().

Podemos combinar funciones anidadas con funciones que retornan funciones:

    function saludator(quien) {
        function alertasaludo() {
            alert("hola "+quien)
        }

        return alertasaludo
    }

    var saluda = saludator("mundo")
    saluda()

Y lo anterior lo podemos combinar con una función anónima auto-ejecutable.

    var saluda = (function(quien) {
        function alertasaludo() {
            alert("hola "+quien)
        }

        return alertasaludo
    })("mundo")

    saluda()

¿Y esto para que puede servir? Un ejemplo es el siguiente:

    var parOimpar = (function() {
        var hoy = new Date()
        if (new Date().getDate() % 2 == 0) {
            return function() { alert("hoy es dia par") }
        } else {
            return function() { alert("hoy es dia impar") }
        }
    })()

    parOimpar()

Con esto tenemos una función anónimoa autoejecutable que, evidentemente, solo se ejecutará una vez, con el único fin de crear una nueva función que nos muestre si el dia de hoy es par o impar.

Resumen

Llegados a este punto ya tenemos que tener claro varias cosas sobre las funciones:

- Que pueden tener nombre o no. Si no tienen nombre, son funciones anónimas.
- La dos sintaxis válidas para definir una función con nombre son:

   function nombre() {}
   var nombre = function() {}

- Que una función es tambien un dato y se puede manipular:
- Puedes asignar una función a una variable (y pasarla como parámetro a otra función)

         function yo() { alert("yo") }
         function saluda(alguien) { alguien() }
         saluda(yo)

- Puedes cambiar una función por otra, tan solo tienes que asignarle otra función al nombre anterior.

	    function yo() { alert("yo") }
	    function tu() { alert("tu") }
	    yo = tu

- Una función anónima puede ser ejecutada inmediatamente:

   (function() { alert("hola mundo") })()

- Las funciones se pueden anidar

   function quien() {
       function tu() { alert("tu") }
       tu()
   }

- Una función puede devolver otra función:

   function quien() {
   	   return function() { alert("yo") }
   }

Y con esto es todo por hoy. Todavía no tenemos el suficiente material para explicar porqué jQuery define todo la librería como una función anónima autoejecutable, pero al menos sabemos que lo hace y conocemos la sintáxis para hacerlo.
El próximo artículo veremos closures y programación orientada a objetos con Javascript, para acercarnos más y más a como funcionan jQuery y la mayoría de frameworks actuales por dentro. ¡Hasta entonces!

Más información:

Debian, Apache 2 y Tomcat 6 usando múltiples dominios, partes 3 y 4

PostedEn Tutoriales     Comentarios 21 comentarios
Jan
31

Continuación del tutorial iniciado hace un par de semanas en este mismo blog en: Debian, Apache 2 y Tomcat 6 usando múltiples dominios, parte 1 y 2 (de 4)

Parte 3: Configuración de software

Configurando Apache2 para que funcione con varios dominios (virtual host)

Aunque estemos trabajando inicialmente con una máquina virtual y tenga poco sentido tener varios dominios, debemos pensar que es solo un lugar de entrenamiento antes de hacer la instalación en un hosting real accesible desde internet. Lo normal es que queramos instalar varias aplicaciones, y que cada una de ellas sea accesible desde un dominio distinto. Vamos a suponer, por ejemplo, que hemos comprado los siguientes dominios: floristeria.com y guerraespacial.com. Estos dos dominios apuntan al mismo servidor, pero cada uno de ellos deberá tener su propia carpeta de Apache2 con sus contenidos estáticos (html, php, imagenes, etc) y su aplicación Tomcat con un war que desplegar.

Primero vamos a hacer que Apache2 muestre un contenido distinto en función del dominio de entrada que se haya utilizado.

Inicialmente, apache2 solo funciona con un dominio, o más bien, con cualquier dominio y siempre muestra el mismo contenido, lo que haya en la carpeta /var/www. Si vamos a esta carpeta, veremos un simple html con la famosa frase “It works!”.

La configuración de apache2 está en /etc/apache2. Nos movemos a esta carpeta y hacemos un ls, y veremos algo así:

debian:/etc/apache2# ls -l
total 40
-rw-r--r-- 1 root root 10104 jul 14 22:00 apache2.conf
drwxr-xr-x 2 root root  4096 oct 23 21:16 conf.d
-rw-r--r-- 1 root root   378 jul 14 22:00 envvars
-rw-r--r-- 1 root root     0 oct 23 20:40 httpd.conf
drwxr-xr-x 2 root root  4096 oct 23 20:40 mods-available
drwxr-xr-x 2 root root  4096 oct 23 20:40 mods-enabled
-rw-r--r-- 1 root root   513 jul 14 22:00 ports.conf
drwxr-xr-x 2 root root  4096 oct 23 20:40 sites-available
drwxr-xr-x 2 root root  4096 oct 23 20:40 sites-enabled

En sites-available es donde se definen todos los sites que existen en la máquina y en sites-enabled es donde están todos los sites que están realmente funcionando ahora mismo. La idea es crear un site por cada dominio en sites-available, y después enlazar dicho site en sites-enabled para habilitarlo. Si quisiéramos deshabilitar temporalmente un site, lo que hacemos es moverlo de sites-enabled a sites-availables sin necesidad de borrarlo. Existen una serie de comandos que nos ayudan mover los sites de sites-enabled a sites-available, por lo que no es necesario hacerlo a mano (aunque podríamos). Estos comandos son:

a2ensite nombredelsiteahabilitar
a2dissite nombredelsiteadeshabilitar

Más información en: http://www.debian-administration.org/articles/207

leer más

Debian, Apache 2 y Tomcat 6 usando múltiples dominios, parte 1 y 2 (de 4)

PostedEn Tutoriales     Comentarios 4 comentarios
Jan
4

Presentación

Hace ya bastante tiempo que administro varias máquinas Linux con la misma configuración: Debian, Apache2, Tomcat 6,  MySql y varios dominios con virtual host. Como casi todo el mundo, tengo en varios sitios apuntado desde direcciones con artículos sobre como instalar algunas cosas, comandos más útiles, hasta scripts típicos que siempre utilizo. Como a veces pasa mucho tiempo hasta que vuelvo a tocar o a instalar un nuevo entorno, siempre tengo que tirar de internet buscando tutoriales o guías, así que, harto de leer siempre la información de otros para hacer siempre las mismas tareas simples (instalar, configurar, parar y arrancar), he decidido crear mi propia guía donde reúna toda esa información que siempre utilizo, de una manera que pudiera leerse como un tutorial, con pasos y explicando las cosas con detalle.

El hecho de escribir este tutorial me sirve a mí mismo para afianzar mis propios conocimientos, además de poder leerlo cuando quiera sin necesidad de buscar en internet casi todas las cosas. Para que el tutorial lo pudiese leer y practicar cualquiera sin necesidad de usar una máquina real, lo he adaptado a una máquina virtual en Virtual Box. Además, le he dado formato, lo he corregido y lo he probado (es decir, cuando he acabado de hacerlo, lo he seguido al pie de la letra de principio a fin). Y ahora lo comparto con quien quiera que le pueda interesar. Como es un poco largo, lo publicaré en dos posts, uno ahora y otro la semana que viene. ¡Espero que le sea útil a alguien!

Introducción

El objetivo del tutorial es explicar como hacer una instalación y configuración de un servidor Linux con Debian 5, MySql, Apache 2 y Tomcat 6 desde cero. Para hacerlo más práctico y parecido a una posible configuración real, vamos a suponer los siguientes puntos:

  • Que tenemos dos dominios ficticios llamados guerraespacial.com y floristeria.com.
  • Que tenemos dos aplicaciones web java (war), una para cada dominio.
  • Que queremos acceder a cada aplicación a través de su propio dominio.
  • Que estas aplicaciones usan MySql, y así que para administrar la base de datos usaremos phpMyAdmin, por lo que necesitaremos Apache con php5.
  • Que queremos usar Apache 2 para servir contenidos estáticos (css, javascript, imágenes…) y como frontal para balancear Tomcat 6
  • Y que queremos darle un mínimo de seguridad al sistema.

La instalación de Debian la haremos en una máquina virtual creada con Virtual Box. Es decir, en vez de utilizar un servidor real (de un hosting dedicado que hayamos contratado o un servidor de la oficina, por ejemplo), utilizaremos Virtual Box para crear una máquina ficticia en la que instalaremos Debian 5. De esta manera conseguiremos aprender a realizar todo el proceso de instalación sin necesidad de tener acceso real a un servidor, lo que nos ayuda a practicar de una manera mucho más segura, pues si se comenten errores en una máquina virtual, no pasa absolutamente nada. Además, al usar Virtual Box como software de virtualización, el único requisito para seguir el tutorial es tener Windows, Linux o Mac, pues funciona en todos estos sistemas operativos y, además, es gratuito y de código abierto (no hay excusas)

El tutorial se compone de las siguientes partes:

Parte 1: Creación de una máquina virtual Linux con Virtual Box e instalación de Debian 5

Descarga de Virtual Box y Debain 5
Creación de máquina virtual.
Instalación de Debian 5.0 (lenny) en la máquina virtual.
Apertura de puertos http y ssh en Virtual Box con nat.
Instalación de ssh.
Configuración de dominios en el dns local (etc/host) para que apunten a la máquina virtual

Parte 2: Instalación de software
Actualización del sistema. Instalación de Apache 2, MySql, phpMyAdmin, JDK6 y Tomcat 6 en Debian 5.

Parte 3: Configuración de software

Configurando Apache2 para que funcione con varios dominios (virtual hosts)
Configurando Tomcat 6 para que arranque automáticamente (scripts)
Configurando un host de Tomcat 6 por dominio (en config.xml)
Conectando Apache a Tomcat 6 (con mod_proxy)

Parte 4: Seguridad

Bloqueando accesos inseguros a phpMyAdmin
Protegiendo con password realm el virtual host por defecto

Se puede hacer el tutorial sin Virtual Box en una máquina real, instalando Debian 5 desde cero tambien, o desde un hosting (dedicado o VPS) mientras tengamos acceso completo al servidor. En este caso, deberíamos empezar por la parte 2, ignorando la parte 1 que trata sobre la creación de la máquina virtual con Virtual Box. Además, tener en cuenta que se deben usar siempre los puertos reales del servidor, y no los que se han mapeado en Virtual Box.
leer más

Tutorial H2 Database

La base de datos H2 es un base de datos relacional programada integramente en Java. Una de las características más importantes a consecuencia de esto es que podemos integrarla completamente en nuestras aplicaciones Java y acceder a a ella lanzando SQL directamente, sin tener que pasar por una conexión a través de sockets, como ocurirría con MySQL, Oracle, Postgress, etc. (aunque también es posible utilizarla a través de conexiones JDBC externas). Esto implica una mayor velocidad y una mejor integración, como ahora veremos.
Cuando trabajamos con la base de datos dentro de nuestra aplicaciones, se llama modo “embedded” (incrustado). Una vez que nuestra aplicación ha abierto la base de datos para trabajar con ella, esta queda fisicamente bloqueada, no permitiendo que otro motor H2 (en otra aplicación Java por ejemplo) pueda acceder a ella. Esto permite mantener la integridad del fichero físico de la base de datos, ya que si dos motores H2 escribieran a la vez podrían corromperla.

Usar y crear bases de datos incrustadas con H2 desde Java es realmente facil. Primero tenemos que bajarnos el último jar de http://www.h2database.com e incluirlo en nuestro CLASSPATH (o en el directorio WEB-INF/lib de nuestra aplicación WAR).

El siguiente código abre una conexión contra una base de datos, definiendo donde se encuentra físicamente en nuestro disco, sin tener que especificar ningún host, ip o puerto, ya que no hay conexión a través de sockets, sino que se accede directamenete al disco.

import java.sql.*;
public class Test {
  public static void main(String[] a) throws Exception {
    Class.forName("org.h2.Driver");
    Connection conn = DriverManager.getConnection("jdbc:h2:/home/vilches/h2/test", "sa", "");
  }
}

Si al abrir una conexión no existe físicamente los archivos de la base de datos, H2 los creará. Por ejemplo:

/home/vilches/h2/test.2.log.db
/home/vilches/h2/test.data.db
/home/vilches/h2/test.index.db
/home/vilches/h2/test.trace.db

La ruta a la base de datos elegida es /home/vilches/h2/test. Esto significa que se utilizará el directorio /home/vilches/h2/ y que en ese directorio se crearán los ficheros de la base de datos, que empezarán por test.* y tendrán distintas extensiones. De esta manera, cambiando solo el nombre del fichero es posible tener varias bases de datos el el mismo directorio, ya que empezarán con nombres distintos (por ejemplo /home/vilches/h2/test y /home/vilches/h2/otro).

Una conexión por sesión es suficiente

Una de las mayores ventajas de usar H2 de forma embebida es que podemos utilizar conexiones sin necesidad de un pool de conexiones. Podemos, por ejemplo, utilizar una única conexión para toda nuestra aplicación y no cerrarla nunca (o cerrarla al salir de la aplicación). En caso de aplicaciones Web, podemos crear una conexión por sesión con un listener que implemente HtppSessionListener:

package test;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.io.*;
public class MySessionListener implements HttpSessionListener {
    public Connection openConnection() throws SQLException, ClassNotFoundException {
        Class.forName("org.h2.Driver");
        return DriverManager.getConnection("jdbc:h2:/home/vilches/h2/test", "", "sa");
    }

    public void sessionCreated(HttpSessionEvent se) {
        try {
            se.getSession().setAttribute("h2.connection", openConnection());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sessionDestroyed(HttpSessionEvent se) {
        try {
            Connection con = (Connection)se.getSession().getAttribute("h2.connection");
            con.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Para que funcione el listener es necesario darlo de alta en el web.xml:

<listener>
    <listener-class>test.MySessionListener</listener-class>
</listener>

Ahora, desde nuestros servlets o JSPs, podemos acceder a la conexión con:

Connection con = (Connection)se.getSession().getAttribute("h2.connection");

y podremos utilizarla sin preocuparnos por cerrarla.

Abriendo la base de datos al arrancar la aplicación

Una buena practica es abrir por lo menos una conexión al arrancar la aplicación, de esta manera nos aseguramos de que H2 abre fisicamente la base de datos en el disco y la bloquea para el resto de procesos. Para hacer esto, podemos ampliar el listener anterior para que implemente también ServletContextListener, el cual tiene dos métodos que se ejecutan cuando se crea y se destruye el contexto (es decir, se arranca y se para la aplicación web).

Además, vamos a definir la ruta de la base de datos como un parámetro del contexto en el WEB-INF/web.xml llamado “h2.database.path” que leeremos en el arranque (si el parámetro no existe, cogeremos la home del usuario actual con System.getProperty("user.home")) y utilizaremos para crear la url jdbc :

package test;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.io.*;

public class MySessionListener implements ServletContextListener,
    HttpSessionListener {

    // Constante para el nombre de los ficheros
    private final static String DBFILENAME = "test";

    String url;
    Connection globalConnection;

    public void contextInitialized(ServletContextEvent sce) {
        // Leemos el parametro del contexto
        String spath = sce.getServletContext().getInitParameter("h2.database.path");
        if (spath == null) {
            // Si no existe, es la home del usuario
            spath = System.getProperty("user.home");
        }
        try {
            Class.forName("org.h2.Driver");
            File dbfile = new File(spath, DBFILENAME);
            url = "jdbc:h2:file:" + dbfile.getAbsolutePath().replaceAll("\\\\", "/");
            globalConnection = openConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Connection openConnection() throws SQLException {
        return DriverManager.getConnection(url, "", "sa");
    }

    public void contextDestroyed(ServletContextEvent sce) {
        try {
            globalConnection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void sessionCreated(HttpSessionEvent se) {
        try {
            se.getSession().setAttribute("h2.connection", openConnection());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void sessionDestroyed(HttpSessionEvent se) {
        try {
            Connection con = (Connection)se.getSession().getAttribute("h2.connection");
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Para que funcione el listener es necesario darlo de alta en el web.xml y definir el parámetro de contexto con la ruta :

<context-param>
    <param-name>h2.database.path</param-name>
    <param-value>/home/vilches/h2</param-value>
</context-param>
<listener>
    <listener-class>test.MySessionListener</listener-class>
</listener>

Creando tablas al arrancar por primera vez

Ahora supongamos que queremos crear una serie de tablas cuando hemos arrancado la base de datos, pero solo la primera vez, cuando la base de datos está vacía. Para hacer esto vamos a verificar, antes de abrir la primera conexión, si la base de datos existe. Y si no existe, crearemos las tablas (después de abrir la primera conexión). Modificaremos el método contextInitialized para que quede así:

public void contextInitialized(ServletContextEvent sce) {
    // Leemos el parametro del contexto
    String spath = sce.getServletContext().getInitParameter("h2.database.path");
    if (spath == null) {
        // Si no existe, es la home del usuario
        spath = System.getProperty("user.home");
    }

    // Comprobamos si no existe la base de datos
    boolean exists = new File(spath, DBFILENAME+".data.db").exists();

    try {
        Class.forName("org.h2.Driver");
        File dbfile = new File(spath, DBFILENAME);
        url = "jdbc:h2:file:" + dbfile.getAbsolutePath().replaceAll("\\\\", "/");
        globalConnection = openConnection();

        // Si no existe, llamamos al metodo initDb()
        if (!exists) {
            initDb();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Ahora solo queda implementar initDb() a nuestro gusto.

Ejecutando un script SQL desde Java

Una buena practica es crear un fichero de script con las sentencias SQL y ejecutarlo directamente, sin tener que implementar, una a una, las sentencias de creación de tablas en nuestro código. El siguiente código lee un fichero de script llamado squema-h2.sql.txt situado dentro de la carpeta de de clases (es decir en /WEB-INF/classes/squema-h2.sql.txt) y lo ejecuta. Dentro de este script podemos incluir sentencias para crear tablas y añadir registros. El script necesita que cada sentencia acabe en punto y coma “;”, permite partir las sentencias en más de una línea e ignora los comentarios (líneas que empiezan por “–”, “#” y “//”) y líneas en blanco.

private void initDb() throws SQLException, IOException {
    InputStream is = getClass().getClassLoader().getResourceAsStream("squema-h2.sql.txt");
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    Connection connection = null;
    try {
        connection = openConnection();
        String line = br.readLine();
        StringBuilder statement = new StringBuilder();
        while (line != null) {
            line = line.trim();
            if (!line.startsWith("--") && !line.startsWith("#") && !line.startsWith("//")) {
                statement.append(line);
                if (line.endsWith(";")) {
                    executeLine(connection, statement.toString());
                    statement = new StringBuilder();
                }
            }
            line = br.readLine();
        }
        if (statement.length() > 0) {
            executeLine(connection, statement.toString());
        }
    } finally {
        try {
            br.close();
        } catch (Exception e) {;}
        try {
            if (connection != null) connection.close();
        } catch (Exception e) {;}
    }
}

private void executeLine(Connection connection, String statement) throws SQLException {
    PreparedStatement pstmt = connection.prepareStatement(statement);
    pstmt.execute();
    pstmt.close();
    System.out.println("Ejecutando "+statement);
}

El script /WEB-INF/classes/squema-h2.sql.txt podría ser:

CREATE TABLE USUARIO (
	ID INT AUTO_INCREMENT,
	LOGIN VARCHAR(25) NOT NULL UNIQUE,
	PASSWORD VARCHAR(25) NOT NULL,
	NOMBRE VARCHAR(100) NOT NULL,
	EMAIL VARCHAR(50),
	WEB	VARCHAR(100),

	PRIMARY KEY(ID)
);

-- Esto es un comentario
// Esto también
# Y esto también lo es

insert into usuario values (null, 'admin','admin123','Alberto Vilches',
	'email@sitio.com', 'http://albertovilches.com');

(Para más información sobre la sintaxis SQL de creación de tablas de H2, consultar H2 SQL Grammar reference)

Finalmente, creamos un JSP de ejemplo que liste los registros de la tabla para ver si todo funciona correctamente:

<%@ page import="java.sql.*" %>
<html>
  <body>
  <%
      Connection con = (Connection) request.getSession().getAttribute("h2.connection");

      PreparedStatement stmt = con.prepareStatement("SELECT * FROM USUARIO");
      ResultSet rst = stmt.executeQuery();
      while (rst.next()) {
      %>

  <%=rst.getString("LOGIN")%>, mailto:<%=rst.getString("EMAIL")%><br/>

      <%
      }

  %>
  </body>
</html>

Resumen

Con esto ya tendríamos un acceso a base de datos muy ligero y rápido disponible en nuestras aplicaciones Web. La ruta de la base de datos irá definida en el parámetro “h2.database.path” en el web.xml. El listener se encargará de crear la base de datos con las todas las tablas y mantenerla siempre abierta mientras esté activa la aplicación Web. También tendremos en la sesión siempre una conexión disponible lista para usar.

Bájate el código de ejemplo completo: War de ejemplo con H2 incrustado

Abrir una url en un navegador desde Java

Sacado del código fuente de H2, clase org.h2.util.StartBrowser

    public static void openURL(String url) {
        String osName = System.getProperty("os.name");
        try {
            if (osName.startsWith("Windows")) {
                Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
            } else if (osName.startsWith("Mac OS X")) {
                // Runtime.getRuntime().exec("open -a safari " + url);
                // Runtime.getRuntime().exec("open " + url + "/index.html");
                Runtime.getRuntime().exec("open " + url);
            } else {
                System.out.println("Please open a browser and go to "+ url);
            }
        } catch (IOException e) {
            System.out.println("Failed to start a browser to open the url " + url);
            e.printStackTrace();
        }
    }

Ofuscando emails desde Java

Para evitar el spam, hay muchas maneras de ocultar el email en una página html. Una de las más efectiva podría ser crear una imagen con la dirección como tengo puesto en mi página de contacto: . Puedes crear esta imagen con el photoshop o desde alguna utilidad externa como esta.

Sin embargo, puede que estemos desarrollando una aplicación en Java y tengamos un listado de usuarios público con sus emails. Crear una imagen para cada uno de ellos podría ser muy laborioso, y escribir el email sin ofuscar u ocultar podría ser peligroso.

Obviando los trucos de poner los emails con el formato “nombre ARROBA dominio PUNTO es” o “email@[QUITAESTO]dominio.es” podemos escribir cada carácter ASCII de nuestro email uno por uno en hexadecimal o decimal. Para esto, utilizaremos las entidades html con este formato:

  • &#D; siendo D el número del código ASCII en decimal
  • &#xH; siendo H el número del código ASCII en hexadecimal

Por ejemplo, para pintar la letra a, cuyo código ASCII es 97 en decimal y 61 en hexadecimal podemos utilizar &#97; o &#x61;
(Una tabla completa con todos los caracteres ASCII aqui)

Bueno, ahora lo que queremos es escribir nuestros emails codificados en decimal y hexadecimal. Para eso utilizaremos esta clase Java:

public class HtmlCoder {
   public static final Random r = new Random(System.currentTimeMillis());
   public static String randomHtmlEncode(String data) {
        if (data == null || data.length() == 0) return data;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < data.length(); i++) {
            switch (r.nextInt(3)) {
            case 0 : // En decimal
                sb.append("&#").append((int)data.charAt(i)).append(";");
                break;
            case 1 : // En hexadecimal
                sb.append("&#x").append(Integer.toHexString(data.charAt(i))).append(";");
                break;
            case 2 : // Tal cual
                sb.append(data.charAt(i));
            }
        }
        return sb.toString();
    }
}

Esta clase crea un texto codificando cada carácter en su equivalente ascii en decimal, hexadecimal o sin codificar de manera aleatoria. De esta manera, un email se quedaría así: &#x73;&#x6f;&#x79;&#x70;ic&#x61;p&#105;&#99;a&#x40;&#x79;&#97;&#x68;o&#x6f;.&#x65;&#115;

Paginacion (y II)

El otro día comenté en Paginacion (I) como obtener resultados paginados desde la base de datos, mostrando dos formas distintas para hacerlo.
El resultado final es que se devolvía un objeto Page que contenía una coleccion de resultados (los beans de la página) y algunos valores numéricos con información de la página, como el tamaño de la misma, el número de página y el número total de páginas (última página) y elementos (último elemento).

Veamos antes de continuar, un ejemplo de utilización del metodo “getPage” de obtencion de páginas. Esto sería el código de un Servlet cualquiera que recibe como parametros “page” y “size” en su url la página a mostrar y el tamaño de la página. Despues el objeto Page devuelto se introduce en la request con el nombre “vuelos”.
Además, se muestra un “truquillo” para recoger el parametro “page” y “size” sin muchos quebraderos de cabeza. Es el método getParameterInt.

public static final int DEFAULT_PAGE_SIZE = 20;

protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
    int numPage = getParameterInt(req, "page", 1);
    int pageSize = getParameterInt(req, "size", DEFAULT_PAGE_SIZE);

    Page pageVuelos = getPage(numeroPagina, pageSize);

    request.setAttribute("vuelos", pageVuelos);
    req.getRequestDispatcher("/mipagina.jsp").forward(req, res);
}

public int getParameterInt(HttpServletRequest req, String name, int defaultValue) {
    try {
        return Integer.parseInt(req.getParameter(name));
    } catch (NumberFormatException e) {
        // Si llegamos hasta aqui es que número recibido como parámetro es null o no es númerico.
        // Por lo tanto, retornamos el valor por defecto
        return defaultValue;
    }
}

A partir de aqui, el trabajo consiste, desde el JSP, recoger el objeto Page que hemos dejado en el atributo “vuelos” y pintar, con un Iterator (o con lo que se quiera) la coleccion de objetos que en el método getResults()

Una vez pintado la lista de objetos de nuestra página, queremos que el usuario pueda elegir cualquier otra página para poder navegar por todo el conjunto de resultados real. Esto se puede hacer de varias maneras. Podríamos, por ejemplo, hacer un bucle que pintase todas las páginas posibles:

     <%
        Page vuelos = (Page)request.getAttribute("vuelos");
        int n = 1;
        for (n=1; n <= vuelos.getLastPage(); n++) {
        %>
           <a href="/consultaVuelos?page=<%=n%>"><%=n%></a>
        <%
        }
     %>

leer más

Categorías

-moz-border-radius: 4px; -ms-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px;