/* * Copyright 2000-2009 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 org.jetbrains.idea.svn.branchConfig; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManagerQueue; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.CalledInBackground; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.integrate.SvnBranchItem; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import java.util.HashMap; import java.util.List; import java.util.Map; // synch is here public class NewRootBunch implements SvnBranchConfigManager { private final static Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.branchConfig.NewRootBunch"); private final Object myLock = new Object(); private final Project myProject; private final ProgressManagerQueue myBranchesLoader; private final Map> myMap; public NewRootBunch(final Project project, ProgressManagerQueue branchesLoader) { myProject = project; myBranchesLoader = branchesLoader; myMap = new HashMap>(); } public void updateForRoot(@NotNull final VirtualFile root, @NotNull final InfoStorage config, @Nullable final PairConsumer callbackOnUpdate) { synchronized (myLock) { final InfoStorage existing = myMap.get(root); if (existing == null) { myMap.put(root, config); if (callbackOnUpdate != null) { callbackOnUpdate.consume(null, config.getValue()); } } else { existing.accept(config, callbackOnUpdate); } } } public void updateBranches(@NotNull final VirtualFile root, @NotNull final String branchesParent, @NotNull final InfoStorage> items) { synchronized (myLock) { final InfoStorage existing = myMap.get(root); if (existing == null) { LOG.info("cannot update branches, branches parent not found: " + branchesParent); } else { existing.getValue().updateBranch(branchesParent, items); } } } @NotNull public SvnBranchConfigurationNew getConfig(@NotNull final VirtualFile root) { synchronized (myLock) { final InfoStorage value = myMap.get(root); final SvnBranchConfigurationNew result; if (value == null) { result = new SvnBranchConfigurationNew(); myMap.put(root, new InfoStorage(result, InfoReliability.empty)); myBranchesLoader.run(new DefaultBranchConfigInitializer(myProject, this, root)); } else { result = value.getValue(); } return result; } } public void reloadBranches(@NotNull final VirtualFile root, @NotNull final String branchParentUrl, final Consumer> callback) { ApplicationManager.getApplication().executeOnPooledThread(new BranchesLoadRunnable(myProject, this, branchParentUrl, InfoReliability.setByUser, root, callback, true)); } @Nullable @CalledInBackground public SVNURL getWorkingBranchWithReload(final SVNURL svnurl, final VirtualFile root) { final Ref result = new Ref(); try { final SvnBranchConfigurationNew configuration = myMap.get(root).getValue(); final String group = configuration.getGroupToLoadToReachUrl(svnurl); final Runnable runnable = new Runnable() { public void run() { final SvnBranchConfigurationNew reloadedConfiguration = myMap.get(root).getValue(); try { result.set(reloadedConfiguration.getWorkingBranch(svnurl)); } catch (SVNException e) { // } } }; if (group == null) { runnable.run(); } else { new BranchesLoadRunnable(myProject, this, group, InfoReliability.setByUser, root, new Consumer>() { public void consume(List svnBranchItems) { runnable.run(); } }, true).run(); } } catch (SVNException e) { // } return result.get(); } public static class BranchesLoadRunnable implements Runnable { private final Project myProject; private final SvnBranchConfigManager myBunch; private final VirtualFile myRoot; @Nullable private final Consumer> myCallback; private final String myUrl; private final InfoReliability myInfoReliability; private boolean myPassive; public BranchesLoadRunnable(final Project project, final SvnBranchConfigManager bunch, final String url, final InfoReliability infoReliability, final VirtualFile root, @Nullable final Consumer> callback, boolean passive) { myProject = project; myBunch = bunch; myUrl = url; myInfoReliability = infoReliability; myRoot = root; myCallback = callback; myPassive = passive; } public void run() { boolean callbackCalled = false; try { final List items = BranchesLoader.loadBranches(myProject, myUrl, myPassive); myBunch.updateBranches(myRoot, myUrl, new InfoStorage>(items, myInfoReliability)); if (myCallback != null) { myCallback.consume(items); callbackCalled = true; } } catch (VcsException e) { showError(e); } catch (SVNException e) { showError(e); } finally { // callback must be called by contract if (myCallback != null && (! callbackCalled)) { myCallback.consume(null); } } } private void showError(Exception e) { // already logged inside if (InfoReliability.setByUser.equals(myInfoReliability)) { VcsBalloonProblemNotifier.showOverChangesView(myProject, "Branches load error: " + e.getMessage(), MessageType.ERROR); } } } private static class DefaultBranchConfigInitializer implements Runnable { private final Project myProject; private final SvnBranchConfigManager myBunch; private final VirtualFile myRoot; private DefaultBranchConfigInitializer(final Project project, final SvnBranchConfigManager bunch, final VirtualFile root) { myProject = project; myRoot = root; myBunch = bunch; } public void run() { final SvnBranchConfigurationNew result = DefaultConfigLoader.loadDefaultConfiguration(myProject, myRoot); if (result != null) { final Application application = ApplicationManager.getApplication(); for (String url : result.getBranchUrls()) { application.executeOnPooledThread(new BranchesLoadRunnable(myProject, myBunch, url, InfoReliability.defaultValues, myRoot, null, true)); } myBunch.updateForRoot(myRoot, new InfoStorage(result, InfoReliability.defaultValues), null); } } } public Map getMapCopy() { synchronized (myLock) { final Map result = new HashMap(); for (VirtualFile vf : myMap.keySet()) { result.put(vf, myMap.get(vf).getValue()); } return result; } } }