IDEA-122962 - Clouds: perform connection test in background - auto-reload in frameworks

This commit is contained in:
Michael Golubev
2014-05-30 15:35:07 +02:00
parent 1a7ab390ce
commit ab7b2a0ecf
5 changed files with 250 additions and 68 deletions
@@ -1,6 +1,5 @@
package com.intellij.remoteServer.impl.configuration;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.UnnamedConfigurable;
@@ -14,8 +13,9 @@ import com.intellij.remoteServer.runtime.ServerConnection;
import com.intellij.remoteServer.runtime.ServerConnectionManager;
import com.intellij.remoteServer.runtime.ServerConnector;
import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance;
import com.intellij.remoteServer.util.CloudDataLoader;
import com.intellij.remoteServer.util.DelayedRunner;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.Alarm;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.xmlb.XmlSerializerUtil;
@@ -36,9 +36,6 @@ public class RemoteServerConfigurable extends NamedConfigurable<RemoteServer<?>>
private static final String HELP_TOPIC_ID = "reference.settings.clouds";
private static final int CHANGES_CHECK_TIME = 500;
private static final int CONNECTION_CHECK_TIME = 2000;
private static final int NO_CHANGES = -1;
private final UnnamedConfigurable myConfigurable;
private final RemoteServer<?> myServer;
@@ -48,14 +45,17 @@ public class RemoteServerConfigurable extends NamedConfigurable<RemoteServer<?>>
private JPanel mySettingsPanel;
private JBLabel myConnectionStatusLabel;
private final Alarm myAlarm;
private int myChangesPastTime = NO_CHANGES;
private final DelayedRunner myRunner;
private ConnectionTester myConnectionTester;
private final RemoteServer<?> myInnerServer;
private boolean myInnerApplied;
private boolean myUncheckedApply;
private boolean myConnected;
private CloudDataLoader myDataLoader = CloudDataLoader.NULL;
public <C extends ServerConfiguration> RemoteServerConfigurable(RemoteServer<C> server, Runnable treeUpdater, boolean isNew) {
super(true, treeUpdater);
myServer = server;
@@ -69,64 +69,69 @@ public class RemoteServerConfigurable extends NamedConfigurable<RemoteServer<?>>
myConfigurable = server.getType().createConfigurable(innerConfiguration);
myAlarm = new Alarm().setActivationComponent(myMainPanel);
queueChangesCheck();
}
private void queueChangesCheck() {
if (myAlarm.isDisposed()) {
return;
}
myAlarm.addRequest(new Runnable() {
myConnected = false;
myRunner = new DelayedRunner(myMainPanel) {
@Override
public void run() {
checkChanges();
queueChangesCheck();
protected boolean wasChanged() {
boolean modified = myConfigurable.isModified();
boolean result = modified || myUncheckedApply;
if (result) {
myUncheckedApply = false;
setConnectionStatus("");
myConnectionTester = null;
if (modified) {
try {
myConfigurable.apply();
myInnerApplied = true;
}
catch (ConfigurationException e) {
setConnectionStatus(e.getMessage());
}
}
}
return result;
}
}, CHANGES_CHECK_TIME, ModalityState.any());
@Override
protected void run() {
setConnectionStatus("Connecting...");
myConnectionTester = new ConnectionTester();
myConnectionTester.testConnection();
}
};
}
private void checkChanges() {
boolean modified = myConfigurable.isModified();
if (modified || myUncheckedApply) {
myUncheckedApply = false;
private void setConnectionStatus(String text) {
setConnectionStatus(false, text);
}
setConnectionStatusText("");
myConnectionTester = null;
private void setConnectionStatus(boolean connected, String text) {
boolean changed = myConnected != connected;
myConnected = connected;
myConnectionStatusLabel.setText(UIUtil.toHtml(text));
if (changed) {
notifyDataLoader();
}
}
if (modified) {
try {
myConfigurable.apply();
myInnerApplied = true;
}
catch (ConfigurationException e) {
LOG.debug(e);
return;
}
}
public void setDataLoader(CloudDataLoader dataLoader) {
myDataLoader = dataLoader;
notifyDataLoader();
}
myChangesPastTime = 0;
private void notifyDataLoader() {
if (myConnected) {
myDataLoader.loadCloudData();
}
else {
if (myChangesPastTime != NO_CHANGES) {
myChangesPastTime += CHANGES_CHECK_TIME;
if (myChangesPastTime >= CONNECTION_CHECK_TIME) {
myChangesPastTime = NO_CHANGES;
setConnectionStatusText("Connecting...");
myConnectionTester = new ConnectionTester();
myConnectionTester.testConnection();
}
}
myDataLoader.clearCloudData();
}
}
private void setConnectionStatusText(String text) {
myConnectionStatusLabel.setText(UIUtil.toHtml(text));
}
@Override
public RemoteServer<?> getEditableObject() {
return myServer;
@@ -183,7 +188,7 @@ public class RemoteServerConfigurable extends NamedConfigurable<RemoteServer<?>>
@Override
public void disposeUIResources() {
myConfigurable.disposeUIResources();
Disposer.dispose(myAlarm);
Disposer.dispose(myRunner);
}
@Nullable
@@ -232,17 +237,13 @@ public class RemoteServerConfigurable extends NamedConfigurable<RemoteServer<?>>
@Override
public void run() {
showConnectionStatus(connected, connection.getStatusText());
if (myConnectionTester == ConnectionTester.this) {
setConnectionStatus(connected, connected ? "Connection successful" : "Cannot connect: " + connection.getStatusText());
}
}
});
}
}.queue();
}
private void showConnectionStatus(boolean connected, String statusText) {
if (myConnectionTester == this) {
setConnectionStatusText(connected ? "Connection successful" : "Cannot connect: " + statusText);
}
}
}
}
@@ -26,6 +26,7 @@ import com.intellij.openapi.module.ModulePointerManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.remoteServer.ServerType;
import com.intellij.remoteServer.configuration.RemoteServer;
import com.intellij.remoteServer.configuration.RemoteServersManager;
@@ -57,12 +58,18 @@ public class CloudAccountSelectionEditor<SC extends CloudConfigurationBase,
private RemoteServer<SC> myNewServer;
private RemoteServerConfigurable myServerConfigurable;
private DelayedRunner myRunner;
private CloudDataLoader myDataLoader = CloudDataLoader.NULL;
public CloudAccountSelectionEditor(ST cloudType) {
myCloudType = cloudType;
}
private void createUIComponents() {
myServerConfigurablePanel = createServerConfigurablePanel();
myServerConfigurablePanel.setVisible(false);
}
public void initUI() {
@@ -78,6 +85,51 @@ public class CloudAccountSelectionEditor<SC extends CloudConfigurationBase,
myServerComboBox.addItem(new ServerItem(server));
}
myServerComboBox.addItem(new ServerItem(myNewServer));
myRunner= new DelayedRunner(myMainPanel) {
private ServerItem myPreviousServerItem;
@Override
protected boolean wasChanged() {
ServerItem currentServerItem = getSelectedServerItem();
boolean result = myPreviousServerItem != currentServerItem;
if (result) {
myPreviousServerItem = currentServerItem;
myDataLoader.clearCloudData();
}
return result;
}
@Override
protected void run() {
if (getSelectedServerItem().isNew()) {
myServerConfigurable.setDataLoader(new CloudDataLoader() {
@Override
public void clearCloudData() {
if (getSelectedServerItem().isNew()) {
myDataLoader.clearCloudData();
}
}
@Override
public void loadCloudData() {
if (getSelectedServerItem().isNew()) {
myDataLoader.loadCloudData();
}
}
});
}
else {
myDataLoader.loadCloudData();
}
}
};
}
public void setDataLoader(CloudDataLoader dataLoader) {
myDataLoader = dataLoader;
}
private void onAccountSelectionChanged() {
@@ -197,6 +249,7 @@ public class CloudAccountSelectionEditor<SC extends CloudConfigurationBase,
@Override
public void dispose() {
myServerConfigurable.disposeUIResources();
Disposer.dispose(myRunner);
}
private class ServerItem {
@@ -0,0 +1,36 @@
/*
* Copyright 2000-2014 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.remoteServer.util;
public interface CloudDataLoader {
void clearCloudData();
void loadCloudData();
CloudDataLoader NULL = new CloudDataLoader() {
@Override
public void clearCloudData() {
}
@Override
public void loadCloudData() {
}
};
}
@@ -18,6 +18,7 @@ import com.intellij.remoteServer.runtime.ServerConnector;
import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -32,7 +33,7 @@ public abstract class CloudSupportConfigurableBase<
DC extends CloudDeploymentNameConfiguration,
SR extends CloudMultiSourceServerRuntimeInstance<DC, ?, ?, ?>,
ST extends ServerType<SC>>
extends FrameworkSupportConfigurable {
extends FrameworkSupportConfigurable implements CloudDataLoader {
private final ST myCloudType;
private final Project myModelProject;
@@ -58,8 +59,14 @@ public abstract class CloudSupportConfigurableBase<
getAccountSelectionEditor().initUI();
}
protected void reloadExistingApplications() {
Collection<Deployment> deployments = new ConnectionTask<Collection<Deployment>>("Loading existing applications list") {
@Override
public void clearCloudData() {
getExistingComboBox().removeAllItems();
}
@Override
public void loadCloudData() {
new ConnectionTask<Collection<Deployment>>("Loading existing applications list") {
@Override
protected void run(final ServerConnection<DC> connection,
@@ -75,6 +82,14 @@ public abstract class CloudSupportConfigurableBase<
public void run() {
result.set(connection.getDeployments());
semaphore.up();
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
if (!Disposer.isDisposed(CloudSupportConfigurableBase.this)) {
setupExistingApplications(result.get());
}
}
});
}
});
}
@@ -91,12 +106,10 @@ public abstract class CloudSupportConfigurableBase<
protected Collection<Deployment> run(SR serverRuntimeInstance) throws ServerRuntimeException {
return null;
}
}.performSync();
if (deployments == null) {
return;
}
}.performAsync();
}
private void setupExistingApplications(Collection<Deployment> deployments) {
JComboBox existingComboBox = getExistingComboBox();
existingComboBox.removeAllItems();
for (Deployment deployment : deployments) {
@@ -151,6 +164,7 @@ public abstract class CloudSupportConfigurableBase<
getNotifier().showMessage(e.getMessage(), MessageType.ERROR);
}
};
myAccountSelectionEditor.setDataLoader(this);
}
return myAccountSelectionEditor;
}
@@ -0,0 +1,78 @@
/*
* Copyright 2000-2014 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.remoteServer.util;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.Alarm;
import javax.swing.*;
public abstract class DelayedRunner implements Disposable {
private static final int CHANGES_CHECK_TIME = 500;
private static final int RUN_DELAY_TIME = 2000;
private static final int NO_CHANGES = -1;
private final Alarm myAlarm;
private int myChangesPastTime = NO_CHANGES;
public DelayedRunner(JComponent activationComponent) {
myAlarm = new Alarm().setActivationComponent(activationComponent);
queueChangesCheck();
}
private void queueChangesCheck() {
if (myAlarm.isDisposed()) {
return;
}
myAlarm.addRequest(new Runnable() {
@Override
public void run() {
checkChanges();
queueChangesCheck();
}
}, CHANGES_CHECK_TIME, ModalityState.any());
}
private void checkChanges() {
if (wasChanged()) {
myChangesPastTime = 0;
}
else {
if (myChangesPastTime != NO_CHANGES) {
myChangesPastTime += CHANGES_CHECK_TIME;
if (myChangesPastTime >= RUN_DELAY_TIME) {
myChangesPastTime = NO_CHANGES;
run();
}
}
}
}
@Override
public void dispose() {
Disposer.dispose(myAlarm);
}
protected abstract boolean wasChanged();
protected abstract void run();
}