Como controlar el acceso a las paginas?
Como cambiar la clave de un usuario? passwordfield
Como agregar un combo a una pagina?
Como hacer reportes en diferentes formatos?
Como hacer formularios multi pagina? wizardpage pero pensar una sola pagina con dhtml
Para implementar el login, creamos una pagina de nombre Login que usara el componente kayestry:Login. La definicion de la pagina tendria:
<component id="login" type="kayestry:Login"> <binding name="delegate" expression="beans.delegate"/> </component>
Para realizar el logout, se usa la pagina kayestry:Logout.
El control de acceso se realiza solo sobre las paginas de la aplicacion. Este metodo tiene la desventaja de no poder controlar el acceso sobre el resto de los recursos de la aplicacion que pueden accederse por un url, como imagenes, css, js, etc.
Para usar este control de acceso, las paginas deben implementar alguna interfaz que extienda SecurePage (tambien deben heredar de KayaBasePage, pero todas las paginas de la aplicacion ya deberian hacerlo!). Para mas informacion sobre diferentes escenarios del control de acceso, leer KayaBasePage.validate(PageEvent) y PageAccess.
Dependendiendo de la interfaz que implemente la pagina, es el metodo de autenticacion a ser usado. Ahora vamos seguir un ejemplo de agregar el control de acceso a una pagina usando BeanSecurePage.
BeanSecurePage toma los roles permitidos desde un bean definido en la definicion de la pagina. Agregamos en el .page el bean:
<bean name="allowedRoles" class="sf.net.kayestry.pages.access.AccessBean"> <set-property name="roles" expression="{'admin'}"/> </bean>
Luego hacemos que la pagina implemente la interfaz (en este caso no hay que implementar ningun metodo) y eso es todo.
Hay dos tipos de redirecciones posibles, uno es enviando al usuario una respuesta http, lo que hace que se produzca un nuevo pedido y cambie el url. Y otro es una redireccion interna, haciendo que se invoque otra pagina pero manteniendo el mismo url. Por ejemplo, en el caso de usar la respuesta http para redireccionar, realizo un pedido a htttp://ejemplo.org/Page1 y el servidor me devuelve un nuevo url, http://ejemplo.org/Page2. El browser tiene que realizar otro pedido al nuevo url. En el otro caso, hago un pedido a http://ejemplo.org/Page1, la clase de Page1 redirecciona internamente a Page2 y me devuelve el contenido de esta ultima, como si fuera el contenido del primer url.
En Tapestry, para la primera redireccion (usando la redireccion http) se usa una RedirectException. Se puede usar el wrapper que hay en TapestryUtils para simplificar esto.
Para realizar la segunda redireccion solo hace falta usar una PageRedirectException.
Para agregar las paginas de listados y abm de una entidad, si seguimos con las convenciones especificadas en Nombres de las entidades, debemos seguir los pasos siguientes:
Suponiendo que la entidad para la que queremos crear el crud es X y el paquete de la aplicacion es ar.com.ejemplo
package ar.com.ejemplo.pages; import ar.com.ejemplo.model.X; ... public class XCRUD extends AbstractCRUD<X> { ... public void initialize() { setModelObject(new X()); super.initialize(); } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE page-specification PUBLIC "-//Apache Software Foundation//Tapestry Specification 3.0//EN" "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd"> <page-specification class="ar.com.ejemplo.pages.XCRUD"> <description> Listado de X </description> <bean name="delegate" class="org.apache.tapestry.valid.ValidationDelegate"/> <component id="border" type="Border"> <binding name="delegate" expression="beans.delegate"/> <static-binding name="pageTitle" value="Listado de X"/> </component> <component id="form" type="Form"> <binding name="listener" expression="listeners.removeObjects"/> </component> <component id="botones" type="kayestry:BrowseButtons"> <static-binding name="CRUDPage" value="XCRUD"/> </component> <component id="checkbox" type="Checkbox"> <binding name="selected" expression="modelObjectSelected"/> </component> <component id="editLink" type="ActionLink"> <binding name="listener" expression="listeners.editObject"/> </component> <bean name="evenOdd" class="org.apache.tapestry.bean.EvenOdd"/> <component id="table" type="contrib:Table"> <binding name="source" expression="dataPage"/> <static-binding name="columns" value="!checkbox, !editLink, COLUMNAS"/> <binding name="rowsClass" expression="beans.evenOdd.next"/> <binding name="pageSize" expression="25"/> <binding name="row" expression="currentModelObject"/> </component> <context-asset name="editAsset" path="images/page_edit.png"/> <component id="imgEdit" type="Image"> <binding name="image" expression="assets.editAsset"/> </component> </page-specification>
Y el .html seria WEB-INF/pages/crud/XBrowse.html:
<html> <head></head> <body jwcid="$content$"> <span jwcid="border"> <div id="contenu"> <form jwcid="form"> <span jwcid="botones"/> <table class="browsetable" jwcid="table"> <span jwcid="checkboxColumnHeader@Block"></span> <span jwcid="checkboxColumnValue@Block"><span jwcid="checkbox"/></span> <span jwcid="editLinkColumnHeader@Block"></span> <span jwcid="editLinkColumnValue@Block"><a jwcid="editLink"><span jwcid="imgEdit"> [editar]</span></a></span> </table> </form> </div> </span> </body> </html>
Reemplazar X por la clase de la entidad y COLUMNAS por los nombres de las columnas a mostrar en la tabla.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE page-specification PUBLIC "-//Apache Software Foundation//Tapestry Specification 3.0//EN" "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd"> <page-specification class="sf.net.kayestry.example.pages.XCRUD"> <bean name="delegate" class="org.apache.tapestry.valid.ValidationDelegate"/> <component id="border" type="Border"> <binding name="delegate" expression="beans.delegate"/> <static-binding name="pageTitle" value="X"/> <binding name="withMenu" expression="true"/> </component> <component id="CRUDForm" type="Form"> <binding name="listener" expression="listeners.saveObject"/> <binding name="delegate" expression="beans.delegate"/> </component> <component id="id" type="Hidden"> <binding name="value" expression="modelObject.id"/> </component> <component id="description" type="ValidField"> <binding name="value" expression="modelObject.description"/> <static-binding name="class" value="input-text"/> <binding name="validator" expression="beans.descValidator"/> <static-binding name="displayName" value="Descripcion"/> </component> <!-- ********* Botones para guardar / cancelar ***** --> <component id="CrudMenu" type="kayestry:CRUDButtons"> <static-binding name="returningPage" value="XBrowse"/> </component> <!-- ********* VALIDATORS ***** --> <bean name="descValidator" class="org.apache.tapestry.valid.StringValidator"> <set-property name="clientScriptingEnabled" expression="true"/> <set-property name="required" expression="true"/> <set-property name="minimumLength" expression="4"/> </bean> </page-specification>
Y el .html en WEB-INF/pages/crud/XCRUD.html:
<html> <head></head> <body jwcid="$content$"> <span jwcid="border"> <div id="contenu"> <form jwcid="form"> <span jwcid="botones"/> <table class="browsetable" jwcid="table"> <span jwcid="checkboxColumnHeader@Block"></span> <span jwcid="checkboxColumnValue@Block"><span jwcid="checkbox"/></span> <span jwcid="editLinkColumnHeader@Block"></span> <span jwcid="editLinkColumnValue@Block"><a jwcid="editLink"><span jwcid="imgEdit"> [editar]</span></a></span> </table> </form> </div> </span> </body> </html>
En el codigo de arriba se crea una pagina donde solo hay un campo con nombre description. Modificarlo de acuerdo a los atributos de la entidad a editar.
<page name="XBrowse" specification-path="pages/crud/XBrowse.page"/> <page name="XCRUD" specification-path="pages/crud/XCRUD.page"/>
Una forma mas sencilla de utilizar el componente de Tapestry PropertySelection es utilizar Combo. El componente acepta una lista de elementos o una enumeracion y a partir de eso crea el combo html.
Por ejemplo, queremos crear un combo con una lista de sistemas operativos. En la clase de la pagina tenemos un metodo que devuelve la lista:
public List<OS> getOsList() { // obtenemos la lista de algun lado. }
En la pagina agregamos el componente del combo:
<component id="select" type="kayestry:Combo"> <binding name="model" expression="osList"/> <binding name="value" expression="selected"/> </component>
El parametro value es donde setear la opcion que elegio el usuario. Tambien podriamos llamar a un metodo de cierto facade directamente con:
<binding name="model" expression="@ar.com.ejemplo.Application@getService().osFacade.osList"/>
Y en el html lo usamos:
<select jwcid="select"></select>
Para ver que id y etiqueta se usa para cada opcion leer la documentacion de Combo.
En el paquete sf.net.kayestry.reports hay varias clases para manejar reportes, asi como tambien un service de Tapestry para hacer download de los reportes generados. Las clases mencionadas antes son un wrapper a JasperReports.
La forma de usar reportes seria la siguiente:
<service name="reports" class="sf.net.kayestry.reports.ReportService"/>
Luego podemos acceder al servicio como cualquier servicio de Tapestry, por ejemplo usando una redireccion dentro de una pagina o usando un ServiceLink. Los parametros que hay que enviar estan definidos en la documentacion de ReportService.
TODO: falta documentar ->crear facade para reportes TODO: falta documentar ->agregarlo al service