/*******************************************************************************
* Copyright (c) 2015, 2016 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.cloudfoundry.ops;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.AssertionFailedException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.CloudFoundryBootDashModel;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.CloudFoundryRunTarget;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.CloudFoundryTargetProperties;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.MissingPasswordException;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFClientParams;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFCredentials;
import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFExceptions;
import org.springframework.ide.eclipse.boot.dash.dialogs.PasswordDialogModel;
import org.springframework.ide.eclipse.boot.dash.dialogs.StoreCredentialsMode;
import org.springframework.ide.eclipse.boot.dash.model.RefreshState;
import org.springframework.ide.eclipse.boot.dash.model.UserInteractions;
import org.springframework.ide.eclipse.boot.dash.model.runtargettypes.CannotAccessPropertyException;
import org.springframework.ide.eclipse.boot.util.Log;
/**
* Operation for connecting/disconnecting CF run target
*
* @author Alex Boyko
*
*/
public class ConnectOperation extends CloudOperation {
private boolean connect;
private UserInteractions ui;
public ConnectOperation(CloudFoundryBootDashModel model, boolean connect) {
super("Connecting run target " + model.getRunTarget().getName(), model);
this.connect = connect;
}
public ConnectOperation(CloudFoundryBootDashModel model, boolean connect, UserInteractions ui) {
this(model, connect);
this.ui = ui;
}
@Override
protected void doCloudOp(IProgressMonitor monitor) throws Exception, OperationCanceledException {
if (model.getRunTarget() != null) {
if (connect && !model.getRunTarget().isConnected()) {
try {
model.setBaseRefreshState(RefreshState.loading("Connecting..."));
model.getRunTarget().connect();
model.refresh(ui);
model.getRunTarget().getTargetProperties().put(CloudFoundryTargetProperties.DISCONNECTED, null);
model.getViewModel().updateTargetPropertiesInStore();
model.setBaseRefreshState(RefreshState.READY);
if (model.getRunTarget().getTargetProperties().getStoreCredentials()==StoreCredentialsMode.STORE_TOKEN) {
//TODO: This special case doesn't seem like it should be necessary. Instead, any interaction with
// client should publish refresh token as it changes and credentials should be updated in target
// properties automatically any time there is a change.
String refreshToken = model.getRunTarget().getClient().getRefreshToken();
Assert.isNotNull(refreshToken);
model.getRunTarget().getTargetProperties().setCredentials(CFCredentials.fromRefreshToken(refreshToken));
}
} catch (MissingPasswordException|CannotAccessPropertyException|AssertionFailedException e) {
model.setBaseRefreshState(RefreshState.READY);
if (ui == null) {
Log.log(e);
} else {
CloudFoundryRunTarget runtarget = model.getRunTarget();
PasswordDialogModel passwordDialogModel = new PasswordDialogModel(
runtarget.getClientFactory(),
runtarget.getTargetProperties(),
runtarget.getTargetProperties().getStoreCredentials()
);
ui.openPasswordDialog(passwordDialogModel);
if (passwordDialogModel.isOk()) {
model.getRunTarget().getTargetProperties().setStoreCredentials(passwordDialogModel.getStoreVar().getValue());
CFCredentials credentials = passwordDialogModel.getCredentials();
// The password cannot be null or empty string - enforced by the dialog
try {
model.getRunTarget().getTargetProperties().setCredentials(credentials);
} catch (CannotAccessPropertyException e1) {
ui.warningPopup("Failed Storing Password",
"Failed to store password in Secure Storage for " + passwordDialogModel.getTargetId()
+ ". Secure Storage is most likely locked. Current password will be kept until disconnect.");
// Set "remember password" to false. Password hasn't been stored.
model.getRunTarget().getTargetProperties().setStoreCredentials(StoreCredentialsMode.STORE_NOTHING);
}
// At this point the password must be set otherwise an exception from the call above would be thrown
doCloudOp(monitor);
}
}
} catch (Exception e) {
model.setBaseRefreshState(RefreshState.error(e));
if (ui == null) {
throw e;
} else {
String msg = "Failed to connect to " + model.getRunTarget().getId() + ". ";
if (CFExceptions.isAuthFailure(e)) {
msg = msg+ " Ensure login credentials are correct.";
} else {
msg = msg+ " See error log for detailed message.";
Log.log(e);
}
ui.errorPopup("Cannot Connect to Cloud Foundry", msg);
}
}
} else if (!connect && model.getRunTarget().isConnected()) {
model.setBaseRefreshState(RefreshState.loading("Disconnecting..."));
model.getRunTarget().disconnect();
model.getRunTarget().getTargetProperties().put(CloudFoundryTargetProperties.DISCONNECTED, "true"); //$NON-NLS-1$
if (!model.getRunTarget().getTargetProperties().isStoreCredentials()) {
// Forget credentials on disconnect if it's not stored
model.getRunTarget().getTargetProperties().setCredentials(null);
}
model.getViewModel().updateTargetPropertiesInStore();
model.setBaseRefreshState(RefreshState.READY);
}
}
}
public ISchedulingRule getSchedulingRule() {
return new RefreshSchedulingRule(model.getRunTarget());
}
}