未验证 提交 0d322768 编写于 作者: J Jason Song 提交者: GitHub

Merge pull request #1508 from nobodyiam/apollo-open-api

add apollo-openapi client
......@@ -43,7 +43,7 @@ public class ItemController {
ConfigChangeContentBuilder builder = new ConfigChangeContentBuilder();
Item managedEntity = itemService.findOne(appId, clusterName, namespaceName, entity.getKey());
if (managedEntity != null) {
throw new BadRequestException("item already exist");
throw new BadRequestException("item already exists");
} else {
entity = itemService.save(entity);
builder.createItem(entity);
......
......@@ -10,6 +10,11 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>apollo-mockserver</artifactId>
<name>Apollo Mock Server</name>
<properties>
<java.version>1.7</java.version>
</properties>
<dependencyManagement>
<dependencies>
......
......@@ -5,10 +5,9 @@ import com.ctrip.framework.apollo.core.dto.ApolloConfig;
import com.ctrip.framework.apollo.core.dto.ApolloConfigNotification;
import com.ctrip.framework.apollo.core.utils.ResourceUtils;
import com.ctrip.framework.apollo.internals.ConfigServiceLocator;
import com.ctrip.framework.apollo.spring.config.PropertySourcesProcessor;
import com.ctrip.framework.apollo.spring.property.SpringValueDefinitionProcessor;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Method;
......@@ -19,7 +18,6 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
......@@ -110,8 +108,10 @@ public class EmbeddedApollo extends ExternalResource {
private String loadConfigFor(String namespace) {
String filename = String.format("mockdata-%s.properties", namespace);
final Properties prop = ResourceUtils.readConfigFile(filename, new Properties());
Map<String, String> configurations = prop.stringPropertyNames().stream().collect(
Collectors.toMap(key -> key, prop::getProperty));
Map<String, String> configurations = Maps.newHashMap();
for (String propertyName : prop.stringPropertyNames()) {
configurations.put(propertyName, prop.getProperty(propertyName));
}
ApolloConfig apolloConfig = new ApolloConfig("someAppId", "someCluster", namespace, "someReleaseKey");
Map<String, String> mergedConfigurations = mergeOverriddenProperties(namespace, configurations);
......
......@@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.google.common.util.concurrent.SettableFuture;
......@@ -32,9 +33,14 @@ public class ApolloMockServerApiTest {
Config otherConfig = ConfigService.getConfig(otherNamespace);
SettableFuture<ConfigChangeEvent> future = SettableFuture.create();
final SettableFuture<ConfigChangeEvent> future = SettableFuture.create();
otherConfig.addChangeListener(future::set);
otherConfig.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
future.set(changeEvent);
}
});
assertEquals("otherValue1", otherConfig.getProperty("key1", null));
assertEquals("otherValue2", otherConfig.getProperty("key2", null));
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>apollo</artifactId>
<groupId>com.ctrip.framework.apollo</groupId>
<version>1.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apollo-openapi</artifactId>
<name>Apollo Open Api</name>
<properties>
<java.version>1.7</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
package com.ctrip.framework.apollo.openapi.client;
import com.ctrip.framework.apollo.openapi.client.constant.ApolloOpenApiConstants;
import com.ctrip.framework.apollo.openapi.client.service.AppOpenApiService;
import com.ctrip.framework.apollo.openapi.client.service.ItemOpenApiService;
import com.ctrip.framework.apollo.openapi.client.service.NamespaceOpenApiService;
import com.ctrip.framework.apollo.openapi.client.service.ReleaseOpenApiService;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenEnvClusterDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceLockDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenReleaseDTO;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.List;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
/**
* This class contains collections of methods to access Apollo Open Api.
* <br />
* For more information, please refer <a href="https://github.com/ctripcorp/apollo/wiki/">Apollo Wiki</a>.
*
*/
public class ApolloOpenApiClient {
private final String portalUrl;
private final String token;
private final AppOpenApiService appService;
private final ItemOpenApiService itemService;
private final ReleaseOpenApiService releaseService;
private final NamespaceOpenApiService namespaceService;
private ApolloOpenApiClient(String portalUrl, String token, RequestConfig requestConfig) {
this.portalUrl = portalUrl;
this.token = token;
CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(requestConfig)
.setDefaultHeaders(Lists.newArrayList(new BasicHeader("Authorization", token))).build();
Gson gson = new GsonBuilder().setDateFormat(ApolloOpenApiConstants.JSON_DATE_FORMAT).create();
String baseUrl = this.portalUrl + ApolloOpenApiConstants.OPEN_API_V1_PREFIX;
appService = new AppOpenApiService(client, baseUrl, gson);
namespaceService = new NamespaceOpenApiService(client, baseUrl, gson);
itemService = new ItemOpenApiService(client, baseUrl, gson);
releaseService = new ReleaseOpenApiService(client, baseUrl, gson);
}
/**
* Get the environment and cluster information
*/
public List<OpenEnvClusterDTO> getEnvClusterInfo(String appId) {
return appService.getEnvClusterInfo(appId);
}
/**
* Get the namespaces
*/
public List<OpenNamespaceDTO> getNamespaces(String appId, String env, String clusterName) {
return namespaceService.getNamespaces(appId, env, clusterName);
}
/**
* Get the namespace
*/
public OpenNamespaceDTO getNamespace(String appId, String env, String clusterName, String namespaceName) {
return namespaceService.getNamespace(appId, env, clusterName, namespaceName);
}
/**
* Create the app namespace
*/
public OpenAppNamespaceDTO createAppNamespace(OpenAppNamespaceDTO appNamespaceDTO) {
return namespaceService.createAppNamespace(appNamespaceDTO);
}
/**
* Get the namespace lock
*/
public OpenNamespaceLockDTO getNamespaceLock(String appId, String env, String clusterName, String namespaceName) {
return namespaceService.getNamespaceLock(appId, env, clusterName, namespaceName);
}
/**
* Add config
* @return the created config
*/
public OpenItemDTO createItem(String appId, String env, String clusterName, String namespaceName,
OpenItemDTO itemDTO) {
return itemService.createItem(appId, env, clusterName, namespaceName, itemDTO);
}
/**
* Update config
*/
public void updateItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
itemService.updateItem(appId, env, clusterName, namespaceName, itemDTO);
}
/**
* Create config if not exists or update config if already exists
*/
public void createOrUpdateItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
itemService.createOrUpdateItem(appId, env, clusterName, namespaceName, itemDTO);
}
/**
* Remove config
*
* @param operator the user who removes the item
*/
public void removeItem(String appId, String env, String clusterName, String namespaceName, String key,
String operator) {
itemService.removeItem(appId, env, clusterName, namespaceName, key, operator);
}
/**
* publish namespace
* @return the released configurations
*/
public OpenReleaseDTO publishNamespace(String appId, String env, String clusterName, String namespaceName,
NamespaceReleaseDTO releaseDTO) {
return releaseService.publishNamespace(appId, env, clusterName, namespaceName, releaseDTO);
}
/**
* @return the latest active release information or <code>null</code> if not found
*/
public OpenReleaseDTO getLatestActiveRelease(String appId, String env, String clusterName, String namespaceName) {
return releaseService.getLatestActiveRelease(appId, env, clusterName, namespaceName);
}
public String getPortalUrl() {
return portalUrl;
}
public String getToken() {
return token;
}
public static ApolloOpenApiClientBuilder newBuilder() {
return new ApolloOpenApiClientBuilder();
}
public static class ApolloOpenApiClientBuilder {
private String portalUrl;
private String token;
private int connectTimeout = -1;
private int readTimeout = -1;
/**
* @param portalUrl The apollo portal url, e.g http://localhost:8070
*/
public ApolloOpenApiClientBuilder withPortalUrl(String portalUrl) {
this.portalUrl = portalUrl;
return this;
}
/**
* @param token The authorization token, e.g. e16e5cd903fd0c97a116c873b448544b9d086de8
*/
public ApolloOpenApiClientBuilder withToken(String token) {
this.token = token;
return this;
}
/**
* @param connectTimeout an int that specifies the connect timeout value in milliseconds
*/
public ApolloOpenApiClientBuilder withConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}
/**
* @param readTimeout an int that specifies the timeout value to be used in milliseconds
*/
public ApolloOpenApiClientBuilder withReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
return this;
}
public ApolloOpenApiClient build() {
Preconditions.checkArgument(!Strings.isNullOrEmpty(portalUrl), "Portal url should not be null or empty!");
Preconditions.checkArgument(portalUrl.startsWith("http://") || portalUrl.startsWith("https://"), "Portal url should start with http:// or https://" );
Preconditions.checkArgument(!Strings.isNullOrEmpty(token), "Token should not be null or empty!");
if (connectTimeout < 0) {
connectTimeout = ApolloOpenApiConstants.DEFAULT_CONNECT_TIMEOUT;
}
if (readTimeout < 0) {
readTimeout = ApolloOpenApiConstants.DEFAULT_READ_TIMEOUT;
}
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout)
.setSocketTimeout(readTimeout).build();
return new ApolloOpenApiClient(portalUrl, token, requestConfig);
}
}
}
package com.ctrip.framework.apollo.openapi.client.constant;
public interface ApolloOpenApiConstants {
int DEFAULT_CONNECT_TIMEOUT = 1000; //1 second
int DEFAULT_READ_TIMEOUT = 5000; //5 seconds
String OPEN_API_V1_PREFIX = "/openapi/v1";
String JSON_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ";
}
package com.ctrip.framework.apollo.openapi.client.exception;
public class ApolloOpenApiException extends RuntimeException {
public ApolloOpenApiException(int status, String reason, String message) {
super(String.format("Request to apollo open api failed, status code: %d, reason: %s, message: %s", status, reason,
message));
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.openapi.client.exception.ApolloOpenApiException;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
import com.google.gson.Gson;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
abstract class AbstractOpenApiService {
private static final Escaper pathEscaper = UrlEscapers.urlPathSegmentEscaper();
private static final Escaper queryParamEscaper = UrlEscapers.urlFormParameterEscaper();
private final String baseUrl;
protected final CloseableHttpClient client;
protected final Gson gson;
AbstractOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
this.client = client;
this.baseUrl = baseUrl;
this.gson = gson;
}
protected CloseableHttpResponse get(String path) throws IOException {
HttpGet get = new HttpGet(String.format("%s/%s", baseUrl, path));
return execute(get);
}
protected CloseableHttpResponse post(String path, Object entity) throws IOException {
HttpPost post = new HttpPost(String.format("%s/%s", baseUrl, path));
return execute(post, entity);
}
protected CloseableHttpResponse put(String path, Object entity) throws IOException {
HttpPut put = new HttpPut(String.format("%s/%s", baseUrl, path));
return execute(put, entity);
}
protected CloseableHttpResponse delete(String path) throws IOException {
HttpDelete delete = new HttpDelete(String.format("%s/%s", baseUrl, path));
return execute(delete);
}
protected String escapePath(String path) {
return pathEscaper.escape(path);
}
protected String escapeParam(String param) {
return queryParamEscaper.escape(param);
}
private CloseableHttpResponse execute(HttpEntityEnclosingRequestBase requestBase, Object entity) throws IOException {
requestBase.setEntity(new StringEntity(gson.toJson(entity), ContentType.APPLICATION_JSON));
return execute(requestBase);
}
private CloseableHttpResponse execute(HttpUriRequest request) throws IOException {
CloseableHttpResponse response = client.execute(request);
checkHttpResponseStatus(response);
return response;
}
private void checkHttpResponseStatus(HttpResponse response) {
if (response.getStatusLine().getStatusCode() == 200) {
return;
}
StatusLine status = response.getStatusLine();
String message = "";
try {
message = EntityUtils.toString(response.getEntity());
} catch (IOException e) {
//ignore
}
throw new ApolloOpenApiException(status.getStatusCode(), status.getReasonPhrase(), message);
}
protected void checkNotEmpty(String value, String name) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(value), name + " should not be null or empty");
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.openapi.dto.OpenEnvClusterDTO;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
public class AppOpenApiService extends AbstractOpenApiService {
private static final Type OPEN_ENV_CLUSTER_DTO_LIST_TYPE = new TypeToken<List<OpenEnvClusterDTO>>() {
}.getType();
public AppOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
super(client, baseUrl, gson);
}
public List<OpenEnvClusterDTO> getEnvClusterInfo(String appId) {
checkNotEmpty(appId, "App id");
String path = String.format("apps/%s/envclusters", escapePath(appId));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OPEN_ENV_CLUSTER_DTO_LIST_TYPE);
} catch (Throwable ex) {
throw new RuntimeException(String.format("Load env cluster information for appId: %s failed", appId), ex);
}
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
public class ItemOpenApiService extends AbstractOpenApiService {
public ItemOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
super(client, baseUrl, gson);
}
public OpenItemDTO createItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(itemDTO.getKey(), "Item key");
checkNotEmpty(itemDTO.getValue(), "Item value");
checkNotEmpty(itemDTO.getDataChangeCreatedBy(), "Item created by");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/items",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = post(path, itemDTO)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenItemDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Create item: %s for appId: %s, cluster: %s, namespace: %s in env: %s failed", itemDTO.getKey(),
appId, clusterName, namespaceName, env), ex);
}
}
public void updateItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(itemDTO.getKey(), "Item key");
checkNotEmpty(itemDTO.getValue(), "Item value");
checkNotEmpty(itemDTO.getDataChangeLastModifiedBy(), "Item modified by");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName),
escapePath(itemDTO.getKey()));
try (CloseableHttpResponse ignored = put(path, itemDTO)) {
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Update item: %s for appId: %s, cluster: %s, namespace: %s in env: %s failed", itemDTO.getKey(),
appId, clusterName, namespaceName, env), ex);
}
}
public void createOrUpdateItem(String appId, String env, String clusterName, String namespaceName, OpenItemDTO itemDTO) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(itemDTO.getKey(), "Item key");
checkNotEmpty(itemDTO.getValue(), "Item value");
checkNotEmpty(itemDTO.getDataChangeCreatedBy(), "Item created by");
if (Strings.isNullOrEmpty(itemDTO.getDataChangeLastModifiedBy())) {
itemDTO.setDataChangeLastModifiedBy(itemDTO.getDataChangeCreatedBy());
}
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s?createIfNotExists=true",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName),
escapePath(itemDTO.getKey()));
try (CloseableHttpResponse ignored = put(path, itemDTO)) {
} catch (Throwable ex) {
throw new RuntimeException(String
.format("CreateOrUpdate item: %s for appId: %s, cluster: %s, namespace: %s in env: %s failed", itemDTO.getKey(),
appId, clusterName, namespaceName, env), ex);
}
}
public void removeItem(String appId, String env, String clusterName, String namespaceName, String key, String operator) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(key, "Item key");
checkNotEmpty(operator, "Operator");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s?operator=%s",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName), escapePath(key),
escapeParam(operator));
try (CloseableHttpResponse ignored = delete(path)) {
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Remove item: %s for appId: %s, cluster: %s, namespace: %s in env: %s failed", key, appId,
clusterName, namespaceName, env), ex);
}
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceLockDTO;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
public class NamespaceOpenApiService extends AbstractOpenApiService {
private static final Type OPEN_NAMESPACE_DTO_LIST_TYPE = new TypeToken<List<OpenNamespaceDTO>>() {
}.getType();
public NamespaceOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
super(client, baseUrl, gson);
}
public OpenNamespaceDTO getNamespace(String appId, String env, String clusterName, String namespaceName) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s", escapePath(env), escapePath(appId),
escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenNamespaceDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Get namespace for appId: %s, cluster: %s, namespace: %s in env: %s failed", appId, clusterName,
namespaceName, env), ex);
}
}
public List<OpenNamespaceDTO> getNamespaces(String appId, String env, String clusterName) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces", escapePath(env), escapePath(appId),
escapePath(clusterName));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OPEN_NAMESPACE_DTO_LIST_TYPE);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Get namespaces for appId: %s, cluster: %s in env: %s failed", appId, clusterName, env), ex);
}
}
public OpenAppNamespaceDTO createAppNamespace(OpenAppNamespaceDTO appNamespaceDTO) {
checkNotEmpty(appNamespaceDTO.getAppId(), "App id");
checkNotEmpty(appNamespaceDTO.getName(), "Name");
checkNotEmpty(appNamespaceDTO.getDataChangeCreatedBy(), "Created by");
if (Strings.isNullOrEmpty(appNamespaceDTO.getFormat())) {
appNamespaceDTO.setFormat(ConfigFileFormat.Properties.getValue());
}
String path = String.format("apps/%s/appnamespaces", escapePath(appNamespaceDTO.getAppId()));
try (CloseableHttpResponse response = post(path, appNamespaceDTO)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenAppNamespaceDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Create app namespace: %s for appId: %s, format: %s failed", appNamespaceDTO.getName(),
appNamespaceDTO.getAppId(), appNamespaceDTO.getFormat()), ex);
}
}
public OpenNamespaceLockDTO getNamespaceLock(String appId, String env, String clusterName, String namespaceName) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/lock", escapePath(env), escapePath(appId),
escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenNamespaceLockDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Get namespace lock for appId: %s, cluster: %s, namespace: %s in env: %s failed", appId, clusterName,
namespaceName, env), ex);
}
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenReleaseDTO;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
public class ReleaseOpenApiService extends AbstractOpenApiService {
public ReleaseOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
super(client, baseUrl, gson);
}
public OpenReleaseDTO publishNamespace(String appId, String env, String clusterName, String namespaceName,
NamespaceReleaseDTO releaseDTO) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
checkNotEmpty(releaseDTO.getReleaseTitle(), "Release title");
checkNotEmpty(releaseDTO.getReleasedBy(), "Released by");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/releases",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = post(path, releaseDTO)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenReleaseDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Release namespace: %s for appId: %s, cluster: %s in env: %s failed", namespaceName, appId,
clusterName, env), ex);
}
}
public OpenReleaseDTO getLatestActiveRelease(String appId, String env, String clusterName, String namespaceName) {
if (Strings.isNullOrEmpty(clusterName)) {
clusterName = ConfigConsts.CLUSTER_NAME_DEFAULT;
}
if (Strings.isNullOrEmpty(namespaceName)) {
namespaceName = ConfigConsts.NAMESPACE_APPLICATION;
}
checkNotEmpty(appId, "App id");
checkNotEmpty(env, "Env");
String path = String.format("envs/%s/apps/%s/clusters/%s/namespaces/%s/releases/latest",
escapePath(env), escapePath(appId), escapePath(clusterName), escapePath(namespaceName));
try (CloseableHttpResponse response = get(path)) {
return gson.fromJson(EntityUtils.toString(response.getEntity()), OpenReleaseDTO.class);
} catch (Throwable ex) {
throw new RuntimeException(String
.format("Get latest active release for appId: %s, cluster: %s, namespace: %s in env: %s failed", appId,
clusterName, namespaceName, env), ex);
}
}
}
package com.ctrip.framework.apollo.openapi.dto;
import java.util.Date;
public class BaseDTO {
protected String dataChangeCreatedBy;
protected String dataChangeLastModifiedBy;
protected Date dataChangeCreatedTime;
protected Date dataChangeLastModifiedTime;
public String getDataChangeCreatedBy() {
return dataChangeCreatedBy;
}
public void setDataChangeCreatedBy(String dataChangeCreatedBy) {
this.dataChangeCreatedBy = dataChangeCreatedBy;
}
public String getDataChangeLastModifiedBy() {
return dataChangeLastModifiedBy;
}
public void setDataChangeLastModifiedBy(String dataChangeLastModifiedBy) {
this.dataChangeLastModifiedBy = dataChangeLastModifiedBy;
}
public Date getDataChangeCreatedTime() {
return dataChangeCreatedTime;
}
public void setDataChangeCreatedTime(Date dataChangeCreatedTime) {
this.dataChangeCreatedTime = dataChangeCreatedTime;
}
public Date getDataChangeLastModifiedTime() {
return dataChangeLastModifiedTime;
}
public void setDataChangeLastModifiedTime(Date dataChangeLastModifiedTime) {
this.dataChangeLastModifiedTime = dataChangeLastModifiedTime;
}
}
package com.ctrip.framework.apollo.openapi.dto;
public class NamespaceReleaseDTO {
private String releaseTitle;
private String releaseComment;
private String releasedBy;
private boolean isEmergencyPublish;
public String getReleaseTitle() {
return releaseTitle;
}
public void setReleaseTitle(String releaseTitle) {
this.releaseTitle = releaseTitle;
}
public String getReleaseComment() {
return releaseComment;
}
public void setReleaseComment(String releaseComment) {
this.releaseComment = releaseComment;
}
public String getReleasedBy() {
return releasedBy;
}
public void setReleasedBy(String releasedBy) {
this.releasedBy = releasedBy;
}
public boolean isEmergencyPublish() {
return isEmergencyPublish;
}
public void setEmergencyPublish(boolean emergencyPublish) {
isEmergencyPublish = emergencyPublish;
}
}
package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
public class OpenAppNamespaceDTO extends BaseDTO {
private String name;
......
package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
public class OpenItemDTO extends BaseDTO {
private String key;
......
package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
import java.util.List;
public class OpenNamespaceDTO extends BaseDTO {
......
package com.ctrip.framework.apollo.openapi.dto;
import com.ctrip.framework.apollo.common.dto.BaseDTO;
import java.util.Map;
public class OpenReleaseDTO extends BaseDTO {
......
package com.ctrip.framework.apollo.openapi.client;
import static org.junit.Assert.*;
import org.junit.Test;
public class ApolloOpenApiClientTest {
@Test
public void testCreate() {
String someUrl = "http://someUrl";
String someToken = "someToken";
ApolloOpenApiClient client = ApolloOpenApiClient.newBuilder().withPortalUrl(someUrl).withToken(someToken).build();
assertEquals(someUrl, client.getPortalUrl());
assertEquals(someToken, client.getToken());
}
@Test(expected = IllegalArgumentException.class)
public void testCreateWithInvalidUrl() {
String someInvalidUrl = "someInvalidUrl";
String someToken = "someToken";
ApolloOpenApiClient.newBuilder().withPortalUrl(someInvalidUrl).withToken(someToken).build();
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.openapi.client.constant.ApolloOpenApiConstants;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
abstract class AbstractOpenApiServiceTest {
@Mock
protected CloseableHttpClient httpClient;
@Mock
protected CloseableHttpResponse someHttpResponse;
@Mock
protected StatusLine statusLine;
protected Gson gson;
protected String someBaseUrl;
@Before
public void setUp() throws Exception {
gson = new GsonBuilder().setDateFormat(ApolloOpenApiConstants.JSON_DATE_FORMAT).create();
someBaseUrl = "http://someBaseUrl";
when(someHttpResponse.getStatusLine()).thenReturn(statusLine);
when(statusLine.getStatusCode()).thenReturn(200);
when(httpClient.execute(any(HttpUriRequest.class))).thenReturn(someHttpResponse);
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.StringEntity;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class AppOpenApiServiceTest extends AbstractOpenApiServiceTest {
private AppOpenApiService appOpenApiService;
private String someAppId;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
someAppId = "someAppId";
StringEntity responseEntity = new StringEntity("[]");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
appOpenApiService = new AppOpenApiService(httpClient, someBaseUrl, gson);
}
@Test
public void testGetEnvClusterInfo() throws Exception {
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
appOpenApiService.getEnvClusterInfo(someAppId);
verify(httpClient, times(1)).execute(request.capture());
HttpGet get = request.getValue();
assertEquals(String
.format("%s/apps/%s/envclusters", someBaseUrl, someAppId), get.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetEnvClusterInfoWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(500);
appOpenApiService.getEnvClusterInfo(someAppId);
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class ItemOpenApiServiceTest extends AbstractOpenApiServiceTest {
private ItemOpenApiService itemOpenApiService;
private String someAppId;
private String someEnv;
private String someCluster;
private String someNamespace;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
someAppId = "someAppId";
someEnv = "someEnv";
someCluster = "someCluster";
someNamespace = "someNamespace";
StringEntity responseEntity = new StringEntity("{}");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
itemOpenApiService = new ItemOpenApiService(httpClient, someBaseUrl, gson);
}
@Test
public void testCreateItem() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someCreatedBy = "someCreatedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeCreatedBy(someCreatedBy);
final ArgumentCaptor<HttpPost> request = ArgumentCaptor.forClass(HttpPost.class);
itemOpenApiService.createItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPost post = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/items", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), post.getURI().toString());
StringEntity entity = (StringEntity) post.getEntity();
assertEquals(ContentType.APPLICATION_JSON.toString(), entity.getContentType().getValue());
assertEquals(gson.toJson(itemDTO), EntityUtils.toString(entity));
}
@Test(expected = RuntimeException.class)
public void testCreateItemWithError() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someCreatedBy = "someCreatedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeCreatedBy(someCreatedBy);
when(statusLine.getStatusCode()).thenReturn(400);
itemOpenApiService.createItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
}
@Test
public void testUpdateItem() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someModifiedBy = "someModifiedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeLastModifiedBy(someModifiedBy);
final ArgumentCaptor<HttpPut> request = ArgumentCaptor.forClass(HttpPut.class);
itemOpenApiService.updateItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPut put = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace, someKey), put.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testUpdateItemWithError() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someModifiedBy = "someModifiedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeLastModifiedBy(someModifiedBy);
when(statusLine.getStatusCode()).thenReturn(400);
itemOpenApiService.updateItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
}
@Test
public void testCreateOrUpdateItem() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someCreatedBy = "someCreatedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeCreatedBy(someCreatedBy);
final ArgumentCaptor<HttpPut> request = ArgumentCaptor.forClass(HttpPut.class);
itemOpenApiService.createOrUpdateItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPut put = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s?createIfNotExists=true", someBaseUrl, someEnv,
someAppId, someCluster, someNamespace, someKey), put.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testCreateOrUpdateItemWithError() throws Exception {
String someKey = "someKey";
String someValue = "someValue";
String someCreatedBy = "someCreatedBy";
OpenItemDTO itemDTO = new OpenItemDTO();
itemDTO.setKey(someKey);
itemDTO.setValue(someValue);
itemDTO.setDataChangeCreatedBy(someCreatedBy);
when(statusLine.getStatusCode()).thenReturn(400);
itemOpenApiService.createOrUpdateItem(someAppId, someEnv, someCluster, someNamespace, itemDTO);
}
@Test
public void testRemoveItem() throws Exception {
String someKey = "someKey";
String someOperator = "someOperator";
final ArgumentCaptor<HttpDelete> request = ArgumentCaptor.forClass(HttpDelete.class);
itemOpenApiService.removeItem(someAppId, someEnv, someCluster, someNamespace, someKey, someOperator);
verify(httpClient, times(1)).execute(request.capture());
HttpDelete delete = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/items/%s?operator=%s", someBaseUrl, someEnv,
someAppId, someCluster, someNamespace, someKey, someOperator), delete.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testRemoveItemWithError() throws Exception {
String someKey = "someKey";
String someOperator = "someOperator";
when(statusLine.getStatusCode()).thenReturn(404);
itemOpenApiService.removeItem(someAppId, someEnv, someCluster, someNamespace, someKey, someOperator);
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.openapi.dto.OpenAppNamespaceDTO;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class NamespaceOpenApiServiceTest extends AbstractOpenApiServiceTest {
private NamespaceOpenApiService namespaceOpenApiService;
private String someAppId;
private String someEnv;
private String someCluster;
private String someNamespace;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
someAppId = "someAppId";
someEnv = "someEnv";
someCluster = "someCluster";
someNamespace = "someNamespace";
StringEntity responseEntity = new StringEntity("{}");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
namespaceOpenApiService = new NamespaceOpenApiService(httpClient, someBaseUrl, gson);
}
@Test
public void testGetNamespace() throws Exception {
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
namespaceOpenApiService.getNamespace(someAppId, someEnv, someCluster, someNamespace);
verify(httpClient, times(1)).execute(request.capture());
HttpGet get = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), get.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetNamespaceWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(404);
namespaceOpenApiService.getNamespace(someAppId, someEnv, someCluster, someNamespace);
}
@Test
public void testGetNamespaces() throws Exception {
StringEntity responseEntity = new StringEntity("[]");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
namespaceOpenApiService.getNamespaces(someAppId, someEnv, someCluster);
verify(httpClient, times(1)).execute(request.capture());
HttpGet get = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces", someBaseUrl, someEnv, someAppId, someCluster),
get.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetNamespacesWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(404);
namespaceOpenApiService.getNamespaces(someAppId, someEnv, someCluster);
}
@Test
public void testCreateAppNamespace() throws Exception {
String someName = "someName";
String someCreatedBy = "someCreatedBy";
OpenAppNamespaceDTO appNamespaceDTO = new OpenAppNamespaceDTO();
appNamespaceDTO.setAppId(someAppId);
appNamespaceDTO.setName(someName);
appNamespaceDTO.setDataChangeCreatedBy(someCreatedBy);
final ArgumentCaptor<HttpPost> request = ArgumentCaptor.forClass(HttpPost.class);
namespaceOpenApiService.createAppNamespace(appNamespaceDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPost post = request.getValue();
assertEquals(String.format("%s/apps/%s/appnamespaces", someBaseUrl, someAppId), post.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testCreateAppNamespaceWithError() throws Exception {
String someName = "someName";
String someCreatedBy = "someCreatedBy";
OpenAppNamespaceDTO appNamespaceDTO = new OpenAppNamespaceDTO();
appNamespaceDTO.setAppId(someAppId);
appNamespaceDTO.setName(someName);
appNamespaceDTO.setDataChangeCreatedBy(someCreatedBy);
when(statusLine.getStatusCode()).thenReturn(400);
namespaceOpenApiService.createAppNamespace(appNamespaceDTO);
}
@Test
public void testGetNamespaceLock() throws Exception {
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
namespaceOpenApiService.getNamespaceLock(someAppId, someEnv, someCluster, someNamespace);
verify(httpClient, times(1)).execute(request.capture());
HttpGet post = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/lock", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), post.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetNamespaceLockWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(404);
namespaceOpenApiService.getNamespaceLock(someAppId, someEnv, someCluster, someNamespace);
}
}
package com.ctrip.framework.apollo.openapi.client.service;
import static org.junit.Assert.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class ReleaseOpenApiServiceTest extends AbstractOpenApiServiceTest {
private ReleaseOpenApiService releaseOpenApiService;
private String someAppId;
private String someEnv;
private String someCluster;
private String someNamespace;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
someAppId = "someAppId";
someEnv = "someEnv";
someCluster = "someCluster";
someNamespace = "someNamespace";
StringEntity responseEntity = new StringEntity("{}");
when(someHttpResponse.getEntity()).thenReturn(responseEntity);
releaseOpenApiService = new ReleaseOpenApiService(httpClient, someBaseUrl, gson);
}
@Test
public void testPublishNamespace() throws Exception {
String someReleaseTitle = "someReleaseTitle";
String someReleasedBy = "someReleasedBy";
NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
namespaceReleaseDTO.setReleaseTitle(someReleaseTitle);
namespaceReleaseDTO.setReleasedBy(someReleasedBy);
final ArgumentCaptor<HttpPost> request = ArgumentCaptor.forClass(HttpPost.class);
releaseOpenApiService.publishNamespace(someAppId, someEnv, someCluster, someNamespace, namespaceReleaseDTO);
verify(httpClient, times(1)).execute(request.capture());
HttpPost post = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/releases", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), post.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testPublishNamespaceWithError() throws Exception {
String someReleaseTitle = "someReleaseTitle";
String someReleasedBy = "someReleasedBy";
NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
namespaceReleaseDTO.setReleaseTitle(someReleaseTitle);
namespaceReleaseDTO.setReleasedBy(someReleasedBy);
when(statusLine.getStatusCode()).thenReturn(400);
releaseOpenApiService.publishNamespace(someAppId, someEnv, someCluster, someNamespace, namespaceReleaseDTO);
}
@Test
public void testGetLatestActiveRelease() throws Exception {
final ArgumentCaptor<HttpGet> request = ArgumentCaptor.forClass(HttpGet.class);
releaseOpenApiService.getLatestActiveRelease(someAppId, someEnv, someCluster, someNamespace);
verify(httpClient, times(1)).execute(request.capture());
HttpGet get = request.getValue();
assertEquals(String
.format("%s/envs/%s/apps/%s/clusters/%s/namespaces/%s/releases/latest", someBaseUrl, someEnv, someAppId, someCluster,
someNamespace), get.getURI().toString());
}
@Test(expected = RuntimeException.class)
public void testGetLatestActiveReleaseWithError() throws Exception {
when(statusLine.getStatusCode()).thenReturn(400);
releaseOpenApiService.getLatestActiveRelease(someAppId, someEnv, someCluster, someNamespace);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration monitorInterval="60">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="[apollo-open-api][%t]%d %-5p [%c] %m%n"/>
</Console>
<Async name="Async" includeLocation="true">
<AppenderRef ref="Console"/>
</Async>
</appenders>
<loggers>
<logger name="com.ctrip.framework.apollo" additivity="false" level="trace">
<AppenderRef ref="Async" level="WARN"/>
</logger>
<root level="INFO">
<AppenderRef ref="Async"/>
</root>
</loggers>
</configuration>
......@@ -22,6 +22,10 @@
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-common</artifactId>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-openapi</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
......
......@@ -11,6 +11,7 @@ import com.ctrip.framework.apollo.portal.service.ItemService;
import com.ctrip.framework.apollo.portal.spi.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
......@@ -20,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.client.HttpStatusCodeException;
@RestController("openapiItemController")
......@@ -40,10 +42,10 @@ public class ItemController {
RequestPrecondition.checkArguments(
!StringUtils.isContainEmpty(item.getKey(), item.getValue(), item.getDataChangeCreatedBy()),
"key,value,dataChangeCreatedBy 字段不能为空");
"key, value and dataChangeCreatedBy should not be null or empty");
if (userService.findByUserId(item.getDataChangeCreatedBy()) == null) {
throw new BadRequestException("用户不存在.");
throw new BadRequestException("User " + item.getDataChangeCreatedBy() + " doesn't exist!");
}
ItemDTO toCreate = OpenApiBeanUtils.transformToItemDTO(item);
......@@ -64,13 +66,14 @@ public class ItemController {
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/items/{key:.+}", method = RequestMethod.PUT)
public void updateItem(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName, @PathVariable String namespaceName,
@PathVariable String key, @RequestBody OpenItemDTO item, HttpServletRequest request) {
@PathVariable String key, @RequestBody OpenItemDTO item,
@RequestParam(defaultValue = "false") boolean createIfNotExists, HttpServletRequest request) {
RequestPrecondition.checkArguments(item != null, "item payload can not be empty");
RequestPrecondition.checkArguments(
!StringUtils.isContainEmpty(item.getKey(), item.getValue(), item.getDataChangeLastModifiedBy()),
"key,value,dataChangeLastModifiedBy can not be empty");
"key, value and dataChangeLastModifiedBy can not be empty");
RequestPrecondition.checkArguments(item.getKey().equals(key), "Key in path and payload is not consistent");
......@@ -78,16 +81,25 @@ public class ItemController {
throw new BadRequestException("user(dataChangeLastModifiedBy) not exists");
}
ItemDTO toUpdateItem = itemService.loadItem(Env.fromString(env), appId, clusterName, namespaceName, item.getKey());
if (toUpdateItem == null) {
throw new BadRequestException("item not exists");
try {
ItemDTO toUpdateItem = itemService
.loadItem(Env.fromString(env), appId, clusterName, namespaceName, item.getKey());
//protect. only value,comment,lastModifiedBy can be modified
toUpdateItem.setComment(item.getComment());
toUpdateItem.setValue(item.getValue());
toUpdateItem.setDataChangeLastModifiedBy(item.getDataChangeLastModifiedBy());
itemService.updateItem(appId, Env.fromString(env), clusterName, namespaceName, toUpdateItem);
} catch (Throwable ex) {
if (ex instanceof HttpStatusCodeException) {
// check createIfNotExists
if (((HttpStatusCodeException) ex).getStatusCode().equals(HttpStatus.NOT_FOUND) && createIfNotExists) {
createItem(appId, env, clusterName, namespaceName, item, request);
return;
}
}
throw ex;
}
//protect. only value,comment,lastModifiedBy can be modified
toUpdateItem.setComment(item.getComment());
toUpdateItem.setValue(item.getValue());
toUpdateItem.setDataChangeLastModifiedBy(item.getDataChangeLastModifiedBy());
itemService.updateItem(appId, Env.fromString(env), clusterName, namespaceName, toUpdateItem);
}
......
package com.ctrip.framework.apollo.openapi.v1.controller;
import com.ctrip.framework.apollo.common.dto.ReleaseDTO;
import com.ctrip.framework.apollo.common.exception.BadRequestException;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
import com.ctrip.framework.apollo.common.utils.RequestPrecondition;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.core.utils.StringUtils;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenReleaseDTO;
import com.ctrip.framework.apollo.openapi.util.OpenApiBeanUtils;
import com.ctrip.framework.apollo.portal.entity.model.NamespaceReleaseModel;
......@@ -38,7 +39,7 @@ public class ReleaseController {
public OpenReleaseDTO createRelease(@PathVariable String appId, @PathVariable String env,
@PathVariable String clusterName,
@PathVariable String namespaceName,
@RequestBody NamespaceReleaseModel model,
@RequestBody NamespaceReleaseDTO model,
HttpServletRequest request) {
checkModel(model != null);
......@@ -50,12 +51,14 @@ public class ReleaseController {
throw new BadRequestException("user(releaseBy) not exists");
}
model.setAppId(appId);
model.setEnv(Env.fromString(env).toString());
model.setClusterName(clusterName);
model.setNamespaceName(namespaceName);
NamespaceReleaseModel releaseModel = BeanUtils.transfrom(NamespaceReleaseModel.class, model);
releaseModel.setAppId(appId);
releaseModel.setEnv(Env.fromString(env).toString());
releaseModel.setClusterName(clusterName);
releaseModel.setNamespaceName(namespaceName);
return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(model));
return OpenApiBeanUtils.transformFromReleaseDTO(releaseService.publish(releaseModel));
}
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/latest", method = RequestMethod.GET)
......
......@@ -104,6 +104,7 @@
<module>apollo-assembly</module>
<module>apollo-demo</module>
<module>apollo-mockserver</module>
<module>apollo-openapi</module>
</modules>
<dependencyManagement>
......@@ -148,6 +149,11 @@
<artifactId>apollo-portal</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-openapi</artifactId>
<version>${project.version}</version>
</dependency>
<!-- ctrip internal dependencies, only used when ctrip profiles are enabled -->
<dependency>
<groupId>com.dianping.cat</groupId>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册