Commit fc4f3e85 by 张乐 Committed by GitHub

Merge pull request #465 from nobodyiam/json-yml-support

support json and yml config files
parents 8c71054d e546f67e
package com.ctrip.framework.apollo.adminservice.controller;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.ctrip.framework.apollo.biz.entity.Namespace;
import com.ctrip.framework.apollo.biz.entity.Release;
import com.ctrip.framework.apollo.biz.entity.ReleaseHistory;
import com.ctrip.framework.apollo.biz.repository.NamespaceRepository;
import com.ctrip.framework.apollo.biz.repository.ReleaseHistoryRepository;
import com.ctrip.framework.apollo.biz.repository.ReleaseRepository;
import com.ctrip.framework.apollo.biz.service.ReleaseHistoryService;
import com.ctrip.framework.apollo.common.constants.ReleaseOperation;
import com.ctrip.framework.apollo.common.dto.PageDTO;
import com.ctrip.framework.apollo.common.dto.ReleaseHistoryDTO;
import com.ctrip.framework.apollo.common.utils.BeanUtils;
......@@ -20,20 +12,15 @@ import com.ctrip.framework.apollo.common.utils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author Jason Song(song_s@ctrip.com)
......@@ -48,15 +35,6 @@ public class ReleaseHistoryController {
@Autowired
private ReleaseHistoryService releaseHistoryService;
@Autowired
private ReleaseRepository releaseRepository;
@Autowired
private NamespaceRepository namespaceRepository;
@Autowired
private ReleaseHistoryRepository releaseHistoryRepository;
@RequestMapping(value = "/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/releases/histories",
method = RequestMethod.GET)
public PageDTO<ReleaseHistoryDTO> findReleaseHistoriesByNamespace(
......@@ -80,81 +58,6 @@ public class ReleaseHistoryController {
releaseHistoryDTOs.add(dto);
}
return new PageDTO<>(releaseHistoryDTOs, pageable, result.getTotalElements());
}
@RequestMapping(value = "/release-histories/conversions", method = RequestMethod.POST)
public void releaseHistoryConversion(
@RequestParam(name = "namespaceId", required = false) String namespaceId) {
Iterable<Namespace> namespaces;
if (Strings.isNullOrEmpty(namespaceId)) {
namespaces = namespaceRepository.findAll();
} else {
Set<Long> idList = Arrays.stream(namespaceId.split(",")).map(Long::valueOf).collect
(Collectors.toSet());
namespaces = namespaceRepository.findAll(idList);
}
for (Namespace namespace : namespaces) {
List<Release> releases = releaseRepository
.findByAppIdAndClusterNameAndNamespaceNameOrderByIdAsc(namespace.getAppId(), namespace
.getClusterName(), namespace.getNamespaceName());
if (CollectionUtils.isEmpty(releases)) {
continue;
}
Release previousRelease = null;
Set<ReleaseHistory> releaseHistories = Sets.newLinkedHashSet();//ordered set
for (Release release : releases) {
List<ReleaseHistory> histories = releaseHistoryService.findReleaseHistoriesByReleaseId
(release.getId());
//already processed
if (!CollectionUtils.isEmpty(histories)) {
continue;
}
long previousReleaseId = previousRelease == null ? 0 : previousRelease.getId();
ReleaseHistory releaseHistory = assembleReleaseHistory(
release, ReleaseOperation .NORMAL_RELEASE, previousReleaseId);
releaseHistories.add(releaseHistory);
//rollback
if (release.isAbandoned() && previousRelease != null) {
releaseHistory.setDataChangeLastModifiedTime(release.getDataChangeCreatedTime());
ReleaseHistory rollBackReleaseHistory = assembleReleaseHistory(previousRelease,
ReleaseOperation.ROLLBACK, release.getId());
rollBackReleaseHistory.setDataChangeCreatedBy(release.getDataChangeLastModifiedBy());
rollBackReleaseHistory.setDataChangeCreatedTime(release.getDataChangeLastModifiedTime());
rollBackReleaseHistory.setDataChangeLastModifiedTime(release.getDataChangeLastModifiedTime());
releaseHistories.add(rollBackReleaseHistory);
} else {
previousRelease = release;
}
}
releaseHistoryRepository.save(releaseHistories);
}
}
public ReleaseHistory assembleReleaseHistory(Release release, int releaseOperation, long
previousReleaseId) {
ReleaseHistory releaseHistory = new ReleaseHistory();
releaseHistory.setAppId(release.getAppId());
releaseHistory.setClusterName(release.getClusterName());
releaseHistory.setNamespaceName(release.getNamespaceName());
releaseHistory.setBranchName(release.getClusterName());
releaseHistory.setReleaseId(release.getId());
releaseHistory.setPreviousReleaseId(previousReleaseId);
releaseHistory.setOperation(releaseOperation);
releaseHistory.setOperationContext("{}"); //default empty object
releaseHistory.setDataChangeCreatedBy(release.getDataChangeCreatedBy());
releaseHistory.setDataChangeCreatedTime(release.getDataChangeCreatedTime());
releaseHistory.setDataChangeLastModifiedTime(release.getDataChangeLastModifiedTime());
releaseHistory.setDataChangeLastModifiedBy("apollo"); //mark
return releaseHistory;
}
}
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class JsonConfigFile extends PlainTextConfigFile {
public JsonConfigFile(String namespace,
ConfigRepository configRepository) {
super(namespace, configRepository);
}
@Override
public ConfigFileFormat getConfigFileFormat() {
return ConfigFileFormat.JSON;
}
}
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.core.ConfigConsts;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public abstract class PlainTextConfigFile extends AbstractConfigFile {
public PlainTextConfigFile(String namespace, ConfigRepository configRepository) {
super(namespace, configRepository);
}
@Override
public String getContent() {
if (m_configProperties.get() == null) {
return null;
}
return m_configProperties.get().getProperty(ConfigConsts.CONFIG_FILE_CONTENT_KEY);
}
@Override
public boolean hasContent() {
if (m_configProperties.get() == null) {
return false;
}
return m_configProperties.get().containsKey(ConfigConsts.CONFIG_FILE_CONTENT_KEY);
}
}
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class XmlConfigFile extends AbstractConfigFile {
public class XmlConfigFile extends PlainTextConfigFile {
public XmlConfigFile(String namespace,
ConfigRepository configRepository) {
super(namespace, configRepository);
}
@Override
public String getContent() {
if (m_configProperties.get() == null) {
return null;
}
return m_configProperties.get().getProperty(ConfigConsts.CONFIG_FILE_CONTENT_KEY);
}
@Override
public boolean hasContent() {
if (m_configProperties.get() == null) {
return false;
}
return m_configProperties.get().containsKey(ConfigConsts.CONFIG_FILE_CONTENT_KEY);
}
@Override
public ConfigFileFormat getConfigFileFormat() {
return ConfigFileFormat.XML;
}
......
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class YamlConfigFile extends PlainTextConfigFile {
public YamlConfigFile(String namespace, ConfigRepository configRepository) {
super(namespace, configRepository);
}
@Override
public ConfigFileFormat getConfigFileFormat() {
return ConfigFileFormat.YAML;
}
}
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
/**
* @author Jason Song(song_s@ctrip.com)
*/
public class YmlConfigFile extends PlainTextConfigFile {
public YmlConfigFile(String namespace, ConfigRepository configRepository) {
super(namespace, configRepository);
}
@Override
public ConfigFileFormat getConfigFileFormat() {
return ConfigFileFormat.YML;
}
}
......@@ -5,10 +5,13 @@ import com.ctrip.framework.apollo.ConfigFile;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.internals.ConfigRepository;
import com.ctrip.framework.apollo.internals.DefaultConfig;
import com.ctrip.framework.apollo.internals.JsonConfigFile;
import com.ctrip.framework.apollo.internals.LocalFileConfigRepository;
import com.ctrip.framework.apollo.internals.PropertiesConfigFile;
import com.ctrip.framework.apollo.internals.RemoteConfigRepository;
import com.ctrip.framework.apollo.internals.XmlConfigFile;
import com.ctrip.framework.apollo.internals.YamlConfigFile;
import com.ctrip.framework.apollo.internals.YmlConfigFile;
import com.ctrip.framework.apollo.util.ConfigUtil;
import org.slf4j.Logger;
......@@ -40,6 +43,12 @@ public class DefaultConfigFactory implements ConfigFactory {
return new PropertiesConfigFile(namespace, configRepository);
case XML:
return new XmlConfigFile(namespace, configRepository);
case JSON:
return new JsonConfigFile(namespace, configRepository);
case YAML:
return new YamlConfigFile(namespace, configRepository);
case YML:
return new YmlConfigFile(namespace, configRepository);
}
return null;
......
......@@ -4,6 +4,7 @@ package com.ctrip.framework.apollo;
import com.ctrip.framework.apollo.integration.ConfigIntegrationTest;
import com.ctrip.framework.apollo.internals.DefaultConfigManagerTest;
import com.ctrip.framework.apollo.internals.DefaultConfigTest;
import com.ctrip.framework.apollo.internals.JsonConfigFileTest;
import com.ctrip.framework.apollo.internals.LocalFileConfigRepositoryTest;
import com.ctrip.framework.apollo.internals.PropertiesConfigFileTest;
import com.ctrip.framework.apollo.internals.RemoteConfigLongPollServiceTest;
......@@ -28,7 +29,7 @@ import org.junit.runners.Suite.SuiteClasses;
RemoteConfigRepositoryTest.class, SimpleConfigTest.class, DefaultConfigFactoryTest.class,
ConfigIntegrationTest.class, ExceptionUtilTest.class, XmlConfigFileTest.class,
PropertiesConfigFileTest.class, RemoteConfigLongPollServiceTest.class, DateParserTest.class,
DurationParserTest.class
DurationParserTest.class, JsonConfigFileTest.class
})
public class AllTests {
......
package com.ctrip.framework.apollo.internals;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith(MockitoJUnitRunner.class)
public class JsonConfigFileTest {
private String someNamespace;
@Mock
private ConfigRepository configRepository;
@Before
public void setUp() throws Exception {
someNamespace = "someName";
}
@Test
public void testWhenHasContent() throws Exception {
Properties someProperties = new Properties();
String key = ConfigConsts.CONFIG_FILE_CONTENT_KEY;
String someValue = "someValue";
someProperties.setProperty(key, someValue);
when(configRepository.getConfig()).thenReturn(someProperties);
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
assertEquals(ConfigFileFormat.JSON, configFile.getConfigFileFormat());
assertEquals(someNamespace, configFile.getNamespace());
assertTrue(configFile.hasContent());
assertEquals(someValue, configFile.getContent());
}
@Test
public void testWhenHasNoContent() throws Exception {
when(configRepository.getConfig()).thenReturn(null);
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
assertFalse(configFile.hasContent());
assertNull(configFile.getContent());
}
@Test
public void testWhenConfigRepositoryHasError() throws Exception {
when(configRepository.getConfig()).thenThrow(new RuntimeException("someError"));
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
assertFalse(configFile.hasContent());
assertNull(configFile.getContent());
}
@Test
public void testOnRepositoryChange() throws Exception {
Properties someProperties = new Properties();
String key = ConfigConsts.CONFIG_FILE_CONTENT_KEY;
String someValue = "someValue";
String anotherValue = "anotherValue";
someProperties.setProperty(key, someValue);
when(configRepository.getConfig()).thenReturn(someProperties);
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
assertEquals(someValue, configFile.getContent());
Properties anotherProperties = new Properties();
anotherProperties.setProperty(key, anotherValue);
configFile.onRepositoryChange(someNamespace, anotherProperties);
assertEquals(anotherValue, configFile.getContent());
}
@Test
public void testWhenConfigRepositoryHasErrorAndThenRecovered() throws Exception {
Properties someProperties = new Properties();
String key = ConfigConsts.CONFIG_FILE_CONTENT_KEY;
String someValue = "someValue";
someProperties.setProperty(key, someValue);
when(configRepository.getConfig()).thenThrow(new RuntimeException("someError"));
JsonConfigFile configFile = new JsonConfigFile(someNamespace, configRepository);
assertFalse(configFile.hasContent());
assertNull(configFile.getContent());
configFile.onRepositoryChange(someNamespace, someProperties);
assertTrue(configFile.hasContent());
assertEquals(someValue, configFile.getContent());
}
}
......@@ -5,9 +5,12 @@ import com.ctrip.framework.apollo.ConfigFile;
import com.ctrip.framework.apollo.core.enums.ConfigFileFormat;
import com.ctrip.framework.apollo.core.enums.Env;
import com.ctrip.framework.apollo.internals.DefaultConfig;
import com.ctrip.framework.apollo.internals.JsonConfigFile;
import com.ctrip.framework.apollo.internals.LocalFileConfigRepository;
import com.ctrip.framework.apollo.internals.PropertiesConfigFile;
import com.ctrip.framework.apollo.internals.XmlConfigFile;
import com.ctrip.framework.apollo.internals.YamlConfigFile;
import com.ctrip.framework.apollo.internals.YmlConfigFile;
import com.ctrip.framework.apollo.util.ConfigUtil;
import org.junit.Before;
......@@ -79,6 +82,7 @@ public class DefaultConfigFactoryTest extends ComponentTestCase {
public void testCreateConfigFile() throws Exception {
String someNamespace = "someName";
String anotherNamespace = "anotherName";
String yetAnotherNamespace = "yetAnotherNamespace";
Properties someProperties = new Properties();
LocalFileConfigRepository someLocalConfigRepo = mock(LocalFileConfigRepository.class);
......@@ -86,11 +90,18 @@ public class DefaultConfigFactoryTest extends ComponentTestCase {
doReturn(someLocalConfigRepo).when(defaultConfigFactory).createLocalConfigRepository(someNamespace);
doReturn(someLocalConfigRepo).when(defaultConfigFactory).createLocalConfigRepository(anotherNamespace);
doReturn(someLocalConfigRepo).when(defaultConfigFactory).createLocalConfigRepository(yetAnotherNamespace);
ConfigFile propertyConfigFile =
defaultConfigFactory.createConfigFile(someNamespace, ConfigFileFormat.Properties);
ConfigFile xmlConfigFile =
defaultConfigFactory.createConfigFile(anotherNamespace, ConfigFileFormat.XML);
ConfigFile jsonConfigFile =
defaultConfigFactory.createConfigFile(yetAnotherNamespace, ConfigFileFormat.JSON);
ConfigFile ymlConfigFile = defaultConfigFactory.createConfigFile(someNamespace,
ConfigFileFormat.YML);
ConfigFile yamlConfigFile = defaultConfigFactory.createConfigFile(someNamespace,
ConfigFileFormat.YAML);
assertThat("Should create PropertiesConfigFile for properties format", propertyConfigFile, is(instanceOf(
PropertiesConfigFile.class)));
......@@ -99,6 +110,19 @@ public class DefaultConfigFactoryTest extends ComponentTestCase {
assertThat("Should create XmlConfigFile for xml format", xmlConfigFile, is(instanceOf(
XmlConfigFile.class)));
assertEquals(anotherNamespace, xmlConfigFile.getNamespace());
assertThat("Should create JsonConfigFile for json format", jsonConfigFile, is(instanceOf(
JsonConfigFile.class)));
assertEquals(yetAnotherNamespace, jsonConfigFile.getNamespace());
assertThat("Should create YmlConfigFile for yml format", ymlConfigFile, is(instanceOf(
YmlConfigFile.class)));
assertEquals(someNamespace, ymlConfigFile.getNamespace());
assertThat("Should create YamlConfigFile for yaml format", yamlConfigFile, is(instanceOf(
YamlConfigFile.class)));
assertEquals(someNamespace, yamlConfigFile.getNamespace());
}
public static class MockConfigUtil extends ConfigUtil {
......
......@@ -6,7 +6,7 @@ import com.ctrip.framework.apollo.core.utils.StringUtils;
* @author Jason Song(song_s@ctrip.com)
*/
public enum ConfigFileFormat {
Properties("properties"), XML("xml");
Properties("properties"), XML("xml"), JSON("json"), YML("yml"), YAML("yaml");
private String value;
......@@ -27,6 +27,12 @@ public enum ConfigFileFormat {
return Properties;
case "xml":
return XML;
case "json":
return JSON;
case "yml":
return YML;
case "yaml":
return YAML;
}
throw new IllegalArgumentException(value + " can not map enum");
}
......
......@@ -97,6 +97,9 @@
<select class="form-control" name="format" ng-model="appNamespace.format">
<option value="properties">properties</option>
<option value="xml">xml</option>
<option value="json">json</option>
<option value="yml">yml</option>
<option value="yaml">yaml</option>
</select>
</div>
......
......@@ -226,7 +226,8 @@ function directive($window, toastr, AppUtil, EventManager, PermissionService, Na
//namespace view name hide suffix
namespace.viewName =
namespace.baseInfo.namespaceName.replace(".xml", "").replace(
".properties", "");
".properties", "").replace(".json", "").replace(".yml", "")
.replace(".yaml", "");
if (!viewType) {
if (namespace.isPropertiesFormat) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment