Lyifan (and anyone else considering page extention for access control),
First off, in my opinion centralizing access logic in a base page and
forcing protected pages to extend it is an anti-pattern
(http://en.wikipedia.org/wiki/Anti-pattern), and should therefore be
avoided.
Regarding the dispatcher article (which I wrote), your problem is that
you are attempting to use @ApplicationState in a service, and this is
not possible, at least in this case. Why? Because state is based on the
request, and services are by default singletons. This means you have one
instance of your access controller servicing 1 or 10 or 100 simultaneous
requests at once. As such, its not possible to use @ApplicationState.
However it is possible to access request specific data in your service.
I have implemented this, but after reading your message and looking at
my article, I see I didn't touch this important issue. I will update it
soon.
Here's what you need to do.
First remove the @ApplicationState from your service - you can't use it
from a singleton service.
Next, get friendly with the ApplicationStateManager
(http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry/services/ApplicationStateManager.html).
This is a service that can access state objects on for the current request.
Finally, implement your access controller so that it receives an
instance of the ASM in its constructor, and cache that reference as a
member:
...snip
public SingletonAccessControllerImpl(ApplicationStateManager asm) {
this.asm = asm;
}
...snip
Assuming you used auto binding for the service as shown in the article,
T IoC will handle creating your access controller and providing the
needed ASM. Now you can use the ASM to check for state information on a
per-request basis.
I'll update the wiki.
chris
lyifan wrote:
Thanks a lot everyone. Finally the BasePase way works
But the dispatcher way still doesn't work.
lyifan wrote:
I am a 100% new user for tapestry. Currently I'm working on 5.0.5, but I
got stuck from the just beginning.
I want to implement a kind of user access controller. All the pages,
excepts for the login page, can be accessed by authenticated users only.
users who hasn't passed the authentication will be redirected to the login
page to input their user name and password, and then, if the user name and
password are correct, they will see the page they want
I think this is a very very simple thing to do.But after a few days
working, I am very frustrated.
Firstly, I've tried the onActivate method. My code looks like below:
class BasePage {
@ApplicationState
private UserIdentity _userIdentity;
private boolean _userIdentityExists;
Object onActivate() {
if( !_userIdentityExists)
return "Login"; //Login is my login page
return null;
}
}
And the I visited http://localhost:8080/myapp(default page is start), I
got a blank empty page. There is nothing at all on the browser. But I can
see the login page when I went to http://localhost:8080/myapp/login
After that I found an article at
http://wiki.apache.org/tapestry/Tapestry5HowToCreateADispatcher. According
to this, I created my dispatcher. But I found ASO doesn't work in my
dispatcher class.
boolean _myIdentityExists always be false.
And if I contribute it use "before:PageRender", the dispatch method would
not be invoked then I visit the default start page. I had to use
"before:RootPath". Following it my dispatcher class code:
public class SessionController implements Dispatcher {
@ApplicationState
private MyIdentity _myIdentity;
private boolean _myIdentityExists;
public SessionController() {
System.out.println("SessionController: SessionController
created.");
}
public boolean dispatch(Request request, Response response) throws
IOException {
System.out.println("Requesting " + request.getPath());
if (! _myIdentityExists ) { // _myIdentityExists always be false
if( _myIdentity == null ) { // here MyIdentity won't be
created
_myIdentity = new MyIdentity(); // I have to
create it by myself.
System.out.println("SessionController: Identity does
not exist.");
response.sendRedirect("login");
return true; // this works, I can see the
login page correctly.
}else
System.out.println("SessionController: Identity
exists.");
}
return false;
}
}
and here is the code in AppModule:
public void
contributeMasterDispatcher(OrderedConfiguration<Dispatcher> configuration,
@InjectService("SessionController") Dispatcher
sessionController) {
configuration.add("SessionController", sessionController,
"before:PageRender");
}
before:PageRender and before:Asset do not call dispatch method,
before:RootPath does
I set the session timeout to 1 min in the web.xml.
<session-config>
<session-timeout>1</session-timeout>
</session-config>
After 1 min, I came to the start page.supposedly, I would be redirected to
the login page because session is timeout. But I could still visit the
start page, which meas _myIdentity is still in the Session after the
timeout. Is it a bug or I shouldn't create it by myself?