On 24/09/2014 16:22, Garret Wilson wrote:
On 9/24/2014 9:26 AM, Martijn Dashorst wrote:
On Wed, Sep 24, 2014 at 2:13 AM, Garret Wilson
<gar...@globalmentor.com> wrote:
I'm not denying that versioned pages may be a useful concept for
some use
cases (even though I can't think of any offhand).
Persioning is a very useful concept and used in many applications. You
are just focussing on your particular use case for today and not
thinking of broader issues that we have tackled for about a decade.
Take google's search page with the pagination at the bottom. Click on
2, click on back. What do you expect? go back to the page before you
searched google? Or go back to page 1?
But note that in your example you're not talking about the "version of
the page". You're pointing to a /navigation control/, which of course
I would expect to interact with navigation. Notice that when you page
back and forth, you actually change the URL query (e.g. start=10). So
you're not changing the "version" of the page---you're actually
modifying the query you send to the page, and of course you can
navigate among different page queries. In fact Wicket already has a
totally separate mechanism for sending queries to pages through page
parameters, exactly like Google is doing.
I am completely in favor of sending page query parameters in the URL
when I want to specify what data should be retrieved from a query, and
for the user to navigate among queries. But I still (in my use case)
don't have a need for that same query page to be "versioned".
Hi Garret,
(Side note: you probably should not be overriding isVisible(). Call
setVisibilityAllowed() in onConfigure(). isVisible() is often called
multiple times during a request cycle and, if expensive, can lead to
some slowness.)
Page classes are mounted at a specific URL, not page instances. A page
instance is made up of a component tree as well as page state - data
stored in the component tree. When you request a mounted URL, you get a
new page instance as created from that mounted page class. That is the
basic contract of the mount. Serving up anything other than this would
be incorrect, as it breaks the contract.
Humor me here. Please think of the page instance strictly as component
tree and page state. Think of the page class as a starting point, a
factory. If you create a new object from the class, you get a specific
page instance (again, think component tree and page state).
Now, if the page state or component tree changes, the page instance is
no longer "that thing you would get if you created a new instance of
that page class". It is a different beast now. The fact that this
Wicket has no business serving up this beast when the user requested the
mounted URL, aka "that thing you would get if you created a new instance
of that page class".
Every time the component tree or page state changes, it is no longer the
same page. Because it is no longer the same page, the URL changes. This
is where is helps to think of a page as a component tree and page state.
Its not so much different versions of the same page, as much as
different pages.
I'd like to point specifically to the impact of page state here. Being
able to record state in the page object is one of the things that makes
Wicket awesome, but it is not the only place to store state. You can
also store state in the session, in a database, and in cookie, query and
post parameters.
When Wicket talks about stateful pages, its talking about component tree
and page state (the state stored in the component tree - the Page object
being the root of the component tree). A Wicket page is stateful when it
does, or could, change the component tree or PAGE state. When a page
does not modify the PAGE state, then it is stateless in Wicket language
(excuse the simplification).
Using stateless pages reading and writing state outside of the page
object can get you most, if not all, of what you want.
Lets take your Facebook example:
1. "Each time you go to https://www.facebook.com/jdoe, it would
redirect you to https://www.facebook.com/jdoe?1". Not if it was a
stateless page.
2. "Imagine if you clicked "Like" on somebody's picture, and it
redirectred you to https://www.facebook.com/jdoe?3". Again, not if
it was a stateless page. Why should clicking "Like" change the page
state or the component tree? In other words, why does this need to
be a stateful link, why not use a StatelessLink? All the data of who
likes what is not stored in PAGE state. It is stored in a database.
3. "But it still kept https://www.facebook.com/jdoe?2 in memory, so
that when you hit "Back" you'd see the picture before you liked
it.". Again, stateless pages are not stored in the page store, so
you would have a /jdoe?2 in memory. Also, whether or not you like a
picture should not be pulled from page state, but from a database or
cache somewhere. The page runs onConfigure each time before
rendering, so you would highlight the little thumbs up on the next
render if the value in the database now indicates that the picture
is liked.
4. "So you're saying that if I'm careful to use all dynamic models
(even overriding isVisible() for components to dynamically query
whether they should be visible), then my web application will wind
up with many versions of the same page serialized on disk somewhere,
all with different URL queries, and the user can navigate among
them, but when rendered they will all show 100% the same data?" With
a stateless page, you would have no copies serialized. A new page
would be created each time. No navigating between different copies.
Each time the URL is requested, a new instance is created to display
the backing data, whatever that may be at the time.
To take your Google example, the state is being managed in the query
parameters, not the page state. You dont need stateful pages here
either. You can use stateless, bookmarkable links.
Your initial use case of having a staging page which should look the
same for all requests in that session. Would it not make sense to store
the data in the session, use a stateless page to manipulate and display
the data stored in the session?
Cheers,
Jesse