From 05005cc705296475c0d229d52410aa815d8f8cb0 Mon Sep 17 00:00:00 2001
From: buczekp <buczekp>
Date: Mon, 9 Nov 2009 14:32:48 +0000
Subject: [PATCH] [LMS-1257] introduced active callback counter

SVN: 13276
---
 .../application/AbstractAsyncCallback.java    | 48 +++++++++----------
 .../application/AsyncCallbackCollection.java  | 37 --------------
 .../application/CallbackListenerAdapter.java  |  8 ++++
 .../client/application/ICallbackListener.java |  4 ++
 .../SearchableEntitySelectionWidget.java      |  1 +
 .../application/ui/GroupSelectionWidget.java  |  1 +
 .../ui/experiment/ProjectSelectionWidget.java |  1 +
 .../field/VocabularyTermSelectionWidget.java  |  1 +
 .../DataTypeSelectionWidget.java              |  1 +
 ...EntityTypePropertyTypeSelectionWidget.java |  1 +
 .../PropertyTypeSelectionWidget.java          |  1 +
 .../DetailedSearchFieldsSelectionWidget.java  |  1 +
 .../application/AuthenticationTest.java       |  2 +-
 .../testframework/AbstractGWTTestCase.java    |  2 -
 .../client/testframework/ITestCommand.java    |  2 +-
 .../client/testframework/RemoteConsole.java   | 43 ++++++++++++-----
 ...nericExperimentAttachmentDownloadTest.java |  2 +
 17 files changed, 79 insertions(+), 77 deletions(-)
 delete mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AsyncCallbackCollection.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java
index 9aadc1110aa..03c3eeaef84 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java
@@ -95,20 +95,6 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
 
     private static ICallbackListener<?> staticCallbackListener = DEFAULT_CALLBACK_LISTENER;
 
-    private static final AsyncCallbackCollection asyncCallbacks = new AsyncCallbackCollection();
-
-    /**
-     * Sets all callback objects silent.
-     * <p>
-     * <b>Note</b>: THIS METHOD SHOULD NEVER BE USED. It is only used inside the testing framework.
-     * </p>
-     */
-    public static void setAllCallbackObjectsSilent()
-    {
-        asyncCallbacks.setSilent();
-        asyncCallbacks.clear();
-    }
-
     /**
      * Sets the global callback listener.
      * <p>
@@ -124,8 +110,6 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
 
     private final ICallbackListener<T> callbackListener;
 
-    boolean silent;
-
     // can be null only during tests
     protected final IViewContext<?> viewContext;
 
@@ -159,7 +143,6 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
         if (staticCallbackListener != DEFAULT_CALLBACK_LISTENER)
         {
             callbackListener = cast(staticCallbackListener);
-            asyncCallbacks.add(this);
         } else if (callbackListenerOrNull == null)
         {
             callbackListener = cast(staticCallbackListener);
@@ -168,6 +151,9 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
             callbackListener = callbackListenerOrNull;
         }
         assert callbackListener != null : "Unspecified ICallbackListener implementation.";
+
+        // could do this only if staticCallbackListener != DEFAULT_CALLBACK_LISTENER
+        this.callbackListener.registerCallback(this);
     }
 
     @SuppressWarnings("unchecked")
@@ -217,10 +203,6 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
 
     public final void onFailure(final Throwable caught)
     {
-        if (silent)
-        {
-            return;
-        }
         final String msg;
         if (caught instanceof InvocationException)
         {
@@ -290,11 +272,27 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
 
     public final void onSuccess(final T result)
     {
-        if (silent)
-        {
-            return;
-        }
         process(result);
         callbackListener.finishOnSuccessOf(this, result);
     }
+
+    /**
+     * This method should be called if callback will not be processed, to make our system test
+     * framework working properly.
+     */
+    public final void ignore()
+    {
+        // could do this only if staticCallbackListener != DEFAULT_CALLBACK_LISTENER
+        callbackListener.ignoreCallback(this);
+    }
+
+    /**
+     * This method should be called at the beginning of process method if we want to have a reusable
+     * callback that is working properly with our test framework. First ignore should be called in
+     * callback constructor after calling abstract constructor.
+     */
+    protected final void reuse()
+    {
+        callbackListener.registerCallback(this);
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AsyncCallbackCollection.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AsyncCallbackCollection.java
deleted file mode 100644
index da1ab127655..00000000000
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AsyncCallbackCollection.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2008 ETH Zuerich, CISD
- *
- * 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 ch.systemsx.cisd.openbis.generic.client.web.client.application;
-
-import java.util.ArrayList;
-
-/**
- * A collection of {@link AbstractAsyncCallback}.
- * 
- * @author Christian Ribeaud
- */
-final class AsyncCallbackCollection extends ArrayList<AbstractAsyncCallback<?>>
-{
-    private static final long serialVersionUID = 1L;
-
-    final void setSilent()
-    {
-        for (final AbstractAsyncCallback<?> callback : this)
-        {
-            callback.silent = true;
-        }
-    }
-}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/CallbackListenerAdapter.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/CallbackListenerAdapter.java
index db1fe3240eb..516be6e2d10 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/CallbackListenerAdapter.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/CallbackListenerAdapter.java
@@ -46,4 +46,12 @@ public class CallbackListenerAdapter<T> implements ICallbackListener<T>
 
     }
 
+    public void registerCallback(AbstractAsyncCallback<?> callback)
+    {
+    }
+
+    public void ignoreCallback(AbstractAsyncCallback<?> callback)
+    {
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ICallbackListener.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ICallbackListener.java
index 3ed2a123479..45b716f51fe 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ICallbackListener.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ICallbackListener.java
@@ -42,4 +42,8 @@ public interface ICallbackListener<T>
      * object is actually processing the result object.
      */
     public void finishOnSuccessOf(final AbstractAsyncCallback<T> callback, final T result);
+
+    public void registerCallback(AbstractAsyncCallback<?> callback);
+
+    public void ignoreCallback(AbstractAsyncCallback<?> callback);
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/SearchableEntitySelectionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/SearchableEntitySelectionWidget.java
index 0dbcf07eb84..006893b58d4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/SearchableEntitySelectionWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/SearchableEntitySelectionWidget.java
@@ -87,6 +87,7 @@ final class SearchableEntitySelectionWidget extends
     {
         commonContext.getService()
                 .listSearchableEntities(new ListSearchableEntities(commonContext));
+        callback.ignore();
     }
 
     public DatabaseModificationKind[] getRelevantModifications()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/GroupSelectionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/GroupSelectionWidget.java
index 8b0baee3c7f..7ce099cc554 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/GroupSelectionWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/GroupSelectionWidget.java
@@ -176,6 +176,7 @@ public class GroupSelectionWidget extends DropDownList<GroupModel, Group>
     {
         DefaultResultSetConfig<String, Group> config = DefaultResultSetConfig.createFetchAll();
         viewContext.getCommonService().listGroups(config, new ListGroupsCallback(viewContext));
+        callback.ignore();
     }
 
     public DatabaseModificationKind[] getRelevantModifications()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/experiment/ProjectSelectionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/experiment/ProjectSelectionWidget.java
index 6af60829450..43ef99e770e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/experiment/ProjectSelectionWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/experiment/ProjectSelectionWidget.java
@@ -189,6 +189,7 @@ public final class ProjectSelectionWidget extends
     {
         DefaultResultSetConfig<String, Project> config = DefaultResultSetConfig.createFetchAll();
         viewContext.getCommonService().listProjects(config, new ListProjectsCallback(viewContext));
+        callback.ignore();
     }
 
     public void trySelectByIdentifier(String projectIdentifier)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/field/VocabularyTermSelectionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/field/VocabularyTermSelectionWidget.java
index 768eea23ed2..aa19365fee0 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/field/VocabularyTermSelectionWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/field/VocabularyTermSelectionWidget.java
@@ -120,6 +120,7 @@ public class VocabularyTermSelectionWidget extends
             viewContextOrNull.getCommonService().listVocabularyTerms(vocabularyOrNull,
                     new ListTermsCallback(viewContextOrNull));
         }
+        callback.ignore();
     }
 
     public DatabaseModificationKind[] getRelevantModifications()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/DataTypeSelectionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/DataTypeSelectionWidget.java
index 6a5323dd44c..8aef03d0cd1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/DataTypeSelectionWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/DataTypeSelectionWidget.java
@@ -102,6 +102,7 @@ public final class DataTypeSelectionWidget extends DropDownList<DataTypeModel, D
     protected void loadData(AbstractAsyncCallback<List<DataType>> callback)
     {
         viewContext.getService().listDataTypes(new ListDataTypesCallback(viewContext));
+        callback.ignore();
     }
 
     public DatabaseModificationKind[] getRelevantModifications()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/EntityTypePropertyTypeSelectionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/EntityTypePropertyTypeSelectionWidget.java
index c0fa228e305..9d3361edc98 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/EntityTypePropertyTypeSelectionWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/EntityTypePropertyTypeSelectionWidget.java
@@ -151,6 +151,7 @@ public final class EntityTypePropertyTypeSelectionWidget
     protected void loadData(AbstractAsyncCallback<List<EntityTypePropertyType<?>>> callback)
     {
         // nothing to do - list was injected in constructor
+        callback.ignore();
     }
 
     public DatabaseModificationKind[] getRelevantModifications()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeSelectionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeSelectionWidget.java
index fb32f512810..fcd8288a7b3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeSelectionWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property_type/PropertyTypeSelectionWidget.java
@@ -136,6 +136,7 @@ public final class PropertyTypeSelectionWidget extends
                 DefaultResultSetConfig.createFetchAll();
         viewContext.getService().listPropertyTypes(config,
                 new ListPropertyTypesCallback(viewContext));
+        callback.ignore();
     }
 
     public DatabaseModificationKind[] getRelevantModifications()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/search/DetailedSearchFieldsSelectionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/search/DetailedSearchFieldsSelectionWidget.java
index a7f3baea3fa..597d1d06086 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/search/DetailedSearchFieldsSelectionWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/search/DetailedSearchFieldsSelectionWidget.java
@@ -302,6 +302,7 @@ public final class DetailedSearchFieldsSelectionWidget extends
             viewContext.getService().listPropertyTypes(config,
                     new ListPropertyTypesCallback(viewContext));
         }
+        callback.ignore();
     }
 
     public DatabaseModificationKind[] getRelevantModifications()
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AuthenticationTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AuthenticationTest.java
index 3ee6862ddb9..a0f3d1033c5 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AuthenticationTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AuthenticationTest.java
@@ -35,7 +35,7 @@ public class AuthenticationTest extends AbstractGWTTestCase
         remoteConsole.prepare(new Login("test", "a"));
         remoteConsole.prepare(new WaitFor(LoginWidget.LoginCallback.class));
 
-        launchTest(10000);
+        launchTest(30000);
     }
 
     public void testLogout() throws Exception
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractGWTTestCase.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractGWTTestCase.java
index 1882a348e3e..2f7a3d3abc0 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractGWTTestCase.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/AbstractGWTTestCase.java
@@ -25,7 +25,6 @@ import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.Client;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.menu.ActionMenu;
@@ -120,7 +119,6 @@ public abstract class AbstractGWTTestCase extends GWTTestCase
     protected final void gwtTearDown() throws Exception
     {
         remoteConsole.cancelTimer();
-        AbstractAsyncCallback.setAllCallbackObjectsSilent();
         final IViewContext<ICommonClientServiceAsync> viewContext = client.tryToGetViewContext();
         if (viewContext != null)
         {
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/ITestCommand.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/ITestCommand.java
index fda7bbbffc6..5f573e73437 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/ITestCommand.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/ITestCommand.java
@@ -32,7 +32,7 @@ public interface ITestCommand
 {
     /**
      * If the specified callback objects, failureMessage, and throwable should trigger this command
-     * in case if an invocation of {@link AsyncCallback#onFailure(Throwable)} then the result is the
+     * in case of an invocation of {@link AsyncCallback#onFailure(Throwable)} then the result is the
      * list of callbacks which were not expected by the command. Otherwise <code>null</code> is
      * returned.
      * 
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java
index 749e0742317..cd459226b10 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java
@@ -131,6 +131,8 @@ public class RemoteConsole
 
     private final class RemoteConsoleCallbackListener implements ICallbackListener<Object>
     {
+        private int activeCallbacksCounter = 0;
+
         RemoteConsoleCallbackListener()
         {
         }
@@ -154,15 +156,19 @@ public class RemoteConsole
                 final AbstractAsyncCallback<Object> callback, final String failureMessage,
                 final Throwable throwable)
         {
-            registerCallback(callback);
+            detectCallback(callback);
             if (entryIndex < commands.size())
             {
                 ITestCommand cmd = commands.get(entryIndex);
+                // TODO 2009-11-09, Piotr Buczek: just validate failure message
                 List<AbstractAsyncCallback<Object>> unmatchedCallbacks =
                         cmd.tryValidOnFailure(lastCallbackObjects, failureMessage, throwable);
                 if (unmatchedCallbacks != null)
                 {
                     lastCallbackObjects = unmatchedCallbacks;
+                }
+                if (activeCallbacksCounter == 0)
+                {
                     executeCommand();
                     return;
                 }
@@ -174,30 +180,45 @@ public class RemoteConsole
         public final void finishOnSuccessOf(final AbstractAsyncCallback<Object> callback,
                 final Object result)
         {
-            registerCallback(callback);
+            detectCallback(callback);
             if (entryIndex < commands.size())
             {
                 ITestCommand cmd = commands.get(entryIndex);
+                // TODO 2009-11-09, Piotr Buczek: remove tryValidOnSuccess from command interface
                 List<AbstractAsyncCallback<Object>> unmatchedCallbacks =
                         cmd.tryValidOnSucess(lastCallbackObjects, result);
                 if (unmatchedCallbacks != null)
                 {
-                    // uncomment to debug unmatched callbacks in system tests
-                    // System.err.println("callback: " + entryIndex);
-                    // for (AbstractAsyncCallback<?> c : unmatchedCallbacks)
-                    // {
-                    // System.err.println("\t" + c);
-                    // }
                     lastCallbackObjects = unmatchedCallbacks;
+                }
+                if (activeCallbacksCounter == 0)
+                {
                     executeCommand();
+                    return;
                 }
             }
         }
 
-        private void registerCallback(final AbstractAsyncCallback<Object> callback)
+        public void registerCallback(final AbstractAsyncCallback<?> callback)
         {
-            System.out.println("Detected callback '" + callback.getCallbackId() + "'");
-            lastCallbackObjects.add(callback);
+            activeCallbacksCounter++;
+            System.out.println("Registered callback '" + callback.getCallbackId()
+                    + "' (active count: " + activeCallbacksCounter + ")");
         }
+
+        private void detectCallback(final AbstractAsyncCallback<Object> callback)
+        {
+            activeCallbacksCounter--;
+            System.out.println("Detected callback '" + callback.getCallbackId()
+                    + "' (active count: " + activeCallbacksCounter + ")");
+        }
+
+        public void ignoreCallback(final AbstractAsyncCallback<?> callback)
+        {
+            activeCallbacksCounter--;
+            System.out.println("Ignored callback '" + callback.getCallbackId()
+                    + "' (active count: " + activeCallbacksCounter + ")");
+        }
+
     }
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentAttachmentDownloadTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentAttachmentDownloadTest.java
index c4564f54b26..d404ffa6cc4 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentAttachmentDownloadTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/experiment/GenericExperimentAttachmentDownloadTest.java
@@ -89,11 +89,13 @@ public class GenericExperimentAttachmentDownloadTest extends AbstractGWTTestCase
         public OpenedUrlCallback(IViewContext<?> viewContext)
         {
             super(viewContext);
+            ignore();
         }
 
         @Override
         protected void process(String url)
         {
+            reuse();
             this.openedUrl = url;
         }
 
-- 
GitLab