project leak
[fedora-idea.git] / plugins / svn4idea / src / org / jetbrains / idea / svn / SvnFileSystemListenerWrapper.java
blob6bf4014d442dab03c27a82cbca4c913dc4392f9d
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.idea.svn;
18 import com.intellij.openapi.Disposable;
19 import com.intellij.openapi.command.CommandEvent;
20 import com.intellij.openapi.command.CommandListener;
21 import com.intellij.openapi.command.CommandProcessor;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.project.ProjectLocator;
24 import com.intellij.openapi.util.Disposer;
25 import com.intellij.openapi.util.Pair;
26 import com.intellij.openapi.vfs.LocalFileOperationsHandler;
27 import com.intellij.openapi.vfs.LocalFileSystem;
28 import com.intellij.openapi.vfs.VirtualFile;
29 import com.intellij.util.ThrowableConsumer;
30 import org.jetbrains.annotations.Nullable;
32 import java.io.IOException;
33 import java.lang.reflect.InvocationHandler;
34 import java.lang.reflect.Method;
35 import java.lang.reflect.Proxy;
36 import java.util.Arrays;
37 import java.util.HashMap;
38 import java.util.Map;
40 public class SvnFileSystemListenerWrapper {
41 private final LocalFileOperationsHandler myProxy;
42 private final CommandListener myListener;
44 public SvnFileSystemListenerWrapper(final SvnFileSystemListener delegate) {
45 final MyCommandListener listener = new MyCommandListener(delegate);
46 myListener = listener;
47 final MyStorage storage = new MyStorage(listener);
48 myProxy = (LocalFileOperationsHandler) Proxy.newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(),
49 new Class<?>[]{LocalFileOperationsHandler.class}, new MyInvoker(storage, delegate));
52 public void registerSelf() {
53 LocalFileSystem.getInstance().registerAuxiliaryFileOperationsHandler(myProxy);
54 CommandProcessor.getInstance().addCommandListener(myListener);
57 public void unregisterSelf() {
58 LocalFileSystem.getInstance().unregisterAuxiliaryFileOperationsHandler(myProxy);
59 CommandProcessor.getInstance().removeCommandListener(myListener);
62 private static class MyCommandListener implements CommandListener, MyMarker {
63 private volatile boolean myInCommand;
64 private final SvnFileSystemListener myDelegate;
66 public MyCommandListener(final SvnFileSystemListener delegate) {
67 myDelegate = delegate;
70 public void start(final Project project) {
71 if (!myInCommand && project != null) {
72 myDelegate.commandStarted(project);
76 public void finish(final Project project) {
77 if (! myInCommand && project != null) {
78 myDelegate.commandFinished(project);
82 public void commandStarted(CommandEvent event) {
83 myInCommand = true;
84 myDelegate.commandStarted(event);
87 public void beforeCommandFinished(CommandEvent event) {
88 myDelegate.beforeCommandFinished(event);
91 public void commandFinished(CommandEvent event) {
92 myInCommand = false;
93 myDelegate.commandFinished(event);
96 public void undoTransparentActionStarted() {
97 myDelegate.undoTransparentActionStarted();
100 public void undoTransparentActionFinished() {
101 myDelegate.undoTransparentActionFinished();
105 private interface MyMarker {
106 void start(final Project project);
107 void finish(final Project project);
110 private static class MyStorage implements InvocationHandler {
111 private final MyMarker myMarker;
112 private final Map<Project, Pair<String, Object[]>> myStarted;
114 private MyStorage(final MyMarker marker) {
115 myMarker = marker;
116 myStarted = new HashMap<Project, Pair<String, Object[]>>();
119 @Nullable
120 private static Project getProject(Object[] args) {
121 for (Object arg : args) {
122 if (arg instanceof VirtualFile) {
123 return ProjectLocator.getInstance().guessProjectForFile((VirtualFile) arg);
126 return null;
129 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
130 final Project project = getProject(args);
131 if (project != null) {
132 final Pair<String, Object[]> pair = myStarted.get(project);
133 if (pair != null && method.getName().equals(pair.getFirst()) && Arrays.equals(args, pair.getSecond())) {
134 myMarker.finish(project);
137 //dont return null for auto unboxing to not face NPE
138 return "boolean".equals(method.getReturnType().getName()) ? Boolean.TRUE : null;
141 private void register(final Method method, final Object[] args) {
142 final Object[] newArr = new Object[args.length];
143 System.arraycopy(args, 0, newArr, 0, args.length);
144 final Project project = getProject(args);
145 if (project != null) {
146 myMarker.start(project);
147 myStarted.put(project, new Pair<String, Object[]>(method.getName(), newArr));
148 Disposer.register(project, new Disposable() {
149 public void dispose() {
150 myStarted.remove(project);
157 private static class MyInvoker implements InvocationHandler {
158 private final Object myDelegate;
159 private final MyStorage myParent;
160 private final LocalFileOperationsHandler myParentProxy;
162 private MyInvoker(final MyStorage parent, Object delegate) {
163 myParent = parent;
164 myDelegate = delegate;
165 myParentProxy = (LocalFileOperationsHandler) Proxy.newProxyInstance(LocalFileOperationsHandler.class.getClassLoader(),
166 new Class<?>[]{LocalFileOperationsHandler.class}, myParent);
169 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
170 if ("afterDone".equals(method.getName()) && args.length == 1) {
171 ((ThrowableConsumer<LocalFileOperationsHandler, IOException>)args[0]).consume(myParentProxy);
172 return null;
175 if (LocalFileOperationsHandler.class.equals(method.getDeclaringClass())) {
176 myParent.register(method, args);
178 if ("equals".equals(method.getName())) {
179 return args[0].equals(this);
181 else if ("hashCode".equals(method.getName())) {
182 return 1;
184 return method.invoke(myDelegate, args);