com.mvp4g.client.history.PlaceService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mvp4g Show documentation
Show all versions of mvp4g Show documentation
Model View Presenter with Event Bus For GWT
/*
* Copyright (c) 2009 - 2017 - Pierre-Laurent Coirer, Frank Hossfeld
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.mvp4g.client.history;
import java.util.HashMap;
import java.util.Map;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.mvp4g.client.Mvp4gEventPasser;
import com.mvp4g.client.Mvp4gModule;
/**
* Place Service defines the connection between the application and the browser history.
*
* When an event needs to be stored in the history, the place method of PlaceService
is
* called. This method will transform the event to an history token the following way:
*
* myurl#eventName?params
*
* where params is the string returned by the handling method of the history converter for the
* event.
* If params is null, then the URL will be:
*
* myurl#eventName
*
* In case an event of a child module is stored, its history name and history names of all its
* ascendant except the Root Module will be stored in the token:
*
* myurl#childModule/subChildModule/eventName?params
*
* By default "?" is used to seperate the event name from the parameters. You can change it thanks
* to @HistoryConfiguration
.
*
* If the token generated is supposed to be crawlable, then a "!" will be added before the token.
*
* @author plcoirier
*/
public class PlaceService
implements ValueChangeHandler {
public static final String MODULE_SEPARATOR = "/";
public static final String CRAWLABLE = "!";
private HistoryProxy history = null;
private Mvp4gModule module = null;
@SuppressWarnings("rawtypes")
private Map converters = new HashMap();
private boolean enabled = true;
private NavigationConfirmationInterface navigationConfirmation;
/**
* Build a PlaceService
.
*/
public PlaceService() {
this(HistoryProxyProvider.INSTANCE.get());
}
/**
* Build a PlaceService
and inject an HistoryProxy
instance.
*
* This constructor is handy when you want to test PlaceService
without using the
* GWT History class.
* It shouldn't be called otherwise.
*
* @param history
* history proxy to inject
*/
protected PlaceService(HistoryProxy history) {
this.history = history;
history.addValueChangeHandler(this);
}
/**
* Called when the History token has changed.
*
* Decode the history token and call the convertFromToken method of the history converters
* associated with this action stored in the token.
*
* If token is equal to empty string, ask the event bus to dispatch an initEvent.
*
* @param event
* event containing the new history token
*/
public void onValueChange(final ValueChangeEvent event) {
confirmEvent(new NavigationEventCommand(module.getEventBus()) {
protected void execute() {
convertToken(event.getValue());
}
});
}
/**
* Convert the token to an event
*
* @param token
* the token to convert
*/
protected void convertToken(String token) {
boolean toContinue = false;
if (token != null) {
if (token.startsWith(CRAWLABLE)) {
token = token.substring(1);
}
toContinue = (token.length() > 0);
}
if (toContinue) {
String[] result = parseToken(token);
if (!forwardToChildModuleIfNeeded(result[0],
result[1])) {
dispatchEvent(result[0],
result[1],
module);
}
} else {
module.sendInitEvent();
}
}
/**
* Parse the token and return a string array. The first element of this array contains the event
* name whereas the second element contains the parameters associated to the event.
*
* @param token
* token to parse
*
* @return array of string
*/
protected String[] parseToken(String token) {
String[] result = new String[2];
int index = token.lastIndexOf(getParamSeparator());
result[0] = (index == -1) ?
token :
token.substring(0,
index);
result[1] = (index == -1) ?
null :
token.substring(index + 1);
return result;
}
/**
* Check if this event is a child's module event. If it's the case, forward the token to the
* child module and return true.
*
* @param eventName
* name of the event that was stored in the token
* @param param
* parameters stored in the token
*
* @return true if this child module's event.
*/
protected boolean forwardToChildModuleIfNeeded(final String eventName,
final String param) {
boolean forAChild = eventName.contains(MODULE_SEPARATOR);
if (forAChild) {
Mvp4gEventPasser passer = new Mvp4gEventPasser(true) {
@Override
public void pass(Mvp4gModule module) {
if ((Boolean) eventObjects[0]) {
dispatchEvent(eventName,
param,
module);
} else {
sendNotFoundEvent(module);
}
}
};
module.dispatchHistoryEvent(eventName,
passer);
}
return forAChild;
}
/**
* Dispatch the event thanks to the history converter.
*
* @param historyName
* name of the event stored in the token
* @param param
* parameters stored in the token
* @param module
* module to which belongs the event
*/
@SuppressWarnings("unchecked")
protected void dispatchEvent(String historyName,
String param,
Mvp4gModule module) {
if (historyName != null) {
@SuppressWarnings("rawtypes") HistoryConverter converter = converters.get(historyName);
if (converter == null) {
sendNotFoundEvent(module);
} else {
String[] tab = historyName.split(MODULE_SEPARATOR);
String finalEventName = tab[tab.length - 1];
converter.convertFromToken(finalEventName,
param,
module.getEventBus());
}
} else {
sendNotFoundEvent(module);
}
}
/**
* Convert an event and its associated parameters to a token.
*
* @param eventName
* name of the event to store
* @param param
* string representation of the objects associated with the event that needs to be
* stored in the token
* @param onlyToken
* if true, only the token will be generated and browser history won't change
*
* @return the generated token
*/
public String place(String eventName,
String param,
boolean onlyToken) {
if (!enabled && !onlyToken) {
return null;
}
String token = tokenize(eventName,
param);
if (converters.get(eventName)
.isCrawlable()) {
token = CRAWLABLE + token;
}
if (!onlyToken) {
history.newItem(token,
false);
}
return token;
}
/**
* Transform an event and its parameters to a token
*
* @param eventName
* event's name
* @param param
* event's parameters
*
* @return token to store in the history
*/
public String tokenize(String eventName,
String param) {
String token = eventName;
if ((param != null) && (param.length() > 0)) {
token = token + getParamSeparator() + param;
}
return token;
}
/**
* @return separator used to differenciate the event's name and its parameters
*/
protected String getParamSeparator() {
return "?";
}
/**
* Clear the history token stored in the browse history url by adding a new empty token
*/
public void clearHistory() {
history.newItem("",
false);
}
/**
* Add a converter for an event.
*
* @param historyName
* name of the event to store in the token
* @param converter
* converter associated with this event
*/
@SuppressWarnings("rawtypes")
public void addConverter(String historyName,
HistoryConverter converter) {
converters.put(historyName,
converter);
}
/**
* @param module
* the module to set
*/
public void setModule(Mvp4gModule module) {
this.module = module;
}
/**
* @param navigationConfirmation
* the navigationConfirmation to set
*/
public void setNavigationConfirmation(NavigationConfirmationInterface navigationConfirmation) {
this.navigationConfirmation = navigationConfirmation;
}
/**
* Calls not found event. By default it will called a root module
* event, but you can override the method if you want to call some
* specific event for child module
*
* @param module
* the last module where event wasn't found. If you will have
* a correct historyName at the begin of url, then this will be a
* child module, else rootModule.
*/
protected void sendNotFoundEvent(Mvp4gModule module) {
this.module.sendNotFoundEvent();
}
/**
* Ask for user's confirmation before firing an event
*
* @param event
* event to confirm
*/
public void confirmEvent(NavigationEventCommand event) {
if (navigationConfirmation == null) {
//no need to remove the confirmation, there is none
event.fireEvent(false);
} else {
navigationConfirmation.confirm(event);
}
}
/**
* @param enabled
* the enabled to set
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy