Archivo de la etiqueta: Java

Conocer la versión del pom en código

Para proyectos maven, puede sernos de utilidad disponer desde nuestro código de la versión del pom.xml. Para ello añadimos la siguiente de pendencia:

<dependency> 
    <groupId>org.apache.maven</groupId> 
    <artifactId>maven-model</artifactId> 
    <version>3.3.9</version> 
</dependency> 

Ahora desde código podemos obtener la versión:

MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(new FileReader("pom.xml"));
System.out.println(model.getId());
System.out.println(model.getGroupId());
System.out.println(model.getArtifactId());
System.out.println(model.getVersion());

Niveles de Log en Liferay

Si deseamos utilizar los logs gestionados desde Liferay, deberemos utilizar:

import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
...
protected static Log _log = LogFactoryUtil.getLog(Prueba.class);
...
_log.nivel("log de Liferay");

Para establecer el nivel de estos logs, podemos ir al panel de control de Liferay y establecer el nivel de logs para la clase o el paquete. Por defecto, cada vez que reiniciemos la instancia desaparecerán los cambios.

También puede resultarnos útil gestionar los logs directamente con log4j, ya que así no dependemos de esas librerías (y podemos utilizarlo tanto en portlets como en librerías propias que deseemos instalar). El procedimiento sería utilizar el siguiente log:

import org.apache.log4j.Logger;
...
private static Logger log = Logger.getLogger(Prueba.class);
...
log.nivel("log de log4j");

Ahora para establecer los niveles y el fichero de escritura, podemos ver los ficheros de propiedades de webapps/ROOT/WEB-INF/classes, concretamente log4j.properties

log4j.rootLogger=INFO, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ABSOLUTE} %-5p [%c{1}:%L] %m%n

Con esto estamos diciendo que el appender de nombre CONSOLE es de tipo ConsoleAppender, y que cree automáticamente un fichero cada día renombrándolo de la forma específica que se muestra; y por defecto, los logs son de tipo INFO, utilizando el appender CONSOLE.

Ahora nosotros hemos creado un portlet, y deseamos crear nuestros logs:
creamos un fichero log4j.xml en el src de nuestro proyecto; lo
configuramos por ejemplo como sigue:

<?xml version="1.0"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
	<appender name="stdout2" class="org.apache.log4j.DailyRollingFileAppender">
		<param name="File"
			value="/home/usuario/devel/Liferay/bundles/liferay-portal-6.1.1-ce-ga2/tomcat-7.0.27/logs/salida2.%d{yyyy-MM-dd}.log" />
		<param name="DatePattern" value="'.'yyyy-MM-dd" />
		<param name="Encoding" value="UTF-8" />
		<layout class="org.apache.log4j.TTCCLayout" />
	</appender>
	<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
		<errorHandler class="org.apache.log4j.helpers.OnlyOnceErrorHandler" />
		<param name="File"
			value="/home/usuario/devel/Liferay/bundles/liferay-portal-6.1.1-ce-ga2/tomcat-7.0.27/logs/salida2.log" />
		<param name="Append" value="false" />
		<param name="Threshold" value="DEBUG" />
		<!--
			Rollover at midnight each day <param name="DatePattern"
			value="'.'yyyy-MM-dd"/>
		-->
		<!-- Rollover at the top of each hour -->
		<param name="DatePattern" value="'.'yyyy-MM-dd-HH" />
		<layout class="org.apache.log4j.PatternLayout">
			<!-- The default pattern: Date Priority [Category] Message\n -->
			<param name="ConversionPattern" value="%d %-5p [%c] %L %m%n" />
			<!--
				The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
				<param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x)
				%m%n"/>
			-->
		</layout>
	</appender>
	<logger name="com.test" additivity="false">
		<level value="DEBUG" />
		<appender-ref ref="FILE" />
	</logger>
</log4j:configuration>

Según este código, al desplegar en Liferay el portlet se creará un appender de tipo FILE (y otro stdout2 aunque no lo usamos en este ejemplo), y hacemos que todo el contenido del paquete com.test utilice el appender FILE, que escribe en el fichero especificado (y en este caso hace una copia del mismo cada hora, aunque está comentada la parte que hace la copia cada día).

Hooks Liferay

Los hooks se utilizan para para desarrollar plugins que sobreescriben partes del ‘core’ de Liferay pero sin tener que tocarlo, ni usar el entorno de extensión EXT.
Nos permite modificar el comportamiento de Liferay haciendo una buena gestión de esas modificaciones.

Tipos de Hooks en Liferay

  • Sobreescribir ficheros JSP.
  • Sobreescribir servicios del portal.
  • Sobreescribir las traducciones.
  • Sobreescribir Model Listeners.
  • Insertar eventos en el ciclo de vida de Liferay.

En función del tipo de hook el desarrollo se hace de manera diferente, pero a grandes rasgos crear un hook es tan fácil como crearlo des del SDK:
nos colocamos en la carpeta de hooks y ./create.sh nombre-proyecto-hook “Nombre del hook” 
Ejemplo
podemos ver en docroot/WEB-INF el fichero liferay-hook.xml; dentro de las etiquetas
colocamos:

<custom-jsp-dir>/META-INF/custom_jsp</custom-jsp-dir>

para indicar la ruta en la que colocaremos los jsps (en caso de que vayamos a modificar jsp’s, como es el caso en este ejemplo).

Localizamos el fichero dentro de liferay: liferay/tomcat/webapps/ROOT/html/portlet/blogs/view_entry.jsp y lo copiamos en nuestra estructura del proyecto, en docroot/META-INF/custom_jsp/html/portlet/blogs/view_entry.jsp
Ahora podemos modificar ese jsp.
Finalmente hacemos ant deploy.
Veremos que en liferay el fichero liferay/tomcat/webapps/ROOT/html/portlet/blogs/view_entry.jsp es el que tiene los cambios, pero se ha creado un copia de seguridad del original llamado: view_entry.portal.jsp

Obtener datos de usuario desde jsp en Liferay

Para obtener el nombre del usuario o cualquier otro dato del mismo desde un portlet de Liferay y en concreto desde el jsp (view.jsp o cualquier otro), podemos hacer lo siguiente:
En view.jsp, ponemos

<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
…
<liferay-theme:defineObjects />

El defineObjects nos define un montón de variables java accesibles para nuestro código jsp, entre ellas una variable User de esta API. Podemos llamar a cualquiera de sus métodos para obtener cualquier dato que nos interese, por ejemplo, la dirección de correo

<%= user.getEmailAddress() %>

objetos definidos con liferay-theme:defineObjects

themeDisplay – com.liferay.portal.theme.ThemeDisplay
company – com.liferay.portal.model.Company
account – com.liferay.portal.model.Account (deprecated)
user – com.liferay.portal.model.User
realUser – com.liferay.portal.model.User
contact – com.liferay.portal.model.Contact
?layout – com.liferay.portal.model.Layout
?layouts – List
plid – java.lang.Long
?layoutTypePortlet – com.liferay.portal.model.LayoutTypePortlet
portletGroupId – java.lang.Long
permissionChecker – com.liferay.portal.security.permission.PermissionChecker
locale – java.util.Locale
timeZone – java.util.TimeZone
theme – com.liferay.portal.model.Theme
colorScheme – com.liferay.portal.model.ColorScheme
portletDisplay – com.liferay.portal.theme.PortletDisplay

Crear Portlet Liferay con Maven

Disponemos de 3 arquetipos Maven que nos permiten crear la estructura de portlet, temas y layouts, y un plugin de despliegue en Liferay.
Para crear un portlet
mvn archetype:create -DgroupId=info.prueba.portlet 
-DartifactId=maven-portlet 
-DarchetypeArtifactId=liferay-portlet-archetype 
-DarchetypeGroupId=com.liferay.maven.archetypes -DarchetypeVersion=6.1.1

(otra opción para ejecutar este comando es escribir:
mvn archetype:generate
nos saldrá un listado con los arquetipos posibles, pero si la lista es larga no veremos el que buscamos, podemos poner liferay-portlet-archetype y nos pondrá el número en el que aparece en la lista; ponemos este número; luego nos mostrará las versiones disponibles, y luego nos pedirá datos como el artifactId o groupId que deseamos; al finalizar crea el proyecto).

Algunos archetypes que podemos elegir:
liferay-ext-archetype (Provides an archetype to create Liferay exts.)
liferay-hook-archetype (Provides an archetype to create Liferay hooks.)
liferay-layouttpl-archetype (Provides an archetype to create Liferay layout templates.)
liferay-portlet-archetype (Provides an archetype to create Liferay portlets.)
liferay-servicebuilder-archetype (Provides an archetype to create Liferay Service Builder portlets.)
liferay-theme-archetype (Provides an archetype to create Liferay themes.)
liferay-web-archetype (Provides an archetype to create Liferay webs.)
appfuse-basic-jsf (AppFuse archetype for creating a web application with Hibernate, Spring and JSF)

en version ponemos la versión que deseamos (dependiendo de la versión de Liferay que utilicemos). Yo probé con la versión 6.0.5 y la estructura por defecto y el pom.xml que generaba era distinto.
Cuando he generado este proyecto con la versión 6.1.1, en el pom.xml no me aparecían las propiedades, y por tanto daba error en el pom y no dejaba ni compilar con maven. Para solucionarlo añadimos la propiedad liferay.version, ya que se usa para la versión (como vemos en el pom); hay otras propiedades que debemos configurar si se llegan a usar; en mi caso he configurado también la propiedad liferay.auto.deploy.dir, que es el path de despliegue de Liferay (por si ejecutamos el comando para desplegar en liferay).
El pom.xml quedaría más o menos:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.liferay.sample</groupId>
	<artifactId>sample-portlet</artifactId>
	<packaging>war</packaging>
	<name>sample-portlet Portlet</name>
	<version>1.0-SNAPSHOT</version>
	<build>
		<plugins>
			<plugin>
				<groupId>com.liferay.maven.plugins</groupId>
				<artifactId>liferay-maven-plugin</artifactId>
				<version>${liferay.version}</version>
				<configuration>
					<autoDeployDir>${liferay.auto.deploy.dir}</autoDeployDir>
					<!--
					appServerDeployDir>${liferay.app.server.deploy.dir}</appServerDeployDir>
						<appServerLibGlobalDir>${liferay.app.server.lib.global.dir}</appServerLibGlobalDir>
						<appServerPortalDir>${liferay.app.server.portal.dir}</appServerPortalDir>
						<liferayVersion>${liferay.version}</liferayVersion
					-->
					<pluginType>portlet</pluginType>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.5</version>
				<configuration>
					<encoding>UTF-8</encoding>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-resources-plugin</artifactId>
				<version>2.5</version>
				<configuration>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>com.liferay.portal</groupId>
			<artifactId>portal-service</artifactId>
			<version>${liferay.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.liferay.portal</groupId>
			<artifactId>util-bridges</artifactId>
			<version>${liferay.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.liferay.portal</groupId>
			<artifactId>util-taglib</artifactId>
			<version>${liferay.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.liferay.portal</groupId>
			<artifactId>util-java</artifactId>
			<version>${liferay.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.portlet</groupId>
			<artifactId>portlet-api</artifactId>
			<version>2.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.4</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<properties>
		<liferay.auto.deploy.dir>/home/usuario/devel/Liferay/bundles/liferay-portal-6.1.1-ce-ga2</liferay.auto.deploy.dir>
		<liferay.version>6.1.1</liferay.version>
	</properties>
</project>

(En configuration he comentado alguna parte que que las propiedades correspondientes no están creadas; en caso de ser necesario se crearán).

Ahora podemos importar este proyecto de portlet desde Eclipse (debemos tener el plugin de maven instalado en Eclipse). Vamos a File > Import > Existing maven projects y selecionamos la carpeta donde se creó el proyecto.

Podemos probar que se despliega el portlet ejecutando mvn -e clean package liferay:deploy

Ahora vamos a añadir al pom.xml las siguientes dependencias:

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc-portlet</artifactId>
	<version>3.0.4.RELEASE</version>
</dependency>
<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>jstl</artifactId>
	<version>1.2</version>
</dependency>
<dependency>
	<groupId>javax.portlet</groupId>
	<artifactId>portlet-api</artifactId>
	<version>2.0</version>
	<scope>provided</scope>
</dependency>

Hemos puesto provided a portlet-api porque la librería se usa para compilar, pero luego la proporciona el gestor de portales donde desplegamos.

Ejemplo ficheros de configuración de portlets en Liferay

portlet.xml

<portlet-name>hello-world</portlet-name>
<display-name>Hello World</display-name>
...
<portlet-info>
 <title>Hello World</title>
 <short-title>Hello World</short-title>
 <keywords>Hello World</keywords>
</portlet-info>

liferay-display.xml

Aquí podremos cambiar la categoría en la que se muestra nuestro portlet:

<display>
 <category name="My Portlets">
  <portlet id="hello-you" />
 </category>
</display>

liferay-portlet.xml

Aquí añadimos en la etiqueta liferay-portlet-app:

 <portlet>
  <portlet-name>hello-world</portlet-name>
  <icon>/icon.png</icon>
  <instanceable>false</instanceable>
  <header-portlet-css>/css/main.css</header-portlet-css>
  <footer-portlet-javascript>/js/main.js</footer-portlet-javascript>
  <css-class-wrapper>helloworld-portlet</css-class-wrapper>
 </portlet>

 

Eclipse + github + osX

Para poder utilizar Github desde Eclipse en OsX, seguimos los siguientes pasos:

  1. Creamos nuestra cuenta en github
  2. Añadir el plugin egit a Eclipse
  3. Crear una key ssh para comunicarnos con el servidor github (github utiliza una clave ssh para establecer una conexión segura).
    Ejecutamos ssh-keygen -t rsa -C “email_asociado_en_github”
    Nos pedirá un nombre con el que se guarda en el directorio .ssh de nuestro home; por defecto es id_rsa, pero si tenemos varios le ponemos otro nombre, por ejemplo github; el passphrase que nos pide, lo dejamos vacío. Ahora en el directorio indicado anteriormente, estarán creados los ficheros github y github.pub.
    Hacemos cat github.pub y copiamos el contenido; nos vamos a nuestra cuenta de github, en la sección ssh keys añadimos una nueva clave, le damos un nombre y pegamos el contenido de github.pub.
  4. Creamos en github un nuevo repositorio, y obtenemos su dirección ssh, que tiene la forma: git@github.com:nombreCuenta/nombreRepo.git
  5. Vamos a añadir en Eclipse la key de ssh creada; para ello vamos a Eclipse > Preferencias > General > Network Connections > SSH2 y nos aseguramos de tener la clave creada.
  6. En eclipse: File > Import > Git-Project from Git. En la siguiente ventana, URI, en la siguiente ventana de forma similar a la imagen:

Ahora que tenemos nuestro proyecto, pinchamos en el botón derecho sobre él y selecionamos Team > Share Project; elegimos GIT; ahora elegimos el repositorio asociado a nuestro proyecto.

    Temas en Liferay

    Para crear un tema desde línea de comandos, desde la carpeta themes dentro de los plugins:
    ./create.sh nombre “nombre del tema”
    Cuando se crea un tema, se suele hacer basándonos en las diferencias entre el diseño padre (especificado como propiedad en el build.xml) y nuestro tema. Por eso tenemos una carpeta llamada _diffs en nuestro proyecto.
    El tema padre puede ser _styled, _unstyled, classic… por ejemplo:

    por defecto al crear el tema, el theme.parent es _styled, pero podemos poner classic y luego hacer un ant compile.

    Ahora si hacemos ant compile, se añadirán todos los archivos necesarios a la estructura del proyecto a partir del tema padre.
    Las modificaciones debemos hacerlas dentro de _diffs; por ejemplo copiamos custom.css a  diffs/css/custom.css.

    Ficheros
    init_custom.vm > permite añadir variables velocity personalizadas.
    init.vm > en conjunción con VelocityVariables.java en Liferay, establece variables velocity que se correspondne con objetos Java Liferay.
    navigation.vm > implementa la página de navegación dentro del tema.
    portal_normal.vm > plantilla que define el esqueleto de nuestro portal. Podemos analizar este fichero
    portal_pop_up.vm > muestra los popups de liferay
    portlet.vm > muestra el contenido de un portlet y su marco para cada una de las vistas de un portlet (VIEW, EDIT, HELP).

    css por defecto
    application.css 
    base.css
    dockbar.css
    custom.css
    forms.css
    layout.css
    main.css
    navigation.css
    portlet.css

    en main.css tenemos los includes de los otros estilos; como veremos, el último es custom.css, por tanto los estilos que pongamos en custom.css se sobreescriben al resto. Ejemplo:
    copiamos custom.css y main.css a _diff/css; editamos custom.css y cambiamos en body el background a #000000; ahora al hacer deploy, el fondo de este nuevo estilo será negro.
    Nota: Si intentamos buscar en código el código #000000 seguramente no lo encontremos, ya que Liferay nos lo habrá cambiado a #000.

    Soporte multiidioma para portlets en Liferay

    Para hacer multiidioma el portlet, en la carpeta src del proyecto creamos una carpeta llamada content; dentro metemos un fichero llamado Language.properties; ahí ponemos los textos en el lenguaje por defecto.
    Por ejemplo:
    attention-delete=Atención, desea eliminar el registro?

    Ahora en el portlet.xml ponemos:

    <supported-locale>es</supported-locale>
    <supported-locale>en</supported-locale>
    ...
    <resource-bundle>content.Language</resource-bundle>

    En las vistas del portlet podemos usar esa propiedad:

     

    <%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
    ...
    <liferay-ui:message key="attention-delete" />

    Y el texto será sustituido por el del fichero.

    Podemos dar soporte a otros idiomas; por ejemplo, en la carpeta content anterior podemos añadir un fichero llamado Language_en.properties, con el texto:
    attention-delete=ATENTION!! Do you want remove the registry?

    Ahora si en la página donde está el portlet ponemos un portlet de idioma, y seleccionamos el inglés (en), ese texto lo tomará de este nuevo fichero, y por tanto estará en inglés.

    Crear todos la creación de estos ficheros podría hacerse de forma automática:
    en el build.xml, debajo del import, ponemos:

    <target name="build-lang">
    <antcall target="build-lang-cmd">
    <param name="lang.dir" value="docroot/WEB-INF/src/content" />
    <param name="lang.file" value="Language" />
    </antcall>
    </target>

    ahora invocamos la tarea ant build-lang y se generarán los ficheros automáticamente.