martes, 4 de octubre de 2011

Netbeans - Glassfish 3.1

Tras instalar Netbeans 7.0.1 que viene con la versión 3.1.1. de Glassfish, me era imposible lanzar Glassfish desde el IDE. Tras muchas pruebas con y sin sentido encontré un post relacionado con este mismo problema [1]. Adaptándo a lo que yo tengo encontré que en la configuración de Glassfish en el IDE. Tal como se describe en el post mencionado, en la pestaña services, opción servers, clic derecho sobre Glassfish Server 3.x, pestaña Java desmarcar Use IDE's proxy settings. Y el error dejó de aparecer!

java.lang.NoClassDefFoundError: 127/0/0/1*|
Caused by: java.lang.ClassNotFoundException: 127.0.0.1*|
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Could not find the main class: 127.0.0.1*|. Program will exit.

viernes, 26 de agosto de 2011

Impresión silenciosa

Estos días me tuve que enfrentar a una petición que en principio me pareció un tanto descabellada, pero que luego entendí. La petición era que una aplicación web lanzara una impresión en el computador cliente sin que el usuario interviniera en ello.

Si bien en una aplicación web pública sería cuando menos extraño que enviara impresiones sin control del usuario, en una aplicación web publicada en una intranet, es razonable querer hacerlo.

Así, llegué a

http://www.sanjbee.com/content/?p=96

La única nota que tengo es que no me funcionó la opción en la cual se agrega el código javascript directamente en el pdf, tuve que poner el archivo skdSilentPrint.js en la ruta mencionada.

viernes, 1 de abril de 2011

Autenticación con Glassfish

Agregando autenticación en base de datos para una aplicación web en Glassfish:

Es necesario crear al menos dos tablas. En una tendrá la información del usuario (nombre de usuario y contraseña), en la otra se tendrán los grupos a los que pertenece cada usuario (campos: nombre de usuario y nombre de grupo).

Si es una aplicación jee, hay que crear el acceso a la base de datos, creando los recursos jdbc necesarios (Eso no lo incluiremos aqui).

Como la autenticación será una tarea que realice el servidor de aplicaciones, entonces es necesario agregar en los descriptores de la aplicación, lo siguiente:
- web.xml

<security-constraint>
<display-name>protegido</display-name>
<web-resource-collection>
<web-resource-name>protegido</web-resource-name>
<url-pattern>/faces/protegido/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>HEAD</http-method>
<http-method>PUT</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>USERS</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>orclJNDI</realm-name>
<form-login-config>
<form-login-page>/faces/login.xhtml</form-login-page>
<form-error-page>/faces/login_error.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>USERS</role-name>
</security-role>


En la sección security-constraint, se agregan los recursos que se protegerán, y dentro se agregará el rol que tiene permiso en esos recursos.
En security-roles se definen los roles existentes en la aplicación.
En la sección login-config, se define el método de autenticación, y como en este caso el método es FORM, también se definen las páginas de login y de error durante el login. En este punto es importante recalcar sobre un detalle: el faces servlet de la aplicación se encarga de responder peticiones /faces/*. Por esta razón, aunque en la estructura de directorios login.xhtml está en la raíz del contenido web, en la configuración del login se debe agregar como /faces/login.xhtml, porque de lo contrario se encontrarán errores como que en IE intenta descargar el recurso en lugar de dibujarlo (render).

- Ahora la pregunta podría ser: hablamos de tablas para usuarios y para grupos, dónde se hablo de roles?. Pues bien, es una característica de glassfish. Entonces, en el archivo sun-web.xml, se agrega el mapping entre roles y grupos:

<security-role-mapping>
<role-name>USERS</role-name>
<group-name>USERS</group-name>
</security-role-mapping>


Pero el archivo de login, en este caso xhtml, debe cumplir con algunas características bastante conocidas, pero que vamos a especificar aqui:
* el action del formulario es el ya conocido
* el campo del usuario: j_username
* el campo de la contraseña: j_password

En el archivo
/glassfish/domains/domain1/config/login.conf
Se debe escribir la información respecto al LoginModule que se va a utilizar, asi:


myRealm {
com.sun.enterprise.security.auth.login.JDBCLoginModule required;
};

viernes, 18 de marzo de 2011

Acceder EJB desde un JSF custom converter

La utilización de converters de JSF tiene un buen par de sitios para entenderla:

http://download.oracle.com/docs/cd/B31017_01/web.1013/b28967/web_val006.htm

http://facestutorials.icefaces.org/tutorial/converter-tutorial.html

Pero y que pasa si en el método getAsObject necesito acceder a recursos persistentes? (típicamente una db). Bueno, mi aplicación tiene una capa para ello, y resulta ser un EJB. Entonces debería inyectar el EJB al converter....

Un momento. Si puedo inyectar un EJB en un converter?... No. La especificació dice: "Only beans declared to be in request, session, or application scope are eligble for resource injection."

Entonces, hagamos al converter un managed bean para poder inyectarle el recurso necesario. Algo como esto:


@ManagedBean
@ApplicationScoped
public class SomethingConverter implements Converter {
@ManagedProperty
private ElRecurso elrecurso;
...


Y para utilizarlo:


<h:outputText value="#{SomethingBean.something}" converter="#{somethingConverter}" />


No estoy seguro, pero no funciona registrando el converter en el faces-config.xml, hay que escribirlo en el componente.

La solución fue encontrada en:

http://stackoverflow.com/questions/3630403/how-do-i-access-ejb-bean-when-inside-a-custom-converter

j_id[numero]: Error de Validación: Valor no es correcto

Esta es mi plana del día. Me he encontrado con este error en más de una ocasión mientras uso converters en jsf. Ninguna de las veces que me he encontrado este error he podido resolverlo sin una búsqueda en google. Por esto, esta plana debo hacerla para procurar recordarlo.

La clase para la cual se ha creado el converter *debe* implementar el método equals en una forma similar a la que se encuentra a continuación:


public boolean equals(Object obj) {
if (!(obj instanceof Cargo)){
return false;
}
Cargo el = (Cargo) obj;
return this.getId() == el.getId();
}


Sigamos con el código!

martes, 15 de marzo de 2011

line break en campo jasper

Intentando que el resultado de un campo en jasper tuviera formato (insertar un line break), tuve algunos problemas.

Tras encontrar la propiedad markup en ireport, pensé que mis problemas habían terminado, pero tuve que realizar varias pruebas, hasta que encontré este post:

http://jasperforge.org/plugins/espforum/view.php?group_id=102&forumid=103&topicid=38941

Donde se vé que seleccionando como markup "styled" en valores que utilizan
como line break, el reporte formatea bien el campo.

Jasper, ireport, crosstab

Intentando hacerme a la costumbre de escribir lo que me pasa (siempre le puede servir a alguien), hoy voy a resumir un problema que tuve escribiendo un reporte con jasper.

Creando un reporte tuve que utilizar una tabla para mostrar el detalle de un java bean que usé como datasource. El datasource tenía los resultados en un list.

El componente table muestra el listado con una línea por cada elemento de la lista. En muchos casos, el bean podría considerarse el maestro y el listado los detalles, lo que haría que este comportamiento fuera el necesitado. En mi caso, aunque correcto el concepto de maestro con sus detalles, los detalles se deben mostrar como columnas, es decir, los resultados deben mostrarse traspuestos. Para esto, está el componente crosstab de jasper.

Configurando el componente utilizando ireport, es obligatorio seleccionar alguno de los valores de los objetos del list como agrupador por fila, y otro por columna. Mi caso, no requiere y no tiene agrupación por fila, pero ireport no me permite dejar este ítem sin seleccionar.

Entonces, recordé que ireport no es más que una interfaz para jrxml, y decidí dejar (por un rato) la comodidad de ireport y ver el código del jrxml para ver cómo puedo resolver mi problema.

Así encontré que las secciones de interés de mi reporte son éstas:

1. Aqui se define el dataset para la tabla

<subDataset name="Table Dataset 1">
<field name="nombrePrueba" class="java.lang.String">
<fieldDescription><![CDATA[nombrePrueba]]></fieldDescription>
</field>
<field name="valorResultado" class="java.math.BigDecimal">
<fieldDescription><![CDATA[valorResultado]]></fieldDescription>
</field>
</subDataset>


2. Aqui, se crea la tabla, donde puntajesList es el listado de objetos que tienen la estructura definida en 1, es decir, un atributo String y uno BigDecimal:


<crosstabDataset>
<dataset>
<datasetRun subDataset="Table Dataset 1">
<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{puntajesList})]]></dataSourceExpression>
</datasetRun>
</dataset>
</crosstabDataset>


3. Como el componente crosstab debe tener una agrupación tanto por fila como por columna, entonces, el grupo por fila (el que no necesito) lo edito para que quede:


<rowGroup name="valorResultado" width="5">
<bucket>
<bucketExpression class="java.lang.String"><![CDATA[]]></bucketExpression>
</bucket>
....


Así, el componente crosstab aún tiene una agrupación por fila, pero la agrupación no existe.

Este es solo un workaround cuando se sabe que los resultados del crosstab solo tendrán una fila.