CF client config message, modifiable CF client config

Cleanup
This commit is contained in:
BoykoAlex
2017-06-10 00:03:14 -04:00
parent 2a135342f8
commit 9104c35b10
14 changed files with 355 additions and 36 deletions

View File

@@ -56,7 +56,8 @@ public class CFCallableContext {
Throwable deepestCause = ExceptionUtil.getDeepestCause(e);
if (deepestCause instanceof UaaException || deepestCause instanceof AbortedException
|| deepestCause instanceof SocketException || deepestCause instanceof UnknownHostException) {
|| deepestCause instanceof SocketException || deepestCause instanceof UnknownHostException
&& this.paramsProviderMessages != null) {
return new ConnectionException(this.paramsProviderMessages.noNetworkConnection());
}
return null;

View File

@@ -12,6 +12,7 @@ package org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -25,24 +26,28 @@ import com.google.common.cache.LoadingCache;
public class CFTargetCache {
private final ClientParamsProvider paramsProvider;
private final CfClientConfig cfClientConfig;
private final CloudFoundryClientFactory clientFactory;
private final ClientTimeouts timeouts;
private final LoadingCache<ClientParamsCacheKey, CFTarget> cache;
private final CFCallableContext cacheCallableContext;
private LoadingCache<ClientParamsCacheKey, CFTarget> cache;
private CFCallableContext cacheCallableContext;
public static final Duration SERVICES_EXPIRATION = Duration.ofSeconds(10);
public static final Duration TARGET_EXPIRATION = Duration.ofHours(1);
public static final Duration ERROR_EXPIRATION = Duration.ofSeconds(10);
public CFTargetCache(ClientParamsProvider paramsProvider, CloudFoundryClientFactory clientFactory,
public CFTargetCache(CfClientConfig cfClientConfig, CloudFoundryClientFactory clientFactory,
ClientTimeouts timeouts) {
Assert.isLegal(paramsProvider != null,
Assert.isLegal(cfClientConfig != null,
"A Cloud Foundry client parameters provider must be set when creating a target cache.");
this.paramsProvider = paramsProvider;
this.cfClientConfig = cfClientConfig;
this.clientFactory = clientFactory;
this.timeouts = timeouts;
this.cacheCallableContext = new CFCallableContext(paramsProvider.getMessages());
cfClientConfig.addClientParamsProviderChangedListener((newProvider, oldProvider) -> initCache());
initCache();
}
private void initCache() {
CacheLoader<ClientParamsCacheKey, CFTarget> loader = new CacheLoader<ClientParamsCacheKey, CFTarget>() {
@Override
@@ -53,6 +58,7 @@ public class CFTargetCache {
};
cache = CacheBuilder.newBuilder().maximumSize(1).expireAfterAccess(TARGET_EXPIRATION.toMillis(), TimeUnit.MILLISECONDS)
.build(loader);
this.cacheCallableContext = new CFCallableContext(cfClientConfig.getClientParamsProvider().getMessages());
}
/**
@@ -68,7 +74,7 @@ public class CFTargetCache {
protected synchronized List<CFTarget> doGetOrCreate() throws NoTargetsException, Exception {
List<CFClientParams> allParams = paramsProvider.getParams();
Collection<CFClientParams> allParams = cfClientConfig.getClientParamsProvider().getParams();
List<CFTarget> targets = new ArrayList<>();
if (allParams != null) {
for (CFClientParams params : allParams) {
@@ -84,10 +90,10 @@ public class CFTargetCache {
}
}
}
return targets;
}
protected CFTarget create(CFClientParams params) throws Exception {
/*
* Must pass a NEW callable context. Cannot be
@@ -95,7 +101,7 @@ public class CFTargetCache {
* contexts may contain error state
*/
return new CFTarget(getTargetName(params), params, clientFactory.getClient(params, timeouts),
new CFCallableContext(paramsProvider.getMessages()));
new CFCallableContext(cfClientConfig.getClientParamsProvider().getMessages()));
}
protected static String getTargetName(CFClientParams params) {

View File

@@ -29,7 +29,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
*/
public class CfCliParamsProvider implements ClientParamsProvider {
public static final String TARGET = "Target";
public static final String REFRESH_TOKEN = "RefreshToken";
public static final String ORGANIZATION_FIELDS = "OrganizationFields";
@@ -37,14 +36,27 @@ public class CfCliParamsProvider implements ClientParamsProvider {
public static final String NAME = "Name";
public static final String SSL_DISABLED = "SSLDisabled";
private CfCliProviderMessages cfCliProviderMessages = new CfCliProviderMessages();
private static CfCliParamsProvider instance;
public static final CfCliParamsProvider getInstance() {
if (instance == null) {
instance= new CfCliParamsProvider();
}
return instance;
}
private CfCliParamsProvider() {
}
/*
* (non-Javadoc)
*
* @see org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.
* ClientParamsProvider#getParams()
*/
@SuppressWarnings("unchecked")
@Override
public List<CFClientParams> getParams() throws NoTargetsException, ExecutionException {
List<CFClientParams> params = new ArrayList<>();

View File

@@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright (c) 2017 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.vscode.commons.cloudfoundry.client.cftarget;
/**
* CF Client configuration
*
* @author Alex Boyko
*
*/
public interface CfClientConfig {
/**
* Listener to changes in parameters provider
*/
@FunctionalInterface
public interface ClientParamsProviderChangedListener {
void clientParamsProviderChanged(ClientParamsProvider newProvider, ClientParamsProvider oldProvider);
}
/**
* Returns CF client parameters provider
* @return parameters provider
*/
ClientParamsProvider getClientParamsProvider();
/**
* Sets CF client parameters provider
* @param provider
*/
void setClientParamsProvider(ClientParamsProvider provider);
/**
* Adds listener to listen to CF parameter provider changes
* @param listener
*/
void addClientParamsProviderChangedListener(ClientParamsProviderChangedListener listener);
/**
* Removes CF parameter provider change listener
* @param listener
*/
void removeClientParamsProviderChangedListener(ClientParamsProviderChangedListener listener);
/**
* Default CF Client configuration
*/
final static CfClientConfig DEFAULT = new CfClientConfigImpl();
}

View File

@@ -0,0 +1,48 @@
/*******************************************************************************
* Copyright (c) 2017 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.vscode.commons.cloudfoundry.client.cftarget;
import org.springframework.ide.vscode.commons.util.ListenerList;
/**
* Default CF client configuration implementation
*
* @author Alex Boyko
*
*/
class CfClientConfigImpl implements CfClientConfig {
private ClientParamsProvider clientParamsProvider;
private ListenerList<ClientParamsProviderChangedListener> listeners = new ListenerList<>();
@Override
public ClientParamsProvider getClientParamsProvider() {
return clientParamsProvider;
}
@Override
public void setClientParamsProvider(ClientParamsProvider provider) {
ClientParamsProvider oldParamsProvider = this.clientParamsProvider;
this.clientParamsProvider = provider;
listeners.forEach(l -> l.clientParamsProviderChanged(clientParamsProvider, oldParamsProvider));
}
@Override
public void addClientParamsProviderChangedListener(ClientParamsProviderChangedListener listener) {
listeners.add(listener);
}
@Override
public void removeClientParamsProviderChangedListener(ClientParamsProviderChangedListener listener) {
listeners.remove(listener);
}
}

View File

@@ -0,0 +1,106 @@
/*******************************************************************************
* Copyright (c) 2017 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.vscode.commons.cloudfoundry.client.cftarget;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.springframework.ide.vscode.commons.util.StringUtil;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
/**
* CF Client parameter provider based on the JSON data. the JSON data is
* cosidered to be data from the from config changed message defined in the LSP
* spec
* {@link https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#workspace_didChangeConfiguration}
*
* @author Alex Boyko
*
*/
public class CfJsonParamsProvider implements ClientParamsProvider {
private static final String NO_TARGETS_FOUND_MESSAGE = "No targets found";
private static final String NO_NETWORK_CONNECTION = "No connection to Cloud Foundry";
private static final String NO_ORG_SPACE = "No org/space selected";
private static final String TARGET = "Target";
private static final String REFRESH_TOKEN = "RefreshToken";
private static final String SSL_DISABLED = "SSLDisabled";
private static final String ORG_NAME = "OrgName";
private static final String SPACE_NAME = "SpaceName";
private Supplier<Collection<CFClientParams>> paramsSupplier;
public CfJsonParamsProvider(List<?> json) {
this.paramsSupplier = Suppliers.memoize(() -> json
.stream()
.filter(o -> o instanceof Map<?, ?>)
.map(m -> parseCfClientParams((Map<?,?>)m))
.filter(Objects::nonNull)
.collect(Collectors.toList()));
}
@Override
public Collection<CFClientParams> getParams() throws NoTargetsException, ExecutionException {
return paramsSupplier.get();
}
private static CFClientParams parseCfClientParams(Map<?, ?> userData) {
String refreshToken = (String) userData.get(REFRESH_TOKEN);
// Only support connecting to CF via refresh token for now
if (StringUtil.hasText(refreshToken)) {
CFCredentials credentials = CFCredentials.fromRefreshToken(refreshToken);
boolean sslDisabled = (Boolean) userData.get(SSL_DISABLED);
String target = (String) userData.get(TARGET);
String orgName = (String) userData.get(ORG_NAME);
String spaceName = (String) userData.get(SPACE_NAME);
if (target != null && StringUtil.hasText(orgName) && StringUtil.hasText(spaceName)) {
return new CFClientParams(target, null, credentials, orgName, spaceName, sslDisabled);
}
}
return null;
}
@Override
public CFParamsProviderMessages getMessages() {
return new CFParamsProviderMessages() {
@Override
public String noTargetsFound() {
return NO_TARGETS_FOUND_MESSAGE;
}
@Override
public String unauthorised() {
return NO_NETWORK_CONNECTION;
}
@Override
public String noNetworkConnection() {
return NO_NETWORK_CONNECTION;
}
@Override
public String noOrgSpace() {
return NO_ORG_SPACE;
}
};
}
}

View File

@@ -10,18 +10,19 @@
*******************************************************************************/
package org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget;
import java.util.List;
import java.util.Collection;
import java.util.concurrent.ExecutionException;
public interface ClientParamsProvider {
/**
*
* @return non-null list of VALID params to connect to Cloud Foundry
* @throws NoTargetsException if failure to resolve any params for Cloud Foundry
* @throws ExecutionException if failure occurs while resolving params
*/
List<CFClientParams> getParams() throws NoTargetsException, ExecutionException;
Collection<CFClientParams> getParams() throws NoTargetsException, ExecutionException;
CFParamsProviderMessages getMessages();
}

View File

@@ -40,7 +40,7 @@ public class CFClientTest {
@Before
public void setup() throws Exception {
targetCache = new CFTargetCache(cloudfoundry.paramsProvider, cloudfoundry.factory, timeouts);
targetCache = new CFTargetCache(cloudfoundry.cfClientConfig, cloudfoundry.factory, timeouts);
}
@Test

View File

@@ -20,6 +20,7 @@ import org.springframework.ide.vscode.commons.cloudfoundry.client.CloudFoundryCl
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFClientParams;
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CFCredentials;
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CfCliProviderMessages;
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.CfClientConfig;
import org.springframework.ide.vscode.commons.cloudfoundry.client.cftarget.ClientParamsProvider;
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
@@ -32,11 +33,13 @@ public class MockCfCli {
public final CloudFoundryClientFactory factory = mock(CloudFoundryClientFactory.class);
public final ClientRequests client = mock(ClientRequests.class);
public final CfClientConfig cfClientConfig = CfClientConfig.DEFAULT;
public final ClientParamsProvider paramsProvider = mock(ClientParamsProvider.class);
public final CfCliProviderMessages actualCfCliMessages = new CfCliProviderMessages();
public MockCfCli() {
try {
cfClientConfig.setClientParamsProvider(paramsProvider);
//program some default behavior into mocks... most tests will use this.
//other tests should 'reset' the mocks and reprogram them as needed.
when(factory.getClient(any(), any())).thenReturn(client);