Tapestry Components for Web 2.0

55
1 Tapestry Components for Web 2.0 Howard Lewis Ship TWD Consulting, Inc. [email protected]

description

Tapestry Components for Web 2.0. Howard Lewis Ship TWD Consulting, Inc. [email protected]. What is Tapestry?. Application. Page. Page. Component. Component. Component. Component. Component. Component. Controller. View. Model. Java Beans. HTML template. Dynamic HTML output. - PowerPoint PPT Presentation

Transcript of Tapestry Components for Web 2.0

Page 1: Tapestry Components for Web 2.0

1

Tapestry Components for Web 2.0

Howard Lewis Ship

TWD Consulting, Inc.

[email protected]

Page 2: Tapestry Components for Web 2.0

2

What is Tapestry?

Application

PagePage

ComponentComponent ComponentComponent

ComponentComponent

Page 3: Tapestry Components for Web 2.0

3

Controller

ModelView

HTML template Java Beans

Dynamic HTML output

Links / Form Submissions

Page 4: Tapestry Components for Web 2.0

4

Login Form

Page 5: Tapestry Components for Web 2.0

5

Border.html<div jwcid="loginDialog"> <div class="dialog"> <form jwcid="form"> <p> Enter your email address and password to log in. </p> <span jwcid="errors@Errors"/> <label jwcid="@FieldLabel" field="component:email"/> <input jwcid="email" size="30"/> <label jwcid="@FieldLabel" field="component:password"/> <input jwcid="password" size="30"/> <input type="submit" value="Login"/> <input jwcid="@Cancel" ajax="true"/> </form> <p> Not registered yet? <a jwcid="register2"> Click here to setup an account</a>. </p> </div></div>

Page 6: Tapestry Components for Web 2.0

6

Border.html

Placeholder for tacos:Dialog component Dialogs are invisible until un-hidden Active dialogs mask the rest of the page

<div jwcid="loginDialog">

. . .

</div>

Page 7: Tapestry Components for Web 2.0

7

Border.jwc

Dialog visibility from dialogHidden property of page

Login link: Set dialogHidden to false Re-render just the loginDialog

<component id="loginDialog" type="tacos:Dialog"> <binding name="hidden" value="dialogHidden"/></component>

Page 8: Tapestry Components for Web 2.0

8

Border.jwc

Invoke the listener method Re-render just the loginDialog component

<component id="login" type="tacos:AjaxDirectLink"> <binding name="listener" value="listener:doShowLogin"/> <binding name="updateComponents" value="{ 'loginDialog' }"/></component>

Page 9: Tapestry Components for Web 2.0

9

Form component

Tapestry forms are inside a Form component: Unique names & ids for fields (even inside loops) Tracking of user input and errors Handling submit, refresh & cancel AjaxForm: Partial page refreshes

<form jwcid="form"> . . .</form>

Page 10: Tapestry Components for Web 2.0

10

Form Component

listener: Name of listener method to invoke delegate Object that tracks user input and

errors

<component id="form" type="tacos:AjaxForm"> <binding name="updateComponents" value="{ 'errors' }"/> <binding name="success" value="listener:doLogin"/> <binding name="cancel" value="listener:doCancel"/> <binding name="delegate" value="delegate"/></component>

Page 11: Tapestry Components for Web 2.0

11

OGNL

Object Graph Navigation Language Expression language used by Tapestry ognl: prefix when used in HTML template No prefix when used in XML file

Page 12: Tapestry Components for Web 2.0

12

OGNL

Simple: property namesdelegate getDelegate(),

setDelegate() Complex: property paths

poll.title getPoll().getTitle(), getPoll().setTitle()

Much more!

Page 13: Tapestry Components for Web 2.0

13

TextField Component

@FieldLabel anonymous component of type FieldLabel Nothing in the Login.page file

component:email reference to email component

<label jwcid="@FieldLabel" field="component:email"/>:<input jwcid="email" size="30"/>

Page 14: Tapestry Components for Web 2.0

14

TextField Component

value property to read and update validators validations to perform displayName Used in error messages, and

by FieldLabel

<component id="email" type="TextField"> <binding name="value" value="email"/> <binding name="validators" value="validators:required"/> <binding name="displayName" value="message:email-label"/></component>

Page 15: Tapestry Components for Web 2.0

15

Password TextField

<component id="password" type="TextField"> <binding name="value" value="password"/> <binding name="validators" value="validators:required"/> <binding name="displayName" value="message:password-label"/> <binding name="hidden" value="true"/></component>

Page 16: Tapestry Components for Web 2.0

16

Register Link

literal: value is just a string, not an OGNL expression

<p>Not registered yet? <a jwcid="register">Click here to setup an account</a>. </p>

<component id="register" type="PageLink"> <binding name="page" value="literal:Register"/> </component>

Page 17: Tapestry Components for Web 2.0

17

Java Classpublic abstract class Border extends BaseComponent{

public abstract String getEmail();

public abstract String getPassword();

. . .

Page 18: Tapestry Components for Web 2.0

18

Abstract?

Pages are stateful Hold transient data during request Hold persistent data between requests

Pages are expensive to create Pages are pooled

Like database connections

Page 19: Tapestry Components for Web 2.0

19

No, Really, Abstract?

Tapestry extends abstract class Adds getter, setter, instance variables Adds end-of-request cleanup Lots of injections based on getters and

annotations (or XML)

Page 20: Tapestry Components for Web 2.0

20

Embedded Components

Injected CodeApplication

Code

Inherited Code

Page Behavior

Page 21: Tapestry Components for Web 2.0

21

Java Class

getEmail() & setEmail() getPassword() & setPassword()

public abstract class Border extends BaseComponent{

public abstract String getEmail();

public abstract String getPassword();

. . .

Page 22: Tapestry Components for Web 2.0

22

Listener Methods

Public method Changes server side state Form will re-render

public void doCancel(){ getLoginDialog().hide();}

Page 23: Tapestry Components for Web 2.0

23

Injecting Services

Service defined in HiveMind IoC Container Can inject Spring beans as easily Keep business logic out of pages / components

@InjectObject("service:epluribus.LoginAuthenticator")public abstract LoginAuthenticator getAuthenticator();

public interface LoginAuthenticator{ User authenticateCredentials(String email, String plaintextPassword);}

Page 24: Tapestry Components for Web 2.0

24

Listener Methodspublic String doLogin() { String email = getEmail(); String password = getPassword();

User user = getAuthenticator().authenticateCredentials( email, password);

. . .

Page 25: Tapestry Components for Web 2.0

25

Listener Methods . . .

if (user == null) { getDelegate().record(null, "Invalid user name or password."); return null; }

getIdentity().login(user);

getLoginDialog().hide();}

Page 26: Tapestry Components for Web 2.0

26

Server Side State: ASO

Application State Objects Global to all pages Stored in HttpSession Created on demand Defined in HiveMind Injected into pages or components

@InjectState("identity")public abstract Identity getIdentity();

Page 27: Tapestry Components for Web 2.0

27

Identity ASO

public class Identity implements Serializable { . . .

public boolean isLoggedIn() { . . . }

public void login(User user) { . . . } public void logout() { . . . }

public User getUser() { . . . }}

Page 28: Tapestry Components for Web 2.0

28

Loops, Tables and Actions

Page 29: Tapestry Components for Web 2.0

29

Home.html

<table class="data-grid" cellspacing="0" jwcid="polls"/>

<div jwcid="pollingEndColumnValue@Block"><span jwcid="@InsertDate" date="ognl:poll.pollingEnd"/></div>

<div jwcid="statusColumnValue@Block"><span jwcid="@Insert" value="ognl:responseCount"/><a jwcid="respond">Respond</a></div>

Page 30: Tapestry Components for Web 2.0

30

Home.page

<property name="rowIndex"/>

<component id="polls" type="contrib:Table"> <binding name="source" value="polls"/> <binding name="columns" value="message:table-columns"/> <binding name="row" value="poll"/> <binding name="index" value="rowIndex"/> <binding name="rowsClass"> rowIndex == 0 ? "first" : null </binding> </component>

Page 31: Tapestry Components for Web 2.0

31

Home.page

Defines a new property on page Alternately: create abstract property

<property name="rowIndex"/>

<component id="polls" type="contrib:Table"> <binding name="source" value="polls"/> <binding name="columns" value="message:table-columns"/> <binding name="row" value="poll"/> <binding name="index" value="rowIndex"/> <binding name="rowsClass"> rowIndex == 0 ? "first" : null </binding> </component>

Page 32: Tapestry Components for Web 2.0

32

Home.page

contrib: is name of tapestry-contrib.jar library

<property name="rowIndex"/>

<component id="polls" type="contrib:Table"> <binding name="source" value="polls"/> <binding name="columns" value="message:table-columns"/> <binding name="row" value="poll"/> <binding name="index" value="rowIndex"/> <binding name="rowsClass"> rowIndex == 0 ? "first" : null </binding> </component>

Page 33: Tapestry Components for Web 2.0

33

Home.page

source total list of Poll objects

<property name="rowIndex"/>

<component id="polls" type="contrib:Table"> <binding name="source" value="polls"/> <binding name="columns" value="message:table-columns"/> <binding name="row" value="poll"/> <binding name="index" value="rowIndex"/> <binding name="rowsClass"> rowIndex == 0 ? "first" : null </binding> </component>

Page 34: Tapestry Components for Web 2.0

34

Home.page

<property name="rowIndex"/>

<component id="polls" type="contrib:Table"> <binding name="source" value="polls"/> <binding name="columns" value="message:table-columns"/> <binding name="row" value="poll"/> <binding name="index" value="rowIndex"/> <binding name="rowsClass"> rowIndex == 0 ? "first" : null </binding> </component>

columns how to break a Poll object into columns

Page 35: Tapestry Components for Web 2.0

35

Home.properties

column-id : title : OGNL expression poll.title poll.questionCount null calculated elsewhere

!status status is not sortable

table-columns=\ title:Title:title, \ questions:Questions:questionCount, \ pollingEnd:End of Polling:pollingEnd, \ !status:Status:null

Page 36: Tapestry Components for Web 2.0

36

Home.page

<property name="rowIndex"/>

<component id="polls" type="contrib:Table"> <binding name="source" value="polls"/> <binding name="columns" value="message:table-columns"/> <binding name="row" value="poll"/> <binding name="index" value="rowIndex"/> <binding name="rowsClass"> rowIndex == 0 ? "first" : null </binding> </component>

row Property to update with each rendered row (each Poll)

Page 37: Tapestry Components for Web 2.0

37

Home.page

<property name="rowIndex"/>

<component id="polls" type="contrib:Table"> <binding name="source" value="polls"/> <binding name="columns" value="message:table-columns"/> <binding name="row" value="poll"/> <binding name="index" value="rowIndex"/> <binding name="rowsClass"> rowIndex == 0 ? "first" : null </binding> </component>

index Stores index into row (used to set row CSS class)

Page 38: Tapestry Components for Web 2.0

38

Home.page

<property name="rowIndex"/>

<component id="polls" type="contrib:Table"> <binding name="source" value="polls"/> <binding name="columns" value="message:table-columns"/> <binding name="row" value="poll"/> <binding name="index" value="rowIndex"/> <binding name="rowsClass"> rowIndex == 0 ? "first" : null </binding> </component>

rowsClass CSS class value for the <tr> Identify first row to change its formatting

Page 39: Tapestry Components for Web 2.0

39

Home.html

<table class="data-grid" cellspacing="0" jwcid="polls"/>

<div jwcid="pollingEndColumnValue@Block"><span jwcid="@InsertDate" date="ognl:poll.pollingEnd"/></div>

<div jwcid="statusColumnValue@Block"><span jwcid="@Insert" value="ognl:responseCount"/><a jwcid="respond">Respond</a></div>

Page 40: Tapestry Components for Web 2.0

40

Home.html

<table class="data-grid" cellspacing="0" jwcid="polls"/>

<div jwcid="pollingEndColumnValue@Block"><span jwcid="@InsertDate" date="ognl:poll.pollingEnd"/></div>

<div jwcid="statusColumnValue@Block"><span jwcid="@Insert" value="ognl:responseCount"/><a jwcid="respond">Respond</a></div>

Page 41: Tapestry Components for Web 2.0

41

Home.page

DirectLink invokes a listener method when clicked

Can pass parameters into the listener method

<component id="respond" type="DirectLink"> <binding name="listener" value="listener:doRespond"/> <binding name="parameters" value="poll.id"/></component>

Page 42: Tapestry Components for Web 2.0

42

Home.java

Parameters show up … with proper type (not just String)

@InjectPage("RespondToPoll")public abstract RespondToPoll getRespondToPoll();

public void doRespond(long pollId) { Poll poll = getPollAccess().getPoll(pollId);

// TODO: A few checks, i.e., Poll is active getRespondToPoll().activate(poll);}

Page 43: Tapestry Components for Web 2.0

43

Creating New Components

Page 44: Tapestry Components for Web 2.0

44

FCKEditor

"the text editor for the Internet" Open Source http://www.fckeditor.net/

Page 45: Tapestry Components for Web 2.0

45

FCKEditor

Primarily a JavaScript library: FCKeditor/fckeditor.js

Goal: Component to take place of TextArea

Page 46: Tapestry Components for Web 2.0

46

FCKEditor Component

FCKEditor.jwc Copy of TextArea.jwc FCKEditor extends TextArea

Page 47: Tapestry Components for Web 2.0

47

FCKEditor.javaprotected void renderFormComponent(IMarkupWriter writer, IRequestCycle cycle){ super.renderFormComponent(writer, cycle);

// Now, we want to work with the script.

PageRenderSupport support = TapestryUtils.getPageRenderSupport(cycle, this);

support.addExternalScript(getEditorScript().getResourceLocation());

String contextPath = getRequest().getContextPath();

String id = getClientId();

String clientObject = "editor_" + id;

StringBuffer buffer = new StringBuffer();

buffer.append(String.format("var %s = new FCKeditor('%s');\n", clientObject, id)); buffer.append(String.format("%s.BasePath = '%s/FCKeditor/';\n", clientObject, contextPath)); buffer.append(String.format("%s.ReplaceTextarea();\n", clientObject));

support.addInitializationScript(buffer.toString());}

Page 48: Tapestry Components for Web 2.0

48

FCKEditor.java

super.renderFormComponent(writer, cycle);

PageRenderSupport support = TapestryUtils.getPageRenderSupport(cycle, this);

support.addExternalScript( getEditorScript().getResourceLocation());

@Asset("context:FCKeditor/fckeditor.js")public abstract IAsset getEditorScript();

Page 49: Tapestry Components for Web 2.0

49

FCKEditor.java

String contextPath = getRequest().getContextPath();

String id = getClientId();

String clientObject = "editor_" + id;

Page 50: Tapestry Components for Web 2.0

50

FCKEditor.java

StringBuffer buffer = new StringBuffer();

buffer.append(String.format("var %s = new FCKeditor('%s');\n", clientObject, id));

buffer.append(String.format("%s.BasePath = '%s/FCKeditor/';\n", clientObject, contextPath));

buffer.append(String.format("%s.ReplaceTextarea();\n",

clientObject));

support.addInitializationScript(buffer.toString());

Page 51: Tapestry Components for Web 2.0

51

FCKEditor Summary

Easy to knit components & JavaScript Super easy to use:

<input jwcid="@FCKEditor" value="ognl:description"/>

Page 52: Tapestry Components for Web 2.0

52

Wrap Up

Page 53: Tapestry Components for Web 2.0

53

More Tapestry Topics

Persistent Page Properties Creating New Components Localization Packaging component libraries Integration with Hibernate and Spring Unit and Integration Testing Extending and Overriding Tapestry

Page 54: Tapestry Components for Web 2.0

54

ePluribus Source

Via Anonymous SVN:

http://svn.javaforge.com/svn/tapestry/epluribus/trunk

User: anonymous Password: anon

Page 55: Tapestry Components for Web 2.0

55

Links

Tapestry http://tapestry.apache.org

HiveMind http://jakarta.apache.org/hivemind/ http://hivemind.apache.org/

Tacos http://tacos.sf.net/

OGNL http://www.ognl.org/