Archivo de Etiquetas de 'tutorial'

Empezando con Liferay: una guía rápida de instalación

Dado que reciéntemente he tenido que instalar un Liferay limpito en un servidor con Apache, dejo aquí una guía con los pasos que seguí:

  1. ¿Qué es Liferay?
  2. Instalación básica
  3. Usando Liferay con MySQL
  4. Usando Liferay con Apache
  5. Usuario por defecto y un par de ajustes más

¿Qué es Liferay?

Liferay es un gestor de portales web con una gran funcionalidad integrada (gestión de comunidades y usuarios, CMS, wiki, blogs, y mucho más), y a su vez es un contenedor de portlets, lo que le permite ser extendido de manera bastante rápida y flexible (siguiendo la especificación JSR 286: Portlet Specification 2.0). Además, cuenta con una versión Community cuyo uso es gratuito y cuyo código es libre.

Instalación básica

Descargamos la última versión Community con el usuario que arrancará Liferay (en mi caso www-data) en el sitio que queramos (yo he escogido /opt/websites/liferay.deigote.com como directorio base de la instalación):

$ su - www-data
$ cd /opt/websites/
$ wget 'http://sourceforge.net/projects/lportal/files/Liferay%20Portal/liferay-portal-tomcat-6.0-5.2.3.zip'
$ unzip liferay-portal-tomcat-6.0-5.2.3.zip
$ mv liferay-portal-5.2.3/ liferay.deigote.com

Si ahora arrancamos Liferay, podremos ver cómo nos informa en los log de que se usará una base de datos para testing (Hipersonic), y si navegamos por la web, podremos ver una serie de portlets a modo de demo:

$ /opt/websites/liferay.deigote.com/tomcat-6.0.18/bin/startup.sh
$ tail -f logs/catalina.out &
$ firefox http://localhost:8080

Este entorno de demo está bien para cacharrear un poco y ver cómo la gente de Liferay quiere vendernos sus capacidades para hacer un clon de Facebook :D (vienen instanciados portlets de chat, de muro, de añadir usuarios como amigo, de actividad reciente…), pero los datos no persisten, por lo que no podréis pasar de ahí. Además, Liferay viene por defecto con usa serie de portlets (en forma de plugins) preparados para hacer la demostración antes mencionada. Yo normalmente borro dichos portlets antes de continuar (de hecho, en mi caso borro todos los plugins excepto el de web-form-portlet, que es el único que encuentro útil):

$ rm -rf `ls /opt/websites/liferay.deigote.com/tomcat-6.0.18/webapps | grep -v ROOT | grep -v web-form-portlet`

Para la persistencia de los datos, tenemos que conectar Liferay con un viejo conocido :D .

Usando Liferay con MySQL

Para conectar Liferay con MySQL existen varias formas. De momento anotaré aquí la más sencilla (aunque para mi gusto un poco “fea”), puesto que no recuerdo exactamente cómo es la otra :D . Liferay incluye en su core un fichero de propiedades (portal.properties) que configuran prácticamente todos los componentes del portal, base de datos incluida. Ese fichero puede ser extendido mediante el fichero portal-ext.properties, que por defecto no existe. Así que escribimos en él la configuración de la base de datos:

$ echo "# Database connection
jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.url=jdbc:mysql://localhost/liferay_database?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.default.username=mysql-user
jdbc.default.password=mysql-password" > /opt/websites/liferay.deigote.com/tomcat-6.0.18/webapps/ROOT/WEB-INF/classes/portal-ext.properties

A continuación nos conectamos al servidor de mysql (en mi caso, localhost) y creamos la base de datos y un usuario con permisos para la misma:

$ mysql -h localhost -u root -p
$ create database liferay_database
$ grant all privileges on liferay_database.* to "mysql-user"@"localhost" identified by "mysql-password";

Si en este momento arrancamos Liferay de nuevo, deberíamos ver algunos mensajes haciendo mención a la base de datos utilizada (MySQL), y otros que indican que se están creando las tablas..

Usando Liferay con Apache

Para usar Apache como servidor web, creamos un host virtual y lo conectamos al servidor de aplicaciones de Liferay (en mi caso Tomcat) usando un módulo de proxy. Podemos usar el módulo proxy_http, que funcionaría con cualquier servidor de aplicaciones, o el módulo proxy_ajp, específico de Apache, y que presenta algunas ventajas sobre http, aunque yo no las recuerde :D . Dado que Tomcat soporta AJP, será el que usemos. Dado que yo uso Debian, necesito activar el módulo de proxy_ajp y crear un host virtual que use dicho módulo:

$ su -
# a2enmod proxy_ajp
# nano /etc/apache2/sites-available/liferay.deigote.com
# a2ensite liferay.deigote.com
# /etc/init.d/apache2 restart
# exit

El contenido del fichero /etc/apache2/sites-available/liferay.deigote.com será el siguiente:

<VirtualHost *:80>
        ServerName liferay.deigote.com
        ServerAdmin webmaster@localhost
        ErrorLog /var/log/apache2/liferay.deigote.com_error.log
        LogLevel warn
        CustomLog /var/log/apache2/liferay.deigote.com_access.log combined
        # Proxy to Tomcat
        <Proxy *>
                Order deny,allow
                Allow from all
        </Proxy>
        ProxyPass / ajp://liferay.deigote.com:8009/
        ProxyPassReverse / ajp://liferay.deigote.com:8009/
</VirtualHost>

Antes de echar a andar con esta configuración, debemos añadir un par de líneas al fichero de propiedades de Liferay, ya que si no éste dará por hecho que estamos atacando al puerto 8080 (el puerto por defecto de Tomcat) y escribirá las URL’s con dicho puerto. Una vez realizado este paso, deberíamos poder acceder a Liferay a través del host virtual que hemos usado (siempre y cuando nuestro servidor DNS sepa resolver dicho host, claro):

$ /opt/websites/liferay.deigote.com/tomcat-6.0.18/bin/shutdown.sh
$ echo "
# Webserver configuration
web.server.http.port=80
web.server.https.port=443" >> /opt/websites/liferay.deigote.com/tomcat-6.0.18/webapps/ROOT/WEB-INF/classes/portal-ext.properties
$ /opt/websites/liferay.deigote.com/tomcat-6.0.18/bin/startup.sh
$ firefox http://liferay.deigote.com

Usuario por defecto y un par de ajustes más

Una vez estemos navegando por Liferay, podremos acceder usando el usuario test@liferay.com con la contraseña test, que es administrador de la comunidad por defecto (guest) Yo recomiendo un par de ajustes más:

  • Cambiar la dirección de correo (y por tanto el login) y la contraseña del usuario administrador. Esto lo podéis hacer en el Panel de control, en el apartado de Usuarios.
  • Modificar el host virtual de la comunidad por defecto (o la que vayáis a usar) para que coincida con el que estéis usando para acceder a través de Apache. Esto se puede hacer en el panel de control, en el apartado Communities – Guest – Manage pages – Settings – Virtual host, usando el campo Public virtual host. Esto permitirá que las URL’s del tipo http://virtual_host/web/nombre_de_la_comunidad/pagina pasen a ser http://virtual_host/pagina, lo cual es más cómodo. Por ejemplo, la URL de la página por defecto (home) en la comunidad por defecto (guest) en mi caso pasaría de http://liferay.deigote.com/web/guest/home a http://liferay.deigote.com/home

Una vez finalizados estos pasos, ya podemos empezar a trabajar con Liferay en un entorno de producción (a falta, por supuesto, de configuraciones y optimizaciones de Tomcat, Apache y MySQL que no vienen al caso :D ).

Mini tutorial de awk

Por petición popular, voy a escribir un poco sobre un mandato típico de los sistemas operativos UNIX (apareció por primera vez en 1977 nada menos), awk.

awk es un mandato que sirve para procesar líneas de texto (separadas, naturalmente, por un salto de línea). awk cuenta con un pequeño y sencillo lenguaje de programación que es interpretado (no necesita ser compilado), y resulta tremendamente útil cuando queremos extraer información de extensos campos de texto (y, posiblemente, manipularla).

El funcionamiento del madato awk es muy sencillo: basicamente tenemos dos posiblidades:

$ awk -f fuente.awk fichero_entrada.txt
$ awk 'fragmento de código fuente' fichero_entrada.txt

En la primera de ellas, el código fuente está en un fichero (recomendado para usos que vayan a repetirse con el tiempo y con códigos fuentes largos) mientras que el segundo ofrece la ventaja de poder poner el código fuente como un argumento más. Esto es muy útil para el uso de awk en scripts o similares, en los que el uso de ficheros puede ser un engorro. También cabe la posibilidad de omitir el fichero de entrada, en cuyo caso awk leerá de la entrada estándar.

Respecto al lenguaje awk, tiene una estructura similar a lo siguiente:

BEGIN { acción }
/patrón/ { acción }
END { acción }

La forma de funcionamiento la siguiente:

  1. Nada más comenzar la ejecución, se evaluará la acción marcada entre llaves precedida por la palabra reservada BEGIN.
  2. Por cada campo de texto (recordemos, por defecto líneas) awk evaluará si se ajusta al patrón (una expresión regular), y de ser así, ejecutará la acción marcada entre llaves que sigue a dicho patrón. Por cada líneas se evaluarán todos los patrones a menos que en una de las acciones ejecutadas se encuentre la orden next, en cuyo caso se comenzará desde el principio con la siguiente línea.
  3. Finalmente, se procesará la acción marcada entre llaves precedida por la palabra reservada END.

Respecto a los patrones de awk, son, como ya he dicho, expresiones regulares. No voy a explicar aquí todas las posiblidades porque no acabaría nunca (y con la ayuda de la Wikipedia os debería bastar), basten un par de ejemplos:

  • /[afP]MEMOLO[1-3]z/ casará con cualquier línea que contenga las letras a, f o P seguidas de la cadena MEMOLO seguidas de un dígito comprendido del 1 al 3 y seguida por la letra z.
  • /[afP](MEMOLO)+([1-3])*z/ casará con cualquier línea que contenga las letras a, f o P seguidas de la cadena MEMOLO una o varias veces seguidas de un dígito comprendido del 1 al 3 que puede aparecer ninguna, una, o varias veces y seguida por la letra z.

Esta es la parte más complicada de awk (ya sabeis lo que se dice de las expresiones regulares).

En cuanto a las acciones, cualquiera que haya programado en C no tendrá mucho problema, ya que es similar. Como características cabría destacar:

  • El acceso a las línea actual se hace mediante unas variables especiales. En concreto $0 referencia a toda la línea mientras que $1, $2, etcétera, referencian a los campos de dicha línea. El separador de campos por defecto es un espacio o un tabulador, pudiéndose modificar en la acción de BEGIN con la variable FS (otra expresión regular, por cierto).
  • No es necesario declarar ni tipar las variables, cuyo formato es el mismo que en C (su expresión regular, para que vayais practicando, es algo parecido a [a-Z]([a-Z] | [1-9] | _ )*).
  • Están permitidas todas las estructuras clásicas de programación en un formato estilo C (bucles, expresiones condicionales, operadores, etcétera).
  • Para imprimir resultados, existen dos posiblidades. La primera, print, es la más cómoda, puesto que no es necesario usar paréntesis para sus argumentos y cuenta con concatenación automática de los mismos (algo parecido al mandato echo de la terminal. Por ejemplo, print “la línea ” $0 “tiene ” NF ” palabras” imprimirá la frase que precede a print sustituyedo $0 por la línea actual y NF (otra variable especial) por el número de campos de la misma. Como segunda posibilidad, tenemos printf, que ofrece mayor control (es idéntico al del lenguaje C).

¿Y qué pasa con los los jugosos ejemplos? Pues he recopilado alguno que otro según me ha ido surgiendo la necesidad de usarlo estos días.

  • Por ejemplo, el otro día necesitaba obtener del fichero de log de Tomcat las líneas que contuviesen o bien “SOAP21″ o bien ” – 2 “. Esto sería sencillo de hacer con dos grep, pero yo necesitaba que esas líneas mantuviesen el orden en el que habían aparecido en el fichero, y hacer eso con un grep requiere de una expresión regular bastante más compleja de lo que en realidad es necesario. Además, quería saber en qué número de línea del fichero estaba cada línea buscada. Con awk, fue tan sencillo como esto:
    cat tomcat.log | awk '/SOAP21/{print NR " - " $0} / - 2/{print NR " - "$0}'
  • También necesité, en el mismo fichero, verificar que se cumpliese una secuencia, y concretamente, me valía saber que, dentro del conjunto de líneas que contenían “SOAP21″, las múltiplo de 5 eran idénticas, ya que de esta manera sabía que se habían cumplido todos los pasos. Por lo tanto, necesitaba sacar las líneas que tuviesen “SOAP21″, y dentro de éstas, sólo las que su número de línea fuese múltiplo de 5. Nuevamente, awk te lo pone fácil:
    cat tomcat.log | awk 'BEGIN { nl = 1 } /SOAP21/ { if (nl % 5 == 0) print ; nl++}'
  • En plan más “complicado” (teniendo en cuenta que lo de antes era trivial), hice una pequeña línea para sacar la nota media a partir del archivo html que te devuelve la UPM cuando consultas tu expendiente usando la modalidad “Último estado de cada asignatura” (aunque falla cuando tienes alguna matrícula, pero bueno, eso no es lo importante ahora). El código es el siguiente:
    cat consulta.upm.html | grep "
    /<\/table>/ { d = 0 } { if (d > 0) { if (c == 10) { print ; c = 0 } else c++ } }' | grep
    '>\([1-9][0-9]\|[1-9]\|[1-9]\,[0-9]\{1\}\|[1-9]\,[0-9]\{2\}\)<' | cut -d 1 -f2 -d'>' | cut
    -f1 -d'<' | awk 'BEGIN { t=0.0;n=0; } {print ; t=t+$1 ; n++} END { print "Total " t "
    Asignaturas " n " Media " t/n}'

    Como veis, el primer fragmento de awk hace una selección de líneas, imprimiendo sólo las filas de las tablas que sean múltiplo de 10 (son en las que se encuentran las notas) y que estén contenidas entre una línea que tenga la palabra Obs y el primer final de tabla en html. Una vez obtenidas estas líneas, uso grep para quedarme solo con las que tienen nota y cut para dejar sólo la nota, quitando el resto de elementos html. El segundo fragmento de awk se encarga de ir sumando las notas y el número de asignaturas para imprimir la media.
  • EDITO: iré añadiendo más fantabulosos ejemplos ;-) según me los vaya encontrado.

  • Mi hermano el otro día me preguntó como resolvería un problema y le sugerí que usara awk. El problema consistía en que tenía ficheros (por cierto, de más de 80.000 líneas) con una estructura tal que
    frase1 1
    frase2 5
    ...
    fraseN M

    y quería sumar los números de cada frase. En el caso original tenía la ventaja de que las frases siempre iban en el mismo orden en todos los ficheros, pero la sencillez de awk hace que la solución (que corre a cargo de mi hermano, por cierto) valga para casos que no estén en orden (e incluso que aparezcan frases en algunos ficheros y en otros no). Además, se requería que fuese relativamente rápido, y awk cumplió con las expectativas (la solución previa eran pruebas con scripts más o menos a mano y los resultados se iban por encima de los 10 minutos, frente a los 2 minutos de la solución con awk). El único problema era juntar la salida de los ficheros, pero awk permite trabajar con varios ficheros de entrada de datos (si no, un poquito de bash scripting, for i in *.out ; do cat $i ; done, lo hubiese solucionado). Los ficheros tenían extensión .out, por lo que la solución final es:
    awk 'BEGIN { FS = " ";} { resultados[$1] += $2 } END { for(category in resultados) print category, resultados[category]; } *.out'
    Como veis es sencillo, limpio y eficaz :-D ¡con awk, la suciedad se va en un bang! Aquí además podeis ver algunas cosas más de awk, como los bucles, los array (estilo PHP, sin declaración ni reserva de memoria ni inicialización de datos) y la variable especial FS, que sirve para especificar cómo separar los campos de una línea (aunque en este caso no haga falta porque por defecto es espacio o tabulador).

Y esto es todo por hoy. Huelga decir que en Internet encontrareis cientos de ejemplos y tutoriales, pero yo quería hacer una pequeña introducción con un par de ejemplos más prácticos que los que suelo encontrar (al menos, serían prácticos para mí ;-)). Espero que os sea de utilidad.