Merge branch 'develop' of https://github.com/alibaba/nacos into new_develop

This commit is contained in:
chuntaojun 2020-06-24 10:43:54 +08:00
commit 9e7cf30554
36 changed files with 1702 additions and 431 deletions

View File

@ -13,136 +13,145 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.exception;
import com.alibaba.nacos.api.common.Constants;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.nacos.api.utils.StringUtils;
/**
* Nacos Exception
* Nacos Exception.
*
* @author Nacos
*/
public class NacosException extends Exception {
/**
* serialVersionUID
*/
private static final long serialVersionUID = -3913902031489277776L;
private int errCode;
private String errMsg;
private Throwable causeThrowable;
public NacosException() {
}
public NacosException(int errCode, String errMsg) {
super(errMsg);
this.errCode = errCode;
this.errMsg = errMsg;
}
public NacosException(int errCode, Throwable throwable) {
super(throwable);
this.errCode = errCode;
setCauseThrowable(throwable);
}
public NacosException(int errCode, String errMsg, Throwable throwable) {
super(errMsg, throwable);
this.errCode = errCode;
this.errMsg = errMsg;
setCauseThrowable(throwable);
}
public int getErrCode() {
return errCode;
}
public String getErrMsg() {
if (!StringUtils.isBlank(this.errMsg)) {
return errMsg;
}
if (this.causeThrowable != null) {
return causeThrowable.getMessage();
}
return Constants.NULL;
}
public void setErrCode(int errCode) {
this.errCode = errCode;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
public void setCauseThrowable(Throwable throwable) {
this.causeThrowable = getCauseThrowable(throwable);
}
private Throwable getCauseThrowable(Throwable t) {
if (t.getCause() == null) {
return t;
}
return getCauseThrowable(t.getCause());
}
@Override
public String toString() {
return "ErrCode:" + getErrCode() + ", ErrMsg:" + getErrMsg();
}
/**
* client error code
* -400 -503 throw exception to user
*/
/**
* invalid param参数错误
*/
public static final int CLIENT_INVALID_PARAM = -400;
/**
* over client threshold超过server端的限流阈值
*/
public static final int CLIENT_OVER_THRESHOLD = -503;
/**
* server error code
* 400 403 throw exception to user
* 500 502 503 change ip and retry
*/
/**
* invalid param参数错误
*/
public static final int INVALID_PARAM = 400;
/**
* no right鉴权失败
*/
public static final int NO_RIGHT = 403;
/**
* not found
*/
public static final int NOT_FOUND = 404;
/**
* conflict写并发冲突
*/
public static final int CONFLICT = 409;
/**
* server errorserver异常如超时
*/
public static final int SERVER_ERROR = 500;
/**
* bad gateway路由异常如nginx后面的Server挂掉
*/
public static final int BAD_GATEWAY = 502;
/**
* over threshold超过server端的限流阈值
*/
public static final int OVER_THRESHOLD = 503;
public static final int RESOURCE_NOT_FOUND = -404;
/**
* serialVersionUID.
*/
private static final long serialVersionUID = -3913902031489277776L;
private int errCode;
private String errMsg;
private Throwable causeThrowable;
public NacosException() {
}
public NacosException(final int errCode, final String errMsg) {
super(errMsg);
this.errCode = errCode;
this.errMsg = errMsg;
}
public NacosException(final int errCode, final Throwable throwable) {
super(throwable);
this.errCode = errCode;
this.setCauseThrowable(throwable);
}
public NacosException(final int errCode, final String errMsg, final Throwable throwable) {
super(errMsg, throwable);
this.errCode = errCode;
this.errMsg = errMsg;
this.setCauseThrowable(throwable);
}
public int getErrCode() {
return this.errCode;
}
public String getErrMsg() {
if (!StringUtils.isBlank(this.errMsg)) {
return this.errMsg;
}
if (this.causeThrowable != null) {
return this.causeThrowable.getMessage();
}
return Constants.NULL;
}
public void setErrCode(final int errCode) {
this.errCode = errCode;
}
public void setErrMsg(final String errMsg) {
this.errMsg = errMsg;
}
public void setCauseThrowable(final Throwable throwable) {
this.causeThrowable = this.getCauseThrowable(throwable);
}
private Throwable getCauseThrowable(final Throwable t) {
if (t.getCause() == null) {
return t;
}
return this.getCauseThrowable(t.getCause());
}
@Override
public String toString() {
return "ErrCode:" + getErrCode() + ", ErrMsg:" + getErrMsg();
}
/*
* client error code.
* -400 -503 throw exception to user.
*/
/**
* invalid param参数错误.
*/
public static final int CLIENT_INVALID_PARAM = -400;
/**
* over client threshold超过server端的限流阈值.
*/
public static final int CLIENT_OVER_THRESHOLD = -503;
/*
* server error code.
* 400 403 throw exception to user
* 500 502 503 change ip and retry
*/
/**
* invalid param参数错误.
*/
public static final int INVALID_PARAM = 400;
/**
* no right鉴权失败.
*/
public static final int NO_RIGHT = 403;
/**
* not found.
*/
public static final int NOT_FOUND = 404;
/**
* conflict写并发冲突.
*/
public static final int CONFLICT = 409;
/**
* server errorserver异常如超时.
*/
public static final int SERVER_ERROR = 500;
/**
* bad gateway路由异常如nginx后面的Server挂掉.
*/
public static final int BAD_GATEWAY = 502;
/**
* over threshold超过server端的限流阈值.
*/
public static final int OVER_THRESHOLD = 503;
public static final int RESOURCE_NOT_FOUND = -404;
}

View File

@ -13,238 +13,240 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.pojo;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
import com.alibaba.nacos.api.utils.StringUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
import static com.alibaba.nacos.api.common.Constants.NUMBER_PATTERN;
/**
* Instance
* Instance.
*
* @author nkorange
*/
@JsonInclude(Include.NON_NULL)
public class Instance {
/**
* unique id of this instance.
*/
private String instanceId;
/**
* instance ip
* instance ip.
*/
private String ip;
/**
* instance port
* instance port.
*/
private int port;
/**
* instance weight
* instance weight.
*/
private double weight = 1.0D;
/**
* instance health status
* instance health status.
*/
private boolean healthy = true;
/**
* If instance is enabled to accept request
* If instance is enabled to accept request.
*/
private boolean enabled = true;
/**
* If instance is ephemeral
* If instance is ephemeral.
*
* @since 1.0.0
*/
private boolean ephemeral = true;
/**
* cluster information of instance
* cluster information of instance.
*/
private String clusterName;
/**
* Service information of instance
* Service information of instance.
*/
private String serviceName;
/**
* user extended attributes
* user extended attributes.
*/
private Map<String, String> metadata = new HashMap<String, String>();
public String getInstanceId() {
return instanceId;
return this.instanceId;
}
public void setInstanceId(String instanceId) {
public void setInstanceId(final String instanceId) {
this.instanceId = instanceId;
}
public String getIp() {
return ip;
return this.ip;
}
public void setIp(String ip) {
public void setIp(final String ip) {
this.ip = ip;
}
public int getPort() {
return port;
return this.port;
}
public void setPort(int port) {
public void setPort(final int port) {
this.port = port;
}
public double getWeight() {
return weight;
return this.weight;
}
public void setWeight(double weight) {
public void setWeight(final double weight) {
this.weight = weight;
}
public boolean isHealthy() {
return healthy;
return this.healthy;
}
public void setHealthy(boolean healthy) {
public void setHealthy(final boolean healthy) {
this.healthy = healthy;
}
public String getClusterName() {
return clusterName;
return this.clusterName;
}
public void setClusterName(String clusterName) {
public void setClusterName(final String clusterName) {
this.clusterName = clusterName;
}
public String getServiceName() {
return serviceName;
return this.serviceName;
}
public void setServiceName(String serviceName) {
public void setServiceName(final String serviceName) {
this.serviceName = serviceName;
}
public Map<String, String> getMetadata() {
return metadata;
return this.metadata;
}
public void setMetadata(Map<String, String> metadata) {
public void setMetadata(final Map<String, String> metadata) {
this.metadata = metadata;
}
public void addMetadata(String key, String value) {
if (this.metadata == null) {
this.metadata = new HashMap<String, String>(4);
/**
* add meta data.
*
* @param key meta data key
* @param value meta data value
*/
public void addMetadata(final String key, final String value) {
if (metadata == null) {
metadata = new HashMap<String, String>(4);
}
this.metadata.put(key, value);
metadata.put(key, value);
}
public boolean isEnabled() {
return enabled;
return this.enabled;
}
public void setEnabled(boolean enabled) {
public void setEnabled(final boolean enabled) {
this.enabled = enabled;
}
public boolean isEphemeral() {
return ephemeral;
return this.ephemeral;
}
public void setEphemeral(boolean ephemeral) {
public void setEphemeral(final boolean ephemeral) {
this.ephemeral = ephemeral;
}
@Override
public String toString() {
return "Instance{" +
"instanceId='" + instanceId + '\'' +
", ip='" + ip + '\'' +
", port=" + port +
", weight=" + weight +
", healthy=" + healthy +
", enabled=" + enabled +
", ephemeral=" + ephemeral +
", clusterName='" + clusterName + '\'' +
", serviceName='" + serviceName + '\'' +
", metadata=" + metadata +
'}';
return "Instance{" + "instanceId='" + instanceId + '\'' + ", ip='" + ip + '\'' + ", port=" + port
+ ", weight=" + weight + ", healthy=" + healthy + ", enabled=" + enabled + ", ephemeral="
+ ephemeral + ", clusterName='" + clusterName + '\'' + ", serviceName='" + serviceName
+ '\'' + ", metadata=" + metadata + '}';
}
public String toInetAddr() {
return ip + ":" + port;
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (!(obj instanceof Instance)) {
return false;
}
Instance host = (Instance) obj;
return strEquals(host.toString(), toString());
final Instance host = (Instance) obj;
return Instance.strEquals(host.toString(), toString());
}
@Override
public int hashCode() {
return toString().hashCode();
}
private static boolean strEquals(String str1, String str2) {
private static boolean strEquals(final String str1, final String str2) {
return str1 == null ? str2 == null : str1.equals(str2);
}
public long getInstanceHeartBeatInterval() {
return getMetaDataByKeyWithDefault(PreservedMetadataKeys.HEART_BEAT_INTERVAL, Constants.DEFAULT_HEART_BEAT_INTERVAL);
return getMetaDataByKeyWithDefault(PreservedMetadataKeys.HEART_BEAT_INTERVAL,
Constants.DEFAULT_HEART_BEAT_INTERVAL);
}
public long getInstanceHeartBeatTimeOut() {
return getMetaDataByKeyWithDefault(PreservedMetadataKeys.HEART_BEAT_TIMEOUT, Constants.DEFAULT_HEART_BEAT_TIMEOUT);
return getMetaDataByKeyWithDefault(PreservedMetadataKeys.HEART_BEAT_TIMEOUT,
Constants.DEFAULT_HEART_BEAT_TIMEOUT);
}
public long getIpDeleteTimeout() {
return getMetaDataByKeyWithDefault(PreservedMetadataKeys.IP_DELETE_TIMEOUT, Constants.DEFAULT_IP_DELETE_TIMEOUT);
return getMetaDataByKeyWithDefault(PreservedMetadataKeys.IP_DELETE_TIMEOUT,
Constants.DEFAULT_IP_DELETE_TIMEOUT);
}
public String getInstanceIdGenerator() {
return getMetaDataByKeyWithDefault(PreservedMetadataKeys.INSTANCE_ID_GENERATOR, Constants.DEFAULT_INSTANCE_ID_GENERATOR);
return getMetaDataByKeyWithDefault(PreservedMetadataKeys.INSTANCE_ID_GENERATOR,
Constants.DEFAULT_INSTANCE_ID_GENERATOR);
}
private long getMetaDataByKeyWithDefault( String key, long defaultValue) {
private long getMetaDataByKeyWithDefault(final String key, final long defaultValue) {
if (getMetadata() == null || getMetadata().isEmpty()) {
return defaultValue;
}
String value = getMetadata().get(key);
final String value = getMetadata().get(key);
if (!StringUtils.isEmpty(value) && value.matches(NUMBER_PATTERN)) {
return Long.parseLong(value);
}
return defaultValue;
}
private String getMetaDataByKeyWithDefault( String key, String defaultValue) {
private String getMetaDataByKeyWithDefault(final String key, final String defaultValue) {
if (getMetadata() == null || getMetadata().isEmpty()) {
return defaultValue;
}
return getMetadata().get(key);
}
}

View File

@ -18,9 +18,9 @@ package com.alibaba.nacos.api.naming.pojo.healthcheck.impl;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.api.naming.pojo.healthcheck.AbstractHealthChecker;
import com.alibaba.nacos.api.utils.StringUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Objects;
import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
import java.util.HashMap;
@ -32,50 +32,51 @@ import java.util.Map;
* @author yangyi
*/
public class Http extends AbstractHealthChecker {
public static final String TYPE = "HTTP";
private String path = "";
private String headers = "";
private int expectedResponseCode = 200;
public Http() {
super(TYPE);
super(Http.TYPE);
}
public int getExpectedResponseCode() {
return expectedResponseCode;
return this.expectedResponseCode;
}
public void setExpectedResponseCode(int expectedResponseCode) {
public void setExpectedResponseCode(final int expectedResponseCode) {
this.expectedResponseCode = expectedResponseCode;
}
public String getPath() {
return path;
return this.path;
}
public void setPath(String path) {
public void setPath(final String path) {
this.path = path;
}
public String getHeaders() {
return headers;
return this.headers;
}
public void setHeaders(String headers) {
public void setHeaders(final String headers) {
this.headers = headers;
}
@JsonIgnore
public Map<String, String> getCustomHeaders() {
if (StringUtils.isBlank(headers)) {
return Collections.emptyMap();
}
Map<String, String> headerMap = new HashMap<String, String>(16);
for (String s : headers.split(Constants.NAMING_HTTP_HEADER_SPILIER)) {
String[] splits = s.split(":");
final Map<String, String> headerMap = new HashMap<String, String>(16);
for (final String s : headers.split(Constants.NAMING_HTTP_HEADER_SPILIER)) {
final String[] splits = s.split(":");
if (splits.length != 2) {
continue;
}
@ -83,24 +84,24 @@ public class Http extends AbstractHealthChecker {
}
return headerMap;
}
@Override
public int hashCode() {
return Objects.hashCode(path, headers, expectedResponseCode);
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (!(obj instanceof Http)) {
return false;
}
Http other = (Http) obj;
final Http other = (Http) obj;
if (!StringUtils.equals(type, other.getType())) {
return false;
}
if (!StringUtils.equals(path, other.getPath())) {
return false;
}
@ -109,13 +110,13 @@ public class Http extends AbstractHealthChecker {
}
return expectedResponseCode == other.getExpectedResponseCode();
}
@Override
public Http clone() throws CloneNotSupportedException {
Http config = new Http();
config.setPath(this.getPath());
config.setHeaders(this.getHeaders());
config.setExpectedResponseCode(this.getExpectedResponseCode());
final Http config = new Http();
config.setPath(getPath());
config.setHeaders(getHeaders());
config.setExpectedResponseCode(getExpectedResponseCode());
return config;
}
}

View File

@ -16,9 +16,8 @@
package com.alibaba.nacos.api.naming.pojo.healthcheck.impl;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.nacos.api.naming.pojo.healthcheck.AbstractHealthChecker;
import com.alibaba.nacos.api.utils.StringUtils;
import com.google.common.base.Objects;
/**
@ -27,72 +26,73 @@ import com.google.common.base.Objects;
* @author yangyi
*/
public class Mysql extends AbstractHealthChecker {
public static final String TYPE = "MYSQL";
private String user;
private String pwd;
private String cmd;
public Mysql() {
super(TYPE);
super(Mysql.TYPE);
}
public String getCmd() {
return cmd;
return this.cmd;
}
public String getPwd() {
return pwd;
return this.pwd;
}
public String getUser() {
return user;
return this.user;
}
public void setUser(String user) {
public void setUser(final String user) {
this.user = user;
}
public void setCmd(String cmd) {
public void setCmd(final String cmd) {
this.cmd = cmd;
}
public void setPwd(String pwd) {
public void setPwd(final String pwd) {
this.pwd = pwd;
}
@Override
public int hashCode() {
return Objects.hashCode(user, pwd, cmd);
}
@Override
public boolean equals(Object obj) {
public boolean equals(final Object obj) {
if (!(obj instanceof Mysql)) {
return false;
}
Mysql other = (Mysql) obj;
final Mysql other = (Mysql) obj;
if (!StringUtils.equals(user, other.getUser())) {
return false;
}
if (!StringUtils.equals(pwd, other.getPwd())) {
return false;
}
return StringUtils.equals(cmd, other.getCmd());
}
@Override
public Mysql clone() throws CloneNotSupportedException {
Mysql config = new Mysql();
config.setUser(this.getUser());
config.setPwd(this.getPwd());
config.setCmd(this.getCmd());
final Mysql config = new Mysql();
config.setUser(getUser());
config.setPwd(getPwd());
config.setCmd(getCmd());
return config;
}
}

View File

@ -13,26 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.utils;
import com.alibaba.nacos.api.common.Constants;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.nacos.api.utils.StringUtils;
/**
* NamingUtils.
*
* @author nkorange
* @since 1.0.0
*/
public class NamingUtils {
public static String getGroupedName(String serviceName, String groupName) {
StringBuilder resultGroupedName = new StringBuilder()
.append(groupName)
.append(Constants.SERVICE_INFO_SPLITER)
.append(serviceName);
return resultGroupedName.toString().intern();
public static String getGroupedName(final String serviceName, final String groupName) {
final String resultGroupedName = groupName + Constants.SERVICE_INFO_SPLITER + serviceName;
return resultGroupedName.intern();
}
public static String getServiceName(String serviceNameWithGroup) {
public static String getServiceName(final String serviceNameWithGroup) {
if (StringUtils.isBlank(serviceNameWithGroup)) {
return StringUtils.EMPTY;
}
@ -41,8 +41,8 @@ public class NamingUtils {
}
return serviceNameWithGroup.split(Constants.SERVICE_INFO_SPLITER)[1];
}
public static String getGroupName(String serviceNameWithGroup) {
public static String getGroupName(final String serviceNameWithGroup) {
if (StringUtils.isBlank(serviceNameWithGroup)) {
return StringUtils.EMPTY;
}

View File

@ -0,0 +1,187 @@
/*
* 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.utils;
/**
* StringUtils. copy from apache common-lang3.
*
* @author <a href="mailto:lin-mt@outlook.com">lin-mt</a>
*/
public class StringUtils {
/**
* The empty String {@code ""}.
*
* @since 2.0
*/
public static final String EMPTY = "";
/**
* <p>Checks if a CharSequence is empty ("") or null.</p>
*
* <pre>
* StringUtils.isEmpty(null) = true
* StringUtils.isEmpty("") = true
* StringUtils.isEmpty(" ") = false
* StringUtils.isEmpty("bob") = false
* StringUtils.isEmpty(" bob ") = false
* </pre>
*
* <p>NOTE: This method changed in Lang version 2.0.
* It no longer trims the CharSequence. That functionality is available in isBlank().</p>
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is empty or null
* @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
*/
public static boolean isEmpty(final CharSequence cs) {
return cs == null || cs.length() == 0;
}
/**
* <p>Checks if a CharSequence is whitespace, empty ("") or null.</p>
*
* <pre>
* StringUtils.isBlank(null) = true
* StringUtils.isBlank("") = true
* StringUtils.isBlank(" ") = true
* StringUtils.isBlank("bob") = false
* StringUtils.isBlank(" bob ") = false
* </pre>
*
* @param cs the CharSequence to check, may be null
* @return {@code true} if the CharSequence is null, empty or whitespace
* @since 2.0
* @since 3.0 Changed signature from isBlank(String) to isBlank(CharSequence)
*/
public static boolean isBlank(final CharSequence cs) {
final int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
// Trim
//-----------------------------------------------------------------------
/**
* <p>Removes control characters (char &lt;= 32) from both
* ends of this String, handling {@code null} by returning {@code null}.</p>
*
* <p>The String is trimmed using {@link String#trim()}.
* Trim removes start and end characters &lt;= 32.</p>
*
* <pre>
* StringUtils.trim(null) = null
* StringUtils.trim("") = ""
* StringUtils.trim(" ") = ""
* StringUtils.trim("abc") = "abc"
* StringUtils.trim(" abc ") = "abc"
* </pre>
*
* @param str the String to be trimmed, may be null
* @return the trimmed string, {@code null} if null String input
*/
public static String trim(final String str) {
return str == null ? null : str.trim();
}
// Equals
//-----------------------------------------------------------------------
/**
* <p>Compares two CharSequences, returning {@code true} if they represent
* equal sequences of characters.</p>
*
* <p>{@code null}s are handled without exceptions. Two {@code null}
* references are considered to be equal. The comparison is case sensitive.</p>
*
* <pre>
* StringUtils.equals(null, null) = true
* StringUtils.equals(null, "abc") = false
* StringUtils.equals("abc", null) = false
* StringUtils.equals("abc", "abc") = true
* StringUtils.equals("abc", "ABC") = false
* </pre>
*
* @param cs1 the first CharSequence, may be {@code null}
* @param cs2 the second CharSequence, may be {@code null}
* @return {@code true} if the CharSequences are equal (case-sensitive), or both {@code null}
* @see Object#equals(Object)
* @since 3.0 Changed signature from equals(String, String) to equals(CharSequence, CharSequence)
*/
public static boolean equals(final CharSequence cs1, final CharSequence cs2) {
if (cs1 == cs2) {
return true;
}
if (cs1 == null || cs2 == null) {
return false;
}
if (cs1 instanceof String && cs2 instanceof String) {
return cs1.equals(cs2);
}
return StringUtils.regionMatches(cs1, false, 0, cs2, 0, Math.max(cs1.length(), cs2.length()));
}
/**
* Green implementation of regionMatches.
*
* @param cs the {@code CharSequence} to be processed
* @param ignoreCase whether or not to be case insensitive
* @param thisStart the index to start on the {@code cs} CharSequence
* @param substring the {@code CharSequence} to be looked for
* @param start the index to start on the {@code substring} CharSequence
* @param length character length of the region
* @return whether the region matched
*/
public static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart,
final CharSequence substring, final int start, final int length) {
if (cs instanceof String && substring instanceof String) {
return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
}
int index1 = thisStart;
int index2 = start;
int tmpLen = length;
while (tmpLen-- > 0) {
final char c1 = cs.charAt(index1++);
final char c2 = substring.charAt(index2++);
if (c1 == c2) {
continue;
}
if (!ignoreCase) {
return false;
}
// The same check as in String.regionMatches():
if (Character.toUpperCase(c1) != Character.toUpperCase(c2) && Character.toLowerCase(c1) != Character
.toLowerCase(c2)) {
return false;
}
}
return true;
}
}

View File

@ -23,7 +23,9 @@ import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class ServiceInfoTest {

View File

@ -30,7 +30,7 @@ import java.io.IOException;
public class AbstractHealthCheckerTest {
private ObjectMapper objectMapper = new ObjectMapper();
private final ObjectMapper objectMapper = new ObjectMapper();
@Before
public void setUp() {

View File

@ -16,12 +16,13 @@
package com.alibaba.nacos.api.naming.pojo.healthcheck;
import static org.junit.Assert.*;
import org.junit.Test;
import com.alibaba.nacos.api.naming.pojo.healthcheck.impl.Tcp;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class HealthCheckerFactoryTest {
@Test

View File

@ -16,8 +16,6 @@
package com.alibaba.nacos.api.naming.pojo.healthcheck.impl;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Before;
@ -26,6 +24,9 @@ import org.junit.Test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class MysqlTest {
private ObjectMapper objectMapper;

View File

@ -16,6 +16,7 @@
package com.alibaba.nacos.client.naming.net;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.utils.HttpMethod;
import com.alibaba.nacos.common.utils.IoUtils;
import com.alibaba.nacos.common.utils.StringUtils;
@ -35,7 +36,9 @@ import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
/**
* @author nkorange
* @deprecated Use NacosRestTemplate{@link NacosRestTemplate} unified http client
*/
@Deprecated
public class HttpClient {
public static final int READ_TIME_OUT_MILLIS = Integer

View File

@ -16,17 +16,19 @@
package com.alibaba.nacos.client.naming.net;
import com.alibaba.nacos.common.http.*;
import com.alibaba.nacos.common.http.AbstractHttpClientFactory;
import com.alibaba.nacos.common.http.HttpClientBeanHolder;
import com.alibaba.nacos.common.http.HttpClientConfig;
import com.alibaba.nacos.common.http.HttpClientFactory;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
/**
* http Manager
*
* @author mai.jh
* @date 2020/6/14
*/
public class NamingHttpClientManager {
private static final int READ_TIME_OUT_MILLIS = Integer
.getInteger("com.alibaba.nacos.client.naming.rtimeout", 50000);
private static final int CON_TIME_OUT_MILLIS = Integer
@ -34,22 +36,22 @@ public class NamingHttpClientManager {
private static final boolean ENABLE_HTTPS = Boolean
.getBoolean("com.alibaba.nacos.client.naming.tls.enable");
private static final int MAX_REDIRECTS = 5;
private static final HttpClientFactory HTTP_CLIENT_FACTORY = new NamingHttpClientFactory();
public static String getPrefix() {
if (ENABLE_HTTPS) {
return "https://";
}
return "http://";
}
public static NacosRestTemplate getNacosRestTemplate() {
return HttpClientBeanHolder.getNacosRestTemplate(HTTP_CLIENT_FACTORY);
}
private static class NamingHttpClientFactory extends AbstractHttpClientFactory {
@Override
protected HttpClientConfig buildHttpClientConfig() {
return HttpClientConfig.builder()

View File

@ -37,15 +37,19 @@ import com.alibaba.nacos.client.security.SecurityProxy;
import com.alibaba.nacos.client.utils.AppNameUtils;
import com.alibaba.nacos.client.utils.TemplateUtils;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.http.param.Query;
import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.utils.*;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.http.HttpStatus;
import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
@ -53,6 +57,7 @@ import java.util.List;
import java.util.Properties;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.Random;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@ -67,6 +72,8 @@ import static com.alibaba.nacos.client.utils.LogUtils.NAMING_LOGGER;
*/
public class NamingProxy implements Closeable {
private NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getNacosRestTemplate();
private static final int DEFAULT_SERVER_PORT = 8848;
private int serverPort = DEFAULT_SERVER_PORT;
@ -144,15 +151,14 @@ public class NamingProxy implements Closeable {
try {
String urlString = "http://" + endpoint + "/nacos/serverlist";
List<String> headers = builderHeaders();
HttpClient.HttpResult result = HttpClient.httpGet(urlString, headers, null, UtilAndComs.ENCODING);
if (HttpURLConnection.HTTP_OK != result.code) {
Header header = builderHeader();
HttpRestResult<String> restResult = nacosRestTemplate.get(urlString, header, Query.EMPTY, String.class);
if (!restResult.ok()) {
throw new IOException("Error while requesting: " + urlString + "'. Server returned: "
+ result.code);
+ restResult.getCode());
}
String content = result.content;
String content = restResult.getData();
List<String> list = new ArrayList<String>();
for (String line : IoUtils.readLines(new StringReader(content))) {
if (!line.trim().isEmpty()) {
@ -333,10 +339,10 @@ public class NamingProxy implements Closeable {
NAMING_LOGGER.debug("[BEAT] {} sending beat to server: {}", namespaceId, beatInfo.toString());
}
Map<String, String> params = new HashMap<String, String>(8);
String body = StringUtils.EMPTY;
Map<String, String> bodyMap = new HashMap<String, String>(2);
if (!lightBeatEnabled) {
try {
body = "beat=" + URLEncoder.encode(JacksonUtils.toJson(beatInfo), "UTF-8");
bodyMap.put("beat", URLEncoder.encode(JacksonUtils.toJson(beatInfo), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new NacosException(NacosException.SERVER_ERROR, "encode beatInfo error", e);
}
@ -346,7 +352,7 @@ public class NamingProxy implements Closeable {
params.put(CommonParams.CLUSTER_NAME, beatInfo.getCluster());
params.put("ip", beatInfo.getIp());
params.put("port", String.valueOf(beatInfo.getPort()));
String result = reqAPI(UtilAndComs.NACOS_URL_BASE + "/instance/beat", params, body, HttpMethod.PUT);
String result = reqAPI(UtilAndComs.NACOS_URL_BASE + "/instance/beat", params, bodyMap, HttpMethod.PUT);
return JacksonUtils.toObj(result);
}
@ -399,10 +405,10 @@ public class NamingProxy implements Closeable {
}
public String reqAPI(String api, Map<String, String> params, String method) throws NacosException {
return reqAPI(api, params, StringUtils.EMPTY, method);
return reqAPI(api, params, Collections.EMPTY_MAP, method);
}
public String reqAPI(String api, Map<String, String> params, String body, String method) throws NacosException {
public String reqAPI(String api, Map<String, String> params, Map<String, String> body, String method) throws NacosException {
return reqAPI(api, params, body, getServerList(), method);
}
@ -414,16 +420,16 @@ public class NamingProxy implements Closeable {
return snapshot;
}
public String callServer(String api, Map<String, String> params, String body, String curServer) throws NacosException {
public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer) throws NacosException {
return callServer(api, params, body, curServer, HttpMethod.GET);
}
public String callServer(String api, Map<String, String> params, String body, String curServer, String method)
public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer, String method)
throws NacosException {
long start = System.currentTimeMillis();
long end = 0;
injectSecurityInfo(params);
List<String> headers = builderHeaders();
Header header = builderHeader();
String url;
if (curServer.startsWith(UtilAndComs.HTTPS) || curServer.startsWith(UtilAndComs.HTTP)) {
@ -432,27 +438,30 @@ public class NamingProxy implements Closeable {
if (!curServer.contains(UtilAndComs.SERVER_ADDR_IP_SPLITER)) {
curServer = curServer + UtilAndComs.SERVER_ADDR_IP_SPLITER + serverPort;
}
url = HttpClient.getPrefix() + curServer + api;
url = NamingHttpClientManager.getPrefix() + curServer + api;
}
HttpClient.HttpResult result = HttpClient.request(url, headers, params, body, UtilAndComs.ENCODING, method);
end = System.currentTimeMillis();
try {
HttpRestResult<String> restResult = nacosRestTemplate.exchangeForm(url, header, params, body, method, String.class);
end = System.currentTimeMillis();
MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(result.code))
.observe(end - start);
MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(restResult.getCode()))
.observe(end - start);
if (HttpURLConnection.HTTP_OK == result.code) {
return result.content;
if (restResult.ok()) {
return restResult.getData();
}
if (HttpStatus.SC_NOT_MODIFIED == restResult.getCode()) {
return StringUtils.EMPTY;
}
throw new NacosException(restResult.getCode(), restResult.getData());
} catch (Exception e) {
NAMING_LOGGER.error("[NA] failed to request", e);
throw new NacosException(NacosException.SERVER_ERROR, e);
}
if (HttpURLConnection.HTTP_NOT_MODIFIED == result.code) {
return StringUtils.EMPTY;
}
throw new NacosException(result.code, result.content);
}
public String reqAPI(String api, Map<String, String> params, String body, List<String> servers, String method) throws NacosException {
public String reqAPI(String api, Map<String, String> params, Map<String, String> body, List<String> servers, String method) throws NacosException {
params.put(CommonParams.NAMESPACE_ID, getNamespaceId());
@ -526,14 +535,15 @@ public class NamingProxy implements Closeable {
}
}
public List<String> builderHeaders() {
List<String> headers = Arrays.asList(
HttpHeaderConsts.CLIENT_VERSION_HEADER, VersionUtils.version,
HttpHeaderConsts.USER_AGENT_HEADER, UtilAndComs.VERSION,
"Accept-Encoding", "gzip,deflate,sdch",
"Connection", "Keep-Alive",
"RequestId", UuidUtils.generateUuid(), "Request-Module", "Naming");
return headers;
public Header builderHeader() {
Header header = Header.newInstance();
header.addParam(HttpHeaderConsts.CLIENT_VERSION_HEADER, VersionUtils.version);
header.addParam(HttpHeaderConsts.USER_AGENT_HEADER, UtilAndComs.VERSION);
header.addParam(HttpHeaderConsts.ACCEPT_ENCODING, "gzip,deflate,sdch");
header.addParam(HttpHeaderConsts.CONNECTION, "Keep-Alive");
header.addParam(HttpHeaderConsts.REQUEST_ID, UuidUtils.generateUuid());
header.addParam(HttpHeaderConsts.REQUEST_MODULE, "Naming");
return header;
}
private static String getSignData(String serviceName) {

View File

@ -17,18 +17,21 @@ package com.alibaba.nacos.client.security;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.client.naming.net.HttpClient;
import com.alibaba.nacos.common.utils.HttpMethod;
import com.alibaba.nacos.client.naming.net.NamingHttpClientManager;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.codec.Charsets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.HttpURLConnection;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
/**
@ -43,6 +46,8 @@ public class SecurityProxy {
private static final String LOGIN_URL = "/v1/auth/users/login";
private NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getNacosRestTemplate();
private String contextPath;
/**
@ -110,28 +115,31 @@ public class SecurityProxy {
if (StringUtils.isNotBlank(username)) {
Map<String, String> params = new HashMap<String, String>(2);
Map<String, String> bodyMap = new HashMap<>(2);
params.put("username", username);
String body = "password=" + password;
bodyMap.put("password", password);
String url = "http://" + server + contextPath + LOGIN_URL;
if (server.contains(Constants.HTTP_PREFIX)) {
url = server + contextPath + LOGIN_URL;
}
HttpClient.HttpResult result = HttpClient.request(url, new ArrayList<String>(2),
params, body, Charsets.UTF_8.name(), HttpMethod.POST);
if (result.code != HttpURLConnection.HTTP_OK) {
SECURITY_LOGGER.error("login failed: {}", JacksonUtils.toJson(result));
try {
HttpRestResult<String> restResult = nacosRestTemplate.postForm(url, Header.EMPTY, params, bodyMap, String.class);
if (!restResult.ok()) {
SECURITY_LOGGER.error("login failed: {}", JacksonUtils.toJson(restResult));
return false;
}
JsonNode obj = JacksonUtils.toObj(restResult.getData());
if (obj.has(Constants.ACCESS_TOKEN)) {
accessToken = obj.get(Constants.ACCESS_TOKEN).asText();
tokenTtl = obj.get(Constants.TOKEN_TTL).asInt();
tokenRefreshWindow = tokenTtl / 10;
}
} catch (Exception e) {
SECURITY_LOGGER.error("[SecurityProxy] login http request failed" +
" url: {}, params: {}, bodyMap: {}, errorMsg: {}", url, params, bodyMap, e.getMessage());
return false;
}
JsonNode obj = JacksonUtils.toObj(result.content);
if (obj.has(Constants.ACCESS_TOKEN)) {
accessToken = obj.get(Constants.ACCESS_TOKEN).asText();
tokenTtl = obj.get(Constants.TOKEN_TTL).asInt();
tokenRefreshWindow = tokenTtl / 10;
}
}
return true;
}

View File

@ -0,0 +1,35 @@
/*
* 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.common;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation that marks a method as not thread safe.
*
* @author zongtanghu
*/
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface NotThreadSafe {
}

View File

@ -193,7 +193,7 @@ public enum BaseHttpMethod {
* @throws Exception exception
*/
public void initFromEntity(Map<String, String> body, String charset) throws Exception {
if (body.isEmpty()) {
if (body == null || body.isEmpty()) {
return;
}
List<NameValuePair> params = new ArrayList<NameValuePair>(body.size());

View File

@ -37,15 +37,9 @@ public final class HttpClientBeanHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientManager.class);
private static final int TIMEOUT = Integer.getInteger("nacos.http.timeout", 5000);
private static final HttpClientConfig HTTP_CLIENT_CONFIG = HttpClientConfig.builder().setConTimeOutMillis(TIMEOUT)
.setReadTimeOutMillis(TIMEOUT >> 1).build();
private static final Map<String, NacosRestTemplate> SINGLETON_REST = new HashMap<String, NacosRestTemplate>(10);
private static final Map<String, NacosAsyncRestTemplate> SINGLETON_ASYNC_REST = new HashMap<String, NacosAsyncRestTemplate>(
10);
private static final Map<String, NacosAsyncRestTemplate> SINGLETON_ASYNC_REST = new HashMap<String, NacosAsyncRestTemplate>(10);
private static final AtomicBoolean ALREADY_SHUTDOWN = new AtomicBoolean(false);

View File

@ -26,7 +26,6 @@ import java.io.InputStream;
* Represents a client-side HTTP response.
*
* @author mai.jh
* @date 2020/5/23
*/
public interface HttpClientResponse extends Closeable {

View File

@ -197,7 +197,7 @@ public class NacosAsyncRestTemplate {
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void putFrom(String url, Header header, Query query, Map<String, String> bodyValues, Type responseType,
public <T> void putForm(String url, Header header, Query query, Map<String, String> bodyValues, Type responseType,
Callback<T> callback) throws Exception {
execute(url, HttpMethod.PUT,
new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_FORM_URLENCODED), query, bodyValues),
@ -223,7 +223,7 @@ public class NacosAsyncRestTemplate {
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void putFrom(String url, Header header, Map<String, String> paramValues, Map<String, String> bodyValues,
public <T> void putForm(String url, Header header, Map<String, String> paramValues, Map<String, String> bodyValues,
Type responseType, Callback<T> callback) throws Exception {
execute(url, HttpMethod.PUT, new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_FORM_URLENCODED),
Query.newInstance().initParams(paramValues), bodyValues), responseType, callback);
@ -296,7 +296,7 @@ public class NacosAsyncRestTemplate {
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void postFrom(String url, Header header, Query query, Map<String, String> bodyValues, Type responseType,
public <T> void postForm(String url, Header header, Query query, Map<String, String> bodyValues, Type responseType,
Callback<T> callback) throws Exception {
execute(url, HttpMethod.POST,
new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_FORM_URLENCODED), query, bodyValues),
@ -322,7 +322,7 @@ public class NacosAsyncRestTemplate {
* @param callback callback {@link Callback#onReceive(com.alibaba.nacos.common.model.RestResult)}
* @throws Exception ex
*/
public <T> void postFrom(String url, Header header, Map<String, String> paramValues, Map<String, String> bodyValues,
public <T> void postForm(String url, Header header, Map<String, String> paramValues, Map<String, String> bodyValues,
Type responseType, Callback<T> callback) throws Exception {
execute(url, HttpMethod.POST,
new RequestHttpEntity(header.setContentType(MediaType.APPLICATION_FORM_URLENCODED),

View File

@ -35,7 +35,6 @@ import java.util.Map;
* Nacos rest template Interface specifying a basic set of RESTful operations.
*
* @author mai.jh
* @date 2020/5/24
* @see HttpClientRequest
* @see HttpClientResponse
*/
@ -178,7 +177,7 @@ public class NacosRestTemplate {
* @return {@link HttpRestResult}
* @throws Exception ex
*/
public <T> HttpRestResult<T> putFrom(String url, Header header, Query query, Map<String, String> bodyValues,
public <T> HttpRestResult<T> putForm(String url, Header header, Query query, Map<String, String> bodyValues,
Type responseType) throws Exception {
RequestHttpEntity requestHttpEntity = new RequestHttpEntity(
header.setContentType(MediaType.APPLICATION_FORM_URLENCODED), query, bodyValues);
@ -201,7 +200,7 @@ public class NacosRestTemplate {
* @return {@link HttpRestResult}
* @throws Exception ex
*/
public <T> HttpRestResult<T> putFrom(String url, Header header, Map<String, String> paramValues,
public <T> HttpRestResult<T> putForm(String url, Header header, Map<String, String> paramValues,
Map<String, String> bodyValues, Type responseType) throws Exception {
RequestHttpEntity requestHttpEntity = new RequestHttpEntity(
header.setContentType(MediaType.APPLICATION_FORM_URLENCODED),
@ -268,7 +267,7 @@ public class NacosRestTemplate {
* @return {@link HttpRestResult}
* @throws Exception ex
*/
public <T> HttpRestResult<T> postFrom(String url, Header header, Query query, Map<String, String> bodyValues,
public <T> HttpRestResult<T> postForm(String url, Header header, Query query, Map<String, String> bodyValues,
Type responseType) throws Exception {
RequestHttpEntity requestHttpEntity = new RequestHttpEntity(
header.setContentType(MediaType.APPLICATION_FORM_URLENCODED), query, bodyValues);
@ -291,7 +290,7 @@ public class NacosRestTemplate {
* @return {@link HttpRestResult}
* @throws Exception ex
*/
public <T> HttpRestResult<T> postFrom(String url, Header header, Map<String, String> paramValues,
public <T> HttpRestResult<T> postForm(String url, Header header, Map<String, String> paramValues,
Map<String, String> bodyValues, Type responseType) throws Exception {
RequestHttpEntity requestHttpEntity = new RequestHttpEntity(
header.setContentType(MediaType.APPLICATION_FORM_URLENCODED),
@ -299,6 +298,28 @@ public class NacosRestTemplate {
return execute(url, HttpMethod.POST, requestHttpEntity, responseType);
}
/**
* Execute the HTTP method to the given URI template, writing the given request entity to the request, and
* returns the response as {@link HttpRestResult}.
*
* @param url url
* @param header http header param
* @param paramValues http query param
* @param bodyValues http body param
* @param httpMethod http method
* @param responseType return type
* @return {@link HttpRestResult}
* @throws Exception ex
*/
public <T> HttpRestResult<T> exchangeForm(String url, Header header,
Map<String, String> paramValues, Map<String, String> bodyValues, String httpMethod, Type responseType) throws Exception{
RequestHttpEntity requestHttpEntity = new RequestHttpEntity(
header.setContentType(MediaType.APPLICATION_FORM_URLENCODED),
Query.newInstance().initParams(paramValues),
bodyValues);
return execute(url, httpMethod, requestHttpEntity, responseType);
}
private <T> HttpRestResult<T> execute(String url, String httpMethod, RequestHttpEntity requestEntity,
Type responseType) throws Exception {
URI uri = HttpUtils.buildUri(url, requestEntity.getQuery());

View File

@ -78,14 +78,22 @@ public final class ResponseHandler {
String contentType = headers.getValue(HttpHeaderConsts.CONTENT_TYPE);
InputStream body = response.getBody();
T extractBody = null;
final boolean typeToStr = String.class.toString().equals(type.toString());
if (contentType != null && contentType.startsWith(MediaType.APPLICATION_JSON) && HttpStatus.SC_OK == response
.getStatusCode()) {
extractBody = convert(body, type);
.getStatusCode()) {
// When the type is string type and the response contentType is [application/json],
// then it should be serialized as string
if (typeToStr) {
extractBody = (T) IoUtils.toString(body, headers.getCharset());
} else {
extractBody = convert(body, type);
}
}
if (extractBody == null) {
if (!String.class.toString().equals(type.toString())) {
if (!typeToStr) {
LOGGER.error(
"if the response contentType is not [application/json]," + " only support to java.lang.String");
"if the response contentType is not [application/json]," +
" only support to java.lang.String");
throw new NacosDeserializationException(type);
}
extractBody = (T) IoUtils.toString(body, headers.getCharset());

View File

@ -0,0 +1,210 @@
/*
* 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.common.notify;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
import com.alibaba.nacos.common.utils.ThreadUtils;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.ClassUtils;
import com.alibaba.nacos.common.utils.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import static com.alibaba.nacos.common.notify.NotifyCenter.ringBufferSize;
/**
* The default event publisher implementation.
*
* <p>Internally, use {@link ArrayBlockingQueue <Event/>} as a message staging queue.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @author zongtanghu
*/
public class DefaultPublisher extends Thread implements EventPublisher {
private static final Logger LOGGER = LoggerFactory.getLogger(NotifyCenter.class);
private volatile boolean initialized = false;
private volatile boolean shutdown = false;
private Class<? extends Event> eventType;
private final ConcurrentHashSet<Subscriber> subscribers = new ConcurrentHashSet<Subscriber>();
private int queueMaxSize = -1;
private BlockingQueue<Event> queue;
private volatile Long lastEventSequence = -1L;
private final AtomicReferenceFieldUpdater<DefaultPublisher, Long> updater = AtomicReferenceFieldUpdater
.newUpdater(DefaultPublisher.class, Long.class, "lastEventSequence");
@Override
public void init(Class<? extends Event> type, int bufferSize) {
setDaemon(true);
setName("nacos.publisher-" + type.getName());
this.eventType = type;
this.queueMaxSize = bufferSize;
this.queue = new ArrayBlockingQueue<Event>(bufferSize);
start();
}
public ConcurrentHashSet<Subscriber> getSubscribers() {
return subscribers;
}
@Override
public synchronized void start() {
if (!initialized) {
// start just called once
super.start();
if (queueMaxSize == -1) {
queueMaxSize = ringBufferSize;
}
initialized = true;
}
}
public long currentEventSize() {
return queue.size();
}
@Override
public void run() {
openEventHandler();
}
void openEventHandler() {
try {
// To ensure that messages are not lost, enable EventHandler when
// waiting for the first Subscriber to register
for (; ; ) {
if (shutdown || hasSubscriber()) {
break;
}
ThreadUtils.sleep(1000L);
}
for (; ; ) {
if (shutdown) {
break;
}
final Event event = queue.take();
receiveEvent(event);
updater.compareAndSet(this, lastEventSequence, Math.max(lastEventSequence, event.sequence()));
}
} catch (Throwable ex) {
LOGGER.error("Event listener exception : {}", ex);
}
}
private boolean hasSubscriber() {
return CollectionUtils.isNotEmpty(subscribers);
}
@Override
public void addSubscriber(Subscriber subscriber) {
subscribers.add(subscriber);
}
@Override
public void removeSubscriber(Subscriber subscriber) {
subscribers.remove(subscriber);
}
@Override
public boolean publish(Event event) {
checkIsStart();
boolean success = this.queue.offer(event);
if (!success) {
LOGGER.warn("Unable to plug in due to interruption, synchronize sending time, event : {}", event);
receiveEvent(event);
return true;
}
return true;
}
void checkIsStart() {
if (!initialized) {
throw new IllegalStateException("Publisher does not start");
}
}
@Override
public void shutdown() {
this.shutdown = true;
this.queue.clear();
}
public boolean isInitialized() {
return initialized;
}
void receiveEvent(Event event) {
final long currentEventSequence = event.sequence();
final String sourceName = ClassUtils.getName(event);
// Notification single event listener
for (Subscriber subscriber : subscribers) {
// Whether to ignore expiration events
if (subscriber.ignoreExpireEvent() && lastEventSequence > currentEventSequence) {
LOGGER.debug("[NotifyCenter] the {} is unacceptable to this subscriber, because had expire",
event.getClass());
continue;
}
final String targetName = ClassUtils.getName(subscriber.subscribeType());
if (!Objects.equals(sourceName, targetName)) {
continue;
}
notifySubscriber(subscriber, event);
}
}
@Override
public void notifySubscriber(final Subscriber subscriber, final Event event) {
LOGGER.debug("[NotifyCenter] the {} will received by {}", event, subscriber);
final Runnable job = new Runnable() {
@Override
public void run() {
subscriber.onEvent(event);
}
};
final Executor executor = subscriber.executor();
if (executor != null) {
executor.execute(job);
} else {
try {
job.run();
} catch (Throwable e) {
LOGGER.error("Event callback exception : {}", e);
}
}
}
}

View File

@ -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.common.notify;
import java.io.Serializable;
import java.util.concurrent.atomic.AtomicLong;
/**
* An abstract class for event.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @author zongtanghu
*/
@SuppressWarnings({"PMD.AbstractClassShouldStartWithAbstractNamingRule"})
public abstract class Event implements Serializable {
private static final AtomicLong SEQUENCE = new AtomicLong(0);
private final long sequence = SEQUENCE.getAndIncrement();
/**
* Event sequence number, which can be used to handle the sequence of events.
*
* @return sequence num, It's best to make sure it's monotone.
*/
public long sequence() {
return sequence;
}
}

View File

@ -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.common.notify;
import com.alibaba.nacos.common.lifecycle.Closeable;
import com.alibaba.nacos.common.notify.listener.Subscriber;
/**
* Event publisher.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @author zongtanghu
*/
public interface EventPublisher extends Closeable {
/**
* Initializes the event publisher.
*
* @param type {@link Event >}
* @param bufferSize Message staging queue size
*/
void init(Class<? extends Event> type, int bufferSize);
/**
* The number of currently staged events.
*
* @return event size
*/
long currentEventSize();
/**
* Add listener.
*
* @param subscriber {@link Subscriber}
*/
void addSubscriber(Subscriber subscriber);
/**
* Remove listener.
*
* @param subscriber {@link Subscriber}
*/
void removeSubscriber(Subscriber subscriber);
/**
* publish event.
*
* @param event {@link Event}
* @return publish event is success
*/
boolean publish(Event event);
/**
* Notify listener.
*
* @param subscriber {@link Subscriber}
* @param event {@link Event}
*/
void notifySubscriber(Subscriber subscriber, Event event);
}

View File

@ -0,0 +1,323 @@
/*
* 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.common.notify;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.JustForTest;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.alibaba.nacos.common.notify.listener.SmartSubscriber;
import com.alibaba.nacos.common.utils.BiFunction;
import com.alibaba.nacos.common.utils.ClassUtils;
import com.alibaba.nacos.common.utils.MapUtils;
import com.alibaba.nacos.common.utils.ThreadUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.NoSuchElementException;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import static com.alibaba.nacos.api.exception.NacosException.SERVER_ERROR;
/**
* Unified Event Notify Center.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @author zongtanghu
*/
public class NotifyCenter {
private static final Logger LOGGER = LoggerFactory.getLogger(NotifyCenter.class);
public static int ringBufferSize = 16384;
public static int shareBufferSize = 1024;
private static final AtomicBoolean CLOSED = new AtomicBoolean(false);
private static BiFunction<Class<? extends Event>, Integer, EventPublisher> publisherFactory = null;
private static final NotifyCenter INSTANCE = new NotifyCenter();
private EventPublisher sharePublisher;
private static Class<? extends EventPublisher> clazz = null;
/**
* Publisher management container.
*/
private final Map<String, EventPublisher> publisherMap = new ConcurrentHashMap<String, EventPublisher>(16);
static {
// Internal ArrayBlockingQueue buffer size. For applications with high write throughput,
// this value needs to be increased appropriately. default value is 16384
String ringBufferSizeProperty = "nacos.core.notify.ring-buffer-size";
ringBufferSize = Integer.getInteger(ringBufferSizeProperty, 16384);
// The size of the public publisher's message staging queue buffer
String shareBufferSizeProperty = "nacos.core.notify.share-buffer-size";
shareBufferSize = Integer.getInteger(shareBufferSizeProperty, 1024);
final ServiceLoader<EventPublisher> loader = ServiceLoader.load(EventPublisher.class);
Iterator<EventPublisher> iterator = loader.iterator();
if (iterator.hasNext()) {
clazz = iterator.next().getClass();
} else {
clazz = DefaultPublisher.class;
}
publisherFactory = new BiFunction<Class<? extends Event>, Integer, EventPublisher>() {
@Override
public EventPublisher apply(Class<? extends Event> cls, Integer buffer) throws NacosException {
try {
EventPublisher publisher = clazz.newInstance();
publisher.init(cls, buffer);
return publisher;
} catch (Throwable ex) {
LOGGER.error("Service class newInstance has error : {}", ex);
throw new NacosException(SERVER_ERROR, ex);
}
}
};
try {
INSTANCE.sharePublisher = publisherFactory.apply(SlowEvent.class, shareBufferSize);
} catch (Throwable ex) {
LOGGER.error("Service class newInstance has error : {}", ex);
}
ThreadUtils.addShutdownHook(new Runnable() {
@Override
public void run() {
shutdown();
}
});
}
@JustForTest
public static Map<String, EventPublisher> getPublisherMap() {
return INSTANCE.publisherMap;
}
@JustForTest
public static EventPublisher getPublisher(Class<? extends Event> topic) {
if (ClassUtils.isAssignableFrom(SlowEvent.class, topic)) {
return INSTANCE.sharePublisher;
}
return INSTANCE.publisherMap.get(topic.getCanonicalName());
}
@JustForTest
public static EventPublisher getSharePublisher() {
return INSTANCE.sharePublisher;
}
/**
* Shutdown the serveral publisher instance which notifycenter has.
*/
public static void shutdown() {
if (!CLOSED.compareAndSet(false, true)) {
return;
}
LOGGER.warn("[NotifyCenter] Start destroying Publisher");
for (Map.Entry<String, EventPublisher> entry : INSTANCE.publisherMap.entrySet()) {
try {
EventPublisher eventPublisher = entry.getValue();
eventPublisher.shutdown();
} catch (Throwable e) {
LOGGER.error("[EventPublisher] shutdown has error : {}", e);
}
}
try {
INSTANCE.sharePublisher.shutdown();
} catch (Throwable e) {
LOGGER.error("[SharePublisher] shutdown has error : {}", e);
}
LOGGER.warn("[NotifyCenter] Destruction of the end");
}
/**
* Register a Subscriber. If the Publisher concerned by the Subscriber does not exist, then PublihserMap will
* preempt a placeholder Publisher first.
*
* @param consumer subscriber
* @param <T> event type
*/
public static <T> void registerSubscriber(final Subscriber consumer) throws NacosException {
final Class<? extends Event> cls = consumer.subscribeType();
// If you want to listen to multiple events, you do it separately,
// based on subclass's subscribeTypes method return list, it can register to publisher.
if (consumer instanceof SmartSubscriber) {
for (Class<? extends Event> subscribeType : ((SmartSubscriber) consumer).subscribeTypes()) {
addSubscriber(consumer, subscribeType);
}
return;
}
if (ClassUtils.isAssignableFrom(SlowEvent.class, cls)) {
INSTANCE.sharePublisher.addSubscriber(consumer);
return;
}
addSubscriber(consumer, consumer.subscribeType());
}
/**
* Add a subscriber to pusblisher.
*
* @param consumer subscriber instance.
* @param subscribeType subscribeType.
* @throws NacosException BiFunction mappingFunction may throw a NacosException.
*/
private static void addSubscriber(final Subscriber consumer, Class<? extends Event> subscribeType)
throws NacosException {
final String topic = ClassUtils.getCanonicalName(subscribeType);
MapUtils.computeIfAbsent(INSTANCE.publisherMap, topic, publisherFactory, subscribeType, ringBufferSize);
EventPublisher publisher = INSTANCE.publisherMap.get(topic);
publisher.addSubscriber(consumer);
}
/**
* Deregister subscriber.
*
* @param consumer subscriber instance.
*/
public static <T> void deregisterSubscriber(final Subscriber consumer) {
final Class<? extends Event> cls = consumer.subscribeType();
if (consumer instanceof SmartSubscriber) {
for (Class<? extends Event> subscribeType : ((SmartSubscriber) consumer).subscribeTypes()) {
removeSubscriber(consumer, subscribeType);
}
return;
}
if (ClassUtils.isAssignableFrom(SlowEvent.class, cls)) {
INSTANCE.sharePublisher.removeSubscriber(consumer);
return;
}
if (removeSubscriber(consumer, consumer.subscribeType())) {
return;
}
throw new NoSuchElementException("The subcriber has no event publisher");
}
/**
* Remove subscriber.
*
* @param consumer subscriber instance.
* @param subscribeType subscribeType.
* @return whether remove subscriber successfully or not.
*/
private static boolean removeSubscriber(final Subscriber consumer, Class<? extends Event> subscribeType) {
final String topic = ClassUtils.getCanonicalName(subscribeType);
if (INSTANCE.publisherMap.containsKey(topic)) {
EventPublisher publisher = INSTANCE.publisherMap.get(topic);
publisher.removeSubscriber(consumer);
return true;
}
return false;
}
/**
* Request publisher publish event Publishers load lazily, calling publisher. Start () only when the event is
* actually published.
*
* @param event class Instances of the event.
*/
public static boolean publishEvent(final Event event) {
try {
return publishEvent(event.getClass(), event);
} catch (Throwable ex) {
LOGGER.error("There was an exception to the message publishing : {}", ex);
return false;
}
}
/**
* Request publisher publish event Publishers load lazily, calling publisher.
*
* @param eventType class Instances type of the event type.
* @param event event instance.
*/
private static boolean publishEvent(final Class<? extends Event> eventType, final Event event) {
final String topic = ClassUtils.getCanonicalName(eventType);
if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {
return INSTANCE.sharePublisher.publish(event);
}
if (INSTANCE.publisherMap.containsKey(topic)) {
EventPublisher publisher = INSTANCE.publisherMap.get(topic);
return publisher.publish(event);
}
throw new NoSuchElementException("There are no [" + topic + "] publishers for this event, please register");
}
/**
* Register to share-publisher.
*
* @param eventType class Instances type of the event type.
* @return share publisher instance.
*/
public static EventPublisher registerToSharePublisher(final Class<? extends SlowEvent> eventType) {
return INSTANCE.sharePublisher;
}
/**
* Register publisher.
*
* @param eventType class Instances type of the event type.
* @param queueMaxSize the publisher's queue max size.
*/
public static EventPublisher registerToPublisher(final Class<? extends Event> eventType, final int queueMaxSize)
throws NacosException {
if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {
return INSTANCE.sharePublisher;
}
final String topic = ClassUtils.getCanonicalName(eventType);
MapUtils.computeIfAbsent(INSTANCE.publisherMap, topic, publisherFactory, eventType, queueMaxSize);
EventPublisher publisher = INSTANCE.publisherMap.get(topic);
return publisher;
}
/**
* Deregister publisher.
*
* @param eventType class Instances type of the event type.
*/
public static void deregisterPublisher(final Class<? extends Event> eventType) {
final String topic = ClassUtils.getCanonicalName(eventType);
EventPublisher publisher = INSTANCE.publisherMap.remove(topic);
try {
publisher.shutdown();
} catch (Throwable ex) {
LOGGER.error("There was an exception when publisher shutdown : {}", ex);
}
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.common.notify;
/**
* This event share one event-queue.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @author zongtanghu
*/
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
public abstract class SlowEvent extends Event {
@Override
public long sequence() {
return 0;
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.common.notify.listener;
import com.alibaba.nacos.common.notify.Event;
import java.util.List;
/**
* Subscribers to multiple events can be listened to.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @author zongtanghu
*/
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
public abstract class SmartSubscriber extends Subscriber {
/**
* Returns which event type are smartsubscriber interested in.
*
* @return The interestd event types.
*/
public abstract List<Class<? extends Event>> subscribeTypes();
@Override
public final Class<? extends Event> subscribeType() {
return null;
}
@Override
public final boolean ignoreExpireEvent() {
return false;
}
}

View File

@ -0,0 +1,63 @@
/*
* 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.common.notify.listener;
import com.alibaba.nacos.common.notify.Event;
import java.util.concurrent.Executor;
/**
* An abstract subscriber class for subscriber interface.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
* @author zongtanghu
*/
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
public abstract class Subscriber<T extends Event> {
/**
* Event callback.
*
* @param event {@link Event}
*/
public abstract void onEvent(T event);
/**
* Type of this subscriber's subscription.
*
* @return Class which extends {@link Event}
*/
public abstract Class<? extends Event> subscribeType();
/**
* It is up to the listener to determine whether the callback is asynchronous or synchronous.
*
* @return {@link Executor}
*/
public Executor executor() {
return null;
}
/**
* Whether to ignore expired events.
*
* @return default value is {@link Boolean#FALSE}
*/
public boolean ignoreExpireEvent() {
return false;
}
}

View File

@ -0,0 +1,42 @@
/*
* 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.common.utils;
import com.alibaba.nacos.api.exception.NacosException;
/**
* Represents a function that accepts two arguments and produces a result.
* The following utility functions are extracted from org.apache.commons.lang3.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object, Object)}.
*
* @author zongtanghu
*
*/
public interface BiFunction<T, U, R> {
/**
* Applies this function to the two given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
* @throws NacosException function throws NacosException
*/
R apply(T t, U u) throws NacosException;
}

View File

@ -0,0 +1,123 @@
/*
* 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.common.utils;
import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException;
import static com.alibaba.nacos.api.exception.NacosException.SERVER_ERROR;
/**
* Utils for Class.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
public final class ClassUtils {
/**
* Finds and returns class by className.
*
* @param className String value for className.
* @return class Instances of the class represent classes and interfaces.
*/
public static Class findClassByName(String className) {
try {
return Class.forName(className);
} catch (Exception e) {
throw new NacosRuntimeException(SERVER_ERROR, "this class name not found");
}
}
/**
* Determines if the class or interface represented by this object is either the same as, or is a superclass or
* superinterface of, the class or interface represented by the specified parameter.
*
* @param clazz Instances of the class represent classes and interfaces.
* @param cls Instances of the class represent classes and interfaces.
* @return the value indicating whether objects of the type can be assigned to objects of this class.
*/
public static boolean isAssignableFrom(Class clazz, Class cls) {
Objects.requireNonNull(cls, "cls");
return clazz.isAssignableFrom(cls);
}
/**
* Gets and returns the class name.
*
* @param cls Instances of the class represent classes and interfaces.
* @return the name of the class or interface represented by this object.
*/
public static String getName(Class cls) {
Objects.requireNonNull(cls, "cls");
return cls.getName();
}
/**
* Gets and returns className.
*
* @param obj Object instance.
* @return className.
*/
public static String getName(Object obj) {
Objects.requireNonNull(obj, "obj");
return obj.getClass().getName();
}
/**
* Gets and returns the canonical name of the underlying class.
*
* @param cls Instances of the class represent classes and interfaces.
* @return The canonical name of the underlying class.
*/
public static String getCanonicalName(Class cls) {
Objects.requireNonNull(cls, "cls");
return cls.getCanonicalName();
}
/**
* Gets and returns the canonical name of the underlying class.
*
* @param obj Object instance.
* @return The canonical name of the underlying class.
*/
public static String getCanonicalName(Object obj) {
Objects.requireNonNull(obj, "obj");
return obj.getClass().getCanonicalName();
}
/**
* Gets and returns the simple name of the underlying class.
*
* @param cls Instances of the class represent classes and interfaces.
* @return the simple name of the underlying class.
*/
public static String getSimplaName(Class cls) {
Objects.requireNonNull(cls, "cls");
return cls.getSimpleName();
}
/**
* Gets and returns the simple name of the underlying class as given in the source code.
*
* @param obj Object instance.
* @return the simple name of the underlying class.
*/
public static String getSimplaName(Object obj) {
Objects.requireNonNull(obj, "obj");
return obj.getClass().getSimpleName();
}
}

View File

@ -16,6 +16,9 @@
package com.alibaba.nacos.common.utils;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.common.NotThreadSafe;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Map;
@ -124,4 +127,32 @@ public class MapUtils {
}
}
/**
* ComputeIfAbsent lazy load.
*
* @param target target Map data.
* @param key map key.
* @param mappingFunction funtion which is need to be executed.
* @param param1 function's parameter value1.
* @param param2 function's parameter value1.
* @return
*/
@NotThreadSafe
public static Object computeIfAbsent(Map target, Object key, BiFunction mappingFunction, Object param1,
Object param2) throws NacosException {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(key, "mappingFunction");
Objects.requireNonNull(key, "param1");
Objects.requireNonNull(key, "param2");
Object val = target.get(key);
if (val == null) {
Object ret = mappingFunction.apply(param1, param2);
target.put(key, ret);
return ret;
}
return val;
}
}

View File

@ -48,14 +48,14 @@ Volunteer wanted.
#### checkstyle
[chechstyle-idea-install](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea)
1. Preferences/Settings --> Other Settings --> Checkstyle
1. `Preferences/Settings --> Other Settings --> Checkstyle` OR `Preferences/Settings --> Tools --> Checkstyle`
2. Set checkstyle version at least 8.30 and scan scope `All resource(including tests)` in checkstyle plugin.
3. Import `style/NacosCheckStyle.xml` to checkstyle plugin.
4. Scan and check your modified code by plugin.
[chechstyle插件idea安装](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea)
1. Preferences/Settings --> Other Settings --> Checkstyle
1. `Preferences/Settings --> Other Settings --> Checkstyle` 或者 `Preferences/Settings --> Tools --> Checkstyle`
2. 在checkstyle插件中设置checkstyle版本至少为8.30,并将扫描作用域设置为`All resource(including tests)`
3. 导入源代码下`style/NacosCheckStyle.xml`文件到checkstyle插件。
4. 用checkstyle插件扫描你修改的代码。

View File

@ -88,14 +88,14 @@ public class NacosAsyncRestTemplate_ITCase {
}
@Test
public void test_url_post_from() throws Exception{
public void test_url_post_form() throws Exception{
String url = IP + CONFIG_INSTANCE_PATH + "/instance";
Map<String, String> param = new HashMap<>();
param.put("serviceName", "app-test");
param.put("port", "8080");
param.put("ip", "11.11.11.11");
CallbackMap<String> callbackMap = new CallbackMap<>();
nacosRestTemplate.postFrom(url, Header.newInstance(), Query.newInstance(), param, String.class, callbackMap);
nacosRestTemplate.postForm(url, Header.newInstance(), Query.newInstance(), param, String.class, callbackMap);
Thread.sleep(2000);
HttpRestResult<String> restResult = callbackMap.getRestResult();
System.out.println(restResult.getData());
@ -104,14 +104,14 @@ public class NacosAsyncRestTemplate_ITCase {
}
@Test
public void test_url_put_from() throws Exception{
public void test_url_put_form() throws Exception{
String url = IP + CONFIG_INSTANCE_PATH + "/instance";
Map<String, String> param = new HashMap<>();
param.put("serviceName", "app-test-change");
param.put("port", "8080");
param.put("ip", "11.11.11.11");
CallbackMap<String> callbackMap = new CallbackMap<>();
nacosRestTemplate.putFrom(url, Header.newInstance(), Query.newInstance(), param, String.class, callbackMap);
nacosRestTemplate.postForm(url, Header.newInstance(), Query.newInstance(), param, String.class, callbackMap);
Thread.sleep(2000);
HttpRestResult<String> restResult = callbackMap.getRestResult();
System.out.println(restResult.getData());

View File

@ -69,7 +69,7 @@ public class NacosRestTemplate_ITCase {
param.put("dataId", "test-1");
param.put("group", "DEFAULT_GROUP");
param.put("content", "aaa=b");
HttpRestResult<String> restResult = nacosRestTemplate.postFrom(url, Header.newInstance(), Query.EMPTY, param, String.class);
HttpRestResult<String> restResult = nacosRestTemplate.postForm(url, Header.newInstance(), Query.EMPTY, param, String.class);
Assert.assertTrue(restResult.ok());
System.out.println(restResult.getData());
System.out.println(restResult.getHeader());
@ -87,13 +87,13 @@ public class NacosRestTemplate_ITCase {
@Test
public void test_url_post_from() throws Exception{
public void test_url_post_form() throws Exception{
String url = IP + INSTANCE_PATH + "/instance";
Map<String, String> param = new HashMap<>();
param.put("serviceName", "app-test");
param.put("port", "8080");
param.put("ip", "11.11.11.11");
HttpRestResult<String> restResult = nacosRestTemplate.postFrom(url, Header.newInstance(), Query.newInstance(), param, String.class);
HttpRestResult<String> restResult = nacosRestTemplate.postForm(url, Header.newInstance(), Query.newInstance(), param, String.class);
Assert.assertTrue(restResult.ok());
System.out.println(restResult.getData());
}
@ -105,7 +105,7 @@ public class NacosRestTemplate_ITCase {
param.put("serviceName", "app-test-change");
param.put("port", "8080");
param.put("ip", "11.11.11.11");
HttpRestResult<String> restResult = nacosRestTemplate.putFrom(url, Header.newInstance(), Query.newInstance(), param, String.class);
HttpRestResult<String> restResult = nacosRestTemplate.putForm(url, Header.newInstance(), Query.newInstance(), param, String.class);
Assert.assertTrue(restResult.ok());
System.out.println(restResult.getData());
}

View File

@ -74,7 +74,7 @@ public class AutoDeregisterInstance_ITCase {
}
@After
public void destroy() {
public void destroy() throws Exception{
NamingBase.destoryServer(port);
}

View File

@ -16,10 +16,13 @@
package com.alibaba.nacos.test.naming;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.net.HttpClient;
import com.alibaba.nacos.client.naming.net.NamingHttpClientManager;
import com.alibaba.nacos.common.constant.HttpHeaderConsts;
import com.alibaba.nacos.common.http.HttpRestResult;
import com.alibaba.nacos.common.http.client.NacosRestTemplate;
import com.alibaba.nacos.common.http.param.Header;
import com.alibaba.nacos.common.http.param.Query;
import com.alibaba.nacos.test.base.HttpClient4Test;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.junit.Assert;
@ -30,6 +33,7 @@ import java.util.*;
*/
public class NamingBase extends HttpClient4Test {
private static final NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getNacosRestTemplate();
public static final String TEST_DOM_1 = "nacos.test.1";
public static final String TEST_IP_4_DOM_1 = "127.0.0.1";
@ -166,39 +170,32 @@ public class NamingBase extends HttpClient4Test {
return true;
}
public static void prepareServer(int localPort) {
public static void prepareServer(int localPort) throws Exception{
prepareServer(localPort, "UP");
}
public static void prepareServer(int localPort, String status) {
public static void prepareServer(int localPort, String status) throws Exception {
String url = "http://127.0.0.1:" + localPort + "/nacos/v1/ns/operator/switches?entry=overriddenServerStatus&value=" + status;
List<String> headers = new ArrayList<String>();
headers.add(HttpHeaderConsts.USER_AGENT_HEADER);
headers.add("Nacos-Server");
HttpClient.HttpResult result =
HttpClient.request(url, headers, new HashMap<String, String>(), StringUtils.EMPTY, "UTF-8", "PUT");
Header header = Header.newInstance();
header.addParam(HttpHeaderConsts.USER_AGENT_HEADER, "Nacos-Server");
HttpRestResult<String> result = nacosRestTemplate.putForm(url, header, Query.EMPTY, new HashMap<>(), String.class);
System.out.println(result);
Assert.assertEquals(HttpStatus.SC_OK, result.code);
Assert.assertEquals(HttpStatus.SC_OK, result.getCode());
url = "http://127.0.0.1:" + localPort + "/nacos/v1/ns/operator/switches?entry=autoChangeHealthCheckEnabled&value=" + false;
headers = new ArrayList<String>();
headers.add(HttpHeaderConsts.USER_AGENT_HEADER);
headers.add("Nacos-Server");
result =
HttpClient.request(url, headers, new HashMap<String, String>(), StringUtils.EMPTY, "UTF-8", "PUT");
result = nacosRestTemplate.putForm(url, header, Query.EMPTY, new HashMap<>(), String.class);
System.out.println(result);
Assert.assertEquals(HttpStatus.SC_OK, result.code);
Assert.assertEquals(HttpStatus.SC_OK, result.getCode());
}
public static void destoryServer(int localPort) {
public static void destoryServer(int localPort) throws Exception{
String url = "http://127.0.0.1:" + localPort + "/nacos/v1/ns/operator/switches?entry=autoChangeHealthCheckEnabled&value=" + true;
List<String> headers = new ArrayList<String>();
headers.add(HttpHeaderConsts.USER_AGENT_HEADER);
headers.add("Nacos-Server");
HttpClient.HttpResult result =
HttpClient.request(url, headers, new HashMap<String, String>(), StringUtils.EMPTY, "UTF-8", "PUT");
Header header = Header.newInstance();
header.addParam(HttpHeaderConsts.USER_AGENT_HEADER, "Nacos-Server");
HttpRestResult<String> result = nacosRestTemplate.putForm(url, header, Query.EMPTY, new HashMap<>(), String.class);
System.out.println(result);
Assert.assertEquals(HttpStatus.SC_OK, result.code);
Assert.assertEquals(HttpStatus.SC_OK, result.getCode());
}
}