Merge pull request #2288 from alibaba/develop
Merge develop into develop_1.2.0
This commit is contained in:
commit
50e511d904
@ -1,8 +1,6 @@
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
- xchaos8@126.com
|
||||
- nacos_dev@linux.alibaba.com
|
||||
- dev-nacos@googlegroups.com
|
||||
- mw_configcenter@list.alibaba-inc.com
|
||||
on_success: change
|
||||
@ -30,7 +28,7 @@ before_install:
|
||||
|
||||
script:
|
||||
- mvn -B clean package apache-rat:check findbugs:findbugs -Dmaven.test.skip=true
|
||||
- mvn -Prelease-nacos clean install -U
|
||||
- mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U
|
||||
- mvn clean package -Pit-test
|
||||
after_success:
|
||||
- mvn clean package -Pit-test
|
||||
|
@ -62,6 +62,8 @@ public class Constants {
|
||||
|
||||
public static final String CONFIG_VERSION = "Config-Version";
|
||||
|
||||
public static final String CONFIG_TYPE = "Config-Type";
|
||||
|
||||
public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
|
||||
|
||||
public static final String SPACING_INTERVAL = "client-spacing-interval";
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.api.config;
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ConfigChangeEvent
|
||||
*
|
||||
* @author rushsky518
|
||||
*/
|
||||
public class ConfigChangeEvent {
|
||||
private Map<String, ConfigChangeItem> data;
|
||||
|
||||
public ConfigChangeEvent(Map<String, ConfigChangeItem> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public ConfigChangeItem getChangeItem(String key) {
|
||||
return data.get(key);
|
||||
}
|
||||
|
||||
public Collection<ConfigChangeItem> getChangeItems() {
|
||||
return data.values();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.api.config;
|
||||
|
||||
/**
|
||||
* ConfigChangeItem
|
||||
*
|
||||
* @author rushsky518
|
||||
*/
|
||||
public class ConfigChangeItem {
|
||||
private String key;
|
||||
private String oldValue;
|
||||
private String newValue;
|
||||
|
||||
private PropertyChangeType type;
|
||||
|
||||
public ConfigChangeItem(String key, String oldValue, String newValue) {
|
||||
this.key = key;
|
||||
this.oldValue = oldValue;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getOldValue() {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public void setOldValue(String oldValue) {
|
||||
this.oldValue = oldValue;
|
||||
}
|
||||
|
||||
public String getNewValue() {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
public void setNewValue(String newValue) {
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
public PropertyChangeType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(PropertyChangeType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConfigChangeItem{" +
|
||||
"key='" + key + '\'' +
|
||||
", oldValue='" + oldValue + '\'' +
|
||||
", newValue='" + newValue + '\'' +
|
||||
", type=" + type +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 = the "License"");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.api.config;
|
||||
|
||||
/**
|
||||
* Property Change Type
|
||||
*
|
||||
* @author rushsky518
|
||||
*/
|
||||
public enum PropertyChangeType {
|
||||
/** add */
|
||||
ADDED,
|
||||
/** modified */
|
||||
MODIFIED,
|
||||
/** deleted */
|
||||
DELETED
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.api.config.listener;
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ConfigChangeParser
|
||||
*
|
||||
* @author rushsky518
|
||||
*/
|
||||
public interface ConfigChangeParser {
|
||||
/**
|
||||
* judge type
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
boolean isResponsibleFor(String type);
|
||||
|
||||
/**
|
||||
* compare old and new data
|
||||
* @param oldContent
|
||||
* @param newContent
|
||||
* @param type
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
Map<String, ConfigChangeItem> doParse(String oldContent, String newContent, String type) throws IOException;
|
||||
}
|
@ -116,6 +116,10 @@
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
@ -140,9 +140,8 @@ public class NacosConfigService implements ConfigService {
|
||||
}
|
||||
|
||||
try {
|
||||
content = worker.getServerConfig(dataId, group, tenant, timeoutMs);
|
||||
|
||||
cr.setContent(content);
|
||||
String[] ct = worker.getServerConfig(dataId, group, tenant, timeoutMs);
|
||||
cr.setContent(ct[0]);
|
||||
|
||||
configFilterChainManager.doFilter(null, cr);
|
||||
content = cr.getContent();
|
||||
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.client.config.impl;
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
import com.alibaba.nacos.api.config.PropertyChangeType;
|
||||
import com.alibaba.nacos.api.config.listener.ConfigChangeParser;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AbstractConfigChangeParser
|
||||
*
|
||||
* @author rushsky518
|
||||
*/
|
||||
public abstract class AbstractConfigChangeParser implements ConfigChangeParser {
|
||||
private String configType;
|
||||
|
||||
public AbstractConfigChangeParser(String configType) {
|
||||
this.configType = configType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResponsibleFor(String type) {
|
||||
return this.configType.equalsIgnoreCase(type);
|
||||
}
|
||||
|
||||
protected Map<String, ConfigChangeItem> filterChangeData(Map oldMap, Map newMap) {
|
||||
Map<String, ConfigChangeItem> result = new HashMap<String, ConfigChangeItem>(16);
|
||||
for (Iterator<Map.Entry<String, Object>> entryItr = oldMap.entrySet().iterator(); entryItr.hasNext();) {
|
||||
Map.Entry<String, Object> e = entryItr.next();
|
||||
ConfigChangeItem cci = null;
|
||||
if (newMap.containsKey(e.getKey())) {
|
||||
if (e.getValue().equals(newMap.get(e.getKey()))) {
|
||||
continue;
|
||||
}
|
||||
cci = new ConfigChangeItem(e.getKey(), e.getValue().toString(), newMap.get(e.getKey()).toString());
|
||||
cci.setType(PropertyChangeType.MODIFIED);
|
||||
} else {
|
||||
cci = new ConfigChangeItem(e.getKey(), e.getValue().toString(), null);
|
||||
cci.setType(PropertyChangeType.DELETED);
|
||||
}
|
||||
|
||||
result.put(e.getKey(), cci);
|
||||
}
|
||||
|
||||
for (Iterator<Map.Entry<String, Object>> entryItr = newMap.entrySet().iterator(); entryItr.hasNext();) {
|
||||
Map.Entry<String, Object> e = entryItr.next();
|
||||
if (!oldMap.containsKey(e.getKey())) {
|
||||
ConfigChangeItem cci = new ConfigChangeItem(e.getKey(), null, e.getValue().toString());
|
||||
cci.setType(PropertyChangeType.ADDED);
|
||||
result.put(e.getKey(), cci);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -16,11 +16,13 @@
|
||||
package com.alibaba.nacos.client.config.impl;
|
||||
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.config.ConfigChangeEvent;
|
||||
import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
|
||||
import com.alibaba.nacos.api.config.listener.Listener;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager;
|
||||
import com.alibaba.nacos.client.config.filter.impl.ConfigResponse;
|
||||
import com.alibaba.nacos.client.config.listener.impl.AbstractConfigChangeListener;
|
||||
import com.alibaba.nacos.client.config.utils.MD5;
|
||||
import com.alibaba.nacos.client.utils.LogUtils;
|
||||
import com.alibaba.nacos.client.utils.TenantUtil;
|
||||
@ -28,6 +30,7 @@ import org.slf4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
@ -59,9 +62,17 @@ public class CacheData {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String newContent) {
|
||||
this.content = newContent;
|
||||
this.md5 = getMd5String(content);
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
this.md5 = getMd5String(this.content);
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,7 +85,9 @@ public class CacheData {
|
||||
if (null == listener) {
|
||||
throw new IllegalArgumentException("listener is null");
|
||||
}
|
||||
ManagerListenerWrap wrap = new ManagerListenerWrap(listener, md5);
|
||||
ManagerListenerWrap wrap = (listener instanceof AbstractConfigChangeListener) ?
|
||||
new ManagerListenerWrap(listener, md5, content) : new ManagerListenerWrap(listener, md5);
|
||||
|
||||
if (listeners.addIfAbsent(wrap)) {
|
||||
LOGGER.info("[{}] [add-listener] ok, tenant={}, dataId={}, group={}, cnt={}", name, tenant, dataId, group,
|
||||
listeners.size());
|
||||
@ -158,12 +171,12 @@ public class CacheData {
|
||||
void checkListenerMd5() {
|
||||
for (ManagerListenerWrap wrap : listeners) {
|
||||
if (!md5.equals(wrap.lastCallMd5)) {
|
||||
safeNotifyListener(dataId, group, content, md5, wrap);
|
||||
safeNotifyListener(dataId, group, content, type, md5, wrap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void safeNotifyListener(final String dataId, final String group, final String content,
|
||||
private void safeNotifyListener(final String dataId, final String group, final String content, final String type,
|
||||
final String md5, final ManagerListenerWrap listenerWrap) {
|
||||
final Listener listener = listenerWrap.listener;
|
||||
|
||||
@ -188,6 +201,15 @@ public class CacheData {
|
||||
configFilterChainManager.doFilter(null, cr);
|
||||
String contentTmp = cr.getContent();
|
||||
listener.receiveConfigInfo(contentTmp);
|
||||
|
||||
// compare lastContent and content
|
||||
if (listener instanceof AbstractConfigChangeListener) {
|
||||
Map data = ConfigChangeHandler.getInstance().parseChangeData(listenerWrap.lastContent, content, type);
|
||||
ConfigChangeEvent event = new ConfigChangeEvent(data);
|
||||
((AbstractConfigChangeListener)listener).receiveConfigChange(event);
|
||||
listenerWrap.lastContent = content;
|
||||
}
|
||||
|
||||
listenerWrap.lastCallMd5 = md5;
|
||||
LOGGER.info("[{}] [notify-ok] dataId={}, group={}, md5={}, listener={} ", name, dataId, group, md5,
|
||||
listener);
|
||||
@ -282,11 +304,13 @@ public class CacheData {
|
||||
private volatile String content;
|
||||
private int taskId;
|
||||
private volatile boolean isInitializing = true;
|
||||
private String type;
|
||||
}
|
||||
|
||||
class ManagerListenerWrap {
|
||||
final Listener listener;
|
||||
String lastCallMd5 = CacheData.getMd5String(null);
|
||||
String lastContent = null;
|
||||
|
||||
ManagerListenerWrap(Listener listener) {
|
||||
this.listener = listener;
|
||||
@ -297,6 +321,12 @@ class ManagerListenerWrap {
|
||||
this.lastCallMd5 = md5;
|
||||
}
|
||||
|
||||
ManagerListenerWrap(Listener listener, String md5, String lastContent) {
|
||||
this.listener = listener;
|
||||
this.lastCallMd5 = md5;
|
||||
this.lastContent = lastContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (null == obj || obj.getClass() != getClass()) {
|
||||
|
@ -17,6 +17,7 @@ package com.alibaba.nacos.client.config.impl;
|
||||
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.common.Constants;
|
||||
import com.alibaba.nacos.api.config.ConfigType;
|
||||
import com.alibaba.nacos.api.config.listener.Listener;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.config.common.GroupKey;
|
||||
@ -46,6 +47,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static com.alibaba.nacos.api.common.Constants.LINE_SEPARATOR;
|
||||
import static com.alibaba.nacos.api.common.Constants.WORD_SEPARATOR;
|
||||
import static com.alibaba.nacos.api.common.Constants.CONFIG_TYPE;
|
||||
|
||||
/**
|
||||
* Longpolling
|
||||
@ -183,8 +185,8 @@ public class ClientWorker {
|
||||
cache = new CacheData(configFilterChainManager, agent.getName(), dataId, group, tenant);
|
||||
// fix issue # 1317
|
||||
if (enableRemoteSyncConfig) {
|
||||
String content = getServerConfig(dataId, group, tenant, 3000L);
|
||||
cache.setContent(content);
|
||||
String[] ct = getServerConfig(dataId, group, tenant, 3000L);
|
||||
cache.setContent(ct[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,8 +212,9 @@ public class ClientWorker {
|
||||
return cacheMap.get().get(GroupKey.getKeyTenant(dataId, group, tenant));
|
||||
}
|
||||
|
||||
public String getServerConfig(String dataId, String group, String tenant, long readTimeout)
|
||||
public String[] getServerConfig(String dataId, String group, String tenant, long readTimeout)
|
||||
throws NacosException {
|
||||
String[] ct = new String[2];
|
||||
if (StringUtils.isBlank(group)) {
|
||||
group = Constants.DEFAULT_GROUP;
|
||||
}
|
||||
@ -236,10 +239,16 @@ public class ClientWorker {
|
||||
switch (result.code) {
|
||||
case HttpURLConnection.HTTP_OK:
|
||||
LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, result.content);
|
||||
return result.content;
|
||||
ct[0] = result.content;
|
||||
if (result.headers.containsKey(CONFIG_TYPE)) {
|
||||
ct[1] = result.headers.get(CONFIG_TYPE).get(0);
|
||||
} else {
|
||||
ct[1] = ConfigType.TEXT.getType();
|
||||
}
|
||||
return ct;
|
||||
case HttpURLConnection.HTTP_NOT_FOUND:
|
||||
LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, null);
|
||||
return null;
|
||||
return ct;
|
||||
case HttpURLConnection.HTTP_CONFLICT: {
|
||||
LOGGER.error(
|
||||
"[{}] [sub-server-error] get server config being modified concurrently, dataId={}, group={}, "
|
||||
@ -517,12 +526,15 @@ public class ClientWorker {
|
||||
tenant = key[2];
|
||||
}
|
||||
try {
|
||||
String content = getServerConfig(dataId, group, tenant, 3000L);
|
||||
String[] ct = getServerConfig(dataId, group, tenant, 3000L);
|
||||
CacheData cache = cacheMap.get().get(GroupKey.getKeyTenant(dataId, group, tenant));
|
||||
cache.setContent(content);
|
||||
LOGGER.info("[{}] [data-received] dataId={}, group={}, tenant={}, md5={}, content={}",
|
||||
cache.setContent(ct[0]);
|
||||
if (null != ct[1]) {
|
||||
cache.setType(ct[1]);
|
||||
}
|
||||
LOGGER.info("[{}] [data-received] dataId={}, group={}, tenant={}, md5={}, content={}, type={}",
|
||||
agent.getName(), dataId, group, tenant, cache.getMd5(),
|
||||
ContentUtils.truncateContent(content));
|
||||
ContentUtils.truncateContent(ct[0]), ct[1]);
|
||||
} catch (NacosException ioe) {
|
||||
String message = String.format(
|
||||
"[%s] [get-update] get changed config exception. dataId=%s, group=%s, tenant=%s",
|
||||
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.client.config.impl;
|
||||
|
||||
import com.alibaba.nacos.api.config.listener.ConfigChangeParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Map;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* ConfigChangeHandler
|
||||
*
|
||||
* @author rushsky518
|
||||
*/
|
||||
public class ConfigChangeHandler {
|
||||
private static class ConfigChangeHandlerHolder {
|
||||
private final static ConfigChangeHandler INSTANCE = new ConfigChangeHandler();
|
||||
}
|
||||
|
||||
private ConfigChangeHandler() {
|
||||
this.parserList = new LinkedList<ConfigChangeParser>();
|
||||
|
||||
ServiceLoader<ConfigChangeParser> loader = ServiceLoader.load(ConfigChangeParser.class);
|
||||
Iterator<ConfigChangeParser> itr = loader.iterator();
|
||||
while (itr.hasNext()) {
|
||||
this.parserList.add(itr.next());
|
||||
}
|
||||
|
||||
this.parserList.add(new PropertiesChangeParser());
|
||||
this.parserList.add(new YmlChangeParser());
|
||||
}
|
||||
|
||||
public static ConfigChangeHandler getInstance() {
|
||||
return ConfigChangeHandlerHolder.INSTANCE;
|
||||
}
|
||||
|
||||
public Map parseChangeData(String oldContent, String newContent, String type) throws IOException {
|
||||
for (ConfigChangeParser changeParser: this.parserList) {
|
||||
if (changeParser.isResponsibleFor(type)) {
|
||||
return changeParser.doParse(oldContent, newContent, type);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
private List<ConfigChangeParser> parserList;
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.client.config.impl;
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
import com.alibaba.nacos.client.utils.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* PropertiesChangeParser
|
||||
*
|
||||
* @author rushsky518
|
||||
*/
|
||||
public class PropertiesChangeParser extends AbstractConfigChangeParser {
|
||||
public PropertiesChangeParser() {
|
||||
super("properties");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ConfigChangeItem> doParse(String oldContent, String newContent, String type) throws IOException {
|
||||
Properties oldProps = new Properties();
|
||||
Properties newProps = new Properties();
|
||||
|
||||
if (StringUtils.isNotBlank(oldContent)) {
|
||||
oldProps.load(new StringReader(oldContent));
|
||||
}
|
||||
if (StringUtils.isNotBlank(newContent)) {
|
||||
newProps.load(new StringReader(newContent));
|
||||
}
|
||||
|
||||
return filterChangeData(oldProps, newProps);
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.client.config.impl;
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
import com.alibaba.nacos.client.utils.StringUtils;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* YmlChangeParser
|
||||
*
|
||||
* @author rushsky518
|
||||
*/
|
||||
public class YmlChangeParser extends AbstractConfigChangeParser {
|
||||
public YmlChangeParser() {
|
||||
super("yaml");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ConfigChangeItem> doParse(String oldContent, String newContent, String type) {
|
||||
Map<String, Object> oldMap = Collections.emptyMap();
|
||||
Map<String, Object> newMap = Collections.emptyMap();
|
||||
|
||||
if (StringUtils.isNotBlank(oldContent)) {
|
||||
oldMap = (new Yaml()).load(oldContent);
|
||||
oldMap = getFlattenedMap(oldMap);
|
||||
}
|
||||
if (StringUtils.isNotBlank(newContent)) {
|
||||
newMap = (new Yaml()).load(newContent);
|
||||
newMap = getFlattenedMap(newMap);
|
||||
}
|
||||
|
||||
return filterChangeData(oldMap, newMap);
|
||||
}
|
||||
|
||||
private final Map<String, Object> getFlattenedMap(Map<String, Object> source) {
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>(128);
|
||||
buildFlattenedMap(result, source, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, String path) {
|
||||
for (Iterator<Map.Entry<String, Object>> itr = source.entrySet().iterator(); itr.hasNext(); ) {
|
||||
Map.Entry<String, Object> e = itr.next();
|
||||
String key = e.getKey();
|
||||
if (StringUtils.isNotBlank(path)) {
|
||||
if (e.getKey().startsWith("[")) {
|
||||
key = path + key;
|
||||
} else {
|
||||
key = path + '.' + key;
|
||||
}
|
||||
}
|
||||
if (e.getValue() instanceof String) {
|
||||
result.put(key, e.getValue());
|
||||
} else if (e.getValue() instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) e.getValue();
|
||||
buildFlattenedMap(result, map, key);
|
||||
} else if (e.getValue() instanceof Collection) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Object> collection = (Collection<Object>) e.getValue();
|
||||
if (collection.isEmpty()) {
|
||||
result.put(key, "");
|
||||
} else {
|
||||
int count = 0;
|
||||
for (Object object : collection) {
|
||||
buildFlattenedMap(result, Collections.singletonMap("[" + (count++) + "]", object), key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.put(key, (e.getValue() != null ? e.getValue() : ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.client.config.listener.impl;
|
||||
|
||||
import com.alibaba.nacos.api.config.listener.AbstractListener;
|
||||
import com.alibaba.nacos.api.config.ConfigChangeEvent;
|
||||
|
||||
/**
|
||||
* AbstractConfigChangeListener
|
||||
*
|
||||
* @author rushsky518
|
||||
*/
|
||||
public abstract class AbstractConfigChangeListener extends AbstractListener {
|
||||
/**
|
||||
* handle config change
|
||||
* @param event
|
||||
*/
|
||||
public abstract void receiveConfigChange(final ConfigChangeEvent event);
|
||||
|
||||
@Override
|
||||
public void receiveConfigInfo(final String configInfo) {}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.client.config.listener.impl;
|
||||
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
import com.alibaba.nacos.client.config.impl.ConfigChangeHandler;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigChangeHandlerTest {
|
||||
@Test
|
||||
public void testParseProperties() throws IOException {
|
||||
Map properties = ConfigChangeHandler.getInstance().parseChangeData("", "app.name = nacos", "properties");
|
||||
Assert.assertEquals("nacos", ((ConfigChangeItem)properties.get("app.name")).getNewValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseYaml() throws IOException {
|
||||
Map properties = ConfigChangeHandler.getInstance().parseChangeData("", "app:\n name: nacos", "yaml");
|
||||
Assert.assertEquals("nacos", ((ConfigChangeItem)properties.get("app.name")).getNewValue());
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.client.config.listener.impl;
|
||||
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
import com.alibaba.nacos.client.config.impl.PropertiesChangeParser;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class PropertiesChangeParserTest {
|
||||
private PropertiesChangeParser parser = new PropertiesChangeParser();
|
||||
private final String type = "properties";
|
||||
|
||||
@Test
|
||||
public void testType() {
|
||||
Assert.assertEquals(true, parser.isResponsibleFor(type));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddKey() throws IOException {
|
||||
Map<String, ConfigChangeItem> map = parser.doParse("", "app.name = nacos", type);
|
||||
Assert.assertEquals(null, map.get("app.name").getOldValue());
|
||||
Assert.assertEquals("nacos", map.get("app.name").getNewValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveKey() throws IOException {
|
||||
Map<String, ConfigChangeItem> map = parser.doParse("app.name = nacos", "", type);
|
||||
Assert.assertEquals("nacos", map.get("app.name").getOldValue());
|
||||
Assert.assertEquals(null, map.get("app.name").getNewValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModifyKey() throws IOException {
|
||||
Map<String, ConfigChangeItem> map = parser.doParse("app.name = rocketMQ", "app.name = nacos", type);
|
||||
Assert.assertEquals("rocketMQ", map.get("app.name").getOldValue());
|
||||
Assert.assertEquals("nacos", map.get("app.name").getNewValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.client.config.listener.impl;
|
||||
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
import com.alibaba.nacos.client.config.impl.YmlChangeParser;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class YmlChangeParserTest {
|
||||
private YmlChangeParser parser = new YmlChangeParser();
|
||||
private final String type = "yaml";
|
||||
|
||||
@Test
|
||||
public void testType() {
|
||||
Assert.assertEquals(true, parser.isResponsibleFor(type));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddKey() throws IOException {
|
||||
Map<String, ConfigChangeItem> map = parser.doParse("", "app:\n name: nacos", type);
|
||||
Assert.assertEquals(null, map.get("app.name").getOldValue());
|
||||
Assert.assertEquals("nacos", map.get("app.name").getNewValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveKey() throws IOException {
|
||||
Map<String, ConfigChangeItem> map = parser.doParse("app:\n name: nacos", "", type);
|
||||
Assert.assertEquals("nacos", map.get("app.name").getOldValue());
|
||||
Assert.assertEquals(null, map.get("app.name").getNewValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModifyKey() throws IOException {
|
||||
Map<String, ConfigChangeItem> map = parser.doParse("app:\n name: rocketMQ", "app:\n name: nacos", type);
|
||||
Assert.assertEquals("rocketMQ", map.get("app.name").getOldValue());
|
||||
Assert.assertEquals("nacos", map.get("app.name").getNewValue());
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,6 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* Config main
|
||||
*
|
||||
@ -30,7 +28,7 @@ import java.net.UnknownHostException;
|
||||
@SpringBootApplication
|
||||
public class Config {
|
||||
|
||||
public static void main(String[] args) throws UnknownHostException {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Config.class, args);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.config.server.auth;
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,7 @@ package com.alibaba.nacos.config.server.controller;
|
||||
import com.alibaba.nacos.config.server.auth.ConfigResourceParser;
|
||||
import com.alibaba.nacos.config.server.constant.Constants;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.config.server.controller.parameters.SameNamespaceCloneConfigBean;
|
||||
import com.alibaba.nacos.config.server.model.*;
|
||||
import com.alibaba.nacos.config.server.result.ResultBuilder;
|
||||
import com.alibaba.nacos.config.server.result.code.ResultCodeEnum;
|
||||
@ -49,6 +50,7 @@ import java.io.IOException;
|
||||
import java.net.URLDecoder;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.alibaba.nacos.core.utils.SystemUtils.LOCAL_IP;
|
||||
|
||||
@ -69,7 +71,7 @@ public class ConfigController {
|
||||
|
||||
private static final String EXPORT_CONFIG_FILE_NAME_EXT = ".zip";
|
||||
|
||||
private static final String EXPORT_CONFIG_FILE_NAME_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
private static final String EXPORT_CONFIG_FILE_NAME_DATE_FORMAT = "yyyyMMddHHmmss";
|
||||
|
||||
private final ConfigServletInner inner;
|
||||
|
||||
@ -542,15 +544,20 @@ public class ConfigController {
|
||||
return ResultBuilder.buildSuccessResult("导入成功", saveResult);
|
||||
}
|
||||
|
||||
@GetMapping(params = "clone=true")
|
||||
@Secured(action = ActionTypes.READ, parser = ConfigResourceParser.class)
|
||||
@PostMapping(params = "clone=true")
|
||||
public RestResult<Map<String, Object>> cloneConfig(HttpServletRequest request,
|
||||
@RequestParam(value = "src_user", required = false) String srcUser,
|
||||
@RequestParam(value = "tenant", required = true) String namespace,
|
||||
@RequestParam(value = "ids", required = true) List<Long> ids,
|
||||
@RequestBody(required = true)
|
||||
List<SameNamespaceCloneConfigBean> configBeansList,
|
||||
@RequestParam(value = "policy", defaultValue = "ABORT")
|
||||
SameConfigPolicy policy) throws NacosException {
|
||||
Map<String, Object> failedData = new HashMap<>(4);
|
||||
if(CollectionUtils.isEmpty(configBeansList)){
|
||||
failedData.put("succCount", 0);
|
||||
return ResultBuilder.buildResult(ResultCodeEnum.NO_SELECTED_CONFIG, failedData);
|
||||
}
|
||||
configBeansList.removeAll(Collections.singleton(null));
|
||||
|
||||
if (NAMESPACE_PUBLIC_KEY.equalsIgnoreCase(namespace)) {
|
||||
namespace = "";
|
||||
@ -559,8 +566,14 @@ public class ConfigController {
|
||||
return ResultBuilder.buildResult(ResultCodeEnum.NAMESPACE_NOT_EXIST, failedData);
|
||||
}
|
||||
|
||||
ids.removeAll(Collections.singleton(null));
|
||||
List<ConfigAllInfo> queryedDataList = persistService.findAllConfigInfo4Export(null, null, null, null, ids);
|
||||
List<Long> idList = new ArrayList<>(configBeansList.size());
|
||||
Map<Long, SameNamespaceCloneConfigBean> configBeansMap = configBeansList.stream()
|
||||
.collect(Collectors.toMap(SameNamespaceCloneConfigBean::getCfgId, cfg -> {
|
||||
idList.add(cfg.getCfgId());
|
||||
return cfg;
|
||||
},(k1, k2) -> k1));
|
||||
|
||||
List<ConfigAllInfo> queryedDataList = persistService.findAllConfigInfo4Export(null, null, null, null, idList);
|
||||
|
||||
if (queryedDataList == null || queryedDataList.isEmpty()) {
|
||||
failedData.put("succCount", 0);
|
||||
@ -570,11 +583,12 @@ public class ConfigController {
|
||||
List<ConfigAllInfo> configInfoList4Clone = new ArrayList<>(queryedDataList.size());
|
||||
|
||||
for (ConfigAllInfo ci : queryedDataList) {
|
||||
SameNamespaceCloneConfigBean prarmBean = configBeansMap.get(ci.getId());
|
||||
ConfigAllInfo ci4save = new ConfigAllInfo();
|
||||
ci4save.setTenant(namespace);
|
||||
ci4save.setType(ci.getType());
|
||||
ci4save.setGroup(ci.getGroup());
|
||||
ci4save.setDataId(ci.getDataId());
|
||||
ci4save.setGroup((prarmBean != null && StringUtils.isNotBlank(prarmBean.getGroup())) ? prarmBean.getGroup() : ci.getGroup());
|
||||
ci4save.setDataId((prarmBean != null && StringUtils.isNotBlank(prarmBean.getDataId())) ? prarmBean.getDataId() : ci.getDataId());
|
||||
ci4save.setContent(ci.getContent());
|
||||
if (StringUtils.isNotBlank(ci.getAppName())) {
|
||||
ci4save.setAppName(ci.getAppName());
|
||||
@ -598,7 +612,7 @@ public class ConfigController {
|
||||
configInfo.getTenant(), requestIpApp, time.getTime(),
|
||||
LOCAL_IP, ConfigTraceService.PERSISTENCE_EVENT_PUB, configInfo.getContent());
|
||||
}
|
||||
return ResultBuilder.buildSuccessResult("导入成功", saveResult);
|
||||
return ResultBuilder.buildSuccessResult("克隆成功", saveResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -130,6 +130,8 @@ public class ConfigServletInner {
|
||||
isBeta = true;
|
||||
}
|
||||
}
|
||||
String configType = cacheItem.getType();
|
||||
response.setHeader("Config-Type", (null != configType) ? configType : "text");
|
||||
}
|
||||
File file = null;
|
||||
ConfigInfoBase configInfoBase = null;
|
||||
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.config.server.controller.parameters;
|
||||
|
||||
/**
|
||||
* @author klw(213539 @ qq.com)
|
||||
* @ClassName: SameNamespaceCloneConfigBean
|
||||
* @Description: 同namespace克隆接口的配制bean
|
||||
* @date 2019/12/13 16:10
|
||||
*/
|
||||
public class SameNamespaceCloneConfigBean {
|
||||
|
||||
private Long cfgId;
|
||||
|
||||
private String dataId;
|
||||
|
||||
private String group;
|
||||
|
||||
public Long getCfgId() {
|
||||
return cfgId;
|
||||
}
|
||||
|
||||
public void setCfgId(Long cfgId) {
|
||||
this.cfgId = cfgId;
|
||||
}
|
||||
|
||||
public String getDataId() {
|
||||
return dataId;
|
||||
}
|
||||
|
||||
public void setDataId(String dataId) {
|
||||
this.dataId = dataId;
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
}
|
@ -109,6 +109,14 @@ public class CacheItem {
|
||||
this.tagLastModifiedTs = tagLastModifiedTs;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
final String groupKey;
|
||||
public volatile String md5 = Constants.NULL;
|
||||
public volatile long lastModifiedTs;
|
||||
@ -123,5 +131,6 @@ public class CacheItem {
|
||||
public volatile Map<String, String> tagMd5;
|
||||
public volatile Map<String, Long> tagLastModifiedTs;
|
||||
public SimpleReadWriteLock rwLock = new SimpleReadWriteLock();
|
||||
public String type;
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ public class ConfigInfo extends ConfigInfoBase {
|
||||
|
||||
private String appName;
|
||||
|
||||
private String type;
|
||||
|
||||
public ConfigInfo() {
|
||||
|
||||
}
|
||||
@ -63,6 +65,14 @@ public class ConfigInfo extends ConfigInfoBase {
|
||||
this.appName = appName;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
|
@ -44,6 +44,8 @@ public enum ResultCodeEnum implements IResultCode {
|
||||
|
||||
DATA_EMPTY(100005, "导入的文件数据为空"),
|
||||
|
||||
NO_SELECTED_CONFIG(100006, "没有选择任何配制"),
|
||||
|
||||
|
||||
;
|
||||
|
||||
|
@ -57,9 +57,10 @@ public class ConfigService {
|
||||
/**
|
||||
* 保存配置文件,并缓存md5.
|
||||
*/
|
||||
static public boolean dump(String dataId, String group, String tenant, String content, long lastModifiedTs) {
|
||||
static public boolean dump(String dataId, String group, String tenant, String content, long lastModifiedTs, String type) {
|
||||
String groupKey = GroupKey2.getKey(dataId, group, tenant);
|
||||
makeSure(groupKey);
|
||||
CacheItem ci = makeSure(groupKey);
|
||||
ci.setType(type);
|
||||
final int lockResult = tryWriteLock(groupKey);
|
||||
assert (lockResult != 0);
|
||||
|
||||
|
@ -176,7 +176,7 @@ public class DiskUtil {
|
||||
}
|
||||
|
||||
static public File heartBeatFile() {
|
||||
return new File(NACOS_HOME, "status/heartBeat.txt");
|
||||
return new File(NACOS_HOME, "status" + File.separator + "heartBeat.txt");
|
||||
}
|
||||
|
||||
static public String relativePath(String dataId, String group) {
|
||||
|
@ -113,6 +113,7 @@ public class PersistService {
|
||||
info.setGroup(rs.getString("group_id"));
|
||||
info.setTenant(rs.getString("tenant_id"));
|
||||
info.setAppName(rs.getString("app_name"));
|
||||
info.setType(rs.getString("type"));
|
||||
|
||||
try {
|
||||
info.setContent(rs.getString("content"));
|
||||
@ -235,6 +236,11 @@ public class PersistService {
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
info.setType(rs.getString("type"));
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@ -1325,7 +1331,7 @@ public class PersistService {
|
||||
final String appName = configAdvanceInfo == null ? null : (String) configAdvanceInfo.get("appName");
|
||||
final String configTags = configAdvanceInfo == null ? null : (String) configAdvanceInfo.get("config_tags");
|
||||
String sqlCount = "select count(*) from config_info";
|
||||
String sql = "select ID,data_id,group_id,tenant_id,app_name,content from config_info";
|
||||
String sql = "select ID,data_id,group_id,tenant_id,app_name,content,type from config_info";
|
||||
StringBuilder where = new StringBuilder(" where ");
|
||||
List<String> paramList = new ArrayList<String>();
|
||||
paramList.add(tenantTmp);
|
||||
@ -1944,7 +1950,7 @@ public class PersistService {
|
||||
|
||||
public Page<ConfigInfoWrapper> findAllConfigInfoFragment(final long lastMaxId, final int pageSize) {
|
||||
String select
|
||||
= "SELECT id,data_id,group_id,tenant_id,app_name,content,md5,gmt_modified from config_info where id > ? "
|
||||
= "SELECT id,data_id,group_id,tenant_id,app_name,content,md5,gmt_modified,type from config_info where id > ? "
|
||||
+ "order by id asc limit ?,?";
|
||||
PaginationHelper<ConfigInfoWrapper> helper = new PaginationHelper<ConfigInfoWrapper>();
|
||||
try {
|
||||
@ -2927,8 +2933,8 @@ public class PersistService {
|
||||
final String tenantTmp = StringUtils.isBlank(tenant) ? StringUtils.EMPTY : tenant;
|
||||
try {
|
||||
return this.jt.queryForObject(
|
||||
"SELECT ID,data_id,group_id,tenant_id,app_name,content,md5 FROM config_info WHERE data_id=? AND group_id=? AND tenant_id=?",
|
||||
new Object[]{dataId, group, tenantTmp}, CONFIG_INFO_ROW_MAPPER);
|
||||
"SELECT ID,data_id,group_id,tenant_id,app_name,content,md5,type FROM config_info WHERE data_id=? AND group_id=? AND tenant_id=?",
|
||||
new Object[] {dataId, group, tenantTmp}, CONFIG_INFO_ROW_MAPPER);
|
||||
} catch (EmptyResultDataAccessException e) { // 表明数据不存在, 返回null
|
||||
return null;
|
||||
} catch (CannotGetJdbcConnectionException e) {
|
||||
|
@ -187,7 +187,7 @@ class DumpProcessor implements TaskProcessor {
|
||||
|
||||
boolean result;
|
||||
if (null != cf) {
|
||||
result = ConfigService.dump(dataId, group, tenant, cf.getContent(), lastModified);
|
||||
result = ConfigService.dump(dataId, group, tenant, cf.getContent(), lastModified, cf.getType());
|
||||
|
||||
if (result) {
|
||||
ConfigTraceService.logDumpEvent(dataId, group, tenant, null, lastModified, handleIp,
|
||||
@ -261,7 +261,7 @@ class DumpAllProcessor implements TaskProcessor {
|
||||
}
|
||||
|
||||
boolean result = ConfigService.dump(cf.getDataId(), cf.getGroup(), cf.getTenant(), cf.getContent(),
|
||||
cf.getLastModified());
|
||||
cf.getLastModified(), cf.getType());
|
||||
|
||||
final String content = cf.getContent();
|
||||
final String md5 = MD5.getInstance().getMD5String(content);
|
||||
|
@ -76,7 +76,7 @@ public class PaginationHelper<E> {
|
||||
page.setTotalCount(rowCountInt);
|
||||
|
||||
if (pageNo > pageCount) {
|
||||
return null;
|
||||
return page;
|
||||
}
|
||||
|
||||
final int startRow = (pageNo - 1) * pageSize;
|
||||
@ -121,7 +121,7 @@ public class PaginationHelper<E> {
|
||||
page.setTotalCount(rowCountInt);
|
||||
|
||||
if (pageNo > pageCount) {
|
||||
return null;
|
||||
return page;
|
||||
}
|
||||
|
||||
String selectSQL = sqlFetchRows;
|
||||
@ -162,7 +162,7 @@ public class PaginationHelper<E> {
|
||||
page.setTotalCount(rowCountInt);
|
||||
|
||||
if (pageNo > pageCount) {
|
||||
return null;
|
||||
return page;
|
||||
}
|
||||
|
||||
String selectSQL = sqlFetchRows;
|
||||
|
@ -19,7 +19,6 @@ import org.apache.commons.lang3.time.FastDateFormat;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Time util
|
||||
@ -29,13 +28,12 @@ import java.util.Date;
|
||||
public class TimeUtils {
|
||||
|
||||
public static Timestamp getCurrentTime() {
|
||||
Date date = new Date();
|
||||
return new Timestamp(date.getTime());
|
||||
return new Timestamp(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static String getCurrentTimeStr() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTime(new Date());
|
||||
c.setTimeInMillis(System.currentTimeMillis());
|
||||
FastDateFormat format = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
|
||||
return format.format(c.getTime());
|
||||
}
|
||||
|
0
config/src/main/resources/META-INF/logback/nacos-included.xml → config/src/main/resources/META-INF/logback/config-included.xml
Executable file → Normal file
0
config/src/main/resources/META-INF/logback/nacos-included.xml → config/src/main/resources/META-INF/logback/config-included.xml
Executable file → Normal file
@ -313,6 +313,7 @@ const I18N_CONF = {
|
||||
delSelectedAlertTitle: 'Delete config',
|
||||
delSelectedAlertContent: 'please select the configuration to delete',
|
||||
delSuccessMsg: 'delete successful',
|
||||
cloneEditableTitle: 'Modify Data Id and Group (optional)',
|
||||
},
|
||||
NewConfig: {
|
||||
newListingMain: 'Create Configuration',
|
||||
|
@ -311,6 +311,7 @@ const I18N_CONF = {
|
||||
delSelectedAlertTitle: '配置删除',
|
||||
delSelectedAlertContent: '请选择要删除的配置',
|
||||
delSuccessMsg: '删除成功',
|
||||
cloneEditableTitle: '修改 Data Id 和 Group (可选操作)',
|
||||
},
|
||||
NewConfig: {
|
||||
newListingMain: '新建配置',
|
||||
|
@ -39,6 +39,7 @@ import ShowCodeing from 'components/ShowCodeing';
|
||||
import DeleteDialog from 'components/DeleteDialog';
|
||||
import DashboardCard from './DashboardCard';
|
||||
import { getParams, setParams, request, aliwareIntl } from '@/globalLib';
|
||||
import axios from 'axios';
|
||||
|
||||
import './index.scss';
|
||||
import { LANGUAGE_KEY } from '../../../constants';
|
||||
@ -689,10 +690,9 @@ class ConfigurationManagement extends React.Component {
|
||||
}
|
||||
|
||||
exportData() {
|
||||
let url =
|
||||
`v1/cs/configs?export=true&group=${this.group}&tenant=${getParams('namespace')}&appName=${
|
||||
this.appName
|
||||
}&ids=&dataId=` + this.dataId;
|
||||
let url = `v1/cs/configs?export=true&group=${this.group}&tenant=${getParams(
|
||||
'namespace'
|
||||
)}&appName=${this.appName}&ids=&dataId=${this.dataId}`;
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
@ -783,19 +783,54 @@ class ConfigurationManagement extends React.Component {
|
||||
}
|
||||
let namespaces = data.data;
|
||||
let namespaceSelectData = [];
|
||||
namespaces.forEach(item => {
|
||||
if (self.state.nownamespace_id !== item.namespace) {
|
||||
let dataItem = {};
|
||||
if (item.namespaceShowName === 'public') {
|
||||
dataItem.label = 'public | public';
|
||||
dataItem.value = 'public';
|
||||
} else {
|
||||
dataItem.label = `${item.namespaceShowName} | ${item.namespace}`;
|
||||
dataItem.value = item.namespace;
|
||||
}
|
||||
namespaceSelectData.push(dataItem);
|
||||
let namespaceSelecItemRender = item => {
|
||||
if (item.isCurrent) {
|
||||
return <span style={{ color: '#00AA00', 'font-weight': 'bold' }}>{item.label}</span>;
|
||||
} else {
|
||||
return <span>{item.label}</span>;
|
||||
}
|
||||
};
|
||||
namespaces.forEach(item => {
|
||||
let dataItem = {};
|
||||
dataItem.isCurrent = false;
|
||||
if (self.state.nownamespace_id === item.namespace) {
|
||||
dataItem.isCurrent = true;
|
||||
}
|
||||
if (item.namespaceShowName === 'public') {
|
||||
dataItem.label = 'public | public';
|
||||
dataItem.value = 'public';
|
||||
} else {
|
||||
dataItem.label = `${item.namespaceShowName} | ${item.namespace}`;
|
||||
dataItem.value = item.namespace;
|
||||
}
|
||||
namespaceSelectData.push(dataItem);
|
||||
});
|
||||
|
||||
let editableTableData = [];
|
||||
let configsTableSelectedDeepCopyed = new Map();
|
||||
configsTableSelected.forEach((value, key, map) => {
|
||||
let dataItem = {};
|
||||
dataItem.id = key;
|
||||
dataItem.dataId = value.dataId;
|
||||
dataItem.group = value.group;
|
||||
editableTableData.push(dataItem);
|
||||
configsTableSelectedDeepCopyed.set(key, JSON.parse(JSON.stringify(value)));
|
||||
});
|
||||
let editableTableOnBlur = (record, type, e) => {
|
||||
if (type === 1) {
|
||||
configsTableSelectedDeepCopyed.get(record.id).dataId = e.target.value;
|
||||
} else {
|
||||
configsTableSelectedDeepCopyed.get(record.id).group = e.target.value;
|
||||
}
|
||||
};
|
||||
|
||||
let renderEditableTableCellDataId = (value, index, record) => (
|
||||
<Input defaultValue={value} onBlur={editableTableOnBlur.bind(this, record, 1)} />
|
||||
);
|
||||
let renderEditableTableCellGroup = (value, index, record) => (
|
||||
<Input defaultValue={value} onBlur={editableTableOnBlur.bind(this, record, 2)} />
|
||||
);
|
||||
|
||||
const cloneConfirm = Dialog.confirm({
|
||||
title: locale.cloningConfiguration,
|
||||
footer: false,
|
||||
@ -822,6 +857,7 @@ class ConfigurationManagement extends React.Component {
|
||||
showSearch
|
||||
hasClear={false}
|
||||
mode="single"
|
||||
itemRender={namespaceSelecItemRender}
|
||||
dataSource={namespaceSelectData}
|
||||
onChange={(value, actionType, item) => {
|
||||
if (value) {
|
||||
@ -866,7 +902,7 @@ class ConfigurationManagement extends React.Component {
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ marginBottom: 10 }}>
|
||||
<Button
|
||||
type={'primary'}
|
||||
style={{ marginRight: 10 }}
|
||||
@ -878,13 +914,21 @@ class ConfigurationManagement extends React.Component {
|
||||
document.getElementById('cloneTargetSpaceSelectErr').style.display = 'none';
|
||||
}
|
||||
let idsStr = '';
|
||||
configsTableSelected.forEach((value, key, map) => {
|
||||
idsStr = `${idsStr + key},`;
|
||||
let clonePostData = [];
|
||||
configsTableSelectedDeepCopyed.forEach((value, key, map) => {
|
||||
let postDataItem = {};
|
||||
postDataItem.cfgId = key;
|
||||
postDataItem.dataId = value.dataId;
|
||||
postDataItem.group = value.group;
|
||||
clonePostData.push(postDataItem);
|
||||
});
|
||||
let cloneTargetSpace = self.field.getValue('cloneTargetSpace');
|
||||
let sameConfigPolicy = self.field.getValue('sameConfigPolicy');
|
||||
request({
|
||||
url: `v1/cs/configs?clone=true&tenant=${cloneTargetSpace}&policy=${sameConfigPolicy}&ids=${idsStr}`,
|
||||
url: `v1/cs/configs?clone=true&tenant=${cloneTargetSpace}&policy=${sameConfigPolicy}&namespaceId=`,
|
||||
method: 'post',
|
||||
data: JSON.stringify(clonePostData),
|
||||
contentType: 'application/json',
|
||||
beforeSend() {
|
||||
self.openLoading();
|
||||
},
|
||||
@ -908,6 +952,25 @@ class ConfigurationManagement extends React.Component {
|
||||
{locale.startCloning}
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ marginBottom: 10 }}>
|
||||
<span style={{ color: '#00AA00', 'font-weight': 'bold' }}>
|
||||
{locale.cloneEditableTitle}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<Table dataSource={editableTableData}>
|
||||
<Table.Column
|
||||
title="Data Id"
|
||||
dataIndex="dataId"
|
||||
cell={renderEditableTableCellDataId}
|
||||
/>
|
||||
<Table.Column
|
||||
title="Group"
|
||||
dataIndex="group"
|
||||
cell={renderEditableTableCellGroup}
|
||||
/>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
@ -1089,7 +1152,9 @@ class ConfigurationManagement extends React.Component {
|
||||
rowSelection.selectedRowKeys = ids;
|
||||
this.setState({ rowSelection });
|
||||
configsTableSelected.clear();
|
||||
records.forEach(item => configsTableSelected.set(item.id, item));
|
||||
records.forEach((record, i) => {
|
||||
configsTableSelected.set(record.id, record);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -17,9 +17,7 @@ package com.alibaba.nacos.core.env;
|
||||
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -25,6 +25,7 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@ -147,9 +148,10 @@ public class StartingSpringApplicationRunListener implements SpringApplicationRu
|
||||
}
|
||||
|
||||
private void logFilePath() {
|
||||
LOGGER.info("Nacos Log files: {}/logs/", NACOS_HOME);
|
||||
LOGGER.info("Nacos Conf files: {}/conf/", NACOS_HOME);
|
||||
LOGGER.info("Nacos Data files: {}/data/", NACOS_HOME);
|
||||
String[] dirNames = new String[]{"logs", "conf", "data"};
|
||||
for (String dirName: dirNames) {
|
||||
LOGGER.info("Nacos Log files: {}{}{}{}", NACOS_HOME, File.separatorChar, dirName, File.separatorChar);
|
||||
}
|
||||
}
|
||||
|
||||
private void logStarting() {
|
||||
|
@ -7,6 +7,8 @@
|
||||
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
|
||||
|
||||
<include resource="META-INF/logback/nacos-included.xml"/>
|
||||
<include optional="true" resource="META-INF/logback/config-included.xml"/>
|
||||
<include optional="true" resource="META-INF/logback/naming-included.xml"/>
|
||||
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
|
@ -79,6 +79,10 @@ public class DistroFilter implements Filter {
|
||||
if (StringUtils.isBlank(serviceName)) {
|
||||
serviceName = req.getParameter("dom");
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(serviceName)) {
|
||||
serviceName = serviceName.trim();
|
||||
}
|
||||
Method method = controllerMethodsCache.getMethod(req.getMethod(), path);
|
||||
|
||||
if (method == null) {
|
||||
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.nacos.test.config;
|
||||
|
||||
import com.alibaba.nacos.api.NacosFactory;
|
||||
import com.alibaba.nacos.api.PropertyKeyConst;
|
||||
import com.alibaba.nacos.api.config.ConfigChangeEvent;
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.config.PropertyChangeType;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.alibaba.nacos.client.config.listener.impl.AbstractConfigChangeListener;
|
||||
import com.alibaba.nacos.config.server.Config;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Config.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
public class ConfigLongPollReturnChanges_ITCase {
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
private ConfigService configService;
|
||||
|
||||
@Before
|
||||
public void init() throws NacosException {
|
||||
Properties properties = new Properties();
|
||||
properties.put(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:" + port);
|
||||
properties.put(PropertyKeyConst.CONFIG_LONG_POLL_TIMEOUT, "20000");
|
||||
properties.put(PropertyKeyConst.CONFIG_RETRY_TIME, "3000");
|
||||
properties.put(PropertyKeyConst.MAX_RETRY, "5");
|
||||
configService = NacosFactory.createConfigService(properties);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdd() throws InterruptedException, NacosException {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
final String dataId = "test" + System.currentTimeMillis();
|
||||
final String group = "DEFAULT_GROUP";
|
||||
final String content = "config data";
|
||||
|
||||
configService.addListener(dataId, group, new AbstractConfigChangeListener() {
|
||||
@Override
|
||||
public void receiveConfigChange(ConfigChangeEvent event) {
|
||||
ConfigChangeItem cci = event.getChangeItem("content");
|
||||
Assert.assertEquals(null, cci.getOldValue());
|
||||
Assert.assertEquals(content, cci.getNewValue());
|
||||
Assert.assertEquals(PropertyChangeType.ADDED, cci.getType());
|
||||
System.out.println(cci);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
});
|
||||
configService.publishConfig(dataId, group, content);
|
||||
|
||||
latch.await();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModify() throws InterruptedException, NacosException {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
final String dataId = "test" + System.currentTimeMillis();
|
||||
final String group = "DEFAULT_GROUP";
|
||||
final String oldData = "old data";
|
||||
final String newData = "new data";
|
||||
|
||||
configService.publishConfig(dataId, group, oldData);
|
||||
|
||||
// query config immediately may return null
|
||||
String config = null;
|
||||
do {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
config = configService.getConfig(dataId, group, 50);
|
||||
} while(null == config);
|
||||
|
||||
configService.addListener(dataId, group, new AbstractConfigChangeListener() {
|
||||
@Override
|
||||
public void receiveConfigChange(ConfigChangeEvent event) {
|
||||
ConfigChangeItem cci = event.getChangeItem("content");
|
||||
Assert.assertEquals(oldData, cci.getOldValue());
|
||||
Assert.assertEquals(newData, cci.getNewValue());
|
||||
Assert.assertEquals(PropertyChangeType.MODIFIED, cci.getType());
|
||||
System.out.println(cci);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
});
|
||||
configService.publishConfig(dataId, group, newData);
|
||||
|
||||
latch.await();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelete() throws InterruptedException, NacosException {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
final String dataId = "test" + System.currentTimeMillis();
|
||||
final String group = "DEFAULT_GROUP";
|
||||
final String oldData = "old data";
|
||||
|
||||
configService.publishConfig(dataId, group, oldData);
|
||||
|
||||
// query config immediately may return null
|
||||
String config = null;
|
||||
do {
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
config = configService.getConfig(dataId, group, 50);
|
||||
} while(null == config);
|
||||
|
||||
configService.addListener(dataId, group, new AbstractConfigChangeListener() {
|
||||
@Override
|
||||
public void receiveConfigChange(ConfigChangeEvent event) {
|
||||
ConfigChangeItem cci = event.getChangeItem("content");
|
||||
Assert.assertEquals(oldData, cci.getOldValue());
|
||||
Assert.assertEquals(null, cci.getNewValue());
|
||||
Assert.assertEquals(PropertyChangeType.DELETED, cci.getType());
|
||||
System.out.println(cci);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
});
|
||||
configService.removeConfig(dataId, group);
|
||||
|
||||
latch.await();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.nacos.test.config;
|
||||
|
||||
import com.alibaba.nacos.api.config.ConfigChangeItem;
|
||||
import com.alibaba.nacos.api.config.PropertyChangeType;
|
||||
import com.alibaba.nacos.api.config.listener.ConfigChangeParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TextChangeParser implements ConfigChangeParser {
|
||||
@Override
|
||||
public boolean isResponsibleFor(String type) {
|
||||
return (null == type || "text".equalsIgnoreCase(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ConfigChangeItem> doParse(String oldContent, String newContent, String type) throws IOException {
|
||||
Map<String, ConfigChangeItem> map = new HashMap<>(4);
|
||||
final String key = "content";
|
||||
|
||||
ConfigChangeItem cci = new ConfigChangeItem(key, oldContent, newContent);
|
||||
if (null == oldContent && null != newContent) {
|
||||
cci.setType(PropertyChangeType.ADDED);
|
||||
} else if (null != oldContent && null != newContent && !oldContent.equals(newContent)) {
|
||||
cci.setType(PropertyChangeType.MODIFIED);
|
||||
} else if (null != oldContent && null == newContent) {
|
||||
cci.setType(PropertyChangeType.DELETED);
|
||||
}
|
||||
map.put(key, cci);
|
||||
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
com.alibaba.nacos.test.config.TextChangeParser
|
Loading…
Reference in New Issue
Block a user