remote servers: show deployments in 'Application Servers' view

This commit is contained in:
nik
2013-08-09 11:00:29 +04:00
parent 8ae15b747c
commit 0f2785424a
13 changed files with 229 additions and 48 deletions
@@ -1,8 +1,14 @@
package com.intellij.remoteServer.runtime;
import com.intellij.openapi.util.text.StringUtil;
/**
* @author nik
*/
public enum ConnectionStatus {
DISCONNECTED, CONNECTED, CONNECTING, DISCONNECTING
DISCONNECTED, CONNECTED, CONNECTING, DISCONNECTING;
public String getPresentableText() {
return StringUtil.capitalize(name().toLowerCase());
}
}
@@ -0,0 +1,23 @@
package com.intellij.remoteServer.runtime;
import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime;
import com.intellij.remoteServer.runtime.deployment.DeploymentStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author nik
*/
public interface Deployment {
@NotNull
String getName();
@NotNull
DeploymentStatus getStatus();
@NotNull
String getStatusText();
@Nullable
DeploymentRuntime getRuntime();
}
@@ -2,11 +2,11 @@ package com.intellij.remoteServer.runtime;
import com.intellij.remoteServer.configuration.RemoteServer;
import com.intellij.remoteServer.configuration.deployment.DeploymentConfiguration;
import com.intellij.remoteServer.configuration.deployment.DeploymentSource;
import com.intellij.remoteServer.runtime.deployment.DeploymentStatus;
import com.intellij.remoteServer.runtime.deployment.DeploymentTask;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* @author nik
*/
@@ -26,8 +26,8 @@ public interface ServerConnection<D extends DeploymentConfiguration> {
void deploy(@NotNull DeploymentTask<D> task);
void undeploy(@NotNull DeploymentTask<D> task);
void computeDeployments(@NotNull Runnable onFinished);
@NotNull
DeploymentStatus getDeploymentStatus(@NotNull DeploymentSource source);
Collection<Deployment> getDeployments();
}
@@ -0,0 +1,20 @@
package com.intellij.remoteServer.runtime.deployment;
import com.intellij.remoteServer.runtime.RemoteOperationCallback;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public class DeploymentRuntime {
public boolean isUndeploySupported() {
return false;
}
public void undeploy(@NotNull UndeploymentTaskCallback callback) {
}
public interface UndeploymentTaskCallback extends RemoteOperationCallback {
void succeeded();
}
}
@@ -1,8 +1,19 @@
package com.intellij.remoteServer.runtime.deployment;
import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
public enum DeploymentStatus {
DEPLOYED, NOT_DEPLOYED, DEPLOYING, UNDEPLOYING
DEPLOYED("Deployed"), NOT_DEPLOYED("Not deployed"), DEPLOYING("Deploying"), UNDEPLOYING("Undeploying");
private String myPresentableText;
DeploymentStatus(@NotNull String presentableText) {
myPresentableText = presentableText;
}
public String getPresentableText() {
return myPresentableText;
}
}
@@ -1,9 +1,13 @@
package com.intellij.remoteServer.runtime.deployment;
import com.intellij.remoteServer.configuration.deployment.DeploymentConfiguration;
import com.intellij.remoteServer.configuration.deployment.DeploymentSource;
import com.intellij.remoteServer.runtime.Deployment;
import com.intellij.remoteServer.runtime.RemoteOperationCallback;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author nik
*/
@@ -11,9 +15,18 @@ public abstract class ServerRuntimeInstance<D extends DeploymentConfiguration> {
public abstract void deploy(@NotNull DeploymentTask<D> task, @NotNull DeploymentOperationCallback callback);
public abstract void undeploy(@NotNull DeploymentTask<D> task, @NotNull DeploymentOperationCallback callback);
public abstract void computeDeployments(@NotNull ComputeDeploymentsCallback deployments);
@NotNull
public String getDeploymentName(@NotNull DeploymentSource source) {
return source.getPresentableName();
}
public interface DeploymentOperationCallback extends RemoteOperationCallback {
void succeeded();
void succeeded(@NotNull DeploymentRuntime deployment);
}
public interface ComputeDeploymentsCallback extends RemoteOperationCallback {
void succeeded(@NotNull List<Deployment> deployments);
}
}
@@ -158,7 +158,6 @@ public class DeployToServerSettingsEditor<S extends ServerConfiguration, D exten
return FormBuilder.createFormBuilder()
.addLabeledComponent("Server:", myServerComboBox)
.addLabeledComponent("Deployment:", mySourceComboBox)
.addSeparator()
.addComponent(myDeploymentSettingsComponent)
.getPanel();
}
@@ -47,4 +47,14 @@ public class ServerConnectionEventDispatcher {
}
});
}
public void queueDeploymentsChanged(final ServerConnectionImpl<?> connection) {
myEventsQueue.activate();
myEventsQueue.queue(new Update(connection) {
@Override
public void run() {
myMessageBus.syncPublisher(ServerConnectionListener.TOPIC).onDeploymentsChanged(connection);
}
});
}
}
@@ -3,16 +3,18 @@ package com.intellij.remoteServer.impl.runtime;
import com.intellij.remoteServer.configuration.RemoteServer;
import com.intellij.remoteServer.configuration.deployment.DeploymentConfiguration;
import com.intellij.remoteServer.configuration.deployment.DeploymentSource;
import com.intellij.remoteServer.impl.runtime.deployment.DeploymentInformation;
import com.intellij.remoteServer.impl.runtime.deployment.DeploymentImpl;
import com.intellij.remoteServer.runtime.ConnectionStatus;
import com.intellij.remoteServer.runtime.Deployment;
import com.intellij.remoteServer.runtime.ServerConnection;
import com.intellij.remoteServer.runtime.ServerConnector;
import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime;
import com.intellij.remoteServer.runtime.deployment.DeploymentStatus;
import com.intellij.remoteServer.runtime.deployment.DeploymentTask;
import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ConcurrentHashMap;
import java.util.*;
/**
* @author nik
@@ -24,7 +26,8 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements
private volatile ConnectionStatus myStatus = ConnectionStatus.DISCONNECTED;
private volatile String myStatusText;
private volatile ServerRuntimeInstance<D> myRuntimeInstance;
private final ConcurrentHashMap<DeploymentSource, DeploymentInformation> myDeploymentInfos = new ConcurrentHashMap<DeploymentSource, DeploymentInformation>();
private final Map<String, Deployment> myRemoteDeployments = new HashMap<String, Deployment>();
private final Map<DeploymentSource, Deployment> myLocalDeployments = Collections.synchronizedMap(new HashMap<DeploymentSource, Deployment>());
public ServerConnectionImpl(RemoteServer<?> server, ServerConnector<D> connector, ServerConnectionEventDispatcher eventDispatcher) {
myServer = server;
@@ -47,7 +50,7 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements
@NotNull
@Override
public String getStatusText() {
return myStatusText;
return myStatusText != null ? myStatusText : myStatus.getPresentableText();
}
@Override
@@ -79,30 +82,59 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements
connectIfNeeded(new ConnectionCallbackBase<D>() {
@Override
public void connected(@NotNull ServerRuntimeInstance<D> instance) {
myDeploymentInfos.put(task.getSource(), new DeploymentInformation(DeploymentStatus.DEPLOYING));
instance.deploy(task, new UpdateDeploymentStatusCallback(task.getSource(), DeploymentStatus.DEPLOYED,
DeploymentStatus.NOT_DEPLOYED));
DeploymentSource source = task.getSource();
String deploymentName = instance.getDeploymentName(source);
myLocalDeployments.put(source, new DeploymentImpl(deploymentName, DeploymentStatus.DEPLOYING, null, null));
instance.deploy(task, new DeploymentOperationCallbackImpl(task.getSource(), deploymentName));
}
});
}
@Override
public void undeploy(@NotNull final DeploymentTask<D> task) {
public void computeDeployments(@NotNull final Runnable onFinished) {
connectIfNeeded(new ConnectionCallbackBase<D>() {
@Override
public void connected(@NotNull ServerRuntimeInstance<D> instance) {
myDeploymentInfos.put(task.getSource(), new DeploymentInformation(DeploymentStatus.UNDEPLOYING));
instance.undeploy(task, new UpdateDeploymentStatusCallback(task.getSource(), DeploymentStatus.NOT_DEPLOYED,
DeploymentStatus.DEPLOYED));
instance.computeDeployments(new ServerRuntimeInstance.ComputeDeploymentsCallback() {
@Override
public void succeeded(@NotNull List<Deployment> deployments) {
synchronized (myRemoteDeployments) {
myRemoteDeployments.clear();
for (Deployment deployment : deployments) {
myRemoteDeployments.put(deployment.getName(), deployment);
}
}
myEventDispatcher.queueDeploymentsChanged(ServerConnectionImpl.this);
onFinished.run();
}
@Override
public void errorOccurred(@NotNull String errorMessage) {
synchronized (myRemoteDeployments) {
myRemoteDeployments.clear();
}
myStatusText = "Cannot obtain deployments: " + errorMessage;
myEventDispatcher.queueDeploymentsChanged(ServerConnectionImpl.this);
onFinished.run();
}
});
}
});
}
@NotNull
@Override
public DeploymentStatus getDeploymentStatus(@NotNull DeploymentSource source) {
DeploymentInformation information = myDeploymentInfos.get(source);
return information != null ? information.getStatus() : DeploymentStatus.NOT_DEPLOYED;
public Collection<Deployment> getDeployments() {
Map<String, Deployment> result;
synchronized (myRemoteDeployments) {
result = new HashMap<String, Deployment>(myRemoteDeployments);
}
synchronized (myLocalDeployments) {
for (Deployment deployment : myLocalDeployments.values()) {
result.put(deployment.getName(), deployment);
}
}
return result.values();
}
private void connectIfNeeded(final ServerConnector.ConnectionCallback<D> callback) {
@@ -142,25 +174,25 @@ public class ServerConnectionImpl<D extends DeploymentConfiguration> implements
}
}
private class UpdateDeploymentStatusCallback implements ServerRuntimeInstance.DeploymentOperationCallback {
private class DeploymentOperationCallbackImpl implements ServerRuntimeInstance.DeploymentOperationCallback {
private final DeploymentSource mySource;
private DeploymentStatus mySuccessStatus;
private DeploymentStatus myFailedStatus;
private final String myDeploymentName;
public UpdateDeploymentStatusCallback(DeploymentSource source, final DeploymentStatus successStatus, final DeploymentStatus failedStatus) {
public DeploymentOperationCallbackImpl(DeploymentSource source, String deploymentName) {
mySource = source;
mySuccessStatus = successStatus;
myFailedStatus = failedStatus;
myDeploymentName = deploymentName;
}
@Override
public void succeeded() {
myDeploymentInfos.put(mySource, new DeploymentInformation(mySuccessStatus));
public void succeeded(@NotNull DeploymentRuntime deployment) {
myLocalDeployments.put(mySource, new DeploymentImpl(myDeploymentName, DeploymentStatus.DEPLOYED, null, deployment));
myEventDispatcher.queueDeploymentsChanged(ServerConnectionImpl.this);
}
@Override
public void errorOccurred(@NotNull String errorMessage) {
myDeploymentInfos.put(mySource, new DeploymentInformation(myFailedStatus, errorMessage));
myLocalDeployments.put(mySource, new DeploymentImpl(myDeploymentName, DeploymentStatus.NOT_DEPLOYED, errorMessage, null));
myEventDispatcher.queueDeploymentsChanged(ServerConnectionImpl.this);
}
}
}
@@ -0,0 +1,44 @@
package com.intellij.remoteServer.impl.runtime.deployment;
import com.intellij.remoteServer.runtime.Deployment;
import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime;
import com.intellij.remoteServer.runtime.deployment.DeploymentStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author nik
*/
public class DeploymentImpl implements Deployment {
private final String myName;
private final DeploymentStatus myStatus;
private final String myStatusText;
private final DeploymentRuntime myRuntime;
public DeploymentImpl(@NotNull String name, @NotNull DeploymentStatus status, @Nullable String statusText, @Nullable DeploymentRuntime runtime) {
myName = name;
myStatus = status;
myStatusText = statusText;
myRuntime = runtime;
}
@NotNull
public String getName() {
return myName;
}
@Override
@NotNull
public DeploymentStatus getStatus() {
return myStatus;
}
@NotNull
public String getStatusText() {
return myStatusText != null ? myStatusText : myStatus.getPresentableText();
}
public DeploymentRuntime getRuntime() {
return myRuntime;
}
}
@@ -69,6 +69,8 @@ import com.intellij.packaging.impl.artifacts.ArtifactUtil;
import com.intellij.packaging.impl.compiler.ArtifactCompileScope;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime;
import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance;
import com.intellij.util.net.HttpConfigurable;
import com.intellij.util.xml.GenericDomValue;
import org.jetbrains.annotations.NotNull;
@@ -90,40 +92,39 @@ public class AppEngineUploader {
private final AppEngineSdk mySdk;
private final String myEmail;
private final String myPassword;
private final ServerRuntimeInstance.DeploymentOperationCallback myCallback;
private AppEngineUploader(Project project,
Artifact artifact,
AppEngineFacet appEngineFacet,
AppEngineSdk sdk,
String email,
String password) {
private AppEngineUploader(Project project, Artifact artifact, AppEngineFacet appEngineFacet, AppEngineSdk sdk, String email,
String password, ServerRuntimeInstance.DeploymentOperationCallback callback) {
myProject = project;
myArtifact = artifact;
myAppEngineFacet = appEngineFacet;
mySdk = sdk;
myEmail = email;
myPassword = password;
myCallback = callback;
}
@Nullable
public static AppEngineUploader createUploader(@NotNull Project project,
@NotNull Artifact artifact,
@Nullable AppEngineServerConfiguration configuration) {
@Nullable AppEngineServerConfiguration configuration,
ServerRuntimeInstance.DeploymentOperationCallback callback) {
final String explodedPath = artifact.getOutputPath();
if (explodedPath == null) {
Messages.showErrorDialog(project, "Output path isn't specified for '" + artifact.getName() + "' artifact", CommonBundle.getErrorTitle());
callback.errorOccurred("Output path isn't specified for '" + artifact.getName() + "' artifact");
return null;
}
final AppEngineFacet appEngineFacet = AppEngineUtil.findAppEngineFacet(project, artifact);
if (appEngineFacet == null) {
Messages.showErrorDialog(project, "App Engine facet not found in '" + artifact.getName() + "' artifact", CommonBundle.getErrorTitle());
callback.errorOccurred("App Engine facet not found in '" + artifact.getName() + "' artifact");
return null;
}
final AppEngineSdk sdk = appEngineFacet.getSdk();
if (!sdk.getAppCfgFile().exists()) {
Messages.showErrorDialog(project, "Path to App Engine SDK isn't specified correctly in App Engine Facet settings", CommonBundle.getErrorTitle());
callback.errorOccurred("Path to App Engine SDK isn't specified correctly in App Engine Facet settings");
return null;
}
@@ -169,7 +170,7 @@ public class AppEngineUploader {
password = dialog.getPassword();
}
return new AppEngineUploader(project, artifact, appEngineFacet, sdk, email, password);
return new AppEngineUploader(project, artifact, appEngineFacet, sdk, email, password, callback);
}
public void startUploading() {
@@ -235,7 +236,7 @@ public class AppEngineUploader {
process = commandLine.createProcess();
}
catch (ExecutionException e) {
Messages.showErrorDialog(myProject, "Cannot start uploading: " + e.getMessage(), CommonBundle.getErrorTitle());
myCallback.errorOccurred("Cannot start uploading: " + e.getMessage());
return;
}
@@ -281,5 +282,12 @@ public class AppEngineUploader {
}
}
}
@Override
public void processTerminated(ProcessEvent event) {
if (event.getExitCode() == 0) {
myCallback.succeeded(new DeploymentRuntime());
}
}
}
}
@@ -24,6 +24,9 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.remoteServer.runtime.deployment.DeploymentRuntime;
import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -57,7 +60,17 @@ public class UploadApplicationAction extends AnAction {
return;
}
}
final AppEngineUploader uploader = AppEngineUploader.createUploader(project, artifact, null);
final AppEngineUploader uploader = AppEngineUploader.createUploader(project, artifact, null, new ServerRuntimeInstance.DeploymentOperationCallback() {
@Override
public void succeeded(@NotNull DeploymentRuntime deployment) {
}
@Override
public void errorOccurred(@NotNull String errorMessage) {
Messages.showErrorDialog(project, errorMessage, CommonBundle.getErrorTitle());
}
});
if (uploader != null) {
uploader.startUploading();
}
@@ -25,10 +25,12 @@ import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.artifacts.ArtifactPointerManager;
import com.intellij.remoteServer.ServerType;
import com.intellij.remoteServer.configuration.deployment.*;
import com.intellij.remoteServer.runtime.Deployment;
import com.intellij.remoteServer.runtime.ServerConnector;
import com.intellij.remoteServer.runtime.ServerTaskExecutor;
import com.intellij.remoteServer.runtime.deployment.DeploymentTask;
import com.intellij.remoteServer.runtime.deployment.ServerRuntimeInstance;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.FormBuilder;
import icons.GoogleAppEngineIcons;
import org.jetbrains.annotations.NotNull;
@@ -181,15 +183,15 @@ public class AppEngineCloudType extends ServerType<AppEngineServerConfiguration>
Artifact artifact = ((ArtifactDeploymentSource)task.getSource()).getArtifact();
if (artifact == null) return;
AppEngineUploader uploader = AppEngineUploader.createUploader(task.getProject(), artifact, myConfiguration);
AppEngineUploader uploader = AppEngineUploader.createUploader(task.getProject(), artifact, myConfiguration, callback);
if (uploader != null) {
uploader.startUploading();
}
}
@Override
public void undeploy(@NotNull DeploymentTask<DummyDeploymentConfiguration> task,
@NotNull DeploymentOperationCallback callback) {
public void computeDeployments(@NotNull ComputeDeploymentsCallback deployments) {
deployments.succeeded(ContainerUtil.<Deployment>emptyList());
}
}
}