IDEA-26360 (Performance and inconsistency issues with svn:externals and "Detect neste...
[fedora-idea.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / update / AbstractCommonUpdateAction.java
blobf227b677890702c4f13d42c0fa0924ab7f7ef4a7
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 com.intellij.openapi.vcs.update;
18 import com.intellij.history.Label;
19 import com.intellij.history.LocalHistory;
20 import com.intellij.history.LocalHistoryAction;
21 import com.intellij.ide.errorTreeView.HotfixData;
22 import com.intellij.openapi.actionSystem.AnActionEvent;
23 import com.intellij.openapi.actionSystem.Presentation;
24 import com.intellij.openapi.application.ApplicationManager;
25 import com.intellij.openapi.diagnostic.Logger;
26 import com.intellij.openapi.options.Configurable;
27 import com.intellij.openapi.progress.ProcessCanceledException;
28 import com.intellij.openapi.progress.ProgressIndicator;
29 import com.intellij.openapi.progress.ProgressManager;
30 import com.intellij.openapi.progress.Task;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.project.ex.ProjectManagerEx;
33 import com.intellij.openapi.ui.MessageType;
34 import com.intellij.openapi.util.Ref;
35 import com.intellij.openapi.vcs.*;
36 import com.intellij.openapi.vcs.actions.AbstractVcsAction;
37 import com.intellij.openapi.vcs.actions.VcsContext;
38 import com.intellij.openapi.vcs.changes.RemoteRevisionsCache;
39 import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
40 import com.intellij.openapi.vcs.changes.VcsDirtyScopeManagerImpl;
41 import com.intellij.openapi.vcs.changes.committed.CommittedChangesAdapter;
42 import com.intellij.openapi.vcs.changes.committed.CommittedChangesCache;
43 import com.intellij.openapi.vcs.changes.committed.IntoSelfVirtualFileConvertor;
44 import com.intellij.openapi.vcs.changes.ui.ChangesViewContentManager;
45 import com.intellij.openapi.vcs.ex.ProjectLevelVcsManagerEx;
46 import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
47 import com.intellij.openapi.vfs.VfsUtil;
48 import com.intellij.openapi.vfs.VirtualFile;
49 import com.intellij.openapi.vfs.VirtualFileManager;
50 import com.intellij.openapi.wm.ToolWindowManager;
51 import com.intellij.util.messages.MessageBusConnection;
52 import com.intellij.util.ui.OptionsDialog;
53 import com.intellij.vcsUtil.VcsUtil;
54 import org.jetbrains.annotations.NonNls;
55 import org.jetbrains.annotations.NotNull;
56 import org.jetbrains.annotations.Nullable;
58 import java.io.File;
59 import java.util.*;
61 public abstract class AbstractCommonUpdateAction extends AbstractVcsAction {
62 private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.update.AbstractCommonUpdateAction");
64 private final ActionInfo myActionInfo;
65 private final ScopeInfo myScopeInfo;
67 protected AbstractCommonUpdateAction(ActionInfo actionInfo, ScopeInfo scopeInfo) {
68 myActionInfo = actionInfo;
69 myScopeInfo = scopeInfo;
72 private String getCompleteActionName(VcsContext dataContext) {
73 return myActionInfo.getActionName(myScopeInfo.getScopeName(dataContext, myActionInfo));
76 protected void actionPerformed(final VcsContext context) {
77 final Project project = context.getProject();
79 boolean showUpdateOptions = myActionInfo.showOptions(project);
81 if (project != null) {
82 try {
83 final FilePath[] filePaths = myScopeInfo.getRoots(context, myActionInfo);
84 final FilePath[] roots = filterDescindingFiles(filterRoots(filePaths, context), project);
85 if (roots.length == 0) {
86 return;
89 final Map<AbstractVcs, Collection<FilePath>> vcsToVirtualFiles = createVcsToFilesMap(roots, project);
91 if (showUpdateOptions || OptionsDialog.shiftIsPressed(context.getModifiers())) {
92 showOptionsDialog(vcsToVirtualFiles, project, context);
95 for (AbstractVcs vcs : vcsToVirtualFiles.keySet()) {
96 final UpdateEnvironment updateEnvironment = myActionInfo.getEnvironment(vcs);
97 if ((updateEnvironment != null) && (! updateEnvironment.validateOptions(vcsToVirtualFiles.get(vcs)))) {
98 // messages already shown
99 return;
103 if (ApplicationManager.getApplication().isDispatchThread()) {
104 ApplicationManager.getApplication().saveAll();
106 Task.Backgroundable task = new Updater(project, roots, vcsToVirtualFiles);
107 ProgressManager.getInstance().run(task);
109 catch (ProcessCanceledException e1) {
110 //ignore
115 private boolean canGroupByChangelist(final Set<AbstractVcs> abstractVcses) {
116 if (myActionInfo.canGroupByChangelist()) {
117 for(AbstractVcs vcs: abstractVcses) {
118 if (vcs.getCachingCommittedChangesProvider() != null) {
119 return true;
123 return false;
126 private static boolean someSessionWasCanceled(List<UpdateSession> updateSessions) {
127 for (UpdateSession updateSession : updateSessions) {
128 if (updateSession.isCanceled()) {
129 return true;
132 return false;
135 private static String getAllFilesAreUpToDateMessage(FilePath[] roots) {
136 if (roots.length == 1 && !roots[0].isDirectory()) {
137 return VcsBundle.message("message.text.file.is.up.to.date");
139 else {
140 return VcsBundle.message("message.text.all.files.are.up.to.date");
144 private void showOptionsDialog(final Map<AbstractVcs, Collection<FilePath>> updateEnvToVirtualFiles, final Project project,
145 final VcsContext dataContext) {
146 LinkedHashMap<Configurable, AbstractVcs> envToConfMap = createConfigurableToEnvMap(updateEnvToVirtualFiles);
147 if (!envToConfMap.isEmpty()) {
148 UpdateOrStatusOptionsDialog dialogOrStatus = myActionInfo.createOptionsDialog(project, envToConfMap,
149 myScopeInfo.getScopeName(dataContext,
150 myActionInfo));
151 dialogOrStatus.show();
152 if (!dialogOrStatus.isOK()) {
153 throw new ProcessCanceledException();
158 private LinkedHashMap<Configurable, AbstractVcs> createConfigurableToEnvMap(Map<AbstractVcs, Collection<FilePath>> updateEnvToVirtualFiles) {
159 LinkedHashMap<Configurable, AbstractVcs> envToConfMap = new LinkedHashMap<Configurable, AbstractVcs>();
160 for (AbstractVcs vcs : updateEnvToVirtualFiles.keySet()) {
161 Configurable configurable = myActionInfo.getEnvironment(vcs).createConfigurable(updateEnvToVirtualFiles.get(vcs));
162 if (configurable != null) {
163 envToConfMap.put(configurable, vcs);
166 return envToConfMap;
169 private Map<AbstractVcs,Collection<FilePath>> createVcsToFilesMap(FilePath[] roots, Project project) {
170 HashMap<AbstractVcs, Collection<FilePath>> resultPrep = new HashMap<AbstractVcs, Collection<FilePath>>();
172 for (FilePath file : roots) {
173 AbstractVcs vcs = VcsUtil.getVcsFor(project, file);
174 if (vcs != null) {
175 UpdateEnvironment updateEnvironment = myActionInfo.getEnvironment(vcs);
176 if (updateEnvironment != null) {
177 if (!resultPrep.containsKey(vcs)) resultPrep.put(vcs, new HashSet<FilePath>());
178 resultPrep.get(vcs).add(file);
183 final Map<AbstractVcs, Collection<FilePath>> result = new HashMap<AbstractVcs, Collection<FilePath>>();
184 for (Map.Entry<AbstractVcs, Collection<FilePath>> entry : resultPrep.entrySet()) {
185 final AbstractVcs vcs = entry.getKey();
186 final List<FilePath> paths = new ArrayList<FilePath>(entry.getValue());
187 final List<VirtualFile> files = ObjectsConvertor.convert(paths, ObjectsConvertor.FILEPATH_TO_VIRTUAL, ObjectsConvertor.NOT_NULL);
188 result.put(vcs, ObjectsConvertor.vf2fp(vcs.filterUniqueRoots(files, IntoSelfVirtualFileConvertor.getInstance())));
191 return result;
194 private static boolean containsParent(FilePath[] array, FilePath file) {
195 for (FilePath virtualFile : array) {
196 if (virtualFile == file) continue;
197 if (VfsUtil.isAncestor(virtualFile.getIOFile(), file.getIOFile(), false)) return true;
199 return false;
202 @NotNull
203 private FilePath[] filterRoots(FilePath[] roots, VcsContext vcsContext) {
204 final ArrayList<FilePath> result = new ArrayList<FilePath>();
205 final Project project = vcsContext.getProject();
206 for (FilePath file : roots) {
207 AbstractVcs vcs = VcsUtil.getVcsFor(project, file);
208 if (vcs != null) {
209 if (!myScopeInfo.filterExistsInVcs() || AbstractVcs.fileInVcsByFileStatus(project, file)) {
210 UpdateEnvironment updateEnvironment = myActionInfo.getEnvironment(vcs);
211 if (updateEnvironment != null) {
212 result.add(file);
215 else {
216 final VirtualFile virtualFile = file.getVirtualFile();
217 if (virtualFile != null && virtualFile.isDirectory()) {
218 final VirtualFile[] vcsRoots = ProjectLevelVcsManager.getInstance(vcsContext.getProject()).getAllVersionedRoots();
219 for(VirtualFile vcsRoot: vcsRoots) {
220 if (VfsUtil.isAncestor(virtualFile, vcsRoot, false)) {
221 result.add(file);
228 return result.toArray(new FilePath[result.size()]);
231 protected abstract boolean filterRootsBeforeAction();
233 protected void update(VcsContext vcsContext, Presentation presentation) {
234 Project project = vcsContext.getProject();
236 if (project != null) {
238 String actionName = getCompleteActionName(vcsContext);
239 if (myActionInfo.showOptions(project) || OptionsDialog.shiftIsPressed(vcsContext.getModifiers())) {
240 actionName += "...";
243 presentation.setText(actionName);
245 presentation.setVisible(true);
246 presentation.setEnabled(true);
248 if (supportingVcsesAreEmpty(vcsContext.getProject(), myActionInfo)) {
249 presentation.setVisible(false);
250 presentation.setEnabled(false);
253 if (filterRootsBeforeAction()) {
254 FilePath[] roots = filterRoots(myScopeInfo.getRoots(vcsContext, myActionInfo), vcsContext);
255 if (roots.length == 0) {
256 presentation.setVisible(false);
257 presentation.setEnabled(false);
261 if (presentation.isVisible() && presentation.isEnabled() &&
262 ProjectLevelVcsManager.getInstance(project).isBackgroundVcsOperationRunning()) {
263 presentation.setEnabled(false);
265 } else {
266 presentation.setVisible(false);
267 presentation.setEnabled(false);
271 protected boolean forceSyncUpdate(final AnActionEvent e) {
272 return true;
275 private static boolean supportingVcsesAreEmpty(final Project project, final ActionInfo actionInfo) {
276 if (project == null) return true;
277 final AbstractVcs[] allActiveVcss = ProjectLevelVcsManager.getInstance(project).getAllActiveVcss();
278 for (AbstractVcs activeVcs : allActiveVcss) {
279 if (actionInfo.getEnvironment(activeVcs) != null) return false;
281 return true;
284 private class Updater extends Task.Backgroundable {
285 private final Project myProject;
286 private final ProjectLevelVcsManagerEx myProjectLevelVcsManager;
287 private UpdatedFiles myUpdatedFiles;
288 private final FilePath[] myRoots;
289 private final Map<AbstractVcs, Collection<FilePath>> myVcsToVirtualFiles;
290 private final Map<HotfixData, List<VcsException>> myGroupedExceptions;
291 private final List<UpdateSession> myUpdateSessions;
292 private int myUpdateNumber;
294 // vcs name, context object
295 private final Map<AbstractVcs, SequentialUpdatesContext> myContextInfo;
296 private VcsDirtyScopeManager myDirtyScopeManager;
298 private Label myBefore;
299 private Label myAfter;
301 public Updater(final Project project, final FilePath[] roots, final Map<AbstractVcs, Collection<FilePath>> vcsToVirtualFiles) {
302 super(project, getTemplatePresentation().getText(), true, VcsConfiguration.getInstance(project).getUpdateOption());
303 myProject = project;
304 myProjectLevelVcsManager = ProjectLevelVcsManagerEx.getInstanceEx(project);
305 myDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject);
306 myRoots = roots;
307 myVcsToVirtualFiles = vcsToVirtualFiles;
309 myUpdatedFiles = UpdatedFiles.create();
310 myGroupedExceptions = new HashMap<HotfixData, List<VcsException>>();
311 myUpdateSessions = new ArrayList<UpdateSession>();
313 // create from outside without any context; context is created by vcses
314 myContextInfo = new HashMap<AbstractVcs, SequentialUpdatesContext>();
315 myUpdateNumber = 1;
318 private void reset() {
319 myUpdatedFiles = UpdatedFiles.create();
320 myGroupedExceptions.clear();
321 myUpdateSessions.clear();
322 ++ myUpdateNumber;
325 private void suspendIfNeeded() {
326 if (! myActionInfo.canChangeFileStatus()) {
327 // i.e. for update but not for integrate or status
328 ((VcsDirtyScopeManagerImpl) myDirtyScopeManager).suspendMe();
332 private void releaseIfNeeded() {
333 if (! myActionInfo.canChangeFileStatus()) {
334 // i.e. for update but not for integrate or status
335 ((VcsDirtyScopeManagerImpl) myDirtyScopeManager).reanimate();
339 public void run(@NotNull final ProgressIndicator indicator) {
340 suspendIfNeeded();
341 try {
342 runImpl(indicator);
343 } catch (Throwable t) {
344 releaseIfNeeded();
345 if (t instanceof Error) {
346 throw ((Error) t);
347 } else if (t instanceof RuntimeException) {
348 throw ((RuntimeException) t);
350 throw new RuntimeException(t);
354 private void runImpl(@NotNull final ProgressIndicator indicator) {
355 ProjectManagerEx.getInstanceEx().blockReloadingProjectOnExternalChanges();
356 myProjectLevelVcsManager.startBackgroundVcsOperation();
358 myBefore = LocalHistory.putSystemLabel(myProject, "Before update");
360 ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
362 try {
363 int toBeProcessed = myVcsToVirtualFiles.size();
364 int processed = 0;
365 for (AbstractVcs vcs : myVcsToVirtualFiles.keySet()) {
366 final UpdateEnvironment updateEnvironment = myActionInfo.getEnvironment(vcs);
367 updateEnvironment.fillGroups(myUpdatedFiles);
368 Collection<FilePath> files = myVcsToVirtualFiles.get(vcs);
370 final SequentialUpdatesContext context = myContextInfo.get(vcs);
371 final Ref<SequentialUpdatesContext> refContext = new Ref<SequentialUpdatesContext>(context);
372 UpdateSession updateSession =
373 updateEnvironment.updateDirectories(files.toArray(new FilePath[files.size()]), myUpdatedFiles, progressIndicator, refContext);
374 myContextInfo.put(vcs, refContext.get());
375 processed++;
376 if (progressIndicator != null) {
377 progressIndicator.setFraction((double)processed / (double)toBeProcessed);
378 progressIndicator.setText2("");
380 final List<VcsException> exceptionList = updateSession.getExceptions();
381 gatherExceptions(vcs, exceptionList);
382 myUpdateSessions.add(updateSession);
384 } finally {
385 try {
386 if (progressIndicator != null) {
387 progressIndicator.setText(VcsBundle.message("progress.text.synchronizing.files"));
388 progressIndicator.setText2("");
390 doVfsRefresh();
391 } finally {
392 myAfter = LocalHistory.putSystemLabel(myProject, "After update");
393 myProjectLevelVcsManager.stopBackgroundVcsOperation();
398 private void gatherExceptions(final AbstractVcs vcs, final List<VcsException> exceptionList) {
399 final VcsExceptionsHotFixer fixer = vcs.getVcsExceptionsHotFixer();
400 if (fixer == null) {
401 putExceptions(null, exceptionList);
402 } else {
403 putExceptions(fixer.groupExceptions(ActionType.update, exceptionList));
407 private void putExceptions(final Map<HotfixData, List<VcsException>> map) {
408 for (Map.Entry<HotfixData, List<VcsException>> entry : map.entrySet()) {
409 putExceptions(entry.getKey(), entry.getValue());
413 private void putExceptions(final HotfixData key, @NotNull final List<VcsException> list) {
414 if (list.isEmpty()) return;
415 List<VcsException> exceptionList = myGroupedExceptions.get(key);
416 if (exceptionList == null) {
417 exceptionList = new ArrayList<VcsException>();
418 myGroupedExceptions.put(key, exceptionList);
420 exceptionList.addAll(list);
423 private void doVfsRefresh() {
424 final String actionName = VcsBundle.message("local.history.update.from.vcs");
425 final LocalHistoryAction action = LocalHistory.startAction(myProject, actionName);
426 try {
427 LOG.info("Calling refresh files after update for roots: " + Arrays.toString(myRoots));
428 RefreshVFsSynchronously.updateAllChanged(myUpdatedFiles);
430 finally {
431 action.finish();
432 LocalHistory.putSystemLabel(myProject, actionName);
436 @Nullable
437 public NotificationInfo getNotificationInfo() {
438 StringBuffer text = new StringBuffer();
439 final List<FileGroup> groups = myUpdatedFiles.getTopLevelGroups();
440 for (FileGroup group : groups) {
441 appendGroup(text, group);
444 return new NotificationInfo("VCS Update", "VCS Update Finished", text.toString(), true);
447 private void appendGroup(final StringBuffer text, final FileGroup group) {
448 final int s = group.getFiles().size();
449 if (s > 0) {
450 if (text.length() > 0) text.append("\n");
451 text.append(s + " Files " + group.getUpdateName());
454 final List<FileGroup> list = group.getChildren();
455 for (FileGroup g : list) {
456 appendGroup(text, g);
460 public void onSuccess() {
461 try {
462 onSuccessImpl();
463 } finally {
464 releaseIfNeeded();
468 private void onSuccessImpl() {
469 if (myProject.isDisposed()) {
470 ProjectManagerEx.getInstanceEx().unblockReloadingProjectOnExternalChanges();
471 return;
473 boolean continueChain = false;
474 for (SequentialUpdatesContext context : myContextInfo.values()) {
475 continueChain |= (context != null) && (context.shouldFail());
477 final boolean continueChainFinal = continueChain;
479 final boolean someSessionWasCancelled = someSessionWasCanceled(myUpdateSessions);
480 if (! someSessionWasCancelled) {
481 for (final UpdateSession updateSession : myUpdateSessions) {
482 updateSession.onRefreshFilesCompleted();
486 if (myActionInfo.canChangeFileStatus()) {
487 final List<VirtualFile> files = new ArrayList<VirtualFile>();
488 final RemoteRevisionsCache revisionsCache = RemoteRevisionsCache.getInstance(myProject);
489 revisionsCache.invalidate(myUpdatedFiles);
490 UpdateFilesHelper.iterateFileGroupFiles(myUpdatedFiles, new UpdateFilesHelper.Callback() {
491 public void onFile(final String filePath, final String groupId) {
492 @NonNls final String path = VfsUtil.pathToUrl(filePath.replace(File.separatorChar, '/'));
493 final VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(path);
494 if (file != null) {
495 files.add(file);
499 myDirtyScopeManager.filesDirty(files, null);
502 final boolean updateSuccess = (! someSessionWasCancelled) && (myGroupedExceptions.isEmpty());
504 if (! someSessionWasCancelled) {
505 ApplicationManager.getApplication().invokeLater(new Runnable() {
506 public void run() {
507 if (myProject.isDisposed()) {
508 ProjectManagerEx.getInstanceEx().unblockReloadingProjectOnExternalChanges();
509 return;
511 if (! myGroupedExceptions.isEmpty()) {
512 if (continueChainFinal) {
513 gatherContextInterruptedMessages();
515 AbstractVcsHelper.getInstance(myProject).showErrors(myGroupedExceptions, VcsBundle.message("message.title.vcs.update.errors",
516 getTemplatePresentation().getText()));
518 else {
519 final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
520 if (indicator != null) {
521 indicator.setText(VcsBundle.message("progress.text.updating.done"));
525 final boolean noMerged = myUpdatedFiles.getGroupById(FileGroup.MERGED_WITH_CONFLICT_ID).isEmpty();
526 if (myUpdatedFiles.isEmpty() && myGroupedExceptions.isEmpty()) {
527 ToolWindowManager.getInstance(myProject).notifyByBalloon(
528 ChangesViewContentManager.TOOLWINDOW_ID, MessageType.INFO, getAllFilesAreUpToDateMessage(myRoots));
530 else if (! myUpdatedFiles.isEmpty()) {
531 showUpdateTree(continueChainFinal && updateSuccess && noMerged);
533 final CommittedChangesCache cache = CommittedChangesCache.getInstance(myProject);
534 cache.processUpdatedFiles(myUpdatedFiles);
537 ProjectManagerEx.getInstanceEx().unblockReloadingProjectOnExternalChanges();
539 if (continueChainFinal && updateSuccess) {
540 if (!noMerged) {
541 showContextInterruptedError();
542 } else {
543 // trigger next update; for CVS when updating from several branvhes simultaneously
544 reset();
545 ProgressManager.getInstance().run(Updater.this);
550 } else if (continueChain) {
551 // since error
552 showContextInterruptedError();
553 ProjectManagerEx.getInstanceEx().unblockReloadingProjectOnExternalChanges();
557 private void showContextInterruptedError() {
558 gatherContextInterruptedMessages();
559 AbstractVcsHelper.getInstance(myProject).showErrors(myGroupedExceptions,
560 VcsBundle.message("message.title.vcs.update.errors", getTemplatePresentation().getText()));
563 private void gatherContextInterruptedMessages() {
564 for (Map.Entry<AbstractVcs, SequentialUpdatesContext> entry : myContextInfo.entrySet()) {
565 final SequentialUpdatesContext context = entry.getValue();
566 if ((context == null) || (! context.shouldFail())) continue;
567 final VcsException exception = new VcsException(context.getMessageWhenInterruptedBeforeStart());
568 gatherExceptions(entry.getKey(), Collections.singletonList(exception));
572 private void showUpdateTree(final boolean willBeContinued) {
573 RestoreUpdateTree restoreUpdateTree = RestoreUpdateTree.getInstance(myProject);
574 restoreUpdateTree.registerUpdateInformation(myUpdatedFiles, myActionInfo);
575 final String text = getTemplatePresentation().getText() + ((willBeContinued || (myUpdateNumber > 1)) ? ("#" + myUpdateNumber) : "");
576 final UpdateInfoTree updateInfoTree = myProjectLevelVcsManager.showUpdateProjectInfo(myUpdatedFiles, text, myActionInfo);
578 updateInfoTree.setBefore(myBefore);
579 updateInfoTree.setAfter(myAfter);
581 // todo make temporal listener of changes reload
582 if (updateInfoTree != null) {
583 updateInfoTree.setCanGroupByChangeList(canGroupByChangelist(myVcsToVirtualFiles.keySet()));
584 final MessageBusConnection messageBusConnection = myProject.getMessageBus().connect();
585 messageBusConnection.subscribe(CommittedChangesCache.COMMITTED_TOPIC, new CommittedChangesAdapter() {
586 public void incomingChangesUpdated(final List<CommittedChangeList> receivedChanges) {
587 if (receivedChanges != null) {
588 updateInfoTree.setChangeLists(receivedChanges);
589 messageBusConnection.disconnect();
596 public void onCancel() {
597 onSuccess();