cc.kune.core.client.state.impl.StateManagerDefault.java Source code

Java tutorial

Introduction

Here is the source code for cc.kune.core.client.state.impl.StateManagerDefault.java

Source

/*
 *
    
 * Copyright (C) 2007-2015 Licensed to the Comunes Association (CA) under
 * one or more contributor license agreements (see COPYRIGHT for details).
 * The CA licenses this file to you under the GNU Affero General Public
 * License version 3, (the "License"); you may not use this file except in
 * compliance with the License. This file is part of kune.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package cc.kune.core.client.state.impl;

import org.waveprotocol.wave.client.events.ClientEvents;
import org.waveprotocol.wave.client.events.WaveSelectionEvent;
import org.waveprotocol.wave.model.waveref.InvalidWaveRefException;
import org.waveprotocol.wave.util.escapers.GwtWaverefEncoder;

import cc.kune.common.client.actions.BeforeActionCollection;
import cc.kune.common.client.actions.BeforeActionListener;
import cc.kune.common.client.log.Log;
import cc.kune.common.client.notify.NotifyLevel;
import cc.kune.common.client.notify.ProgressHideEvent;
import cc.kune.common.shared.utils.Pair;
import cc.kune.common.shared.utils.TextUtils;
import cc.kune.core.client.auth.SignIn;
import cc.kune.core.client.events.AppStartEvent;
import cc.kune.core.client.events.AppStartEvent.AppStartHandler;
import cc.kune.core.client.events.GoHomeEvent;
import cc.kune.core.client.events.GroupChangedEvent;
import cc.kune.core.client.events.GroupChangedEvent.GroupChangedHandler;
import cc.kune.core.client.events.SocialNetworkChangedEvent;
import cc.kune.core.client.events.SocialNetworkChangedEvent.SocialNetworkChangedHandler;
import cc.kune.core.client.events.StateChangedEvent;
import cc.kune.core.client.events.StateChangedEvent.StateChangedHandler;
import cc.kune.core.client.events.ToolChangedEvent;
import cc.kune.core.client.events.ToolChangedEvent.ToolChangedHandler;
import cc.kune.core.client.events.UserSignInEvent;
import cc.kune.core.client.events.UserSignOutEvent;
import cc.kune.core.client.rpcservices.AsyncCallbackSimple;
import cc.kune.core.client.sitebar.spaces.Space;
import cc.kune.core.client.sitebar.spaces.SpaceConfEvent;
import cc.kune.core.client.sitebar.spaces.SpaceSelectEvent;
import cc.kune.core.client.state.ContentCache;
import cc.kune.core.client.state.HistoryTokenCallback;
import cc.kune.core.client.state.HistoryWrapper;
import cc.kune.core.client.state.Session;
import cc.kune.core.client.state.SiteTokenListeners;
import cc.kune.core.client.state.SiteTokens;
import cc.kune.core.client.state.StateManager;
import cc.kune.core.client.state.TokenMatcher;
import cc.kune.core.client.state.TokenUtils;
import cc.kune.core.shared.domain.utils.StateToken;
import cc.kune.core.shared.dto.SocialNetworkDataDTO;
import cc.kune.core.shared.dto.StateAbstractDTO;
import cc.kune.gspace.client.actions.ShowHelpContainerEvent;

import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.web.bindery.event.shared.EventBus;
import com.google.web.bindery.event.shared.HandlerRegistration;

/**
 * The Class StateManagerDefault.
 *
 * @author danigb@gmail.com
 * @author vjrj@ourproject.org (Vicente J. Ruiz Jurado)
 */
public class StateManagerDefault implements StateManager, ValueChangeHandler<String> {

    /**
     * The Interface OnFinishGetContent.
     *
     * @author danigb@gmail.com
     * @author vjrj@ourproject.org (Vicente J. Ruiz Jurado)
     */
    public interface OnFinishGetContent {

        /**
         * Finish.
         */
        void finish();
    }

    /** The before state change collection. */
    private final BeforeActionCollection beforeStateChangeCollection;

    /** The content cache. */
    private final ContentCache contentCache;

    /** The event bus. */
    private final EventBus eventBus;

    /** The history. */
    private final HistoryWrapper history;

    /** The previous group token. */
    private StateToken previousGroupToken;

    /** The previous hash. */
    private String previousHash;

    /**
     * When a historyChanged is interrupted (for instance because you are editing
     * something), the new history token is stored here.
     */
    private String resumedHistoryToken;

    /** The session. */
    private final Session session;

    /** The sign in. */
    private final Provider<SignIn> signIn;

    /** The site tokens. */
    private final SiteTokenListeners siteTokens;

    /**
     * Instantiates a new state manager default.
     *
     * @param contentProvider
     *          the content provider
     * @param session
     *          the session
     * @param history
     *          the history
     * @param tokenMatcher
     *          the token matcher
     * @param eventBus
     *          the event bus
     * @param siteTokens
     *          the site tokens
     * @param signIn
     *          the sign in
     */
    @Inject
    public StateManagerDefault(final ContentCache contentProvider, final Session session,
            final HistoryWrapper history, final EventBus eventBus, final SiteTokenListeners siteTokens,
            final Provider<SignIn> signIn) {
        this.eventBus = eventBus;
        this.contentCache = contentProvider;
        this.session = session;
        this.history = history;
        this.signIn = signIn;
        this.previousGroupToken = null;
        this.previousHash = null;
        this.resumedHistoryToken = null;
        this.siteTokens = siteTokens;
        beforeStateChangeCollection = new BeforeActionCollection();
        TokenMatcher.init(GwtWaverefEncoder.INSTANCE);
        session.onAppStart(true, new AppStartHandler() {
            @Override
            public void onAppStart(final AppStartEvent event) {
                session.onUserSignIn(false, new UserSignInEvent.UserSignInHandler() {
                    @Override
                    public void onUserSignIn(final UserSignInEvent event) {
                        // refreshCurrentGroupState();
                    }
                });
                session.onUserSignOut(false, new UserSignOutEvent.UserSignOutHandler() {
                    @Override
                    public void onUserSignOut(final UserSignOutEvent event) {
                        refreshCurrentStateWithoutCache();
                    }
                });
                processCurrentHistoryToken();
            }
        });
        onSocialNetworkChanged(false, new SocialNetworkChangedHandler() {
            @Override
            public void onSocialNetworkChanged(final SocialNetworkChangedEvent event) {
                contentCache.removeCacheOfGroup(event.getState().getStateToken().getGroup());
            }
        });
        eventBus.addHandler(GoHomeEvent.getType(), new GoHomeEvent.GoHomeHandler() {
            @Override
            public void onGoHome(final GoHomeEvent event) {
                gotoDefaultHomepage();
            }
        });
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#addBeforeStateChangeListener(cc.
     * kune.common.client.actions.BeforeActionListener)
     */
    @Override
    public void addBeforeStateChangeListener(final BeforeActionListener listener) {
        beforeStateChangeCollection.add(listener);
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#addSiteToken(java.lang.String,
     * cc.kune.core.client.state.HistoryTokenCallback)
     */
    @Override
    public void addSiteToken(final String token, final HistoryTokenCallback callback) {
        siteTokens.put(token.toLowerCase(), callback);
    }

    /**
     * Check group and tool change.
     *
     * @param newState
     *          the new state
     */
    private void checkGroupAndToolChange(final StateAbstractDTO newState) {
        final String newGroup = newState.getStateToken().getGroup();
        final String previousGroup = getPreviousGroup();
        if (startingUp() || !previousGroup.equals(newGroup)) {
            Log.debug("New group: " + newGroup);
            GroupChangedEvent.fire(eventBus, previousGroup, newGroup);
        }
        final String previousToolName = getPreviousTool();
        final String newTokenTool = newState.getStateToken().getTool();
        final String newToolName = newTokenTool == null ? "" : newTokenTool;
        if (startingUp() || previousToolName == null || !previousToolName.equals(newToolName)) {
            Log.debug("New tool: " + newToolName);
            ToolChangedEvent.fire(eventBus, previousGroupToken, newState.getStateToken());
        }
    }

    /**
     * Do action or sign in if needed.
     *
     * @param tokenListener
     *          the token listener
     * @param currentToken
     *          the current token
     * @param secondPart
     *          the second part
     */
    private void doActionOrSignInIfNeeded(final HistoryTokenCallback tokenListener, final String currentToken,
            final String firstPart, final String secondPart) {
        // First of all we see if we are starting up, and we get the def content
        // first
        if (startingUp()) {
            // Starting with some token like "signin": load defContent first
            Log.debug("Starting up with a token like #signin or #token(param): load defContent first");
            getContent(new StateToken(SiteTokens.GROUP_HOME), false, new OnFinishGetContent() {
                @Override
                public void finish() {
                    doActionOrSignInIfNeededAfterStarted(tokenListener, currentToken, firstPart, secondPart);
                }
            });
        } else {
            doActionOrSignInIfNeededAfterStarted(tokenListener, currentToken, firstPart, secondPart);
        }
    }

    /**
     * Do action or sign in if needed started.
     *
     * @param tokenListener
     *          the token listener
     * @param currentToken
     *          the current token
     * @param secondPart
     *          the second part
     */
    private void doActionOrSignInIfNeededAfterStarted(final HistoryTokenCallback tokenListener,
            final String currentToken, final String firstPart, final String secondPart) {
        if (tokenListener.authMandatory() && session.isNotLogged()) {
            Log.debug("login mandatory for " + currentToken);
            // Ok, we have to redirect because this token (for instance
            // #translate) needs the user authenticated
            final String infoMessage = tokenListener.getInfoMessage();
            if (TextUtils.notEmpty(infoMessage)) {
                signIn.get().setErrorMessage(infoMessage, NotifyLevel.info);
            }
            if (SiteTokens.SIGN_IN.equals(firstPart)) {
                signIn.get().showSignInDialog(secondPart);
            } else {
                redirectButSignInBefore(currentToken);
            }
        } else {
            // The auth is not mandatory, go ahead with the token action
            Log.debug("Executing action related with historytoken " + secondPart);
            tokenListener.onHistoryToken(secondPart);
        }
    }

    /**
     * Gets the content.
     *
     * @param newState
     *          the new state
     * @return the content
     */
    private void getContent(final StateToken newState) {
        Log.debug("Get Content: " + newState);
        getContent(newState, false);
    }

    /**
     * Gets the content.
     *
     * @param newState
     *          the new state
     * @param setBrowserHistory
     *          the set browser history
     * @return the content
     */
    private void getContent(final StateToken newState, final boolean setBrowserHistory) {
        final OnFinishGetContent doNothing = new OnFinishGetContent() {
            @Override
            public void finish() {
                // Do nothing
            }
        };
        getContent(newState, setBrowserHistory, doNothing);
    }

    /**
     * Gets the content.
     *
     * @param newState
     *          the new state
     * @param setBrowserHistory
     *          the set browser history
     * @param andThen
     *          the and then
     * @return the content
     */
    private void getContent(final StateToken newState, final boolean setBrowserHistory,
            final OnFinishGetContent andThen) {
        // NotifyUser.info("loading: " + newState + " because current:" +
        // session.getCurrentStateToken());
        contentCache.getContent(session.getUserHash(), newState, new AsyncCallbackSimple<StateAbstractDTO>() {
            @Override
            public void onSuccess(final StateAbstractDTO newState) {
                Log.debug("Retrived new state sucessfully");
                setState(newState);
                final String currentToken = newState.getStateToken().toString();
                SpaceConfEvent.fire(eventBus, Space.groupSpace, currentToken);
                SpaceConfEvent.fire(eventBus, Space.publicSpace, TokenUtils.preview(currentToken));
                if (setBrowserHistory) {
                    previousHash = history.getToken();
                    history.newItem(currentToken, false);
                    SpaceSelectEvent.fire(eventBus, Space.groupSpace);
                }
                // if (newState instanceof StateContentDTO) {
                // final StateContentDTO cnt = (StateContentDTO) newState;
                // }
                andThen.finish();
            }
        });
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#getCurrentToken()
     */
    @Override
    public String getCurrentToken() {
        return history.getToken();
    }

    /**
     * Gets the previous group.
     *
     * @return the previous group
     */
    private String getPreviousGroup() {
        final String previousGroup = startingUp() ? "" : previousGroupToken.getGroup();
        return previousGroup;
    }

    /**
     * Gets the previous tool.
     *
     * @return the previous tool
     */
    private String getPreviousTool() {
        final String previousTool = startingUp() ? "" : previousGroupToken.getTool();
        return previousTool;
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#gotoDefaultHomepage()
     */
    @Override
    public void gotoDefaultHomepage() {
        Log.debug("Goto def page called");
        getContent(new StateToken(SiteTokens.GROUP_HOME), true);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#gotoHistoryToken(java.lang.String)
     */
    @Override
    public void gotoHistoryToken(final String token) {
        Log.debug("StateManager: history goto-string-token: " + token);
        previousHash = history.getToken();
        history.newItem(token);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#gotoHistoryTokenButRedirectToCurrent
     * (java.lang.String)
     */
    @Override
    public void gotoHistoryTokenButRedirectToCurrent(final String token) {
        gotoHistoryToken(TokenUtils.addRedirect(token, history.getToken()));
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#gotoHomeSpace()
     */
    @Override
    public void gotoHomeSpace() {
        gotoHistoryToken(SiteTokens.HOME);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#gotoStateToken(cc.kune.core.shared
     * .domain.utils.StateToken)
     */
    @Override
    public void gotoStateToken(final StateToken newToken) {
        Log.debug("StateManager: history goto-token: " + newToken + ", previous: " + previousGroupToken);
        previousHash = history.getToken();
        history.newItem(newToken.getEncoded());
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#gotoStateToken(cc.kune.core.shared
     * .domain.utils.StateToken, boolean)
     */
    @Override
    public void gotoStateToken(final StateToken token, final boolean useCache) {
        if (!useCache) {
            contentCache.remove(token);
        }
        gotoStateToken(token);
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#onGroupChanged(boolean,
     * cc.kune.core.client.events.GroupChangedEvent.GroupChangedHandler)
     */
    @Override
    public HandlerRegistration onGroupChanged(final boolean fireNow, final GroupChangedHandler handler) {
        final HandlerRegistration handlerReg = eventBus.addHandler(GroupChangedEvent.getType(), handler);
        final StateAbstractDTO currentState = session.getCurrentState();
        if (fireNow && currentState != null) {
            handler.onGroupChanged(
                    new GroupChangedEvent(getPreviousGroup(), currentState.getStateToken().getGroup()));
        }
        return handlerReg;
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#onSocialNetworkChanged(boolean,
     * cc
     * .kune.core.client.events.SocialNetworkChangedEvent.SocialNetworkChangedHandler
     * )
     */
    @Override
    public HandlerRegistration onSocialNetworkChanged(final boolean fireNow,
            final SocialNetworkChangedHandler handler) {
        final HandlerRegistration handlerReg = eventBus.addHandler(SocialNetworkChangedEvent.getType(), handler);
        final StateAbstractDTO currentState = session.getCurrentState();
        if (fireNow && currentState != null) {
            handler.onSocialNetworkChanged(new SocialNetworkChangedEvent(currentState));
        }
        return handlerReg;
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#onStateChanged(boolean,
     * cc.kune.core.client.events.StateChangedEvent.StateChangedHandler)
     */
    @Override
    public HandlerRegistration onStateChanged(final boolean fireNow, final StateChangedHandler handler) {
        final HandlerRegistration handlerReg = eventBus.addHandler(StateChangedEvent.getType(), handler);
        final StateAbstractDTO currentState = session.getCurrentState();
        if (fireNow && currentState != null) {
            handler.onStateChanged(new StateChangedEvent(currentState));
        }
        return handlerReg;
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#onToolChanged(boolean,
     * cc.kune.core.client.events.ToolChangedEvent.ToolChangedHandler)
     */
    @Override
    public HandlerRegistration onToolChanged(final boolean fireNow, final ToolChangedHandler handler) {
        final HandlerRegistration handlerReg = eventBus.addHandler(ToolChangedEvent.getType(), handler);
        final StateAbstractDTO currentState = session.getCurrentState();
        if (fireNow && currentState != null) {
            handler.onToolChanged(new ToolChangedEvent(previousGroupToken, currentState.getStateToken()));
        }
        return handlerReg;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.google.gwt.event.logical.shared.ValueChangeHandler#onValueChange(com
     * .google.gwt.event.logical.shared.ValueChangeEvent)
     */
    @Override
    public void onValueChange(final ValueChangeEvent<String> event) {
        Log.debug("History event value changed: " + event.getValue());
        // First of all check that we are generating this #!fragment urls, later
        history.checkHashbang();
        processHistoryToken(HistoryUtils.undoHashbang(event.getValue()));
    }

    /**
     * Process current history token.
     */
    private void processCurrentHistoryToken() {
        processHistoryToken(history.getToken());
    }

    /**
     * Process #history token changes (this method should be rewritten).
     *
     * @param newToken
     *          the new token
     */
    void processHistoryToken(final String newToken) {
        // http://code.google.com/p/google-web-toolkit-doc-1-5/wiki/DevGuideHistory
        if (beforeStateChangeCollection.checkBeforeAction()) {
            // There isn't a beforeStateChange listener that stops this history
            // change

            // WARNING: String.toLowerCase breaks Wave URls
            final HistoryTokenCallback tokenListener = newToken != null ? siteTokens.get(newToken.toLowerCase())
                    : null;
            boolean isSpecialHash = false;
            Log.debug("StateManager: on history changed '" + newToken + "'");
            if (tokenListener != null) {
                isSpecialHash = true;
                Log.debug("token is one of #newgroup #signin #translate without #hash(redirection) ...");
                doActionOrSignInIfNeeded(tokenListener, newToken, newToken, newToken);
            } else {
                Log.debug("Is not a special hash like #newgroup, etc, or maybe has a #hash(redirection)");
                // token is not one of #newgroup #signin #translate ...
                final String newTokenLower = newToken != null ? newToken.toLowerCase() : null;
                if (newTokenLower != null && TokenMatcher.hasRedirect(newTokenLower)) {
                    final Pair<String, String> redirect = TokenMatcher.getRedirect(newToken);
                    final String firstToken = redirect.getLeft().toLowerCase();
                    final String sndToken = redirect.getRight();
                    final StateToken sndTokenT = new StateToken(sndToken);
                    if (firstToken.equals(SiteTokens.PREVIEW)) {
                        SpaceSelectEvent.fire(eventBus, Space.publicSpace);
                        SpaceConfEvent.fire(eventBus, Space.groupSpace, sndToken);
                        SpaceConfEvent.fire(eventBus, Space.publicSpace, TokenUtils.preview(sndToken));
                        getContent(sndTokenT);
                        // Don't continue
                        return;
                    } else if (firstToken.equals(SiteTokens.TUTORIAL)) {
                        getContent(sndTokenT, true, new OnFinishGetContent() {
                            @Override
                            public void finish() {
                                ShowHelpContainerEvent.fire(eventBus, sndTokenT.getTool());
                            }
                        });
                        // Don't continue
                        return;
                    } else {
                        final HistoryTokenCallback tokenWithRedirect = siteTokens.get(firstToken);
                        if (tokenWithRedirect != null) {
                            isSpecialHash = true;
                            Log.debug("Is some #subtitle(foo) or #verifyemail(hash) etc, firstToken " + firstToken);
                            doActionOrSignInIfNeeded(tokenWithRedirect, newToken, firstToken, sndToken);
                        }
                    }
                }
                if (TokenMatcher.isWaveToken(newToken)) {
                    if (session.isLogged()) {
                        SpaceConfEvent.fire(eventBus, Space.userSpace, newToken);
                        SpaceSelectEvent.fire(eventBus, Space.userSpace);
                        try {
                            ClientEvents.get().fireEvent(
                                    new WaveSelectionEvent(GwtWaverefEncoder.decodeWaveRefFromPath(newToken)));
                        } catch (final InvalidWaveRefException e) {
                            Log.error(newToken, e);
                        }
                    } else {
                        // Wave, but don't logged
                        redirectButSignInBefore(newToken);
                        if (startingUp()) {
                            // Starting application (with Wave)
                            getContent(new StateToken(SiteTokens.GROUP_HOME), false);
                        }
                    }
                } else if (!isSpecialHash) {
                    // FIXME This can be in the top of isWaveToken....
                    if (TokenMatcher.isGroupToken(newToken)) {
                        Log.debug("StateManager: is a group token: '" + newToken + "'");
                        SpaceConfEvent.fire(eventBus, Space.groupSpace, newToken);
                        SpaceConfEvent.fire(eventBus, Space.publicSpace, TokenUtils.preview(newToken));
                        SpaceSelectEvent.fire(eventBus, Space.groupSpace);
                        getContent(new StateToken(newToken));
                    } else {
                        Log.debug("Last option, get default with token: " + newToken);
                        getContent(new StateToken(SiteTokens.GROUP_HOME), false);
                    }
                }
            }
        } else {
            resumedHistoryToken = newToken;
        }
    }

    /**
     * Redirect but sign in before.
     *
     * @param newHistoryToken
     *          the new history token
     */
    private void redirectButSignInBefore(final String newHistoryToken) {
        history.newItem(TokenUtils.addRedirect(SiteTokens.SIGN_IN, newHistoryToken));
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#redirectOrRestorePreviousToken(boolean
     * )
     */
    @Override
    public void redirectOrRestorePreviousToken(final boolean fireChange) {
        final String token = history.getToken();
        if (TokenMatcher.hasRedirect(token)) {
            // URL of the form signin(group.tool)
            final String previousToken = TokenMatcher.getRedirect(token).getRight();
            if (previousToken.equals(SiteTokens.WAVE_INBOX) && session.isNotLogged()) {
                // signin(inbox) && cancel
                restorePreviousToken(fireChange);
            } else {
                history.newItem(previousHash);
            }
        } else {
            // No redirect then restore previous token
            restorePreviousToken(fireChange);
        }
    }

    /**
     * <p>
     * Reload current state (using client cache if available)
     * </p>
     * .
     */
    @Override
    public void refreshCurrentState() {
        processHistoryToken(history.getToken());
    }

    /**
     * <p>
     * Reload current state (not using client cache)
     * </p>
     * .
     */
    @Override
    public void refreshCurrentStateWithoutCache() {
        final StateToken currentStateToken = session.getCurrentStateToken();
        if (currentStateToken == null) {
            processCurrentHistoryToken();
        } else {
            contentCache.remove(currentStateToken);
            getContent(currentStateToken);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#removeBeforeStateChangeListener(
     * cc.kune.common.client.actions.BeforeActionListener)
     */
    @Override
    public void removeBeforeStateChangeListener(final BeforeActionListener listener) {
        beforeStateChangeCollection.remove(listener);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#removeCache(cc.kune.core.shared.
     * domain.utils.StateToken)
     */
    @Override
    public void removeCache(final StateToken parentToken) {
        contentCache.remove(parentToken);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#removeCacheOfGroup(java.lang.String)
     */
    @Override
    public void removeCacheOfGroup(final String group) {
        contentCache.removeCacheOfGroup(group);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#removeSiteToken(java.lang.String)
     */
    @Override
    public void removeSiteToken(final String token) {
        siteTokens.remove(token);
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#restorePreviousToken(boolean)
     */
    @Override
    public void restorePreviousToken(final boolean fireChange) {
        if (previousHash != null) {
            if (fireChange) {
                gotoHistoryToken(previousHash);
            } else {
                setHistoryStateToken(previousHash);
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see cc.kune.core.client.state.StateManager#resumeTokenChange()
     */
    @Override
    public void resumeTokenChange() {
        if (resumedHistoryToken != null) {
            // Is this reload redundant?
            refreshCurrentState();
            gotoHistoryToken(resumedHistoryToken);
            resumedHistoryToken = null;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#setHistoryStateToken(java.lang.String
     * )
     */
    @Override
    public void setHistoryStateToken(final String newToken) {
        Log.debug("StateManager: history goto-token: " + newToken + ", previous: " + previousGroupToken);
        previousHash = history.getToken();
        history.newItem(newToken, false);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#setRetrievedState(cc.kune.core.shared
     * .dto.StateAbstractDTO)
     */
    @Override
    public void setRetrievedState(final StateAbstractDTO newState) {
        contentCache.cache(newState.getStateToken(), newState);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#setRetrievedStateAndGo(cc.kune.core
     * .shared.dto.StateAbstractDTO)
     */
    @Override
    public void setRetrievedStateAndGo(final StateAbstractDTO newState) {
        setRetrievedState(newState);
        final String token = newState.getStateToken().toString();
        if (history.getToken().equals(token)) {
            setState(newState);
        }
        previousHash = history.getToken();
        history.newItem(token);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cc.kune.core.client.state.StateManager#setSocialNetwork(cc.kune.core.shared
     * .dto.SocialNetworkDataDTO)
     */
    @Override
    public void setSocialNetwork(final SocialNetworkDataDTO socialNet) {
        StateAbstractDTO state;
        if (session != null && (state = session.getCurrentState()) != null) {
            // After a SN operation, usually returns a SocialNetworkResultDTO
            // with new SN data and we refresh the state
            // to avoid to reload() again the state
            state.setSocialNetworkData(socialNet);
            SocialNetworkChangedEvent.fire(eventBus, state);
        }
    }

    /**
     * Sets the state.
     *
     * @param newState
     *          the new state
     */
    void setState(final StateAbstractDTO newState) {
        session.setCurrentState(newState);
        final StateToken newToken = newState.getStateToken();
        Log.debug("Set new state: " + newToken);
        contentCache.cache(newToken, newState);
        // history.newItem(newToken.toString(), false);
        StateChangedEvent.fire(eventBus, newState);
        checkGroupAndToolChange(newState);
        previousGroupToken = newToken.copy();
        eventBus.fireEvent(new ProgressHideEvent());
    }

    /**
     * Starting up.
     *
     * @return true, if successful
     */
    private boolean startingUp() {
        return previousGroupToken == null;
    }
}