All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.openapi.util.RequestsMerger Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition platform-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * 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.intellij.openapi.util;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.SomeQueue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * For exactly same refresh requests buffering:
 * 

* - refresh requests can be merged into one, but general principle is that each request should be reliably followed by refresh action * - at the moment only one refresh action is being done * - if request had been submitted while refresh action was in progress, new refresh action is initiated right after first refresh action finishes */ @SomeQueue public class RequestsMerger { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.RequestsMerger"); private final MyWorker myWorker; private final Object myLock = new Object(); private MyState myState; private final Consumer myAlarm; private final List myWaitingStartListeners = new ArrayList(); private final List myWaitingFinishListeners = new ArrayList(); public RequestsMerger(final Runnable runnable, final Consumer alarm) { myAlarm = alarm; myWorker = new MyWorker(runnable); myState = MyState.empty; } public void request() { LOG.debug("ext: request"); doAction(MyAction.request); } public boolean isEmpty() { synchronized (myLock) { return MyState.empty.equals(myState); } } public void waitRefresh(final Runnable runnable) { LOG.debug("ext: wait refresh"); synchronized (myLock) { myWaitingStartListeners.add(runnable); } request(); } private class MyWorker implements Runnable { private volatile boolean myInitialized; private final Runnable myRunnable; private MyWorker(Runnable runnable) { myRunnable = runnable; } @Override public void run() { LOG.debug("worker: started refresh"); try { doAction(MyAction.start); myRunnable.run(); myInitialized = true; } finally { doAction(MyAction.finish); } } public boolean isInitialized() { return myInitialized; } } private void doAction(final MyAction action) { LOG.debug("doAction: START " + action.name()); final MyExitAction[] exitActions; List toBeCalled = null; synchronized (myLock) { final MyState oldState = myState; myState = myState.transition(action); if (oldState.equals(myState)) return; exitActions = MyTransitionAction.getExit(oldState, myState); LOG.debug("doAction: oldState: " + oldState.name() + ", newState: " + myState.name()); if (LOG.isDebugEnabled() && exitActions != null) { final String debugExitActions = StringUtil.join(exitActions, new Function() { @Override public String fun(MyExitAction exitAction) { return exitAction.name(); } }, " "); LOG.debug("exit actions: " + debugExitActions); } if (exitActions != null) { for (MyExitAction exitAction : exitActions) { if (MyExitAction.markStart.equals(exitAction)) { myWaitingFinishListeners.addAll(myWaitingStartListeners); myWaitingStartListeners.clear(); } else if (MyExitAction.markEnd.equals(exitAction)) { toBeCalled = new ArrayList(myWaitingFinishListeners); myWaitingFinishListeners.clear(); } } } } if (exitActions != null) { for (MyExitAction exitAction : exitActions) { if (MyExitAction.submitRequestToExecutor.equals(exitAction)) { myAlarm.consume(myWorker); //myAlarm.addRequest(myWorker, ourDelay); //ApplicationManager.getApplication().executeOnPooledThread(myWorker); } } } if (toBeCalled != null) { for (Runnable runnable : toBeCalled) { runnable.run(); } } LOG.debug("doAction: END " + action.name()); } private enum MyState { empty() { @Override @NotNull public MyState transition(MyAction action) { if (MyAction.request.equals(action)) { return MyState.requestSubmitted; } logWrongAction(this, action); return this; } }, inProgress() { @Override @NotNull public MyState transition(MyAction action) { if (MyAction.finish.equals(action)) { return empty; } else if (MyAction.request.equals(action)) { return MyState.inProgressRequestSubmitted; } logWrongAction(this, action); return this; } }, inProgressRequestSubmitted() { @Override @NotNull public MyState transition(MyAction action) { if (MyAction.finish.equals(action)) { return MyState.requestSubmitted; } if (MyAction.start.equals(action)) { logWrongAction(this, action); } return this; } }, requestSubmitted() { @Override @NotNull public MyState transition(MyAction action) { if (MyAction.start.equals(action)) { return inProgress; } else if (MyAction.finish.equals(action)) { // to be able to be started by another request logWrongAction(this, action); return empty; } return this; } }; // under lock @NotNull public abstract MyState transition(final MyAction action); private static void logWrongAction(final MyState state, final MyAction action) { LOG.info("Wrong action: state=" + state.name() + ", action=" + action.name()); } } private static class MyTransitionAction { private static final Map, MyExitAction[]> myMap = new HashMap, MyExitAction[]>(); static { add(MyState.empty, MyState.requestSubmitted, MyExitAction.submitRequestToExecutor); add(MyState.requestSubmitted, MyState.inProgress, MyExitAction.markStart); add(MyState.inProgress, MyState.empty, MyExitAction.markEnd); add(MyState.inProgressRequestSubmitted, MyState.requestSubmitted, MyExitAction.submitRequestToExecutor, MyExitAction.markEnd); //... and not real but to be safe: add(MyState.inProgressRequestSubmitted, MyState.empty, MyExitAction.markEnd); add(MyState.inProgress, MyState.requestSubmitted, MyExitAction.markEnd); } private static void add(final MyState from, final MyState to, final MyExitAction... action) { myMap.put(Couple.of(from, to), action); } @Nullable public static MyExitAction[] getExit(final MyState from, final MyState to) { return myMap.get(Couple.of(from, to)); } } private enum MyExitAction { empty, submitRequestToExecutor, markStart, markEnd } private enum MyAction { request, start, finish } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy