Package com.mvp4g.client.history

Source Code of com.mvp4g.client.history.PlaceService

/*
* Copyright 2010 Pierre-Laurent Coirier
*
* 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.<br/>
* <br/>
* When an event needs to be stored in the history, the place method of <code>PlaceService</code> is
* called. This method will transform the event to an history token the following way:<br/>
* <br/>
* <b>myurl#eventName?params</b><br/>
* <br/>
* where params is the string returned by the handling method of the history converter for the
* event.<br/>
* If params is null, then the URL will be:<br/>
* <br/>
* <b>myurl#eventName</b><br/>
* <br/>
* 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:<br/>
* <br/>
* <b>myurl#childModule/subChildModule/eventName?params</b><br/>
* <br/>
* By default "?" is used to seperate the event name from the parameters. You can change it thanks
* to <code>@HistoryConfiguration</code>.<br/>
* <br/>
* If the token generated is supposed to be crawlable, then a "!" will be added before the token.
*
*
*
* @author plcoirier
*
*/
public abstract class PlaceService implements ValueChangeHandler<String> {

  public static final String MODULE_SEPARATOR = "/";

  public static final String CRAWLABLE = "!";

  private HistoryProxy history = null;
  private Mvp4gModule module = null;

  @SuppressWarnings( "rawtypes" )
  private Map<String, HistoryConverter> converters = new HashMap<String, HistoryConverter>();
 
  private boolean enabled = true;

  private NavigationConfirmationInterface navigationConfirmation;

  /**
   * Build a <code>PlaceService</code>.
   *
   */
  public PlaceService() {
    this( DefaultHistoryProxy.INSTANCE );
  }

  /**
   * Build a <code>PlaceService</code> and inject an <code>HistoryProxy</code> instance.<br/>
   * <br/>
   * This constructor is handy when you want to test <code>PlaceService</code> without using the
   * GWT History class.<br/>
   * 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.<br/>
   * <br/>
   * Decode the history token and call the convertFromToken method of the history converters
   * associated with this action stored in the token.<br/>
   * <br/>
   * 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<String> 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 {
      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.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();
      } else {
        String[] tab = historyName.split( MODULE_SEPARATOR );
        String finalEventName = tab[tab.length - 1];
        converter.convertFromToken( finalEventName, param, module.getEventBus() );
      }
    } else {
      sendNotFoundEvent();
    }
  }

  /**
   * Convert an event and its associated parameters to a token.<br/>
   *
   * @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;
  }

  /**
   * 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;
  }

  /**
   * 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;
  }

  /**
   * @return
   *     separator used to differenciate the event's name and its parameters
   */
  protected String getParamSeparator() {
    return "?";
  }

  /**
   * Call when token retrieved is null or equals to empty string
   *
   * Don't implement this method, the framework will.
   */
  abstract protected void sendInitEvent();

  /**
   * Call when token retrieved doesn't correspond to an event
   *
   * Don't implement this method, the framework will.
   */
  abstract protected void sendNotFoundEvent();

}
TOP

Related Classes of com.mvp4g.client.history.PlaceService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.