Package org.intellij.vcs.mks.realtime

Source Code of org.intellij.vcs.mks.realtime.SandboxListSynchronizerImpl

package org.intellij.vcs.mks.realtime;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.vcs.VcsException;
import org.intellij.vcs.mks.MKSHelper;
import org.intellij.vcs.mks.MksConfiguration;
import org.intellij.vcs.mks.MksVcs;
import org.intellij.vcs.mks.sicommands.cli.ListSandboxes;
import org.intellij.vcs.mks.sicommands.SandboxInfo;
import org.intellij.vcs.mks.sicommands.cli.SandboxesCommand;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.locks.ReentrantLock;

/**
* starts a si sandboxes --persist and listens to updates but doesn't actually use the output.
* Whenever a new update is detected, issues a si sandboxes (without --persist), compares the output to
* the previous state and issues events accordingly to any registered listeners.
* <p/>
* A listener being registered while comparison is in progress should get the new list
*
* @author Thibaut Fagart
*/
public class SandboxListSynchronizerImpl extends AbstractMKSSynchronizer
        implements ApplicationComponent, SandboxListSynchronizer {
    private final ArrayList<SandboxListListener> listeners = new ArrayList<SandboxListListener>();


    private ArrayList<SandboxInfo> currentList = new ArrayList<SandboxInfo>();
    private final ReentrantLock sandboxCacheLock = new ReentrantLock();

    /**
     * used to not process sandbox list update immediately to avoid doing it for every subsandbox being checkedout
     */
    private Timer timer;
    /**
     * delay while new update may be ignored
     */
    private static final int DELAY = 5000;
    /**
     * lock to manipulate the timer
     */
    private final Object fireUpdateLock = new Object();

    public SandboxListSynchronizerImpl() {
        this(ApplicationManager.getApplication().getComponent(MksConfiguration.class));
    }

    protected SandboxListSynchronizerImpl(MksConfiguration config) {
        super(ListSandboxes.COMMAND, config);
    }

    public void addListener(@NotNull SandboxListListener listener) {
        if (this.listeners.contains(listener)) {
            return;
        }
        sandboxCacheLock.lock();
        try {
            final ArrayList<SandboxInfo> newList =
                    new ArrayList<SandboxInfo>(currentList);
            this.listeners.add(listener);
            final ArrayList<SandboxListListener> listeners = new ArrayList<SandboxListListener>();
            // only fire updates to the newly added listener
            listeners.add(listener);
            compareAndFireUpdates(new ArrayList<SandboxInfo>(), newList, listeners);
        } finally {
            sandboxCacheLock.unlock();
        }
    }

    public void removeListener(@NotNull SandboxListListener sandboxListListener) {
        this.listeners.remove(sandboxListListener);
    }


    @NonNls
    @NotNull
    public String getComponentName() {
        return "MKS.sandboxListSaynchronizer";
    }

    public void initComponent() {
        MKSHelper.startClient();
        addIgnoredFiles();
        /*
           no need to fill in the sandbox list, si sandboxes --refresh issues 2 lists, one without the date, and
           the next one with it
            */

        start();
    }

    public void disposeComponent() {
        stop();
        currentList = null;
        listeners.clear();
    }

    private static void addIgnoredFiles() {
        String patterns = FileTypeManager.getInstance().getIgnoredFilesList();

        StringBuffer newPattern = new StringBuffer(patterns);
        if (patterns.indexOf(MksVcs.PROJECT_PJ_FILE) == -1) {
            newPattern.append((newPattern.charAt(newPattern.length() - 1) == ';') ? "" : ";")
                    .append(MksVcs.PROJECT_PJ_FILE);
        }

        final String newPatternString = newPattern.toString();
        if (!newPatternString.equals(patterns)) {
            ApplicationManager.getApplication().runWriteAction(new Runnable() {
                public void run() {
                    FileTypeManager.getInstance().setIgnoredFilesList(newPatternString);
                }
            }
            );
        }
    }

    @Override
    protected void handleLine(String line) {
        try {
            if (shoudIgnore(line)) {
                return;
            }
            if (line.startsWith("-----")) {
                // detection of a new update
                LOGGER.debug("update notification : " + line);
                fireUpdateSandboxList();
            }
        } catch (Exception e) {
            LOGGER.error("error parsing mks synchronizer output [" + line + "], skipping that line  because : " +
                    e.getMessage(), e);
        }
    }

    /**
     * don't process the update right now, only do it after a bit, to avoid updating sandbox list for every subsandbox
     */
    private void fireUpdateSandboxList() {
        synchronized (this.fireUpdateLock) {
            if (timer != null) {
                timer.cancel();
            }
            timer = new Timer(true);
            final TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    updateSandboxList();
                }
            };
            timer = new Timer();
            timer.schedule(task, DELAY);
        }
    }

    private void updateSandboxList() {
        this.sandboxCacheLock.lock();
        ArrayList<SandboxInfo> oldList;
        final ArrayList<SandboxListListener> listeners;
        ArrayList<SandboxInfo> newSandboxList;
        try {
            oldList = this.currentList;
            listeners = new ArrayList<SandboxListListener>(this.listeners);
            newSandboxList = getNewSandboxList();
            this.currentList = newSandboxList;
        } finally {
            this.sandboxCacheLock.unlock();
        }

        compareAndFireUpdates(oldList, newSandboxList, listeners);
    }

    /**
     * compares the 2 (sorted) lists of sandbox and fire updates appropriately to the provided list of listeners
     *
     * @param oldList   supposed to be sorted
     * @param newList   supposed to be sorted
     * @param listeners
     */
    protected void compareAndFireUpdates(ArrayList<SandboxInfo> oldList,
                                         ArrayList<SandboxInfo> newList,
                                         ArrayList<SandboxListListener> listeners) {
        int oldIndex = 0;
        int newIndex = 0;

        while (oldIndex < oldList.size() && newIndex < newList.size()) {
            final SandboxInfo oldSandbox = oldList.get(oldIndex);
            final SandboxInfo newSandbox = newList.get(newIndex);

            final int compareCode = oldSandbox.sandboxPath.compareTo(newSandbox.sandboxPath);
            if (0 == compareCode) {
                if (!oldSandbox.equals(newSandbox)) {
                    fireSandboxUpdated(newSandbox, listeners);
                }
                oldIndex++;
                newIndex++;
            } else if (compareCode < 0) {
                fireSandboxRemoved(oldSandbox, listeners);
                oldIndex++;
            } else {
                fireSandboxAdded(newSandbox, listeners);
                newIndex++;
            }
        }

        while (oldIndex < oldList.size()) {
            fireSandboxRemoved(oldList.get(oldIndex), listeners);
            oldIndex++;
        }
        while (newIndex < newList.size()) {
            fireSandboxAdded(newList.get(newIndex), listeners);
            newIndex++;
        }
    }


    private void fireSandboxAdded(SandboxInfo sandbox, ArrayList<SandboxListListener> listeners) {
        for (SandboxListListener listener : listeners) {
            listener.addSandboxPath(sandbox.sandboxPath, sandbox.serverHostAndPort, sandbox.projectPath,
                    sandbox.projectVersion, sandbox.subSandbox);
        }
    }

    private void fireSandboxRemoved(SandboxInfo sandbox, ArrayList<SandboxListListener> listeners) {
        for (SandboxListListener listener : listeners) {
            listener.removeSandboxPath(sandbox.sandboxPath, sandbox.subSandbox);
        }
    }

    private void fireSandboxUpdated(SandboxInfo sandbox, ArrayList<SandboxListListener> listeners) {
        for (SandboxListListener listener : listeners) {
            listener.updateSandboxPath(sandbox.sandboxPath, sandbox.serverHostAndPort, sandbox.projectPath,
                    sandbox.projectVersion, sandbox.subSandbox);
        }
    }

    public String getDescription() {
        return "sandbox list listener";
    }

    protected ArrayList<SandboxInfo> getNewSandboxList() {
        final SandboxesCommand command = new SandboxesCommand(new ArrayList<VcsException>(),
                ApplicationManager.getApplication().getComponent(MksConfiguration.class));
        command.execute();

        Collections.sort(command.result, SandboxInfo.COMPARATOR);
        return command.result;
    }
}
TOP

Related Classes of org.intellij.vcs.mks.realtime.SandboxListSynchronizerImpl

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.