Dynamic Schema Processor con Pentaho y Saiku
Category : Noticias
Los cubos OLAP de Mondrian permiten incorporar la definición del control de acceso al dato en función de una serie de parámetros cómo puede ser el usuario de la sesión, sus roles o cualquier otro parámetro que consideremos oportuno.Saiku
Para definir los permisos de acceso a los datos existen los Roles de mondrian que se pueden definir según las especificaciones y que son un trozo de código xml que se incluye en el archivo de schema ( schema.mondrian.xml ) y que acostumbra a tener este aspecto:
<Role name=»Mi Rol»>
<SchemaGrant access=»none»>
<CubeGrant cube=»Mi Cubo» access=»all»>
<HierarchyGrant hierarchy=»[Area]» access=»custom» rollupPolicy=»partial»>
<MemberGrant member=»[Area Comercial].[EXP]» access=»all»/>
<MemberGrant member=»[Area Comercial].[HOR]» access=»none»/>
<MemberGrant member=»[Area Comercial].[ALI]» access=»none»/>
</HierarchyGrant>
</CubeGrant>
</SchemaGrant>
</Role>
Y es una solución muy buena. Pero poco flexible porque, ¿ Que pasa cuando se define un nuevo rol ? Pues que tenemos que coger el archivo schema.mondidrian.xml que hay en nuestro servidor, editarlo, añadir el nuevo rol y su visibilitad y volverlo a subir al servidor…. Fácil… Si esto ocurre una vez cada dos o tres años, pero si los roles cambian diariamente, semanalmente, mensualmente…. es una tarea de mantenimiento inasequible.
Para solucionar este problema está el Dynamic Schema Processor cuya idea base es: Definamos una clase java que processará el schema en el momento de ejecución, cuando el usuario se conecte a los cubos OLAP y que lo modificará dinamicamente según nuestros intereses. Reduciéndolo a un ejemplo muy simple. Se trata de definir una clase Java que coja el archivo xml del schema y que inyecte, donde nosotros le digamos, la definición de los roles o lo que a nosotros no dé la gana. Eso lo hará dinámicamente para cada sesión por lo que tendremos un schema dinámicos según el usuario y su sesión.
Me interesa! ¿Qué debemos hacer para tener esto?
Primero de todo… definamos el entorno de trabajo: Por un lado Pentaho BA Server en su versión CE + Saiku . Por otro lado, tu IDE favorito, en mi caso Eclipse.
1. Nos aseguraremos que Pentaho pasa los roles a mondrian.
En según que versiones no lo hace ( anteriores a la 5 creo ) por lo que es bueno asegurarse. Además, la forma en cómo se mapea la información puede variar.
Así que editaremos el archivo ${biserver-ce}/pentaho-solutions/system/pentahoObjects.spring.xml y nos fijaremos en el bean Mondrian-UserRoleMapper. Es el bean que mapea los objetos de sesión con los roles que se le pasan a mondrian. Para pasarle los roles de la sesión de usuario a mondrian deberíamos tener habilitado el tag:
<bean id=»Mondrian-UserRoleMapper»
name=»Mondrian-One-To-One-UserRoleMapper»
class=»org.pentaho.platform.plugin.action.mondrian.mapper.MondrianOneToOneUserRoleListMapper»
scope=»singleton» />
Si yo soy el usuario pepito y tengo los roles HOR y EXP ahora mondrian reccibirá esos roles y me dejará ver lo que me toca.
Pero por ejemplo, puedo querer roles más personalizados y ligados al usuario… para eso deberemos comentar el tag anterior y habilitar:
<bean id=»Mondrian-UserRoleMapper»
name=»Mondrian-SampleUserSession-UserRoleMapper»
class=»org.pentaho.platform.plugin.action.mondrian.mapper.MondrianUserSessionUserRoleListMapper»
scope=»singleton»>
<property name=»sessionProperty» value=»MondrianUserRoles» />
</bean>
2. Definamos nuestro schema mondrian.
Asumo que ya sabes definir un schema de mondrian por lo que aqui sólo me voy a referir a la parte que nos toca… definir los sitios donde inyectaremos los roles. Para eso tenemos varias opciones. La primera opción es definir el schema con normalidad y definir los roles dinámicamente. Para tal caso, lo que haremos será añadir un tag que nos permitirá inyectar los roles después… Algo parecido a esto:
bla bla bla
<Measure name=»mi_medida» column=»mi_columna» aggregator=»sum» visible=»false» />
<CalculatedMember name=»YTD» formula=»sum(YTD([Tiempo].[Dia].CurrentMember), [Measures].[mi_medidad])» dimension=»Measures» />
</Cube>
%MIS_ROLES_VAN_AQUI%
</Schema>
Con lo que ya tengo la etiqueta %MIS_ROLES_VAN_AQUI% que usará mi clase java para inyectar los roles que haya generado dinamicamente.
3. Definimos nuestra clase Java.
Tenemos varias opciones, pero la mayoría se basan en extender la clase FilterDynamicSchemaProcessor o LocalizingDynamicSchemaProcessor al final todo es lo mismo, implementar una clase que se ejecutará en el momento de cargar el schema y que lo modificará según nuestros intereses. Os pongo un ejemplo muy simple de FilterDynamicSchemaProcessor
package com.jortilles.mondrian.dsp; import java.io.InputStream, mondrian.olap.Util; import mondrian.spi.DynamicSchemaProcessor; import mondrian.spi.impl.FilterDynamicSchemaProcessor; public class VSDSP extends FilterDynamicSchemaProcessor {
@Override protected String filter(final String schemaUrl, final Util.PropertyList connectInfo, final InputStream stream) throws java.lang.Exception { String originalSchema = super.filter(schemaUrl, connectInfo, stream); String mis_roles = "<Role name=\"Mi Rol\"> <SchemaGrant access=\"none\"><CubeGrant cube=\"Mi Cubo\" access=\"all\"><HierarchyGrant hierarchy=\"[Area]\" access=\"custom\" rollupPolicy=\"partial\"><MemberGrant member=\"[Area Comercial].[EXP]\" access=\"all\"/> <MemberGrant member=\"[Area Comercial].[HOR]\" access=\"none\"/></HierarchyGrant></CubeGrant></SchemaGrant></Role>" ; String modifiedSchema = originalSchema.replace("%MIS_ROLES_VAN_AQUI%",mis_roles); return modifiedSchema; } }
A partir de aqui las posibilidades son infinitas….
4. Usemos nuestra clase Saiku
Una vez compilada y empaquetada (si queremos) debemos ponerla en un sitio accesible. Tipicamente ${biserver-ce}/tomcat/webapps/pentaho/WEB-INF/lib o ${biserver-ce}/tomcat/webapps/pentaho/WEB-INF/classes si no la hemos empaquetado.
NOTA MUY MUY MUY IMPORTANTE: para las versiones 5 y 6 de pentaho, si queremos usar nuestro dynamic schema proccesor con Saiku, debemos ponerlo tambien en el directorio lib de saku…. ${biserver-ce}/pentaho-solutions/system/saiku/lib/ Si no os dará un problema de que no puede hacer el cast de la clase a dynamic schema processor.
Una vez que tenemos nuestra clase en su sitio, debemos modificar la conexión de mondrian para que la use, para eso añadiremos los parámetros
DynamicSchemaProcessor para indicar nuestra clase, UseContentChecksum=true para que revise siempre si debe volver a generar el schema y JdbcConnectionUuid=MI_DS para identificar la conexion. Más información en la documentación
Con esto ya tenemos nuestro Dynamic Schema Processor definido y listo para funcionar con Pentaho y Saiku
P.D.: No estoy descubriendo la rueda, hay mucha información ahí fuera relativa a este punto, pero quería tener una guía fiable y conocida.