You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Peter Svensson <ps...@gmail.com> on 2006/03/04 18:33:07 UTC

How do I specify a callback method in a custom component?

Hi!

I am making a small simple component which wraps contrib:Table but only
requires source, so it figures out names and ordering by reflection.
Anyway, it works great, and now I would like to make another component which
wraps it and adds delete buttons (Maybe with the T-deli checkbox groups to
select all and/or all shown (http://www.t-deli.com/)).

But one thing I can't find either in Kens book or while googling heavily,
which is how to specify a method/callback function to be called when someone
does submit one or more deletions to the component.

I think I should use some kind of listener, but since I'm quite new to all
this I'm hoping for directions.

Cheers,
PS

Re: How do I specify a callback method in a custom component?

Posted by Peter Svensson <ps...@gmail.com>.
First Adam, thanks for a quick reply. I realize that "callback" is used
almost exclusively in tapestry when invoking pages, and whyat I meant was
how to make and use a parameter to a component which refers to a mwthod in
another class (the component using class).

However, it's always nice to see examples of code I might actually need
anyway :)  Thanks!


Cheers,
PS

On 3/4/06, Adam Zimowski <zi...@gmail.com> wrote:
>
> I use callbacks heavily, although not sure if that's exactly what you
> need. I have an Authenticate component for instance which validates
> itself against the database, submits itself and creates a member
> session on success. It uses a callback of a hosting page to find out
> what page to go to upon successfull login. I do that thru an interface
> which a hosting page can (although doesn't have to) implement. If
> IAuthenticate is implemented by a hosting page, then component will
> use a callback to delegate all the login responsibility (except the
> validation) onto the page. If ClassCastException occurs (when page
> does not implement IAuthenticate) the component uses its default
> logic.
>
> I have two pages that use Authenticate component:  Home page and a
> Login page. Home page is happy with component's default behavior, so
> it does not implement IAuthenticate thus not proving a callback. Login
> page, on the other hand wants to control the Login process, and so it
> implements IAuthenticate.
>
> This works very nicely for me.
>
>
> -----------------------------------------------------------------------------------------------
>
> package org.opendating.tapestry.components.support;
>
> import org.apache.tapestry.IPage;
>
> /**
> * Allows to define custom Login behavior for pages that utilize
> Authenticate
> * component (which provides a Login feature). Implementing this interface
> * is not mandatory because by default, Authenticate will execute a
> standard
> * action which is to create a session and a member object (which gets put
> in
> * the session), and returning back to the same page.
> *
> * @author Adam Zimowski
> */
> public interface IAuthenticate {
>
>         /**
>          *
>          * @param aError <i>true</i> if login error occurred, <i>false</i>
> otherwise.
>          * @return destination page after successfull login.
>          */
>         public IPage onLogin(boolean aError);
>
>         /**
>          * If <i>true</i> is returned, then Authenticate component will
> automatically
>          * create member object, and put it in session. If <i>false</i> is
> returned
>          * the Authenticate component merely calls the implemented version
> of
>          * onLogin(boolean) and returns the desitnation page.
>          *
>          * @return <i>true</i> if session and member object should be
> created,
>          *      <i>false</i> otherwise.
>          */
>         public boolean createMemberOnLogin();
> }
>
>
> -----------------------------------------------------------------------------------------------
>
> package org.opendating.tapestry.components;
>
> import org.apache.tapestry.IPage;
> import org.apache.tapestry.annotations.Bean;
> import org.apache.tapestry.valid.ValidationDelegate;
> import org.opendating.exceptions.MemberException;
> import org.opendating.model.Member;
> import org.opendating.tapestry.components.support.IAuthenticate;
> import org.opendating.tapestry.log.LoggableBaseComponent;
> import org.opendating.tapestry.state.IMember;
>
> public abstract class Authenticate extends LoggableBaseComponent
>         implements IMember {
>
>         @Bean
>         public abstract ValidationDelegate getDelegate();
>
>         public abstract String getLoginId();
>
>         public abstract String getPassword();
>
>         public IPage onLogin() {
>
>                 boolean isError = getDelegate().getHasErrors();
>                 if(aDbg()) _aLog.debug("error? " + isError);
>
>                 IAuthenticate loginPage = null;
>                 try {
>                         loginPage = (IAuthenticate)getPage();
>                         if(!loginPage.createMemberOnLogin())
>                                 return loginPage.onLogin(isError);
>                 }
>                 catch(ClassCastException cce) {
>                         if(!isError) {
>                                 String host = getPage().getPageName();
>                                 _aLog.info("default login; page '" + host
> + "' did not implement " +
>                                         IAuthenticate.class.getSimpleName
> ());
>                         }
>                 }
>
>                 if(!isError) {
>                         Member member = null;
>                         try { member = new Member(getLoginId()); }
>                         catch(MemberException me) {
>                                 _aLog.error(me.getMessage());
>                         }
>
>                         if(aDbg()) {
>                                 _aLog.debug("isLoggedIn: " +
> isLoggedIn());
>                                 _aLog.debug("loginId: " + getLoginId());
>                                 _aLog.debug("systemId: " +
> member.getSystemId());
>                         }
>
>                         setMember(member);
>
>                         if(aDbg())
>                                 _aLog.debug("isLoggedIn: " +
> isLoggedIn());
>                 }
>
>                 try { return loginPage.onLogin(isError); }
>                 catch(NullPointerException npe) { return null; }
>         }
>
> }
>
>
> -----------------------------------------------------------------------------------------------
>
> Note that Home page does not implement IAuthenticate:
>
> package org.opendating.tapestry.pages;
>
> import org.opendating.tapestry.log.LoggableBasePage;
> import org.opendating.tapestry.state.IMember;
>
> public abstract class Home extends LoggableBasePage implements IMember {
>
>         public static final String NAME = "Home";
>
>         public String getUserName() {
>
>                 String guest = "Guest";
>
>                 try {
>                         if(isLoggedIn())
>                                 return getMember().getLoginId();
>                         else
>                                 return guest;
>                 }
>                 catch(Exception e) { return guest; }
>         }
> }
>
>
> -----------------------------------------------------------------------------------------------
>
> But Login page does because it wants custom Login logic:
>
> package org.opendating.tapestry.pages;
>
> import org.apache.tapestry.IPage;
> import org.apache.tapestry.annotations.InjectComponent;
> import org.apache.tapestry.annotations.Persist;
> import org.opendating.tapestry.components.Authenticate;
> import org.opendating.tapestry.components.support.IAuthenticate;
> import org.opendating.tapestry.log.LoggableBasePage;
>
> /**
> * Page designed specifically for Login only, which would be used in
> situations
> * when user forges a URL trying to access member-only pages. In such
> situations
> * instead of accessing page illegaly, this login page would be displayed.
> *
> * There is nothing that prevents from using this page as a main Login
> gateway,
> * however, a more flexible approach is available because any given page
> can
> * use "Authenticate" component which provides a Login feature.
> *
> * @author Adam Zimowski
> */
> public abstract class Login extends LoggableBasePage implements
> IAuthenticate {
>
>         public static final String NAME = "Login";
>
>         @Persist("client")
>         public abstract String getReturnPage();
>         public abstract void setReturnPage(String aPage);
>
>         @InjectComponent("authenticator")
>         public abstract Authenticate getLoginComponent();
>
>         public IPage onLogin(boolean aError) {
>
>                 if(!aError) {
>
>                         String page = getReturnPage();
>                         if(aDbg()) _aLog.debug("returning to: " + page);
>
>                         return getRequestCycle().getPage(page);
>                 }
>
>                 return null;
>         }
>
>         public boolean createMemberOnLogin() {
>                 return true;
>         }
> }
>
>
> Hope it helps.
>
>
> On 3/4/06, Peter Svensson <ps...@gmail.com> wrote:
> > Hi!
> >
> > I am making a small simple component which wraps contrib:Table but only
> > requires source, so it figures out names and ordering by reflection.
> > Anyway, it works great, and now I would like to make another component
> which
> > wraps it and adds delete buttons (Maybe with the T-deli checkbox groups
> to
> > select all and/or all shown (http://www.t-deli.com/)).
> >
> > But one thing I can't find either in Kens book or while googling
> heavily,
> > which is how to specify a method/callback function to be called when
> someone
> > does submit one or more deletions to the component.
> >
> > I think I should use some kind of listener, but since I'm quite new to
> all
> > this I'm hoping for directions.
> >
> > Cheers,
> > PS
> >
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>
>

Re: How do I specify a callback method in a custom component?

Posted by Adam Zimowski <zi...@gmail.com>.
I use callbacks heavily, although not sure if that's exactly what you
need. I have an Authenticate component for instance which validates
itself against the database, submits itself and creates a member
session on success. It uses a callback of a hosting page to find out
what page to go to upon successfull login. I do that thru an interface
which a hosting page can (although doesn't have to) implement. If
IAuthenticate is implemented by a hosting page, then component will
use a callback to delegate all the login responsibility (except the
validation) onto the page. If ClassCastException occurs (when page
does not implement IAuthenticate) the component uses its default
logic.

I have two pages that use Authenticate component:  Home page and a
Login page. Home page is happy with component's default behavior, so
it does not implement IAuthenticate thus not proving a callback. Login
page, on the other hand wants to control the Login process, and so it
implements IAuthenticate.

This works very nicely for me.

-----------------------------------------------------------------------------------------------

package org.opendating.tapestry.components.support;

import org.apache.tapestry.IPage;

/**
 * Allows to define custom Login behavior for pages that utilize Authenticate
 * component (which provides a Login feature). Implementing this interface
 * is not mandatory because by default, Authenticate will execute a standard
 * action which is to create a session and a member object (which gets put in
 * the session), and returning back to the same page.
 *
 * @author Adam Zimowski
 */
public interface IAuthenticate {

	/**
	 *
	 * @param aError <i>true</i> if login error occurred, <i>false</i> otherwise.
	 * @return destination page after successfull login.
	 */
	public IPage onLogin(boolean aError);
	
	/**
	 * If <i>true</i> is returned, then Authenticate component will automatically
	 * create member object, and put it in session. If <i>false</i> is returned
	 * the Authenticate component merely calls the implemented version of
	 * onLogin(boolean) and returns the desitnation page.
	 *
	 * @return <i>true</i> if session and member object should be created,
	 * 	<i>false</i> otherwise.
	 */
	public boolean createMemberOnLogin();
}

-----------------------------------------------------------------------------------------------

package org.opendating.tapestry.components;

import org.apache.tapestry.IPage;
import org.apache.tapestry.annotations.Bean;
import org.apache.tapestry.valid.ValidationDelegate;
import org.opendating.exceptions.MemberException;
import org.opendating.model.Member;
import org.opendating.tapestry.components.support.IAuthenticate;
import org.opendating.tapestry.log.LoggableBaseComponent;
import org.opendating.tapestry.state.IMember;

public abstract class Authenticate extends LoggableBaseComponent
	implements IMember {

	@Bean
	public abstract ValidationDelegate getDelegate();

	public abstract String getLoginId();
	
	public abstract String getPassword();
	
	public IPage onLogin() {

		boolean isError = getDelegate().getHasErrors();
		if(aDbg()) _aLog.debug("error? " + isError);

		IAuthenticate loginPage = null;
		try {
			loginPage = (IAuthenticate)getPage();
			if(!loginPage.createMemberOnLogin())
				return loginPage.onLogin(isError);
		}
		catch(ClassCastException cce) {
			if(!isError) {
				String host = getPage().getPageName();
				_aLog.info("default login; page '" + host + "' did not implement " +
					IAuthenticate.class.getSimpleName());
			}
		}
		
		if(!isError) {
			Member member = null;
			try { member = new Member(getLoginId()); }
			catch(MemberException me) {
				_aLog.error(me.getMessage());
			}

			if(aDbg()) {
				_aLog.debug("isLoggedIn: " + isLoggedIn());
				_aLog.debug("loginId: " + getLoginId());
				_aLog.debug("systemId: " + member.getSystemId());
			}
			
			setMember(member);
			
			if(aDbg())
				_aLog.debug("isLoggedIn: " + isLoggedIn());
		}
		
		try { return loginPage.onLogin(isError); }
		catch(NullPointerException npe) { return null; }
	}
	
}

-----------------------------------------------------------------------------------------------

Note that Home page does not implement IAuthenticate:

package org.opendating.tapestry.pages;

import org.opendating.tapestry.log.LoggableBasePage;
import org.opendating.tapestry.state.IMember;

public abstract class Home extends LoggableBasePage implements IMember {

	public static final String NAME = "Home";

	public String getUserName() {
		
		String guest = "Guest";
		
		try {
			if(isLoggedIn())
				return getMember().getLoginId();
			else
				return guest;
		}
		catch(Exception e) { return guest; }
	}
}

-----------------------------------------------------------------------------------------------

But Login page does because it wants custom Login logic:

package org.opendating.tapestry.pages;

import org.apache.tapestry.IPage;
import org.apache.tapestry.annotations.InjectComponent;
import org.apache.tapestry.annotations.Persist;
import org.opendating.tapestry.components.Authenticate;
import org.opendating.tapestry.components.support.IAuthenticate;
import org.opendating.tapestry.log.LoggableBasePage;

/**
 * Page designed specifically for Login only, which would be used in situations
 * when user forges a URL trying to access member-only pages. In such
situations
 * instead of accessing page illegaly, this login page would be displayed.
 *
 * There is nothing that prevents from using this page as a main Login gateway,
 * however, a more flexible approach is available because any given page can
 * use "Authenticate" component which provides a Login feature.
 *
 * @author Adam Zimowski
 */
public abstract class Login extends LoggableBasePage implements IAuthenticate {

	public static final String NAME = "Login";

	@Persist("client")
	public abstract String getReturnPage();
	public abstract void setReturnPage(String aPage);
	
	@InjectComponent("authenticator")
	public abstract Authenticate getLoginComponent();

	public IPage onLogin(boolean aError) {
		
		if(!aError) {

			String page = getReturnPage();
			if(aDbg()) _aLog.debug("returning to: " + page);
			
			return getRequestCycle().getPage(page);
		}
		
		return null;
	}

	public boolean createMemberOnLogin() {
		return true;
	}
}


Hope it helps.


On 3/4/06, Peter Svensson <ps...@gmail.com> wrote:
> Hi!
>
> I am making a small simple component which wraps contrib:Table but only
> requires source, so it figures out names and ordering by reflection.
> Anyway, it works great, and now I would like to make another component which
> wraps it and adds delete buttons (Maybe with the T-deli checkbox groups to
> select all and/or all shown (http://www.t-deli.com/)).
>
> But one thing I can't find either in Kens book or while googling heavily,
> which is how to specify a method/callback function to be called when someone
> does submit one or more deletions to the component.
>
> I think I should use some kind of listener, but since I'm quite new to all
> this I'm hoping for directions.
>
> Cheers,
> PS
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org