diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java
index 13ef8d37cd5c..3bd67509e586 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java
@@ -1769,7 +1769,12 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
ApplicationManager.getApplication().assertIsDispatchThread(); //TODO: remove this requirement
((XDebugSessionImpl)getXdebugProcess().getSession()).reset();
myState.set(STATE_INITIAL);
- myRequestManager.processDetached(this, false);
+ getManagerThread().schedule(new DebuggerCommandImpl() {
+ @Override
+ protected void action() throws Exception {
+ myRequestManager.processDetached(DebugProcessImpl.this, false);
+ }
+ });
myConnection = environment.getRemoteConnection();
getManagerThread().restartIfNeeded();
createVirtualMachine(environment.getSessionName(), environment.isPollConnection());
diff --git a/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java b/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java
index cb6c6a95c88e..9fb6e4cf989b 100644
--- a/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java
+++ b/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java
@@ -16,6 +16,7 @@
package com.intellij.execution;
import com.intellij.ExtensionPoints;
+import com.intellij.debugger.impl.GenericDebuggerRunnerSettings;
import com.intellij.execution.configurations.*;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
@@ -216,11 +217,16 @@ public abstract class JavaTestFrameworkRunnableState" +
"Please specify single working directory, or change test scope to single module.");
@@ -228,7 +234,7 @@ public abstract class JavaTestFrameworkRunnableStatePlease change fork mode to <none> to " + actionName.toLowerCase(
Locale.ENGLISH) + ".");
diff --git a/java/execution/impl/src/com/intellij/execution/testframework/JavaTestLocator.java b/java/execution/impl/src/com/intellij/execution/testframework/JavaTestLocator.java
index d4e529772a72..ac4c581f15e9 100644
--- a/java/execution/impl/src/com/intellij/execution/testframework/JavaTestLocator.java
+++ b/java/execution/impl/src/com/intellij/execution/testframework/JavaTestLocator.java
@@ -22,10 +22,11 @@ import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.execution.testframework.sm.runner.SMTestLocator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.ClassUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -50,32 +51,27 @@ public class JavaTestLocator implements SMTestLocator {
path = path.substring(0, idx);
}
- JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
if (SUITE_PROTOCOL.equals(protocol)) {
path = StringUtil.trimEnd(path, ".");
- PsiClass[] classes = javaPsiFacade.findClasses(path, scope);
- if (classes.length > 0) {
+ PsiClass aClass = ClassUtil.findPsiClass(PsiManager.getInstance(project), path, null, true, scope);
+ if (aClass != null) {
results = ContainerUtil.newSmartList();
- for (PsiClass aClass : classes) {
- results.add(paramName != null ? PsiMemberParameterizedLocation.getParameterizedLocation(aClass, paramName)
- : new PsiLocation(project, aClass));
- }
+ results.add(paramName != null ? PsiMemberParameterizedLocation.getParameterizedLocation(aClass, paramName)
+ : new PsiLocation(project, aClass));
}
}
else if (TEST_PROTOCOL.equals(protocol)) {
String className = StringUtil.getPackageName(path);
if (!StringUtil.isEmpty(className)) {
String methodName = StringUtil.getShortName(path);
- PsiClass[] classes = javaPsiFacade.findClasses(className, scope);
- if (classes.length > 0) {
+ PsiClass aClass = ClassUtil.findPsiClass(PsiManager.getInstance(project), className, null, true, scope);
+ if (aClass != null) {
results = ContainerUtil.newSmartList();
- for (PsiClass aClass : classes) {
- PsiMethod[] methods = aClass.findMethodsByName(methodName, true);
- if (methods.length > 0) {
- for (PsiMethod method : methods) {
- results.add(paramName != null ? new PsiMemberParameterizedLocation(project, method, aClass, paramName)
- : MethodLocation.elementInClass(method, aClass));
- }
+ PsiMethod[] methods = aClass.findMethodsByName(methodName, true);
+ if (methods.length > 0) {
+ for (PsiMethod method : methods) {
+ results.add(paramName != null ? new PsiMemberParameterizedLocation(project, method, aClass, paramName)
+ : MethodLocation.elementInClass(method, aClass));
}
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java
index 6f503534cb9c..b4ca43f4cc0b 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java
@@ -109,7 +109,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
}
if (ExceptionUtil.getThrownCheckedExceptions(new PsiElement[] {body}).isEmpty()) {
- if (isCollectCall(body, statement.getIterationParameter())) {
+ if (!(iteratedValueType instanceof PsiClassType && ((PsiClassType)iteratedValueType).isRaw()) &&
+ isCollectCall(body, statement.getIterationParameter())) {
holder.registerProblem(iteratedValue, "Can be replaced with collect call",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithCollectCallFix());
} else if (!isTrivial(body, statement.getIterationParameter())) {
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeRawCollection.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeRawCollection.java
new file mode 100644
index 000000000000..fd51db79f84e
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeRawCollection.java
@@ -0,0 +1,22 @@
+// "Replace with forEach" "false"
+import java.util.*;
+import java.util.stream.Collectors
+
+class A {
+ public static List toTypedList1(Collection collection, Class aClass) {
+ if (collection.size() == 0) {
+ return Collections.emptyList();
+ }
+
+ List result = new ArrayList<>(collection.size());
+
+ for (Object obj : collection) {
+ result.add(aClass.cast(obj));
+ }
+
+ return result;
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/HTMLComposerImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/HTMLComposerImpl.java
index c8a8361b020b..a00ffe6c7f4d 100644
--- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/HTMLComposerImpl.java
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/HTMLComposerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2015 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.
@@ -286,7 +286,6 @@ public abstract class HTMLComposerImpl extends HTMLComposer {
@Override
public void appendListItem(StringBuffer buf, RefElement refElement) {
startListItem(buf);
- buf.append(CLOSE_TAG);
appendElementReference(buf, refElement, true);
appendAdditionalListItemInfo(buf, refElement);
doneListItem(buf);
diff --git a/platform/bootstrap/src/com/intellij/ide/BootstrapClassLoaderUtil.java b/platform/bootstrap/src/com/intellij/ide/BootstrapClassLoaderUtil.java
index 6e313990e112..9dab9c62b3a3 100644
--- a/platform/bootstrap/src/com/intellij/ide/BootstrapClassLoaderUtil.java
+++ b/platform/bootstrap/src/com/intellij/ide/BootstrapClassLoaderUtil.java
@@ -58,7 +58,7 @@ public class BootstrapClassLoaderUtil extends ClassUtilCore {
UrlClassLoader.Builder builder = UrlClassLoader.build()
.urls(filterClassPath(new ArrayList(classpath)))
- .allowLock(false)
+ .allowLock()
.usePersistentClasspathIndexForLocalClassDirectories()
.useCache();
if (Boolean.valueOf(System.getProperty(PROPERTY_ALLOW_BOOTSTRAP_RESOURCES, "true"))) {
diff --git a/platform/diff-impl/src/com/intellij/diff/impl/CacheDiffRequestChainProcessor.java b/platform/diff-impl/src/com/intellij/diff/impl/CacheDiffRequestChainProcessor.java
index 49a400022a99..63aabc7bf446 100644
--- a/platform/diff-impl/src/com/intellij/diff/impl/CacheDiffRequestChainProcessor.java
+++ b/platform/diff-impl/src/com/intellij/diff/impl/CacheDiffRequestChainProcessor.java
@@ -21,9 +21,9 @@ import com.intellij.diff.chains.DiffRequestProducer;
import com.intellij.diff.chains.DiffRequestProducerException;
import com.intellij.diff.requests.*;
import com.intellij.diff.tools.util.SoftHardCacheMap;
+import com.intellij.diff.util.DiffTaskQueue;
import com.intellij.diff.util.DiffUserDataKeys;
import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy;
-import com.intellij.diff.util.WaitingBackgroundableTaskExecutor;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -33,9 +33,11 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.util.ProgressWindow;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
import com.intellij.util.Consumer;
+import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.containers.Convertor;
+import org.jetbrains.annotations.CalledInAwt;
import org.jetbrains.annotations.CalledInBackground;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,7 +53,7 @@ public abstract class CacheDiffRequestChainProcessor extends DiffRequestProcesso
@NotNull private final SoftHardCacheMap myRequestCache =
new SoftHardCacheMap(5, 5);
- @NotNull private final WaitingBackgroundableTaskExecutor myTaskExecutor = new WaitingBackgroundableTaskExecutor();
+ @NotNull private final DiffTaskQueue myQueue = new DiffTaskQueue();
public CacheDiffRequestChainProcessor(@Nullable Project project, @NotNull DiffRequestChain requestChain) {
super(project, requestChain);
@@ -62,6 +64,7 @@ public abstract class CacheDiffRequestChainProcessor extends DiffRequestProcesso
// Update
//
+ @CalledInAwt
public void updateRequest(final boolean force, @Nullable final ScrollToPolicy scrollToChangePolicy) {
List extends DiffRequestProducer> requests = myRequestChain.getRequests();
int index = myRequestChain.getIndex();
@@ -78,12 +81,13 @@ public abstract class CacheDiffRequestChainProcessor extends DiffRequestProcesso
return;
}
- myTaskExecutor.execute(
- new Convertor() {
+ myQueue.executeAndTryWait(
+ new Function() {
@Override
- public Runnable convert(ProgressIndicator indicator) {
+ public Runnable fun(ProgressIndicator indicator) {
final DiffRequest request = loadRequest(producer, indicator);
return new Runnable() {
+ @CalledInAwt
@Override
public void run() {
myRequestCache.put(producer, request);
@@ -131,9 +135,10 @@ public abstract class CacheDiffRequestChainProcessor extends DiffRequestProcesso
//
@Override
+ @CalledInAwt
protected void onDispose() {
super.onDispose();
- myTaskExecutor.abort();
+ Disposer.dispose(myQueue);
myRequestCache.clear();
}
diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java b/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java
index 2b6fbcb3a798..74674c4f83ab 100644
--- a/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java
+++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffRequestProcessor.java
@@ -299,6 +299,7 @@ public abstract class DiffRequestProcessor implements Disposable {
protected void onAfterNavigate() {
}
+ @CalledInAwt
protected void onDispose() {
}
diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/base/DiffViewerBase.java b/platform/diff-impl/src/com/intellij/diff/tools/util/base/DiffViewerBase.java
index 16dd6a0fd80c..8e03481e1c7a 100644
--- a/platform/diff-impl/src/com/intellij/diff/tools/util/base/DiffViewerBase.java
+++ b/platform/diff-impl/src/com/intellij/diff/tools/util/base/DiffViewerBase.java
@@ -20,7 +20,7 @@ import com.intellij.diff.FrameDiffTool;
import com.intellij.diff.FrameDiffTool.DiffViewer;
import com.intellij.diff.requests.ContentDiffRequest;
import com.intellij.diff.tools.util.DiffDataKeys;
-import com.intellij.diff.util.WaitingBackgroundableTaskExecutor;
+import com.intellij.diff.util.DiffTaskQueue;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataProvider;
@@ -31,8 +31,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.util.ProgressWindow;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
-import com.intellij.util.Alarm;
-import com.intellij.util.containers.Convertor;
+import com.intellij.util.Function;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.*;
@@ -47,9 +46,7 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
@NotNull protected final DiffContext myContext;
@NotNull protected final ContentDiffRequest myRequest;
- @NotNull private final WaitingBackgroundableTaskExecutor myTaskExecutor = new WaitingBackgroundableTaskExecutor();
- @NotNull private final Alarm myAlarm = new Alarm();
-
+ @NotNull private final DiffTaskQueue myTaskExecutor = new DiffTaskQueue();
@NotNull private final AtomicBoolean myDisposed = new AtomicBoolean(false);
public DiffViewerBase(@NotNull DiffContext context, @NotNull ContentDiffRequest request) {
@@ -75,15 +72,11 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
public final void dispose() {
if (!myDisposed.compareAndSet(false, true)) return;
- Disposer.dispose(myAlarm);
- abortRediff();
-
onDispose();
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
- abortRediff();
onDisposeAwt();
}
});
@@ -92,14 +85,10 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
@CalledInAwt
public final void scheduleRediff() {
if (myDisposed.get()) return;
- myTaskExecutor.abort();
- final int modificationStamp = myTaskExecutor.getModificationStamp();
- myAlarm.cancelAllRequests();
- myAlarm.addRequest(new Runnable() {
+ myTaskExecutor.abortAndSchedule(new Runnable() {
@Override
public void run() {
- if (modificationStamp != myTaskExecutor.getModificationStamp()) return;
rediff();
}
}, ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS);
@@ -127,10 +116,10 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
int waitMillis = trySync || tryRediffSynchronously() ? ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS : 0;
- myTaskExecutor.execute(
- new Convertor() {
+ myTaskExecutor.executeAndTryWait(
+ new Function() {
@Override
- public Runnable convert(ProgressIndicator indicator) {
+ public Runnable fun(ProgressIndicator indicator) {
return performRediff(indicator);
}
},
@@ -199,6 +188,7 @@ public abstract class DiffViewerBase implements DiffViewer, DataProvider {
protected abstract Runnable performRediff(@NotNull ProgressIndicator indicator);
protected void onDispose() {
+ Disposer.dispose(myTaskExecutor);
}
@CalledInAwt
diff --git a/platform/diff-impl/src/com/intellij/diff/util/WaitingBackgroundableTaskExecutor.java b/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java
similarity index 63%
rename from platform/diff-impl/src/com/intellij/diff/util/WaitingBackgroundableTaskExecutor.java
rename to platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java
index 3a95b5c60b9f..9cf267a06075 100644
--- a/platform/diff-impl/src/com/intellij/diff/util/WaitingBackgroundableTaskExecutor.java
+++ b/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java
@@ -21,7 +21,7 @@ import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.EmptyRunnable;
-import com.intellij.util.containers.Convertor;
+import com.intellij.util.Function;
import org.jetbrains.annotations.CalledInAwt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -34,59 +34,38 @@ import java.util.concurrent.atomic.AtomicReference;
* Executor to perform long operations on pooled thread
* Is is used to reduce blinking, in case of fast end of background task.
*/
-public class WaitingBackgroundableTaskExecutor {
+public class BackgroundTaskUtil {
private static final Runnable TOO_SLOW_OPERATION = new EmptyRunnable();
- private int myModificationStamp = 0;
- @Nullable private ProgressIndicator myProgressIndicator;
-
@CalledInAwt
- public int getModificationStamp() {
- return myModificationStamp;
+ @NotNull
+ public static ProgressIndicator executeAndTryWait(@NotNull final Function backgroundTask,
+ @Nullable final Runnable onSlowAction,
+ final int waitMillis) {
+ return executeAndTryWait(backgroundTask, onSlowAction, waitMillis, false);
}
@CalledInAwt
- public void abort() {
- if (myProgressIndicator != null) {
- myProgressIndicator.cancel();
- myProgressIndicator = null;
- myModificationStamp++;
- }
- }
-
- @CalledInAwt
- public void execute(@NotNull final Convertor backgroundTask,
- @Nullable final Runnable onSlowAction,
- final int waitMillis) {
- execute(backgroundTask, onSlowAction, waitMillis, false);
- }
-
- @CalledInAwt
- public void execute(@NotNull final Convertor backgroundTask,
- @Nullable final Runnable onSlowAction,
- final int waitMillis,
- final boolean forceEDT) {
- abort();
-
- myModificationStamp++;
- final int modificationStamp = myModificationStamp;
-
+ @NotNull
+ public static ProgressIndicator executeAndTryWait(@NotNull final Function backgroundTask,
+ @Nullable final Runnable onSlowAction,
+ final int waitMillis,
+ final boolean forceEDT) {
final ModalityState modality = ModalityState.current();
- myProgressIndicator = new EmptyProgressIndicator() {
+ final ProgressIndicator indicator = new EmptyProgressIndicator() {
@NotNull
@Override
public ModalityState getModalityState() {
return modality;
}
};
- final ProgressIndicator indicator = myProgressIndicator;
final Semaphore semaphore = new Semaphore(0);
final AtomicReference resultRef = new AtomicReference();
if (forceEDT) {
- Runnable result = backgroundTask.convert(indicator);
- finish(result, modificationStamp, indicator);
+ Runnable callback = backgroundTask.fun(indicator);
+ finish(callback, indicator);
}
else {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@@ -95,18 +74,18 @@ public class WaitingBackgroundableTaskExecutor {
ProgressManager.getInstance().executeProcessUnderProgress(new Runnable() {
@Override
public void run() {
- final Runnable result = backgroundTask.convert(indicator);
+ final Runnable callback = backgroundTask.fun(indicator);
if (indicator.isCanceled()) {
semaphore.release();
return;
}
- if (!resultRef.compareAndSet(null, result)) {
+ if (!resultRef.compareAndSet(null, callback)) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
- finish(result, modificationStamp, indicator);
+ finish(callback, indicator);
}
}, modality);
}
@@ -123,19 +102,20 @@ public class WaitingBackgroundableTaskExecutor {
}
if (!resultRef.compareAndSet(null, TOO_SLOW_OPERATION)) {
// update presentation in the same thread to reduce blinking, caused by 'invokeLater' and fast background operation
- finish(resultRef.get(), modificationStamp, indicator);
+ finish(resultRef.get(), indicator);
}
else {
if (onSlowAction != null) onSlowAction.run();
}
}
+
+ return indicator;
}
@CalledInAwt
- private void finish(@NotNull Runnable result, int modificationStamp, @NotNull ProgressIndicator indicator) {
+ private static void finish(@NotNull Runnable result, @NotNull ProgressIndicator indicator) {
if (indicator.isCanceled()) return;
- if (myModificationStamp != modificationStamp) return;
-
result.run();
+ indicator.stop();
}
}
diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffTaskQueue.java b/platform/diff-impl/src/com/intellij/diff/util/DiffTaskQueue.java
new file mode 100644
index 000000000000..96027e2a7356
--- /dev/null
+++ b/platform/diff-impl/src/com/intellij/diff/util/DiffTaskQueue.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2000-2015 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.diff.util;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.util.Alarm;
+import com.intellij.util.Function;
+import org.jetbrains.annotations.*;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+public class DiffTaskQueue implements Disposable {
+ @NotNull private final Object LOCK = new Object();
+ @NotNull private final Alarm myAlarm = new Alarm();
+
+ private boolean myDisposed;
+ @NotNull private final AtomicReference myProgressIndicator = new AtomicReference();
+
+ @CalledInAny
+ public void dispose() {
+ // if EDT is awaiting for background progress in executeAndTryWait - it holds LOCK.
+ // so we want to try cancel indicator before getting the lock.
+ cancelProgress();
+ synchronized (LOCK) {
+ if (myDisposed) return;
+ myDisposed = true;
+ cancelProgress();
+ Disposer.dispose(myAlarm);
+ }
+ }
+
+ @CalledInAwt
+ public void abort() {
+ synchronized (LOCK) {
+ cancelProgress();
+ myAlarm.cancelAllRequests();
+ }
+ }
+
+ private void cancelProgress() {
+ ProgressIndicator indicator = myProgressIndicator.getAndSet(null);
+ if (indicator != null) indicator.cancel();
+ }
+
+ @CalledInAwt
+ public void abortAndSchedule(@NotNull final Runnable task, int millis) {
+ synchronized (LOCK) {
+ if (myDisposed) return;
+ abort();
+
+ myAlarm.addRequest(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (LOCK) {
+ if (myDisposed) return;
+ }
+ task.run();
+ }
+ }, millis);
+ }
+ }
+
+ @CalledInAwt
+ public void executeAndTryWait(@NotNull final Function backgroundTask,
+ @Nullable final Runnable onSlowAction,
+ final int waitMillis) {
+ executeAndTryWait(backgroundTask, onSlowAction, waitMillis, false);
+ }
+
+ @CalledInAwt
+ public void executeAndTryWait(@NotNull final Function backgroundTask,
+ @Nullable final Runnable onSlowAction,
+ final int waitMillis,
+ final boolean forceEDT) {
+ synchronized (LOCK) {
+ if (myDisposed) return;
+ abort();
+
+ Function function = new Function() {
+ @Override
+ @CalledInBackground
+ public Runnable fun(final ProgressIndicator indicator) {
+ final Runnable callback = backgroundTask.fun(indicator);
+ return new Runnable() {
+ @Override
+ @CalledInAwt
+ public void run() {
+ synchronized (LOCK) {
+ if (myDisposed) return;
+ indicator.checkCanceled();
+ }
+ callback.run();
+ }
+ };
+ }
+ };
+
+ myProgressIndicator.set(BackgroundTaskUtil.executeAndTryWait(function, onSlowAction, waitMillis, forceEDT));
+ }
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java
index 7516febe596b..c5b459261fa8 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/FileWatcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 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.
@@ -556,7 +556,7 @@ public class FileWatcher {
case CREATE:
case DELETE:
for (String p : paths) {
- myDirtyPaths.dirtyPaths.add(p);
+ myDirtyPaths.dirtyPathsRecursive.add(p);
String parentPath = new File(p).getParent();
if (parentPath != null) {
myDirtyPaths.dirtyPaths.add(parentPath);
diff --git a/platform/platform-tests/testData/badPlugins/plugins/BadPlugin2.jar b/platform/platform-tests/testData/badPlugins/plugins/BadPlugin2.jar
index 5ff3678492ce..56df54520e2e 100644
Binary files a/platform/platform-tests/testData/badPlugins/plugins/BadPlugin2.jar and b/platform/platform-tests/testData/badPlugins/plugins/BadPlugin2.jar differ
diff --git a/platform/platform-tests/testSrc/com/intellij/application/BadPluginTest.java b/platform/platform-tests/testSrc/com/intellij/application/BadPluginTest.java
index 8c2c7f3236be..6bb618d3970f 100644
--- a/platform/platform-tests/testSrc/com/intellij/application/BadPluginTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/application/BadPluginTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2000-2015 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.application;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
@@ -6,7 +21,7 @@ import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.testFramework.PlatformLangTestCase;
+import com.intellij.testFramework.PlatformTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import java.io.File;
@@ -15,24 +30,22 @@ import java.util.List;
/**
* @author Dmitry Avdeev
- * Date: 1/9/13
+ * @since 9.01.2013
*/
-public class BadPluginTest extends PlatformLangTestCase {
-
- private static final String COM_YOURCOMPANY_UNIQUE_PLUGIN_ID = "com.yourcompany.unique.plugin.id";
+public class BadPluginTest extends PlatformTestCase {
+ private static final String COM_YOUR_COMPANY_UNIQUE_PLUGIN_ID = "com.your.company.unique.plugin.id";
public void testBadPlugin() throws Exception {
- IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginId.getId(COM_YOURCOMPANY_UNIQUE_PLUGIN_ID));
+ IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginId.getId(COM_YOUR_COMPANY_UNIQUE_PLUGIN_ID));
if (plugin == null) return;
List disabledPlugins = new ArrayList();
PluginManagerCore.loadDisabledPlugins(PathManager.getConfigPath(), disabledPlugins);
assertEquals(1, disabledPlugins.size());
- assertEquals(COM_YOURCOMPANY_UNIQUE_PLUGIN_ID, disabledPlugins.get(0));
+ assertEquals(COM_YOUR_COMPANY_UNIQUE_PLUGIN_ID, disabledPlugins.get(0));
}
@Override
protected void setUp() throws Exception {
-
String path = PlatformTestUtil.getCommunityPath() + "/platform/platform-tests/testData/badPlugins";
File directory = createTempDirectory(false);
FileUtil.copyDir(new File(path), directory);
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java
index 8baa5a78c50f..7f52a1df5ff6 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/FileWatcherTest.java
@@ -714,6 +714,33 @@ public class FileWatcherTest extends PlatformLangTestCase {
}
}
+ public void testDisplacementByIsomorphicTree() throws Exception {
+ File top = createTestDir("top");
+ File up = createTestDir(top, "up");
+ File middle = createTestDir(up, "middle");
+ File file = createTestFile(middle, "file.txt", "original content");
+ File up_copy = new File(top, "up_copy");
+ FileUtil.copyDir(up, up_copy);
+ FileUtil.writeToFile(file, "new content");
+
+ VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
+ assertNotNull(vFile);
+ assertEquals("new content", VfsUtilCore.loadText(vFile));
+
+ LocalFileSystem.WatchRequest request = watch(up);
+ try {
+ myAccept = true;
+ FileUtil.rename(up, new File(top, "up.bak"));
+ FileUtil.rename(up_copy, up);
+ assertEvent(VFileContentChangeEvent.class, file.getPath());
+ assertTrue(vFile.isValid());
+ assertEquals("original content", VfsUtilCore.loadText(vFile));
+ }
+ finally {
+ unwatch(request);
+ }
+ }
+
@NotNull
private LocalFileSystem.WatchRequest watch(File watchFile) {
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkHandlingTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkHandlingTest.java
index 218cc4c865d6..12aa12edd134 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkHandlingTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkHandlingTest.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
+import com.intellij.testFramework.LightPlatformTestCase;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
@@ -33,7 +34,37 @@ import java.util.Set;
import static com.intellij.openapi.util.io.IoTestUtil.*;
import static com.intellij.testFramework.PlatformTestUtil.assertPathsEqual;
-public class SymlinkHandlingTest extends SymlinkTestCase {
+public class SymlinkHandlingTest extends LightPlatformTestCase {
+ protected LocalFileSystem myFileSystem;
+ protected File myTempDir;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ myFileSystem = LocalFileSystem.getInstance();
+ myTempDir = createTestDir("temp");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ super.tearDown();
+ }
+ finally {
+ delete(myTempDir);
+ }
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ if (SystemInfo.areSymLinksSupported) {
+ super.runTest();
+ }
+ else {
+ System.err.println("Skipped: " + getName());
+ }
+ }
+
public void testMissingLink() throws Exception {
File missingFile = new File(myTempDir, "missing_file");
assertTrue(missingFile.getPath(), !missingFile.exists() || missingFile.delete());
@@ -362,6 +393,17 @@ public class SymlinkHandlingTest extends SymlinkTestCase {
return myFileSystem.findFileByPath(ioFile.getPath());
}
+ protected void refresh() {
+ assertTrue(myTempDir.getPath(), myTempDir.isDirectory() || myTempDir.mkdirs());
+
+ VirtualFile tempDir = myFileSystem.refreshAndFindFileByIoFile(myTempDir);
+ assertNotNull(myTempDir.getPath(), tempDir);
+
+ tempDir.getChildren();
+ tempDir.refresh(false, true);
+ VfsUtilCore.visitChildrenRecursively(tempDir, new VirtualFileVisitor() { });
+ }
+
private static void assertBrokenLink(@NotNull VirtualFile link) {
assertTrue(link.is(VFileProperty.SYMLINK));
assertEquals(0, link.getLength());
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkTestCase.java b/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkTestCase.java
deleted file mode 100644
index 999fa434481c..000000000000
--- a/platform/platform-tests/testSrc/com/intellij/openapi/vfs/local/SymlinkTestCase.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2000-2013 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.vfs.local;
-
-import com.intellij.openapi.util.SystemInfo;
-import com.intellij.openapi.util.io.IoTestUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VfsUtilCore;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileVisitor;
-import com.intellij.testFramework.LightPlatformLangTestCase;
-
-import java.io.File;
-
-import static com.intellij.openapi.util.io.IoTestUtil.createTestDir;
-
-public abstract class SymlinkTestCase extends LightPlatformLangTestCase {
- protected LocalFileSystem myFileSystem;
- protected File myTempDir;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- myFileSystem = LocalFileSystem.getInstance();
- myTempDir = createTestDir("temp");
- }
-
- @Override
- protected void tearDown() throws Exception {
- try {
- super.tearDown();
- }
- finally {
- IoTestUtil.delete(myTempDir);
- }
- }
-
- @Override
- protected void runTest() throws Throwable {
- if (SystemInfo.areSymLinksSupported) {
- super.runTest();
- }
- else {
- System.err.println("Skipped: " + getName());
- }
- }
-
- protected void refresh() {
- assertTrue(myTempDir.getPath(), myTempDir.isDirectory() || myTempDir.mkdirs());
-
- VirtualFile tempDir = myFileSystem.refreshAndFindFileByIoFile(myTempDir);
- assertNotNull(myTempDir.getPath(), tempDir);
-
- tempDir.getChildren();
- tempDir.refresh(false, true);
- VfsUtilCore.visitChildrenRecursively(tempDir, new VirtualFileVisitor() { });
- }
-}
diff --git a/platform/testFramework/src/com/intellij/testFramework/CompositeException.java b/platform/testFramework/src/com/intellij/testFramework/CompositeException.java
index 59e73bf718d4..4ec1c8b21107 100644
--- a/platform/testFramework/src/com/intellij/testFramework/CompositeException.java
+++ b/platform/testFramework/src/com/intellij/testFramework/CompositeException.java
@@ -130,7 +130,8 @@ public class CompositeException extends Exception {
sb.append(line);
line = exceptionProcessor.fun(exception);
- if (!line.endsWith("\n")) line += '\n';
+ if (line == null) line = "null\n";
+ else if (!line.endsWith("\n")) line += '\n';
stringProcessor.process(line);
sb.append(line);
}
diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java
index d4bc09129695..670bcfd7bd43 100644
--- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java
+++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java
@@ -458,15 +458,18 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
result.add(e);
}
- //cleanTheWorld();
try {
- myEditorListenerTracker.checkListenersLeak();
+ if (myEditorListenerTracker != null) {
+ myEditorListenerTracker.checkListenersLeak();
+ }
}
catch (AssertionError error) {
result.add(error);
}
try {
- myThreadTracker.checkLeak();
+ if (myThreadTracker != null) {
+ myThreadTracker.checkLeak();
+ }
}
catch (AssertionError error) {
result.add(error);
@@ -477,9 +480,6 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro
catch (Throwable error) {
result.add(error);
}
- //if (directoryIndex != null) {
- // directoryIndex.assertAncestorConsistent();
- //}
}
finally {
myProjectManager = null;
diff --git a/platform/testFramework/testFramework.iml b/platform/testFramework/testFramework.iml
index 19a4097b1f15..bb99b4dbda56 100644
--- a/platform/testFramework/testFramework.iml
+++ b/platform/testFramework/testFramework.iml
@@ -14,12 +14,12 @@
-
+
-
+
@@ -27,5 +27,4 @@
-
-
+
\ No newline at end of file
diff --git a/platform/util/src/com/intellij/util/diff/PatienceIntLCS.java b/platform/util/src/com/intellij/util/diff/PatienceIntLCS.java
index 672a4b6190f5..947f144e8b3a 100644
--- a/platform/util/src/com/intellij/util/diff/PatienceIntLCS.java
+++ b/platform/util/src/com/intellij/util/diff/PatienceIntLCS.java
@@ -86,8 +86,12 @@ public class PatienceIntLCS {
int matched = matching[0].length;
assert matched > 0;
+ c1 = matching[0][0];
+ c2 = matching[1][0];
+
+ checkReduction(c1, c2);
PatienceIntLCS patienceDiff =
- new PatienceIntLCS(myFirst, mySecond, start1, matching[0][0], start2, matching[1][0], myChanges1, myChanges2);
+ new PatienceIntLCS(myFirst, mySecond, start1, c1, start2, c2, myChanges1, myChanges2);
patienceDiff.execute();
for (int i = 1; i < matching[0].length; i++) {
diff --git a/platform/util/src/com/intellij/util/lang/JarLoader.java b/platform/util/src/com/intellij/util/lang/JarLoader.java
index 68c0bfb5479e..17b8181c619b 100644
--- a/platform/util/src/com/intellij/util/lang/JarLoader.java
+++ b/platform/util/src/com/intellij/util/lang/JarLoader.java
@@ -17,11 +17,11 @@ package com.intellij.util.lang;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.util.io.URLUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.misc.Resource;
+import java.io.File;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.net.URL;
@@ -30,15 +30,18 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
class JarLoader extends Loader {
- private final URL myURL;
+ private final File myCanonicalFile;
+ private final boolean myCanLockJar; // true implies that the zipfile will not be modified in the lifetime of the JarLoader
private SoftReference myMemoryLoader;
+ private volatile SoftReference myZipFileSoftReference; // Used only when myCanLockJar==true
- // todo drop unused parameter
JarLoader(URL url, @SuppressWarnings("unused") boolean canLockJar, int index, boolean preloadJarContents) throws IOException {
- super(new URL(URLUtil.JAR_PROTOCOL, "", -1, url + "!/"), index);
- myURL = url;
+ super(new URL("jar", "", -1, url + "!/"), index);
- ZipFile zipFile = new ZipFile(getFileUrl());
+ myCanonicalFile = new File(FileUtil.unquote(url.getFile())).getCanonicalFile();
+ myCanLockJar = canLockJar;
+
+ ZipFile zipFile = getZipFile(); // IOException from opening is propagated to caller if zip file isn't valid,
try {
if (preloadJarContents) {
JarMemoryLoader loader = JarMemoryLoader.load(zipFile, getBaseURL());
@@ -48,18 +51,14 @@ class JarLoader extends Loader {
}
}
finally {
- zipFile.close();
+ releaseZipFile(zipFile);
}
}
- private String getFileUrl() throws IOException {
- return FileUtil.unquote(myURL.getFile());
- }
-
@NotNull
@Override
public ClasspathCache.LoaderData buildData() throws IOException {
- ZipFile zipFile = new ZipFile(getFileUrl());
+ ZipFile zipFile = getZipFile();
try {
ClasspathCache.LoaderData loaderData = new ClasspathCache.LoaderData();
Enumeration extends ZipEntry> entries = zipFile.entries();
@@ -72,21 +71,21 @@ class JarLoader extends Loader {
return loaderData;
}
finally {
- zipFile.close();
+ releaseZipFile(zipFile);
}
}
@Override
@Nullable
Resource getResource(String name, boolean flag) {
- JarMemoryLoader loader = com.intellij.reference.SoftReference.dereference(myMemoryLoader);
+ JarMemoryLoader loader = myMemoryLoader != null? myMemoryLoader.get() : null;
if (loader != null) {
Resource resource = loader.getResource(name);
if (resource != null) return resource;
}
try {
- ZipFile zipFile = new ZipFile(getFileUrl());
+ ZipFile zipFile = getZipFile();
try {
ZipEntry entry = zipFile.getEntry(name);
if (entry != null) {
@@ -94,18 +93,58 @@ class JarLoader extends Loader {
}
}
finally {
- zipFile.close();
+ releaseZipFile(zipFile);
}
}
catch (Exception e) {
- Logger.getInstance(JarLoader.class).error("url: " + myURL, e);
+ error("file: " + myCanonicalFile, e);
}
return null;
}
+ protected void error(String message, Throwable t) {
+ //Logger.getLogger(JarLoader.class.getName()).log(Level.SEVERE, message, t);
+ Logger.getInstance(JarLoader.class).error(message, t);
+ }
+
+ private void releaseZipFile(ZipFile zipFile) throws IOException {
+ // Closing of zip file when myCanLockJar=true happens in ZipFile.finalize
+ if (!myCanLockJar) {
+ zipFile.close();
+ }
+ }
+
+ @NotNull
+ private ZipFile getZipFile() throws IOException {
+ // This code is executed at least 100K times (O(number of classes needed to load)) and it takes considerable time to open ZipFile's
+ // such number of times so we store reference to ZipFile if we allowed to lock the file (assume it isn't changed)
+ if (myCanLockJar) {
+ SoftReference zipFileSoftReference = myZipFileSoftReference;
+ if(zipFileSoftReference != null) {
+ ZipFile existingZipFile = zipFileSoftReference.get();
+ if (existingZipFile != null) return existingZipFile;
+ }
+ synchronized (ourLock) {
+ zipFileSoftReference = myZipFileSoftReference;
+ if(zipFileSoftReference != null) {
+ ZipFile existingZipFile = zipFileSoftReference.get();
+ if (existingZipFile != null) return existingZipFile;
+ }
+ // ZipFile's native implementation (ZipFile.c, zip_util.c) has path -> file descriptor cache
+ ZipFile zipFile = new ZipFile(myCanonicalFile);
+ myZipFileSoftReference = new SoftReference(zipFile);
+ return zipFile;
+ }
+ } else {
+ return new ZipFile(myCanonicalFile);
+ }
+ }
+
@Override
public String toString() {
- return "JarLoader [" + myURL + "]";
+ return "JarLoader [" + myCanonicalFile + "]";
}
+
+ private static final Object ourLock = new Object();
}
diff --git a/platform/util/src/com/intellij/util/lang/JarMemoryLoader.java b/platform/util/src/com/intellij/util/lang/JarMemoryLoader.java
index f012f1fc6526..497db669ba7f 100644
--- a/platform/util/src/com/intellij/util/lang/JarMemoryLoader.java
+++ b/platform/util/src/com/intellij/util/lang/JarMemoryLoader.java
@@ -15,9 +15,7 @@
*/
package com.intellij.util.lang;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.util.containers.hash.HashMap;
-import com.intellij.util.io.zip.ZipShort;
+import com.intellij.openapi.util.io.FileUtilRt;
import org.jetbrains.annotations.Nullable;
import sun.misc.Resource;
@@ -26,6 +24,7 @@ import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -64,8 +63,8 @@ public class JarMemoryLoader {
ZipEntry sizeEntry = entries.nextElement();
if (sizeEntry == null || !sizeEntry.getName().equals(SIZE_ENTRY)) return null;
- byte[] bytes = FileUtil.loadBytes(zipFile.getInputStream(sizeEntry), 2);
- int size = ZipShort.getValue(bytes);
+ byte[] bytes = FileUtilRt.loadBytes(zipFile.getInputStream(sizeEntry), 2);
+ int size = ((bytes[1] & 0xFF) << 8) + (bytes[0] & 0xFF);
JarMemoryLoader loader = new JarMemoryLoader();
for (int i = 0; i < size && entries.hasMoreElements(); i++) {
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java
index 2df8cad37e62..fd0b781bd06a 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/CacheChangeProcessor.java
@@ -19,9 +19,9 @@ import com.intellij.diff.chains.DiffRequestProducerException;
import com.intellij.diff.impl.DiffRequestProcessor;
import com.intellij.diff.requests.*;
import com.intellij.diff.tools.util.SoftHardCacheMap;
+import com.intellij.diff.util.DiffTaskQueue;
import com.intellij.diff.util.DiffUserDataKeys;
import com.intellij.diff.util.DiffUserDataKeysEx.ScrollToPolicy;
-import com.intellij.diff.util.WaitingBackgroundableTaskExecutor;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -31,10 +31,11 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.util.ProgressWindow;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.changes.actions.diff.ChangeDiffRequestProducer;
+import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.containers.Convertor;
import org.jetbrains.annotations.*;
import java.util.Collections;
@@ -48,7 +49,7 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor {
@Nullable private Change myCurrentChange;
- @NotNull private final WaitingBackgroundableTaskExecutor myTaskExecutor = new WaitingBackgroundableTaskExecutor();
+ @NotNull private final DiffTaskQueue myQueue = new DiffTaskQueue();
public CacheChangeProcessor(@NotNull Project project) {
super(project);
@@ -74,21 +75,25 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor {
// Update
//
+ @CalledInAwt
public void updateRequest(final boolean force, @Nullable final ScrollToPolicy scrollToChangePolicy) {
final Change change = myCurrentChange;
+
DiffRequest cachedRequest = loadRequestFast(change);
if (cachedRequest != null) {
applyRequest(cachedRequest, force, scrollToChangePolicy);
return;
}
- myTaskExecutor.execute(
- new Convertor() {
+ // TODO: check if current loading change is the same as we want to load now? (and not interrupt loading)
+ myQueue.executeAndTryWait(
+ new Function() {
@Override
- public Runnable convert(ProgressIndicator indicator) {
+ public Runnable fun(ProgressIndicator indicator) {
final DiffRequest request = loadRequest(change, indicator);
return new Runnable() {
@Override
+ @CalledInAwt
public void run() {
myRequestCache.put(change, Pair.create(change, request));
applyRequest(request, force, scrollToChangePolicy);
@@ -107,6 +112,7 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor {
}
@Nullable
+ @CalledInAwt
@Contract("null -> !null")
protected DiffRequest loadRequestFast(@Nullable Change change) {
if (change == null) return NoDiffRequest.INSTANCE;
@@ -152,9 +158,10 @@ public abstract class CacheChangeProcessor extends DiffRequestProcessor {
//
@Override
+ @CalledInAwt
protected void onDispose() {
super.onDispose();
- myTaskExecutor.abort();
+ Disposer.dispose(myQueue);
myRequestCache.clear();
}
diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/committed/ExternalChangesDetectionVcsTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/committed/ExternalChangesDetectionVcsTest.java
new file mode 100644
index 000000000000..ece7f752ddc7
--- /dev/null
+++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/committed/ExternalChangesDetectionVcsTest.java
@@ -0,0 +1,211 @@
+package com.intellij.openapi.vcs.changes.committed;
+
+import com.intellij.ide.startup.impl.StartupManagerImpl;
+import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.startup.StartupManager;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vcs.ProjectLevelVcsManager;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vcs.changes.*;
+import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
+import com.intellij.testFramework.fixtures.TempDirTestFixture;
+import com.intellij.testFramework.vcs.AbstractJunitVcsTestCase;
+import com.intellij.util.Processor;
+import com.intellij.util.ui.UIUtil;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * @author irengrig
+ */
+public class ExternalChangesDetectionVcsTest extends AbstractJunitVcsTestCase {
+ private MockAbstractVcs myVcs;
+ private ProjectLevelVcsManagerImpl myVcsManager;
+ private LocalFileSystem myLFS;
+ private ChangeListManager myChangeListManager;
+ private VcsDirtyScopeManager myVcsDirtyScopeManager;
+ private TempDirTestFixture myTempDirTestFixture;
+ private File myClientRoot;
+
+ @Before
+ public void setUp() throws Exception {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory();
+ myTempDirTestFixture = fixtureFactory.createTempDirTestFixture();
+ myTempDirTestFixture.setUp();
+
+ myClientRoot = new File(myTempDirTestFixture.getTempDirPath(), "clientroot");
+ myClientRoot.mkdir();
+
+ initProject(myClientRoot, ExternalChangesDetectionVcsTest.this.getTestName());
+
+ ((StartupManagerImpl)StartupManager.getInstance(myProject)).runPostStartupActivities();
+
+ myVcs = new MockAbstractVcs(myProject);
+ myVcs.setChangeProvider(new MyMockChangeProvider());
+ myVcsManager = (ProjectLevelVcsManagerImpl)ProjectLevelVcsManager.getInstance(myProject);
+ myVcsManager.registerVcs(myVcs);
+ myVcsManager.setDirectoryMapping("", myVcs.getName());
+
+ myLFS = LocalFileSystem.getInstance();
+ myChangeListManager = ChangeListManager.getInstance(myProject);
+ ((ProjectComponent)myChangeListManager).projectOpened();
+ myVcsDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject);
+ ((ProjectComponent)myVcsDirtyScopeManager).projectOpened();
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ myVcsManager.unregisterVcs(myVcs);
+ ((ProjectComponent)myChangeListManager).projectClosed();
+ ((ProjectComponent)myVcsDirtyScopeManager).projectClosed();
+
+ tearDownProject();
+ if (myTempDirTestFixture != null) {
+ myTempDirTestFixture.tearDown();
+ myTempDirTestFixture = null;
+ }
+ FileUtil.delete(myClientRoot);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ @Test
+ public void testDeletion() throws Exception {
+ final File f = new File(myClientRoot, "f.txt");
+ f.createNewFile();
+ final VirtualFile vf = myLFS.refreshAndFindFileByIoFile(f);
+ myChangeListManager.ensureUpToDate(false);
+ ((ChangeListManagerImpl) myChangeListManager).getUnversionedFiles().contains(vf);
+ FileUtil.delete(f);
+ myWorkingCopyDir.refresh(false, true);
+ myChangeListManager.ensureUpToDate(false);
+ ((ChangeListManagerImpl) myChangeListManager).getUnversionedFiles().isEmpty();
+ }
+
+ @Test
+ public void testGeneration() throws Exception {
+ for (int i = 0; i < 100; i++) {
+ final File f = new File(myClientRoot, "f" + i + ".txt");
+ f.createNewFile();
+ }
+ myWorkingCopyDir.refresh(false, true);
+ myChangeListManager.ensureUpToDate(false);
+ final List unversionedFiles = ((ChangeListManagerImpl)myChangeListManager).getUnversionedFiles();
+ final Pattern pattern = Pattern.compile("f([0-9])+\\.txt");
+ int cnt = 0;
+ for (VirtualFile unversionedFile : unversionedFiles) {
+ if (VfsUtil.isAncestor(myWorkingCopyDir, unversionedFile, true)) {
+ ++ cnt;
+ Assert.assertTrue(pattern.matcher(unversionedFile.getName()).matches());
+ }
+ }
+ Assert.assertEquals(100, cnt);
+ }
+
+ /*@Test
+ public void testMoveDir() throws Exception {
+ final File root = new File(myClientRoot, "was");
+ root.mkdir();
+ for (int i = 0; i < 10; i++) {
+ final File dir = new File(root, "dir" + i);
+ dir.mkdir();
+ for (int j = 0; j < 10; j++) {
+ final File f = new File(dir, "f" + j + ".txt");
+ f.createNewFile();
+ }
+ }
+ myWorkingCopyDir.refresh(false, true);
+ myChangeListManager.ensureUpToDate(false);
+ List unversionedFiles = ((ChangeListManagerImpl)myChangeListManager).getUnversionedFiles();
+ final Pattern pattern = Pattern.compile("f([0-9])+\\.txt");
+ final Pattern patternDir = Pattern.compile("dir([0-9])+");
+ int cnt = 0;
+ for (VirtualFile unversionedFile : unversionedFiles) {
+ if (VfsUtil.isAncestor(myWorkingCopyDir, unversionedFile, true) && (! "was".equals(unversionedFile.getName()))) {
+ ++ cnt;
+ Assert.assertTrue(pattern.matcher(unversionedFile.getName()).matches() || patternDir.matcher(unversionedFile.getName()).matches());
+ }
+ }
+ Assert.assertEquals(110, cnt);
+ final File renamedFile = new File(myClientRoot, "newName");
+ FileUtil.copyDir(root, renamedFile);
+ FileUtil.delete(root);
+
+ myWorkingCopyDir.refresh(false, true);
+ myChangeListManager.ensureUpToDate(false);
+ unversionedFiles = ((ChangeListManagerImpl)myChangeListManager).getUnversionedFiles();
+
+ cnt = 0;
+ for (VirtualFile unversionedFile : unversionedFiles) {
+ if (VfsUtil.isAncestor(myWorkingCopyDir, unversionedFile, true) && (! "newName".equals(unversionedFile.getName()))) {
+ ++ cnt;
+ Assert.assertTrue((pattern.matcher(unversionedFile.getName()).matches() || patternDir.matcher(unversionedFile.getName()).matches()));
+ if (unversionedFile.getPath().indexOf("newName") == -1) {
+ System.out.println("wrong " + unversionedFile.getPath());
+ }
+ }
+ }
+ Assert.assertEquals(110, cnt);
+ }*/
+
+ private static class MyMockChangeProvider implements ChangeProvider {
+ @Override
+ public void doCleanup(List files) {
+ }
+
+ @Override
+ public void getChanges(VcsDirtyScope dirtyScope,
+ final ChangelistBuilder builder,
+ ProgressIndicator progress,
+ ChangeListManagerGate addGate) throws VcsException {
+ for (FilePath path : dirtyScope.getDirtyFiles()) {
+ builder.processUnversionedFile(path.getVirtualFile());
+ }
+ final Processor processor = new Processor() {
+ @Override
+ public boolean process(final VirtualFile vf) {
+ builder.processUnversionedFile(vf);
+ return true;
+ }
+ };
+ for (FilePath dir : dirtyScope.getRecursivelyDirtyDirectories()) {
+ VfsUtil.processFilesRecursively(dir.getVirtualFile(), processor);
+ }
+ }
+
+ @Override
+ public boolean isModifiedDocumentTrackingRequired() {
+ return false;
+ }
+ }
+}
diff --git a/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/committed/VcsEventsListenerTest.java b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/committed/VcsEventsListenerTest.java
new file mode 100644
index 000000000000..f24ad1fed284
--- /dev/null
+++ b/platform/vcs-impl/testSrc/com/intellij/openapi/vcs/changes/committed/VcsEventsListenerTest.java
@@ -0,0 +1,355 @@
+package com.intellij.openapi.vcs.changes.committed;
+
+import com.intellij.ide.startup.impl.StartupManagerImpl;
+import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.startup.StartupManager;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vcs.*;
+import com.intellij.openapi.vcs.changes.Change;
+import com.intellij.openapi.vcs.changes.ChangeList;
+import com.intellij.openapi.vcs.changes.ChangeListManager;
+import com.intellij.openapi.vcs.checkin.CheckinEnvironment;
+import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
+import com.intellij.openapi.vcs.rollback.RollbackEnvironment;
+import com.intellij.openapi.vcs.rollback.RollbackProgressListener;
+import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
+import com.intellij.openapi.vcs.update.SequentialUpdatesContext;
+import com.intellij.openapi.vcs.update.UpdateEnvironment;
+import com.intellij.openapi.vcs.update.UpdateSession;
+import com.intellij.openapi.vcs.update.UpdatedFiles;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.UsefulTestCase;
+import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
+import com.intellij.testFramework.fixtures.TempDirTestFixture;
+import com.intellij.testFramework.vcs.AbstractJunitVcsTestCase;
+import com.intellij.util.NullableFunction;
+import com.intellij.util.PairConsumer;
+import com.intellij.util.ui.UIUtil;
+import junit.framework.Assert;
+import org.jetbrains.annotations.NotNull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author irengrig
+ * Date: 12/21/10
+ * Time: 2:03 PM
+ */
+public class VcsEventsListenerTest extends AbstractJunitVcsTestCase {
+ private AbstractVcs myVcs;
+ private ProjectLevelVcsManagerImpl myVcsManager;
+ private ChangeListManager myChangeListManager;
+ private TempDirTestFixture myTempDirFixture;
+ private File myClientRoot;
+
+ @Before
+ public void setUp() {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory();
+ myTempDirFixture = fixtureFactory.createTempDirTestFixture();
+ myTempDirFixture.setUp();
+
+ myClientRoot = new File(myTempDirFixture.getTempDirPath(), "clientroot");
+ myClientRoot.mkdir();
+
+ initProject(myClientRoot, VcsEventsListenerTest.this.getTestName());
+
+ ((StartupManagerImpl)StartupManager.getInstance(myProject)).runPostStartupActivities();
+
+ myChangeListManager = ChangeListManager.getInstance(myProject);
+ myVcs = VcsActiveEnvironmentsProxy.proxyVcs(new MyVcs(myProject, "mock"));
+ myVcsManager = (ProjectLevelVcsManagerImpl)ProjectLevelVcsManager.getInstance(myProject);
+ myVcsManager.registerVcs(myVcs);
+ myVcsManager.setDirectoryMapping(myWorkingCopyDir.getPath(), myVcs.getName());
+
+ ((ProjectComponent)myChangeListManager).projectOpened();
+ }
+ catch (Exception e) {
+ tearDown();
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+
+ @After
+ public void tearDown() {
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (myVcsManager != null && myVcs != null) {
+ myVcsManager.unregisterVcs(myVcs);
+ }
+
+ ((ProjectComponent)myChangeListManager).projectClosed();
+ tearDownProject();
+ if (myTempDirFixture != null) {
+ myTempDirFixture.tearDown();
+ myTempDirFixture = null;
+ }
+ FileUtil.delete(myClientRoot);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ finally {
+ try {
+ UsefulTestCase.clearFields(this);
+ }
+ catch (IllegalAccessException e) {
+ //noinspection ThrowFromFinallyBlock
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ });
+ }
+
+ @Test
+ public void testSimpleListeningWithProxy() throws Exception {
+ final VcsEventsListenerManager manager = myVcsManager.getVcsEventsListenerManager();
+ final List list = Arrays.asList(new VirtualFile[]{myWorkingCopyDir});
+ final MyCheckinListener listener = new MyCheckinListener(list);
+ final Object key = manager.addCheckin(new ForwardingListener(listener));
+
+ myVcs.getCheckinEnvironment().scheduleUnversionedFilesForAddition(list);
+
+ Assert.assertTrue(listener.isChecked());
+ listener.assertCheckOk();
+
+ listener.reset();
+
+ manager.removeCheckin(key);
+ listener.reset();
+ myVcs.getCheckinEnvironment().scheduleUnversionedFilesForAddition(list);
+ Assert.assertFalse(listener.isChecked());
+ }
+
+ @Test
+ public void testSimpleListeningWithoutProxy() throws Exception {
+ myVcsManager.setDirectoryMapping(myWorkingCopyDir.getPath(), "svn");
+
+ testSimpleListeningWithProxy();
+ }
+
+ private static class MyVcs extends MockAbstractVcs {
+ private MyVcs(Project project, String name) {
+ super(project, name);
+ }
+
+ @Override
+ protected UpdateEnvironment createUpdateEnvironment() {
+ return new UpdateEnvironment() {
+ @Override
+ public void fillGroups(UpdatedFiles updatedFiles) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @NotNull
+ @Override
+ public UpdateSession updateDirectories(@NotNull FilePath[] contentRoots,
+ UpdatedFiles updatedFiles,
+ ProgressIndicator progressIndicator,
+ @NotNull Ref context) throws ProcessCanceledException {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public Configurable createConfigurable(Collection files) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public boolean validateOptions(Collection roots) {
+ return false; //To change body of implemented methods use File | Settings | File Templates.
+ }
+ };
+ }
+
+ @Override
+ protected RollbackEnvironment createRollbackEnvironment() {
+ return new RollbackEnvironment() {
+ @Override
+ public String getRollbackOperationName() {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void rollbackChanges(List changes,
+ List vcsExceptions,
+ @NotNull RollbackProgressListener listener) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void rollbackMissingFileDeletion(List files,
+ List exceptions,
+ RollbackProgressListener listener) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void rollbackModifiedWithoutCheckout(List files,
+ List exceptions,
+ RollbackProgressListener listener) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ public void rollbackIfUnchanged(VirtualFile file) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
+ };
+ }
+
+ @Override
+ protected CheckinEnvironment createCheckinEnvironment() {
+ return new CheckinEnvironment() {
+ @Override
+ public RefreshableOnComponent createAdditionalOptionsPanel(CheckinProjectPanel panel,
+ PairConsumer