diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ItemController.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ItemController.java index 3a24de84c0edef11ca21adaab3933e95aac449e8..400e19bd167e5c3ec61aeb7437a4ec82a67f3646 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ItemController.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/controller/ItemController.java @@ -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); diff --git a/apollo-mockserver/pom.xml b/apollo-mockserver/pom.xml index d2c09b551183d81f2a688f193fa86fb917025322..eb8afef3584621356552fd844a80d4a9822b96c1 100644 --- a/apollo-mockserver/pom.xml +++ b/apollo-mockserver/pom.xml @@ -10,6 +10,11 @@ 4.0.0 apollo-mockserver + Apollo Mock Server + + + 1.7 + diff --git a/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java b/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java index 3c2ed099a30544ff929be7da1926b9db66b34ded..02b73355621a8649415e9d07b7ae569c26e3630e 100644 --- a/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java +++ b/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java @@ -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 configurations = prop.stringPropertyNames().stream().collect( - Collectors.toMap(key -> key, prop::getProperty)); + Map configurations = Maps.newHashMap(); + for (String propertyName : prop.stringPropertyNames()) { + configurations.put(propertyName, prop.getProperty(propertyName)); + } ApolloConfig apolloConfig = new ApolloConfig("someAppId", "someCluster", namespace, "someReleaseKey"); Map mergedConfigurations = mergeOverriddenProperties(namespace, configurations); diff --git a/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerApiTest.java b/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerApiTest.java index 7f62cb8dc88dbd8b918efc71c3e2df2167341c29..c99a5f63ab5ad95b9d66796bd674bbda5810cc6b 100644 --- a/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerApiTest.java +++ b/apollo-mockserver/src/test/java/com/ctrip/framework/apollo/mockserver/ApolloMockServerApiTest.java @@ -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 future = SettableFuture.create(); + final SettableFuture 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)); diff --git a/apollo-openapi/pom.xml b/apollo-openapi/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..6a44a9bbb299715d00685f3d4308e8e4c4870cb3 --- /dev/null +++ b/apollo-openapi/pom.xml @@ -0,0 +1,50 @@ + + + + apollo + com.ctrip.framework.apollo + 1.1.0-SNAPSHOT + + 4.0.0 + + apollo-openapi + Apollo Open Api + + + 1.7 + + + + + com.ctrip.framework.apollo + apollo-core + + + org.apache.httpcomponents + httpclient + + + commons-logging + commons-logging + + + + + org.slf4j + jcl-over-slf4j + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + org.apache.logging.log4j + log4j-core + test + + + + diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/ApolloOpenApiClient.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/ApolloOpenApiClient.java new file mode 100644 index 0000000000000000000000000000000000000000..f87a28f7cc2d544ce7b83069ac763da02cc6cbed --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/ApolloOpenApiClient.java @@ -0,0 +1,209 @@ +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. + *
+ * For more information, please refer Apollo Wiki. + * + */ +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 getEnvClusterInfo(String appId) { + return appService.getEnvClusterInfo(appId); + } + + /** + * Get the namespaces + */ + public List 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 null 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); + } + } +} diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/constant/ApolloOpenApiConstants.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/constant/ApolloOpenApiConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..e88759c9ce9b687ec426bc20fe95158841819767 --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/constant/ApolloOpenApiConstants.java @@ -0,0 +1,9 @@ +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"; + +} diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/exception/ApolloOpenApiException.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/exception/ApolloOpenApiException.java new file mode 100644 index 0000000000000000000000000000000000000000..af20a904ceb5a160fc85d91a09b857cfb654a26b --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/exception/ApolloOpenApiException.java @@ -0,0 +1,9 @@ +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)); + } +} diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/AbstractOpenApiService.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/AbstractOpenApiService.java new file mode 100644 index 0000000000000000000000000000000000000000..3093df6cd44101aade5f55a81b2d972abe32d145 --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/AbstractOpenApiService.java @@ -0,0 +1,106 @@ +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"); + } + +} diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/AppOpenApiService.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/AppOpenApiService.java new file mode 100644 index 0000000000000000000000000000000000000000..8358c1c90be7be63bf8bdee2e1be24ba210be24c --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/AppOpenApiService.java @@ -0,0 +1,31 @@ +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>() { + }.getType(); + + public AppOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) { + super(client, baseUrl, gson); + } + + public List 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); + } + } +} diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/ItemOpenApiService.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/ItemOpenApiService.java new file mode 100644 index 0000000000000000000000000000000000000000..dd81c5bd428bad65e66de1538aae5138d5724203 --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/ItemOpenApiService.java @@ -0,0 +1,124 @@ +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); + } + + } +} diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/NamespaceOpenApiService.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/NamespaceOpenApiService.java new file mode 100644 index 0000000000000000000000000000000000000000..15fa8f64dfd5a7aa8b6c6f45e814bcb305ab1c49 --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/NamespaceOpenApiService.java @@ -0,0 +1,109 @@ +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>() { + }.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 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); + } + } +} diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/ReleaseOpenApiService.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/ReleaseOpenApiService.java new file mode 100644 index 0000000000000000000000000000000000000000..f06023ac4d06c7ebea95741ac006a237cf2227dd --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/client/service/ReleaseOpenApiService.java @@ -0,0 +1,67 @@ +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); + } + } + +} diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/BaseDTO.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/BaseDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..dbc2645111336deb2701b92a844409c158a0eb5d --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/BaseDTO.java @@ -0,0 +1,46 @@ +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; + } +} diff --git a/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/NamespaceReleaseDTO.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/NamespaceReleaseDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..c86759c0f249f2ac600d49fe359ef60ad8e6c9ca --- /dev/null +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/NamespaceReleaseDTO.java @@ -0,0 +1,42 @@ +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; + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenAppNamespaceDTO.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenAppNamespaceDTO.java similarity index 94% rename from apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenAppNamespaceDTO.java rename to apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenAppNamespaceDTO.java index e7b1c0bac10c82238980b07ceac958936f8ac688..c067403d5666117df12dbe404d7c2525d52d19e7 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenAppNamespaceDTO.java +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenAppNamespaceDTO.java @@ -1,8 +1,5 @@ package com.ctrip.framework.apollo.openapi.dto; - -import com.ctrip.framework.apollo.common.dto.BaseDTO; - public class OpenAppNamespaceDTO extends BaseDTO { private String name; diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenEnvClusterDTO.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenEnvClusterDTO.java similarity index 100% rename from apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenEnvClusterDTO.java rename to apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenEnvClusterDTO.java diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenItemDTO.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenItemDTO.java similarity index 90% rename from apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenItemDTO.java rename to apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenItemDTO.java index 23393d17cae4db5d1d55faf523074c06fb27bb1f..622ddc04da6d61a5d20402d504aca3c6032dd033 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenItemDTO.java +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenItemDTO.java @@ -1,7 +1,5 @@ package com.ctrip.framework.apollo.openapi.dto; -import com.ctrip.framework.apollo.common.dto.BaseDTO; - public class OpenItemDTO extends BaseDTO { private String key; diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceDTO.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceDTO.java similarity index 95% rename from apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceDTO.java rename to apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceDTO.java index 70658795e8ee5696f54af3cf86c9bb4f8615b168..b3921eaad9726258ebadf600770dcc1393aa7530 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceDTO.java +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceDTO.java @@ -1,7 +1,5 @@ package com.ctrip.framework.apollo.openapi.dto; -import com.ctrip.framework.apollo.common.dto.BaseDTO; - import java.util.List; public class OpenNamespaceDTO extends BaseDTO { diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceLockDTO.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceLockDTO.java similarity index 100% rename from apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceLockDTO.java rename to apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenNamespaceLockDTO.java diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenReleaseDTO.java b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenReleaseDTO.java similarity index 95% rename from apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenReleaseDTO.java rename to apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenReleaseDTO.java index 99befb6c179d1e1a2620eb33ed0d4a33f16a1ae1..5d1c21c76ad1b5aafeaeb39f00c5c670c8f2c824 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenReleaseDTO.java +++ b/apollo-openapi/src/main/java/com/ctrip/framework/apollo/openapi/dto/OpenReleaseDTO.java @@ -1,7 +1,5 @@ package com.ctrip.framework.apollo.openapi.dto; -import com.ctrip.framework.apollo.common.dto.BaseDTO; - import java.util.Map; public class OpenReleaseDTO extends BaseDTO { diff --git a/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/ApolloOpenApiClientTest.java b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/ApolloOpenApiClientTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2aee85260028c8f8ff820cba605ba790d2268f49 --- /dev/null +++ b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/ApolloOpenApiClientTest.java @@ -0,0 +1,27 @@ +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(); + } +} diff --git a/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/AbstractOpenApiServiceTest.java b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/AbstractOpenApiServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7571a5f4267ce18a0e85c7d10cfa676df871c2ad --- /dev/null +++ b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/AbstractOpenApiServiceTest.java @@ -0,0 +1,42 @@ +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); + } + +} diff --git a/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/AppOpenApiServiceTest.java b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/AppOpenApiServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7a04ec1454d603f5f17edb7dc4be37d3e4f63155 --- /dev/null +++ b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/AppOpenApiServiceTest.java @@ -0,0 +1,52 @@ +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 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); + } +} diff --git a/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/ItemOpenApiServiceTest.java b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/ItemOpenApiServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5fa7325dc4a6f49d88161a94595a96cf3f7f6d6c --- /dev/null +++ b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/ItemOpenApiServiceTest.java @@ -0,0 +1,195 @@ +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 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 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 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 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); + } +} diff --git a/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/NamespaceOpenApiServiceTest.java b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/NamespaceOpenApiServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6f03bb49b0de1d5e1f47678a8063db0900c98a75 --- /dev/null +++ b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/NamespaceOpenApiServiceTest.java @@ -0,0 +1,145 @@ +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 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 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 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 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); + } +} diff --git a/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/ReleaseOpenApiServiceTest.java b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/ReleaseOpenApiServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ae1f86da0fbb857e513607f84391efd0a53cb95f --- /dev/null +++ b/apollo-openapi/src/test/java/com/ctrip/framework/apollo/openapi/client/service/ReleaseOpenApiServiceTest.java @@ -0,0 +1,98 @@ +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 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 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); + } +} diff --git a/apollo-openapi/src/test/resources/log4j2.xml b/apollo-openapi/src/test/resources/log4j2.xml new file mode 100644 index 0000000000000000000000000000000000000000..384e92d7a033e05cb41768b7aa7fcfee68cded82 --- /dev/null +++ b/apollo-openapi/src/test/resources/log4j2.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/apollo-portal/pom.xml b/apollo-portal/pom.xml index c3dd9b62e09e316b57323ee32cdfce069ba171a8..0ea96a69169b4d9dc35fc98061e647b93f21a2eb 100644 --- a/apollo-portal/pom.xml +++ b/apollo-portal/pom.xml @@ -22,6 +22,10 @@ com.ctrip.framework.apollo apollo-common + + com.ctrip.framework.apollo + apollo-openapi + com.h2database h2 diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ItemController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ItemController.java index 61a2445f94e0de0ba08ddad1e83e86d1b119c3f8..5c93f344246c5d99bff73d54481f82ccdb8996a0 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ItemController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ItemController.java @@ -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); } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ReleaseController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ReleaseController.java index 2a5911dcf79825e0e5c38d2200e1924c426cf9bf..55643d0e1eccdb884bbf1806033b84320c9b81c4 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ReleaseController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/ReleaseController.java @@ -1,11 +1,12 @@ 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) diff --git a/pom.xml b/pom.xml index c693eebfd7ae6886ad57e15ad975841cb15496cf..deff3bcb44d13dfc7461a5667069b2ac29c44ca0 100644 --- a/pom.xml +++ b/pom.xml @@ -104,6 +104,7 @@ apollo-assembly apollo-demo apollo-mockserver + apollo-openapi @@ -148,6 +149,11 @@ apollo-portal ${project.version} + + com.ctrip.framework.apollo + apollo-openapi + ${project.version} + com.dianping.cat