Activities & Places, token question

387 views
Skip to first unread message

Alex

unread,
May 13, 2011, 9:08:26 AM5/13/11
to Google Web Toolkit
Hi all,

Firstly, please bare with me as I'm still getting to grips with GWT
and Activities & Places (A&P), which I'm really keen to use in my
projects. While experimenting with A&P it looks like a token is always
a requirement.

My question is, what token would you provide for a page that would not
typically have any additional arguments, such as a contact us page. I
would vision it looking like (/#ContactUsPlace:randomToken) with a
random token appended, when in a ideal world I would like (/
#contactus). Is it possible to do this, but still use A&P with its
navigation/history strengths?

NOTE: In regards to source code, I've been following the GWT MVP
tutorial at http://code.google.com/webtoolkit/doc/latest/DevGuideMvpActivitiesAndPlaces.html

Many thanks

Alex

Thomas Broyer

unread,
May 13, 2011, 9:28:28 AM5/13/11
to google-we...@googlegroups.com
First, you could use the empty string instead of a "random token", and it would give you a /#ContactUsPlace: token.

There's also the possibility to either put a bunch of "places" into a single Place class, and using the "token" to disambiguate them (e.g. /#CommonPlace:ContactUs); or you could instead use different Place classes but a single PlaceTokenizer (better IMO) with the same results.
...and because an empty @Prefix is simply ignored when generating the token, you could have /#contactus that way.

Finally, but you shouldn't need it for your use case, you can provide your own implementation of PlaceHistoryMapper instead of relying on the generator (you'd lose all the magic related to @WithTokenizers and @Prefix though and have to do it all by yourself).

Jens

unread,
May 13, 2011, 9:58:46 AM5/13/11
to google-we...@googlegroups.com
Am Freitag, 13. Mai 2011 15:28:28 UTC+2 schrieb Thomas Broyer:
...and because an empty @Prefix is simply ignored when generating the token, you could have /#contactus that way.


 But you can only have on PlaceTokenizer with an empty @Prefix. Just keep it in mind if you now think you could do /#contactus and /#impress with two places and both tokenizer have an empty @Prefix. You will get an exception, at least thats what me happened yesterday.

Jens

unread,
May 13, 2011, 11:02:49 AM5/13/11
to google-we...@googlegroups.com
I also have a Places / Token question and as this thread topic is a more general I post it here.

First of all I do not like the default PrefixAndToken implementation and I would like to have place history tokens like the ones here in the new google groups app (#!place-name/group-name/thread-id). Is this possible with the default implementation of PlaceHistoryMapper or do I have to write my own one? As I can only have one Tokenizer with an empty Prefix I could also have only one "AppPlace" tied to that Tokenizer and so the getToken() / getPlace() methods of that Tokenizer would have to do all the magic to make thinks work. I think this would also mean that this one "AppPlace" needs to hold/know all other places so that they can store their state. Seems to me that this is not the nicest approach. Has someone already tried it? How does Google do that here in Google Groups?

What I currently try is to implement a custom PlaceHistoryMapper that allows me to support Places that extend from other places to reuse their state. Imagine you have a CustomerPlace that stores the currently selected customer id. That CustomerPlace would also have an activity because you can switch between customers and for each switch some stuff has to be done, e.g. load picture, check privileges of the user to present tasks that the user is allowed to do for that customer. Lets say once the task list is loaded you are able to edit the customer so there would be a EditCustomerPlace. Now the EditCustomerPlace also have to store that customer id because if you jump to that place directly via its history token you need that information. How do you handle these situations without code things twice?

So my Idea is to be able to do something like EditCustomerPlace extends CustomerPlace and to generate the EditCustomerPlace history token by reusing the one from CustomerPlace. 

Example:

CustomerPlace -> #/customer/1
EditCustomerPlace -> #/editcustomer/<CustomerPlace state>/<additional EditCustomerPlace state> -> #/editcustomer/customer/1/address

I couldn't do that without a custom PlaceHistoryMapper, right? Or are there other/easier ways to reuse place states? I somehow like the idea of having a more general place that stores the general state and multiple more specific places that only stores the specific state but also have access to the general state they need.

Thanks in advance for any helpful thoughts.

-- J

Alex

unread,
May 13, 2011, 11:10:34 AM5/13/11
to Google Web Toolkit
Thank you so much for your reply, this has really helped me. The
solution for me was to implement my own PlaceHistoryMapper, now I'm
getting the exact behaviour I was looking for, while keeping within
the A&P framework.

Many thanks,
Alex

Thomas Broyer

unread,
May 13, 2011, 11:31:31 AM5/13/11
to google-we...@googlegroups.com


On Friday, May 13, 2011 5:02:49 PM UTC+2, Jens wrote:
I also have a Places / Token question and as this thread topic is a more general I post it here.

First of all I do not like the default PrefixAndToken implementation and I would like to have place history tokens like the ones here in the new google groups app (#!place-name/group-name/thread-id). Is this possible with the default implementation of PlaceHistoryMapper or do I have to write my own one? As I can only have one Tokenizer with an empty Prefix I could also have only one "AppPlace" tied to that Tokenizer and so the getToken() / getPlace() methods of that Tokenizer would have to do all the magic to make thinks work. I think this would also mean that this one "AppPlace" needs to hold/know all other places so that they can store their state. Seems to me that this is not the nicest approach. Has someone already tried it?

You don't need to have "this one 'AppPlace'", you can simply "bind" your empty-prefix PlaceTokenizer with the "Place" type to use it as a catch-all (and it could parse tokens into as many distinct Place subtypes as you need).
If you only have that one PlaceTokenizer, then it won't be that different from having your own PlaceHistoryMapper though, it just let your easily plug a new PlaceTokenizer later on with slightly less refactoring.

@Prefix("")
class CatchAll implements PlaceTokenizer<Place> {
  public Place getPlace(String token) {
    if ("contactus".equals(token)) {
      return new ContactUsPlace();
    }
    if (token.startsWith("foo/")) {
       // parse what follows "foo/" and return a FooPlace
    }
    ...
  }
  public String getToken(Place p) {
    if (p instanceof ContactUsPlace) {
      return "contactus";
    }
    if (p instanceof FooPlace) {
      return "foo/" + getFooToken((FooPlace) p);
    }
    ...
  }
}
 
How does Google do that here in Google Groups?

I suppose they use A&P, and it so, I suppose they use their own PlaceHistoryMapper.
 
What I currently try is to implement a custom PlaceHistoryMapper that allows me to support Places that extend from other places to reuse their state. Imagine you have a CustomerPlace that stores the currently selected customer id. That CustomerPlace would also have an activity because you can switch between customers and for each switch some stuff has to be done, e.g. load picture, check privileges of the user to present tasks that the user is allowed to do for that customer. Lets say once the task list is loaded you are able to edit the customer so there would be a EditCustomerPlace. Now the EditCustomerPlace also have to store that customer id because if you jump to that place directly via its history token you need that information. How do you handle these situations without code things twice?

You can have EditCustomerPlace extends CustomerPlace. If the "sub-token" in both cases is the customer ID, then you can use the same PlaceTokenizer with two distinct @Prefix (either have 2 classes, one simply extending the other without doing anything else, apart from having its own @Prefix; or if you use a PlaceHistoryMapperWithFactory, simply have 2 methods parameterized with the 2 classes and distinct @Prefix: 
   @Prefix("customer") PlaceTokenizer<CustomerPlace> customer() { return new CustomerPlaceTokenizer(); }
   @Prefix("customer-edit") PlaceTokenizer<EditCustomerPlace> editCustomer() { return new CustomerPlaceTokenizer(); }
)
...or you could instead have a single PlaceTokenizer that knows about both classes (and can thus be bound once to a single @prefix):
@Prefix("customer")
class CustomerPlaceTokenizer implemens PlaceTokenizer<CustomerPlace> {
  public String getToken(CustomerPlace p) {
    return ((p instanceof EditCustomerPlace) ? "edit" : "view") + ":" + p.getId();
  }
  ...
}


So my Idea is to be able to do something like EditCustomerPlace extends CustomerPlace and to generate the EditCustomerPlace history token by reusing the one from CustomerPlace. 

Example:

CustomerPlace -> #/customer/1
EditCustomerPlace -> #/editcustomer/<CustomerPlace state>/<additional EditCustomerPlace state> -> #/editcustomer/customer/1/address

I couldn't do that without a custom PlaceHistoryMapper, right? Or are there other/easier ways to reuse place states?

You're in control of the parsing for everything after the prefix, so it's up to you to make it reusable across PlaceTokenizers.

Jens

unread,
Jun 5, 2011, 10:41:58 AM6/5/11
to google-we...@googlegroups.com
Thanks Thomas that helps quite a bit. I have chosen the catch all tokenizer approach with some additional code to make parsing more reusable and it was easy to implement.

SurfMan

unread,
Nov 25, 2011, 10:01:11 AM11/25/11
to google-we...@googlegroups.com
Sorry to wake up an old thread, but I stopped by after pulling my hair out about places with empty tokens.

I don't understand the reasoning behind a token being mandatory. If a place is named "Login" and it does not require any tokens, then why can't I just use myapp.html#Login without resorting to a random token, an empty token or some generic place that functions as a catchall.


Thomas Broyer

unread,
Nov 25, 2011, 10:44:49 AM11/25/11
to SurfMan, Google Web Toolkit
[+Cc GWT Group]

On Fri, Nov 25, 2011 at 3:38 PM, SurfMan <nlsu...@hotmail.com> wrote:
> Sorry to wake up an old thread, but after struggling with an empty
> place/token I ended up here too...
>
> I just don't understand why "#blah" would end up as the default place
> "" with token "blah", and why it's not place "blah" with an empty/null
> token. What is the reasoning behind this?

The serialization and deserialization processes have to be symmetric.
So if you allow an empty prefix and choose to serialize {prefix="",
token="foo"} as #foo (rather than #:foo), then you have to parse #foo
as {prefix="", token="foo"} (rather than {prefix="foo", token=""}).

The current choice is more flexible than the alternative, as it allows
the PlaceTokenizer for the empty prefix to create any kind of Place
depending on the token (if that's what you want), and falling back to
'null' for unknown tokens.
With the alternate design, the generated PlaceHistoryMapper would then
look for a PlaceTokenizer for the prefix "foo" and won't find any so
it'd fall back to the default place, always, without any hook for you
to customize this behavior).

--
Thomas Broyer
/tɔ.ma.bʁwa.je/

Reply all
Reply to author
Forward
0 new messages