com.lst.deploymentautomation.vaadin.core.AppNavigator.java Source code

Java tutorial

Introduction

Here is the source code for com.lst.deploymentautomation.vaadin.core.AppNavigator.java

Source

/*
 *********************************************************************
    
 $Id$
    
    
 Copyright (c) 2007-2014 Whitestein Technologies AG,
 Riedstrasse 13, CH-6330 Cham, Switzerland.
 All rights reserved.
    
 This software is confidential and proprietary information of
 Whitestein Technologies AG.
 You shall not disclose this confidential information and shall use
 it only in accordance with the terms of the license agreement you
 entered into with Whitestein Technologies AG.
 The use of this file in source or binary form requires a written
 license from Whitestein Technologies AG.
 *********************************************************************
 */
package com.lst.deploymentautomation.vaadin.core;

import java.security.AccessControlException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewDisplay;
import com.vaadin.server.Page;
import com.vaadin.server.Page.UriFragmentChangedEvent;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.UI;
import com.whitestein.lsps.engine.lang.ExecutionContext;
import com.whitestein.lsps.lang.Decimal;
import com.whitestein.lsps.lang.exec.MapHolder;
import com.whitestein.lsps.lang.exec.RecordHolder;

/**
 * Custom {@link Navigator} subclass that remembers UI state when moving back/forward in browser history.
 * 
 * @author mhi
 */
public class AppNavigator extends Navigator {

    private static final long serialVersionUID = 1L;

    /** Delimiter used in the URL to keep the ID of the view in the UI history. */
    public static final String HISTORY_ID_DELIMITER = "/~";

    private static final int MAX_VIEW_COUNT = 10;
    private static final long ONE_YEAR = 1000 * 3600 * 24 * 365;

    private String historyId;

    private Map<String, AppView> views = new HashMap<String, AppView>();
    private List<String> history = new LinkedList<String>();
    private List<String> future = new LinkedList<String>();

    /**
     * Full constructor.
     * @param ui
     * @param display
     */
    public AppNavigator(UI ui, ViewDisplay display) {
        super(ui, new AppNavigationManager(ui.getPage()), display);
    }

    @Override
    public void navigateTo(String stateWithHistory) {
        historyId = getHistoryId(stateWithHistory);

        LspsUI ui = (LspsUI) UI.getCurrent();
        if (ui.getPage().getBrowserWindowWidth() < 768) {
            ui.addStyleName("l-menu-collapsed");
            ui.getUser().setSetting("collapsedMenu", true);
        }

        String navigationState;
        AppView view;
        if (historyId == null) {
            historyId = Long.toHexString(System.currentTimeMillis() % ONE_YEAR); //now modulo one year
            navigationState = stateWithHistory;
            view = null;

        } else {
            navigationState = getNavigationState(stateWithHistory);
            view = views.get(historyId);
        }

        if (view != null) {
            int historyIndex = history.indexOf(historyId);
            if (historyIndex >= 0) {
                //move back in history
                List<String> entriesToMove = history.subList(historyIndex + 1, history.size());
                future.addAll(0, entriesToMove); //add to the beginning of the future
                entriesToMove.clear(); //remove from the history
            } else {
                //move forward in history
                int futureIndex = future.indexOf(historyId);
                List<String> entriesToMove = future.subList(0, futureIndex + 1);
                history.addAll(entriesToMove); //add to the beginning of the history
                entriesToMove.clear(); //remove from the future
            }

            //return to an already existing view
            navigateTo(view, navigationState, "");

        } else {
            //create new view and navigate to it
            try {
                super.navigateTo(navigationState);
            } catch (AccessControlException e) {
                Notification.show(e.getMessage(), Type.ERROR_MESSAGE);
            }
        }
    }

    @Override
    protected void navigateTo(View view, String viewName, String parameters) {
        AppView currentView = (view instanceof AppView) ? (AppView) view : null;

        boolean screenNotYetInHistory = currentView != null && views.get(historyId) == null;
        if (screenNotYetInHistory) {
            //remember the view for the given historyId
            views.put(historyId, currentView);
            history.add(historyId);

            //if the history is too long, remove oldest entry
            if (history.size() > MAX_VIEW_COUNT) {
                String oldHistoryId = history.remove(0);
                AppView old = views.remove(oldHistoryId);
                old.cleanup();
            }

            //clear the future and delete all related views
            for (String oldHistoryId : future) {
                AppView old = views.remove(oldHistoryId);
                old.cleanup();
            }
            future.clear();
        }
        try {
            super.navigateTo(view, viewName, parameters);
        } catch (AccessControlException e) {
            Notification.show(e.getMessage(), Type.ERROR_MESSAGE);
        }
    }

    private static String getHistoryId(String stateWithHistory) {
        if (stateWithHistory.contains(HISTORY_ID_DELIMITER)) {
            return stateWithHistory.substring(stateWithHistory.lastIndexOf(HISTORY_ID_DELIMITER) + 2);
        } else {
            return null;
        }
    }

    private static String getNavigationState(String stateWithHistory) {
        if (stateWithHistory.contains(HISTORY_ID_DELIMITER)) {
            return stateWithHistory.substring(0, stateWithHistory.lastIndexOf(HISTORY_ID_DELIMITER));
        } else {
            return stateWithHistory;
        }
    }

    /**
     * Returns the current UI history entries as needed for the {@code human:getUIHistory()} function.
     * @param context not null
     * @return UI history
     */
    public MapHolder getHistory(ExecutionContext context) {
        Map<Decimal, RecordHolder> uiHistory = new LinkedHashMap<Decimal, RecordHolder>();

        long i = history.size() - 1;
        for (String historyId : history) {
            AppView view = views.get(historyId);
            uiHistory.put(Decimal.valueOf(i--), view.getHistoryEntry(context, historyId));
        }
        for (String historyId : future) {
            AppView view = views.get(historyId);
            uiHistory.put(Decimal.valueOf(i--), view.getHistoryEntry(context, historyId));
        }
        return context.getNamespace().createMap(uiHistory);
    }

    /**
     * Cleans up all views. Called when the UI is detached.
     */
    public void cleanup() {
        for (AppView view : views.values()) {
            view.cleanup();
        }
    }

    private static class AppNavigationManager extends UriFragmentManager {

        private static final long serialVersionUID = 1L;

        private AppNavigator navigator;

        public AppNavigationManager(Page page) {
            super(page);
        }

        @Override
        public void setNavigator(Navigator navigator) {
            super.setNavigator(navigator);
            this.navigator = (AppNavigator) navigator;
        }

        @Override
        public void uriFragmentChanged(UriFragmentChangedEvent event) {
            //reset historyId first, otherwise getState would return new view with old historyId
            navigator.historyId = null;

            super.uriFragmentChanged(event);
        }

        @Override
        public String getState() {
            String stateWithHistory = super.getState();
            String historyId = getHistoryId(stateWithHistory);
            if (historyId == null && navigator.historyId != null) {
                stateWithHistory += HISTORY_ID_DELIMITER + navigator.historyId;
            }
            return stateWithHistory;
        }

        @Override
        public void setState(String state) {
            String historyId = navigator.historyId;
            String stateWithHistory = (historyId == null) ? state : state + HISTORY_ID_DELIMITER + historyId;
            super.setState(stateWithHistory);
        }

    }

}