PlaceHistoryHandler for URL with multiple args

600 views
Skip to first unread message

Mike Dee

unread,
Oct 3, 2011, 2:00:19 PM10/3/11
to Google Web Toolkit
Just wondering about how to go about implementing a history mechanism
(using Activities and Places) for URLs with multiple arguments. For
example, lets say I want a book search url (call it BookSearch) to be
bookmarkable and have multiple arguments. In a traditional web app
the URL may look like BookSearch.php?
title=xxx&author=yyy&publisher=zzz.

One idea I can see is to make the place token the entire argument
list. So, in the above case it would look like:
title=xxx&author=yyy&publisher=zzz. Then I could parse each arg (are
there any tools in GWT to help with this?).

Another idea would be to create a separate token for each argument.
The place class may look like this:

public class BookSearchPlace extends Place
{
public BookSearchPlace ( String title, String author, String
publisher )



-sowdri-

unread,
Oct 4, 2011, 1:01:39 AM10/4/11
to google-we...@googlegroups.com
Are you using PlaceTokenizer? If yes, they you can achieve what you are looking for using that. 

>> One idea I can see is to make the place token the entire argument 
list.  So, in the above case it would look like: 
title=xxx&author=yyy&publisher=zzz.  Then I could parse each arg (are 
there any tools in GWT to help with this?). 

This is the way to go!

>> Another idea would be to create a separate token for each argument. 
The place class may look like this

This is not supported, as GWT by default will consider the entire arg list as a single token only. i.e anything after the '#' in the url. Still you can have the constructor 

>> public class BookSearchPlace extends Place 

public BookSearchPlace ( String title, String author, String 
publisher ) 

as such they are not related. 

Ashton Thomas

unread,
Oct 4, 2011, 2:01:12 AM10/4/11
to google-we...@googlegroups.com
Sorry for the rough form but this may help:



public abstract class AppPlace extends Place {

/**
* Method that allows us to create a simple AppPlaceHistroyMapper. Allows
* the AppPlaceHistoryMapper to just call the AppPlace's getToken in order
* to build the url from the place object
* @return
*/
public abstract String getToken();

/**
* Get the integer value of the parameter for the given param key
* @param param
* @param token
* @return
*/
public int getInt(String param, String token) {

if (token.contains(param)) {
return Integer
.valueOf(token.substring(
token.indexOf(param + "=") + param.length() + 1)
.split("&")[0]);
} else {
return -1;
}

}

/**
* Get the String value of the parameter for the given param key
* @param param
* @param token
* @return
*/
public String getString(String param, String token) {
if (token.contains(param)) {
return param.substring(
token.indexOf(token + "=") + param.length() + 1).split("&")[0];
} else {
return null;
}
}

/**
* Create the url for the given params
* @param strings
*            and even length number of strings (key, value, key, value,
*            etc)
* @return
*/
public String createToken(String... strings) {
if (strings.length > 1 && strings.length % 2 == 0) {
String token = "?" + strings[0] + "=" + strings[1];
for (int i = 1; i < strings.length / 2; i++) {
token = token.concat("&" + strings[i * 2 + i - 1] + "="
+ strings[i * 2 + i]);
}
return token;
} else {
return "";
}
}

}

Ashton Thomas

unread,
Oct 12, 2011, 9:31:23 PM10/12/11
to google-we...@googlegroups.com
Adding an example to this piece:


MyPlace extends AppPlace {
  int param1;
  
  public MyPlace(String token){
    this.param1 = getInt("pid", token); //if url is #my-place?pid=12&tid=4
     int var = getInt("tid", token)
..
  }
...
}

Probably a better way of doing all of this but wanted to update this example to link to in another gwt question

sridevi macherla

unread,
Oct 12, 2011, 10:51:02 PM10/12/11
to google-we...@googlegroups.com
Hi Thomas,

Thanks for putting this, but how do u register the tokens specific can you given up a n entire example along with Activities and
Place

eg: http://localhost:/book:id=1&id=2
http://localhost/search?author:name=50&publisher=MIT


Meaning in the above the example you suggested how to parse the token, but how do you register this token for each place.

how to achieve different parameters for each of the place, pls suggest ur thoughts, Thanks in advance
Sri.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/USBmGMFC3DQJ.

To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Ashton Thomas

unread,
Oct 12, 2011, 11:07:35 PM10/12/11
to google-we...@googlegroups.com
Not exactly sure what you are looking for but I think you want to look at the PlaceHistoryMapper:


public class AppPlaceHistoryMapper implements PlaceHistoryMapper{

public Place getPlace(String token) {
if(token.startsWith("something")){
//assume SomethingPlace has params
//so the token is actually "something?p1=2&p2=12"
//this would just route anything starting with "something"
//to the SomethingPlace
//the constructor should handle parsing the actual param values
return new SomethingPlace(token);
}else if(token.startsWith("something-else")){
return new SomethingElsePlace(token);
}
return null;
}

public String getToken(Place place) {
if(place instanceof AppPlace){
return ((AppPlace)place).getToken();
}
return null;
}
}

-sowdri-

unread,
Oct 13, 2011, 1:29:05 AM10/13/11
to google-we...@googlegroups.com

public abstract class AbstractBasePlace extends Place {

private static final Logger logger = Logger.getLogger(AbstractBasePlace.class.getName());

private static final String VALIDATE_TOKENS_MESSAGE_PREFIX = "Missing token(s): ";

private String url;
private Map<String, String> params = new HashMap<String, String>();

/**
* @param token
*            will be parsed to extract the parameters passed as part of url
*/
protected AbstractBasePlace(String... tokens) {

if (tokens.length % 2 != 0) {
logger.warning("Invalid arguments received!"
+ " Must be name,value,name,value ... Ignoring arguments!");
return;
}

StringBuilder stringBuilder = new StringBuilder();

for (int i = 0; i < tokens.length; i++) {

final String paramName = tokens[i++];
final String paramValue = tokens[i];

// build params map
params.put(paramName, paramValue);

// build url
stringBuilder.append(paramName + "=" + paramValue + "&");
}

url = stringBuilder.toString();
}

protected AbstractBasePlace(String url) {

if (url == null || url.isEmpty()) {
logger.warning("Url empty, no-op");
return;
}

this.url = url;

List<String> list = Arrays.asList(url.split("&"));

if (list == null || list.size() < 1) {
logger.warning("Token empty, no-op");
return;
}

for (String listItem : list) {

List<String> nvPair = Arrays.asList(listItem.split("="));

if (nvPair == null || nvPair.size() != 2) {
logger.warning("Invalid paramters");
continue;
}

params.put(nvPair.get(0), nvPair.get(1));
}
}

/**
* Checks whether 'this' is constructed with the required parameters. The
* list of required params must be passed as argument.
* @param requiredLiterals
*/
protected void validate(String... paramNames) {

StringBuffer message = new StringBuffer(VALIDATE_TOKENS_MESSAGE_PREFIX);

for (String name : paramNames) {
if (!params.containsKey(name))
message.append(name + " ");
}

// if something is added to the string show
if (!message.toString().equals(VALIDATE_TOKENS_MESSAGE_PREFIX)) {
logger.warning(message.toString());
// Status.failure(message.toString());
}
}

public String getUrl() {
return url;
}

public String getParameter(String name) {
return params.get(name);
}

public boolean hasParameter(String name) {
return params.containsKey(name);
}
}


All your places can extend this class and you can use 2 constructors depending upon the context:
  1. Use this if you are constructing the place, to be used with placecontroller.
  2. Use this for constructing place within PlaceTokenizer.
And when ever you want a param, just call place.hasParam() and place.getParam()

Hope this helps.

-sowdri-

unread,
Oct 13, 2011, 1:30:45 AM10/13/11
to google-we...@googlegroups.com
// place and placetokenizer for your reference

public class AgencyPlace extends AbstractBasePlace {

public AgencyPlace(String token) {
super(token);
}

@Prefix("agency-place")
public static class Tokenizer implements PlaceTokenizer<AgencyPlace> {

@Override
public AgencyPlace getPlace(String token) {
return new AgencyPlace(token);
}

@Override
public String getToken(AgencyPlace place) {
return place.getUrl();
}
}
}

sridevi macherla

unread,
Oct 17, 2011, 4:45:03 AM10/17/11
to google-we...@googlegroups.com
Hi Sowdri,

Thanks a lot this example help me lot but if we see the example concentrates how to parse the params and spilt.

One basic question how do we append params in the url

http://localhost:8080/#

for this URL how can i append params with activities and places, where as in case of earlier we have Fragements or HistoryTokens.

Can you please clarify or help  as i am having tough time with A&P.

Thanks
Swaroop


--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

-sowdri-

unread,
Oct 17, 2011, 5:08:14 AM10/17/11
to google-we...@googlegroups.com
http://localhost:8080/#place-name:key1=value1&key2=value2&key3=value3 (as many nvpairs as you require)

Once you hit this url, the place tokenizer will take care of parsing the url and you can directly access the values of the params, using place.hasParameter() and place.getParameter() as mentioned in the previous post.

Thanks, 

sridevi macherla

unread,
Oct 17, 2011, 5:10:46 AM10/17/11
to google-we...@googlegroups.com
Thanks Sowdri,  But my question relates to how to append these parameters in URL.  Place name will be defulat.

-                       "key1=value1&key2=value2&key3=value3"


Thanks
Sri

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

-sowdri-

unread,
Oct 17, 2011, 6:47:17 AM10/17/11
to google-we...@googlegroups.com
When you are creating the place, pass this using the constructor. Ex:


placeController.goTo(new MyPlace(key1, value1, key2, value2, key3, value3)); 

Rest must be automatically taken care of! 

When your MyPlace extends AbstractBasePlace, make sure, you also expose all the constructors of AbstractBasePlace!


Reply all
Reply to author
Forward
0 new messages