diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ConnectionStatus.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ConnectionStatus.java index eedc054413d8..60265e802850 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ConnectionStatus.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ConnectionStatus.java @@ -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()); + } } diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java new file mode 100644 index 000000000000..fe0f09a866fb --- /dev/null +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/Deployment.java @@ -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(); +} diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnection.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnection.java index a73037bc80fb..f78921e2272d 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnection.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/ServerConnection.java @@ -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 { void deploy(@NotNull DeploymentTask task); - void undeploy(@NotNull DeploymentTask task); + void computeDeployments(@NotNull Runnable onFinished); @NotNull - DeploymentStatus getDeploymentStatus(@NotNull DeploymentSource source); + Collection getDeployments(); } diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentRuntime.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentRuntime.java new file mode 100644 index 000000000000..6bae6c8739c6 --- /dev/null +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentRuntime.java @@ -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(); + } +} diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentStatus.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentStatus.java index 48908c4cc4e3..a9f7c285ebdb 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentStatus.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/DeploymentStatus.java @@ -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; + } } diff --git a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java index 2d0e08e7de18..05c4bdcdb2d0 100644 --- a/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java +++ b/platform/remote-servers/api/src/com/intellij/remoteServer/runtime/deployment/ServerRuntimeInstance.java @@ -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 { public abstract void deploy(@NotNull DeploymentTask task, @NotNull DeploymentOperationCallback callback); - public abstract void undeploy(@NotNull DeploymentTask 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 deployments); } } diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/deployment/DeployToServerSettingsEditor.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/deployment/DeployToServerSettingsEditor.java index dc4578310663..f6ef4ddaf6d2 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/deployment/DeployToServerSettingsEditor.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/configuration/deployment/DeployToServerSettingsEditor.java @@ -158,7 +158,6 @@ public class DeployToServerSettingsEditor connection) { + myEventsQueue.activate(); + myEventsQueue.queue(new Update(connection) { + @Override + public void run() { + myMessageBus.syncPublisher(ServerConnectionListener.TOPIC).onDeploymentsChanged(connection); + } + }); + } } diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java index af6f408bb744..d93d0c1607fd 100644 --- a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/ServerConnectionImpl.java @@ -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 implements private volatile ConnectionStatus myStatus = ConnectionStatus.DISCONNECTED; private volatile String myStatusText; private volatile ServerRuntimeInstance myRuntimeInstance; - private final ConcurrentHashMap myDeploymentInfos = new ConcurrentHashMap(); + private final Map myRemoteDeployments = new HashMap(); + private final Map myLocalDeployments = Collections.synchronizedMap(new HashMap()); public ServerConnectionImpl(RemoteServer server, ServerConnector connector, ServerConnectionEventDispatcher eventDispatcher) { myServer = server; @@ -47,7 +50,7 @@ public class ServerConnectionImpl implements @NotNull @Override public String getStatusText() { - return myStatusText; + return myStatusText != null ? myStatusText : myStatus.getPresentableText(); } @Override @@ -79,30 +82,59 @@ public class ServerConnectionImpl implements connectIfNeeded(new ConnectionCallbackBase() { @Override public void connected(@NotNull ServerRuntimeInstance 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 task) { + public void computeDeployments(@NotNull final Runnable onFinished) { connectIfNeeded(new ConnectionCallbackBase() { @Override public void connected(@NotNull ServerRuntimeInstance 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 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 getDeployments() { + Map result; + synchronized (myRemoteDeployments) { + result = new HashMap(myRemoteDeployments); + } + synchronized (myLocalDeployments) { + for (Deployment deployment : myLocalDeployments.values()) { + result.put(deployment.getName(), deployment); + } + } + return result.values(); } private void connectIfNeeded(final ServerConnector.ConnectionCallback callback) { @@ -142,25 +174,25 @@ public class ServerConnectionImpl 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); } } } diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java new file mode 100644 index 000000000000..9d4154560f66 --- /dev/null +++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/DeploymentImpl.java @@ -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; + } +} diff --git a/plugins/google-app-engine/source/com/intellij/appengine/actions/AppEngineUploader.java b/plugins/google-app-engine/source/com/intellij/appengine/actions/AppEngineUploader.java index 2e7dae2262ea..5e2d5ead054d 100644 --- a/plugins/google-app-engine/source/com/intellij/appengine/actions/AppEngineUploader.java +++ b/plugins/google-app-engine/source/com/intellij/appengine/actions/AppEngineUploader.java @@ -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()); + } + } } } diff --git a/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java b/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java index 15fb4051d1db..fe7f71dbb51b 100644 --- a/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java +++ b/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java @@ -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(); } diff --git a/plugins/google-app-engine/source/com/intellij/appengine/cloud/AppEngineCloudType.java b/plugins/google-app-engine/source/com/intellij/appengine/cloud/AppEngineCloudType.java index a7b798c6df2e..b69b47a034fe 100644 --- a/plugins/google-app-engine/source/com/intellij/appengine/cloud/AppEngineCloudType.java +++ b/plugins/google-app-engine/source/com/intellij/appengine/cloud/AppEngineCloudType.java @@ -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 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 task, - @NotNull DeploymentOperationCallback callback) { + public void computeDeployments(@NotNull ComputeDeploymentsCallback deployments) { + deployments.succeeded(ContainerUtil.emptyList()); } } }