eu.numberfour.n4js.ui.workingsets.WorkingSetManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for eu.numberfour.n4js.ui.workingsets.WorkingSetManagerImpl.java

Source

/**
 * Copyright (c) 2016 NumberFour AG.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   NumberFour AG - Initial API and implementation
 */
package eu.numberfour.n4js.ui.workingsets;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.FluentIterable.from;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newHashSet;
import static eu.numberfour.n4js.ui.workingsets.WorkingSet.OTHERS_WORKING_SET_ID;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;

import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;

import eu.numberfour.n4js.utils.Diff;
import eu.numberfour.n4js.utils.StatusHelper;

/**
 * Base working set manager which does not allow working set addition, removal and/or edition. The order of the working
 * sets can be modified. This implementation is not thread safe. It is the clients responsibility to synchronize on it
 * when thread safety is required.
 */
public abstract class WorkingSetManagerImpl implements WorkingSetManager, Resetable {

    private static final Logger LOGGER = Logger.getLogger(WorkingSetManagerImpl.class);

    /**
     * Separator used when persisting key value pairs into the OSGi preference store.
     */
    protected static final String SEPARATOR = "#";

    /**
     * An empty string for representing not yet persisted configuration.
     */
    protected static final String EMPTY_STRING = "";

    private static final String ORDERED_IDS_KEY = ".orderedIds";
    private static final String VISIBLE_IDS_KEY = ".visibleIds";

    /**
     * List of all working sets. Used internally for caching purposes.
     */
    private List<WorkingSet> allWorkingSets = null;

    /**
     * List of visible working sets. Used internally for caching purposes.
     */
    private List<WorkingSet> visibleWorkingSets = null;

    /**
     * Ordered list of the working set IDs.
     */
    protected final List<String> orderedWorkingSetIds = newArrayList();

    /**
     * A collection of working set IDs that are configured to be visible on the UI.
     */
    protected final Collection<String> visibleWorkingSetIds = newHashSet();

    /**
     * Status helper for creating {@link IStatus status} instances in a convenient way.
     */
    @Inject
    protected StatusHelper statusHelper;

    @Inject
    private WorkingSetManagerBroker workingSetManagerBroker;

    @Override
    public String getId() {
        return getClass().getName();
    }

    @Override
    public WorkingSetManagerBroker getWorkingSetManagerBroker() {
        return workingSetManagerBroker;
    }

    @Override
    public WorkingSet[] getWorkingSets() {
        return Iterables.toArray(getOrCreateVisibleWorkingSets(), WorkingSet.class);
    }

    @Override
    public WorkingSet[] getAllWorkingSets() {
        return Iterables.toArray(getOrCreateAllWorkingSets(), WorkingSet.class);
    }

    @Override
    public void select(final Iterable<WorkingSet> workingSets) {
        visibleWorkingSetIds.addAll(from(workingSets).transform(ws -> ws.getId()).toList());
    }

    @Override
    public void unselect(final Iterable<WorkingSet> workingSets) {
        visibleWorkingSetIds.removeAll(from(workingSets).transform(ws -> ws.getId()).toList());
    }

    @Override
    public IStatus saveState(final IProgressMonitor monitor) {

        final Preferences node = getPreferences();

        // Save ordered labels.
        node.put(ORDERED_IDS_KEY, Joiner.on(SEPARATOR).join(orderedWorkingSetIds));

        // Save visible labels.
        node.put(VISIBLE_IDS_KEY, Joiner.on(SEPARATOR).join(visibleWorkingSetIds));

        try {
            node.flush();
        } catch (final BackingStoreException e) {
            final String message = "Error occurred while saving state to preference store.";
            LOGGER.error(message, e);
            return statusHelper.createError(message, e);
        }

        return statusHelper.OK();
    }

    @Override
    public IStatus restoreState(final IProgressMonitor monitor) {

        final Preferences node = getPreferences();

        // Restore ordered labels.
        final String orderedLabels = node.get(ORDERED_IDS_KEY, EMPTY_STRING);
        if (!Strings.isNullOrEmpty(orderedLabels)) {
            orderedWorkingSetIds.clear();
            orderedWorkingSetIds.addAll(Arrays.asList(orderedLabels.split(SEPARATOR)));
        }

        // Restore visible labels.
        final String visibleLabels = node.get(VISIBLE_IDS_KEY, EMPTY_STRING);
        if (!Strings.isNullOrEmpty(visibleLabels)) {
            visibleWorkingSetIds.clear();
            visibleWorkingSetIds.addAll(Arrays.asList(visibleLabels.split(SEPARATOR)));
        }

        discardWorkingSetCaches();

        return statusHelper.OK();
    }

    @Override
    public void updateState(final Diff<WorkingSet> diff) {

        if (!diff.isEmpty()) {
            // Deselect all.
            visibleWorkingSetIds.clear();

            // Select visible ones.
            select(Arrays.asList(diff.getNewItems()));

            // Update order.
            orderedWorkingSetIds.clear();
            for (final WorkingSet workingSet : diff.getNewAllItems()) {
                orderedWorkingSetIds.add(workingSet.getId());
            }

            discardWorkingSetCaches();
            getWorkingSetManagerBroker().fireWorkingSetManagerUpdated(getId(), diff);
        }

    }

    /**
     * Orders by case sensitive name ordering, if no explicit ordering is specified yet. The
     * {@link WorkingSet#OTHERS_WORKING_SET_ID Other Projects} reserved working set name/ID is considered to be the
     * first one.
     */
    @Override
    public int compare(final WorkingSet left, final WorkingSet right) {
        if (left == null) {
            return right == null ? 0 : 1;
        }

        final String rightId = right.getId();
        final String leftId = left.getId();

        checkNotNull(leftId, "The ID of the working set must not be null. Working set: " + left);
        checkNotNull(rightId, "The ID of the working set must not be null. Working set: " + right);

        if (orderedWorkingSetIds.isEmpty()) {

            if (OTHERS_WORKING_SET_ID.equals(leftId)) {
                return OTHERS_WORKING_SET_ID.equals(rightId) ? 0 : -1;
            }

            if (OTHERS_WORKING_SET_ID.equals(rightId)) {
                return OTHERS_WORKING_SET_ID.equals(leftId) ? 0 : 1;
            }

            final String rightName = right.getName();
            final String leftName = left.getName();

            checkNotNull(leftName, "The name of the working set must not be null. Working set: " + left);
            checkNotNull(rightName, "The name of the working set must not be null. Working set: " + right);

            return leftName.compareTo(rightName);
        }

        return orderedWorkingSetIds.indexOf(leftId) - orderedWorkingSetIds.indexOf(rightId);
    }

    @Override
    public void reset() {
        try {
            getPreferences().clear();
            getPreferences().flush();
            discardWorkingSetState();
            discardWorkingSetCaches();
            restoreState(new NullProgressMonitor());
        } catch (BackingStoreException e) {
            LOGGER.error("Error occurred while clearing persisted state.", e);
        }
    }

    /**
     * Initializes and returns with all available working sets. The returning list includes the hidden ones as well.
     *
     * @return a list of all available working sets.
     */
    protected abstract List<WorkingSet> initializeWorkingSets();

    /**
     * Discards the state of caches used by the current manager.
     */
    protected void discardWorkingSetCaches() {
        allWorkingSets = null;
        visibleWorkingSets = null;
    }

    /**
     * Discards the state of the working set manager. This state is equivalent with the persisted state. Overriding
     * methods should call super to make sure the entire state of the working set manager is discarded.
     */
    protected void discardWorkingSetState() {
        visibleWorkingSetIds.clear();
        orderedWorkingSetIds.clear();
    }

    /**
     * Returns with all working sets. On demand, creates them by calling {@link #initializeWorkingSets()} internally.
     *
     * @return a list of all working sets.
     */
    protected List<WorkingSet> getOrCreateAllWorkingSets() {

        if (allWorkingSets != null) {
            return allWorkingSets;
        }

        final List<WorkingSet> workingSets = initializeWorkingSets();

        Collections.sort(workingSets, this);

        allWorkingSets = workingSets;

        return allWorkingSets;
    }

    /**
     * Returns with a list of all visible working sets. On demand creates them, otherwise returns with the cached
     * instances.
     *
     * @return a list of visible working set instances.
     */
    protected List<WorkingSet> getOrCreateVisibleWorkingSets() {

        if (visibleWorkingSets != null) {
            return visibleWorkingSets;
        }

        if (allWorkingSets == null) {
            allWorkingSets = getOrCreateAllWorkingSets();
        }

        if (visibleWorkingSetIds.isEmpty()) {
            visibleWorkingSets = newArrayList(allWorkingSets);
        } else {
            visibleWorkingSets = from(allWorkingSets).filter(ws -> visibleWorkingSetIds.contains(ws.getId()))
                    .toList();
        }

        return visibleWorkingSets;
    }

}