From a15ef8eb3ac177fc0bd15d84301b301e9fa0c973 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 28 Aug 2022 17:35:39 +0800 Subject: [PATCH 001/181] Add the base interface and entity for ability control. --- .../api/ability/constant/AbilityKey.java | 111 ++++++++++++++++++ .../api/ability/constant/AbilityStatus.java | 46 ++++++++ .../api/ability/entity/AbilityTable.java | 98 ++++++++++++++++ .../nacos/api/utils/AbilityTableUtils.java | 100 ++++++++++++++++ .../handler/AbilityHandlePreProcessor.java | 36 ++++++ .../ability/handler/HandlerMapping.java | 41 +++++++ .../ability/inter/AbilityControlManager.java | 95 +++++++++++++++ .../ability/inter/AbilityHandlerRegistry.java | 81 +++++++++++++ .../inter/TraceableAbilityControlManager.java | 44 +++++++ 9 files changed, 652 insertions(+) create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java create mode 100644 api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/handler/AbilityHandlePreProcessor.java create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/handler/HandlerMapping.java create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/inter/TraceableAbilityControlManager.java diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java new file mode 100644 index 00000000000..0971ca7af6f --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java @@ -0,0 +1,111 @@ +/* + * Copyright 1999-2022 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.ability.constant; + +import com.alibaba.nacos.api.utils.AbilityTableUtils; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/**. + * @author Daydreamer + * @description Ability table key. It can be a replacement of {@link com.alibaba.nacos.api.ability.ServerAbilities} + * and {@link com.alibaba.nacos.api.ability.ClientAbilities}. + * @date 2022/7/12 19:23 + **/ +@SuppressWarnings("unchecked") +public class AbilityKey { + + private static final HashMap CURRENT_SERVER_SUPPORT_ABILITY = new HashMap<>(); + + private static final HashMap CURRENT_SERVER_ABILITY_OFFSET = new HashMap<>(); + + private static final byte[] ABILITY_BIT_FLAGS; + + private AbilityKey() { + } + + static { + /* + * example: + * There is a function named "compression". + * The key is "compression", the value is the offset of the flag bit of this ability in the ability table. The value should be unique. + * + * You can add a new public static field like: + * public static final String COMPRESSION = "compression"; + * This field can be used outside. + * + * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: + * CURRENT_NODE_ABILITY_TABLE.put("compression", 1); means that is the first bit from left to right in the table. + * + */ + + // put ability here, which you want current server supports + + } + + /**. + * Return ability table of current node + * But this ability is static which means that this ability table is all function this node supports if no one to ask it to close some functions. + * If you want to get what function current node is supporting, you should call AbilityControlManager#getCurrentAbility + * By the way, AbilityControlManager is singleton, you can get it by static method + * + * @return ability table + */ + public static Map getCurrentNodeSupportAbility() { + return Collections.unmodifiableMap(CURRENT_SERVER_SUPPORT_ABILITY); + } + + /**. + * Return the static ability bit table + * + * @return ability bit table + */ + public static byte[] getAbilityBitFlags() { + return ABILITY_BIT_FLAGS.clone(); + } + + /**. + * Is it a legal key + * + * @param key input + * @return whether a legal key + */ + public static boolean isLegal(String key) { + return CURRENT_SERVER_SUPPORT_ABILITY.containsKey(key); + } + + static { + // init the bits table + ABILITY_BIT_FLAGS = AbilityTableUtils.getAbilityBitBy(CURRENT_SERVER_ABILITY_OFFSET.values()); + // init the ability table, default all true + CURRENT_SERVER_ABILITY_OFFSET.forEach((k, v) -> { + CURRENT_SERVER_SUPPORT_ABILITY.put(k, Boolean.TRUE); + }); + } + + /**. + * Return the ability bit offsets + * + * @return bit offset + */ + public static Map offset() { + return CURRENT_SERVER_ABILITY_OFFSET; + } + +} diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java new file mode 100644 index 00000000000..825e99a0a1a --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2022 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.ability.constant; + +/**. + * @author Daydreamer + * @description This enum is used to track the status of the ability table. + * @date 2022/7/13 14:11 + **/ +public enum AbilityStatus { + + /** + * It means that the ability table does not exist in the current node. + */ + NOT_EXIST, + + /** + * It means that current node has received the ability table and the table is initializing by AbilityPostProcessor. + */ + INITIALIZING, + + /** + * It means that the ability table is ready. + */ + READY, + + /** + * It means that the ability table will be removed soon. + */ + EXPIRED + +} diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java new file mode 100644 index 00000000000..921a092a773 --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java @@ -0,0 +1,98 @@ +/* + * Copyright 1999-2022 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.ability.entity; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; + +import java.util.Map; + +/**. + * @author Daydreamer + * @description This table is linked to a server node or client node. + * @date 2022/7/12 19:25 + **/ +public class AbilityTable implements Cloneable { + + /**. + * id in connection instance + */ + private String connectionId; + + /**. + * ability table + * key: name from {@link AbilityKey} + * value: whether to turn on + */ + private Map ability; + + /**. + * whether it from a server node + */ + private boolean isServer; + + /**. + * version of the client corresponding to the connection + */ + private String version; + + public AbilityTable() { + } + + public boolean isServer() { + return isServer; + } + + public AbilityTable setServer(boolean server) { + isServer = server; + return this; + } + + public String getVersion() { + return version; + } + + public AbilityTable setVersion(String version) { + this.version = version; + return this; + } + + public AbilityTable(String connectionId, Map ability, boolean isServer, String version) { + this.connectionId = connectionId; + this.ability = ability; + this.isServer = isServer; + this.version = version; + } + + public String getConnectionId() { + return connectionId; + } + + public AbilityTable setConnectionId(String connectionId) { + this.connectionId = connectionId; + return this; + } + + public Map getAbility() { + return ability; + } + + public AbilityTable setAbility(Map ability) { + this.ability = ability; + return this; + } + +} diff --git a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java new file mode 100644 index 00000000000..11ad28cc054 --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java @@ -0,0 +1,100 @@ +/* + * Copyright 1999-2022 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; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/**. + * @author Daydreamer + * @description It is used to operate ability table. + * @date 2022/7/12 19:23 + **/ +public class AbilityTableUtils { + + private static final int BASE = 128; + + private AbilityTableUtils() { + } + + /**. + * get ability bit table from Collection + * + * @param bitCollection bit offset + * @return bit table + */ + public static byte[] getAbilityBitBy(Collection bitCollection) { + if (bitCollection.size() == 0) { + return new byte[1]; + } + Integer max = Collections.max(bitCollection); + // calculate byte[] + int mark = max % 8; + int length = max / 8 + (mark == 0 ? 0 : 1); + byte[] res = new byte[length]; + bitCollection.forEach(offset -> { + int index = offset / 8 + (offset % 8 == 0 ? -1 : 0); + int flag = offset % 8; + if (flag == 0) { + flag = 8; + } + byte x = (byte) (BASE >>> (flag - 1)); + res[index] = (byte) (res[index] | x); + }); + return res; + } + + /**. + * get ability table by bits + * + * @param bits bit flag + * @param offsetMap offset from {@link AbilityKey} + * @return Return the Map containing AbilityTableKey and isRunning. + */ + public static Map getAbilityTableBy(byte[] bits, Map offsetMap) { + if (bits == null || offsetMap.size() == 0) { + return Collections.emptyMap(); + } + int length = bits.length; + Set> entries = offsetMap.entrySet(); + Map res = new HashMap<>(offsetMap.size()); + for (Map.Entry entry : entries) { + String abilityKey = entry.getKey(); + Integer offset = entry.getValue(); + // if not exists + int index = offset / 8 + (offset % 8 == 0 ? -1 : 0); + if (index + 1 > length) { + res.put(abilityKey, Boolean.FALSE); + continue; + } + // find + int flag = offset % 8; + if (flag == 0) { + flag = 8; + } + byte x = (byte) (BASE >>> (flag - 1)); + byte tmp = (byte) (x & bits[index]); + res.put(abilityKey, x == tmp); + } + return res; + } +} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/handler/AbilityHandlePreProcessor.java b/common/src/main/java/com/alibaba/nacos/common/ability/handler/AbilityHandlePreProcessor.java new file mode 100644 index 00000000000..252f8112359 --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/handler/AbilityHandlePreProcessor.java @@ -0,0 +1,36 @@ +/* + * Copyright 1999-2022 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.ability.handler; + +import com.alibaba.nacos.api.ability.entity.AbilityTable; + +/**. + * @author Daydreamer + * @description This handler will should be invoked before ability table joining current node. + * @date 2022/7/12 19:24 + **/ +public interface AbilityHandlePreProcessor { + + /** + * Handling before joining current node. + * + * @param source source ability handler + * @return result table + */ + AbilityTable handle(AbilityTable source); + +} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/handler/HandlerMapping.java b/common/src/main/java/com/alibaba/nacos/common/ability/handler/HandlerMapping.java new file mode 100644 index 00000000000..e7623d5e033 --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/handler/HandlerMapping.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2022 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.ability.handler; + +/**. + * @author Daydreamer + * @description This component will be invoked if the ability of current node is turned on/off. + * @date 2022/7/12 19:21 + **/ +public interface HandlerMapping { + + /**. + * It will be invoked in order to enable this component after update the + * ability table key to true + */ + default void enable() { + // Nothing to do! + } + + /**. + * It will be invoked in order to disable this component after update the + * ability table key to false + */ + default void disable() { + // Nothing to do! + } +} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java new file mode 100644 index 00000000000..15adf7fc924 --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java @@ -0,0 +1,95 @@ +/* + * Copyright 1999-2022 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.ability.inter; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.common.ability.handler.AbilityHandlePreProcessor; + +import java.util.Map; + +/**. + * @author Daydreamer + * @description This is a base interface to manage ability table + * @date 2022/8/10 23:18 + **/ +public interface AbilityControlManager { + + /** + * Whether the ability is supported for Connection. If the ability of current node is closed, it will return false. + * + * @param connectionId the connection range of ability table. + * @param abilityKey key name which comes from {@link AbilityKey}. + * @return whether the ability is supported in certain connection. + */ + boolean isSupport(String connectionId, String abilityKey); + + /** + * Whether the ability current node supporting is running. Return false if current node doesn't support. + * + * @param abilityKey ability key + * @return is running + */ + boolean isCurrentNodeAbilityRunning(String abilityKey); + + /** + * Register a new ability table. + * + * @param table the ability table. + */ + void addNewTable(AbilityTable table); + + /**. + * Remove a ability table + * + * @param connectionId the ability table which is removing. + */ + void removeTable(String connectionId); + + /**. + * whether contains this ability table + * + * @param connectionId connection id + * @return whether contains + */ + boolean contains(String connectionId); + + /**. + * Return ability table of current node + * + * @return ability table + */ + Map getCurrentRunningAbility(); + + /**. + * They will be invoked before updating ability table, but the order in which + * they are called cannot be guaranteed + * + * @param postProcessor PostProcessor instance + */ + void addPostProcessor(AbilityHandlePreProcessor postProcessor); + + /**. + * Initialize the manager + */ + void init(); + + /**. + * It should be invoked before destroy + */ + void destroy(); +} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java new file mode 100644 index 00000000000..c2725478466 --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java @@ -0,0 +1,81 @@ +/* + * Copyright 1999-2022 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.ability.inter; + +import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; +import com.alibaba.nacos.common.ability.handler.HandlerMapping; + +/**. + * @author Daydreamer + * @description It provides the capability to notify components which interested in one ability for the {@link AbilityControlManager} + * @date 2022/8/10 23:43 + **/ +public interface AbilityHandlerRegistry { + + /**. + * Turn on the ability whose key is

abilityKey

+ * + * @param abilityKey ability key + * @return if turn success + */ + boolean enableCurrentNodeAbility(String abilityKey); + + /**. + * Turn off the ability whose key is

abilityKey

+ * + * @param abilityKey ability key + * @return if turn success + */ + boolean disableCurrentNodeAbility(String abilityKey); + + /**. + * Register the component which is managed by {@link AbstractAbilityControlManager}. + * if you are hoping that a component will be invoked when turn on/off the ability whose key is

abilityKey

. + * + * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param priority a positive number, the higher the priority is, the faster it will be called. `1` is the lowest priority. + * @param handlerMapping component instance. + */ + void registerComponent(String abilityKey, HandlerMapping handlerMapping, int priority); + + /**. + * Default method to register component with the lowest priority. + * + * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param handlerMapping component instance. + */ + default void registerComponent(String abilityKey, HandlerMapping handlerMapping) { + registerComponent(abilityKey, handlerMapping, 1); + } + + /** + * Remove the component instance of

handlerMappingClazz

. + * + * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param handlerMappingClazz implement of {@link HandlerMapping} + * @return the count of components have removed + */ + int removeComponent(String abilityKey, Class handlerMappingClazz); + + /** + * Remove all {@link HandlerMapping} interested in the special ability. + * @param abilityKey abnility key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @return the count of components have removed + */ + int removeAll(String abilityKey); + +} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/TraceableAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/TraceableAbilityControlManager.java new file mode 100644 index 00000000000..6b87b9b38fc --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/TraceableAbilityControlManager.java @@ -0,0 +1,44 @@ +/* + * Copyright 1999-2022 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.ability.inter; + +import com.alibaba.nacos.api.ability.constant.AbilityStatus; + +/**. + * @author Daydreamer + * @description It provides the capability to trace the state of AbilityTable for the {@link AbilityControlManager} + * @date 2022/8/10 23:30 + **/ +public interface TraceableAbilityControlManager extends AbilityControlManager { + + /** + * Get the status of the ability table. + * + * @param connectionId connection id + * @return status of ability table {@link AbilityStatus} + */ + AbilityStatus trace(String connectionId); + + /**. + * Trace the status of connection if {@link AbilityStatus#INITIALIZING}, wake up if {@link AbilityStatus#READY} + * It will return if status is {@link AbilityStatus#EXPIRED} or {@link AbilityStatus#NOT_EXIST} + * + * @param connectionId connection id + * @return if success to {@link AbilityStatus#READY} + */ + boolean traceReadySyn(String connectionId); +} From 4098297e51832b00ac839fe28e199f296a48868b Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 28 Aug 2022 17:38:08 +0800 Subject: [PATCH 002/181] Add the base implements for ability control. --- .../AbstractAbilityControlManager.java | 401 ++++++++++++++++++ .../ability/DefaultAbilityControlManager.java | 343 +++++++++++++++ .../ability/discover/AbilityHandleLoader.java | 49 +++ .../discover/NacosAbilityManagerHolder.java | 92 ++++ 4 files changed, 885 insertions(+) create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/discover/AbilityHandleLoader.java create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java new file mode 100644 index 00000000000..f78fd0a2044 --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -0,0 +1,401 @@ +/* + * Copyright 1999-2022 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.ability; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; +import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.common.ability.handler.AbilityHandlePreProcessor; +import com.alibaba.nacos.common.ability.inter.TraceableAbilityControlManager; +import com.alibaba.nacos.common.notify.Event; +import com.alibaba.nacos.common.notify.NotifyCenter; +import com.alibaba.nacos.common.utils.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; + +/**. + * @author Daydreamer + * @description Base class for ability control. It can only be used internally by Nacos.It showld be sington. + * @date 2022/7/12 19:18 + **/ +@SuppressWarnings("all") +public abstract class AbstractAbilityControlManager implements TraceableAbilityControlManager { + + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAbilityControlManager.class); + + /** + * Abilities current supporting + *

+ * key: ability key from {@link AbilityKey} + * value: whether to turn on + */ + protected final Map currentRunningAbility = new ConcurrentHashMap<>(); + + /** + * Ability table collections + *

+ * key: connectionId + * value: AbilityTable + */ + protected final Map nodeAbilityTable = new ConcurrentHashMap<>(); + + /**. + * These handlers will be invoke before combine the ability table + */ + private final List abilityHandlePreProcessors = new ArrayList<>(); + + /** + * This map is used to trace the status of ability table. + * Its status should be update after {@link #addNewTable(AbilityTable)} and {@link #removeTable(String)} + */ + protected final Map> abilityStatus = new ConcurrentHashMap<>(); + + private final ReentrantLock lockForProcessors = new ReentrantLock(); + + private final ReentrantLock lockForAbilityTable = new ReentrantLock(); + + protected AbstractAbilityControlManager() { + // register events + registerAbilityEvent(); + // put abilities + currentRunningAbility.putAll(AbilityKey.getCurrentNodeSupportAbility()); + // initialize + init(); + } + + + private void registerAbilityEvent(){ + // register events + NotifyCenter.registerToPublisher(AbilityComeEvent.class, 16384); + NotifyCenter.registerToPublisher(AbilityExpiredEvent.class, 16384); + } + + /** + * Whether the ability current node supporting is running. Return false if current node doesn't support. + * + * @param abilityKey ability key + * @return is running + */ + @Override + public boolean isCurrentNodeAbilityRunning(String abilityKey) { + return currentRunningAbility.getOrDefault(abilityKey, false); + } + + /** + * Register a new ability table. + * + * @param table the ability table. + */ + @Override + public final void addNewTable(AbilityTable table) { + // id should not be null + String connectionId = table.getConnectionId(); + // if exists + if (contains(connectionId) || connectionId == null) { + return; + } + lockForAbilityTable.lock(); + try { + // check + if (contains(connectionId)) { + return; + } + // update status + abilityStatus.put(connectionId, new AtomicReference<>(AbilityStatus.INITIALIZING)); + // handle ability table before joining current node + AbilityTable processed = process(table); + // hook method + add(processed); + // add to node + nodeAbilityTable.put(connectionId, table); + } finally { + lockForAbilityTable.unlock(); + } + // update status + AtomicReference abilityStatusAtomicReference = abilityStatus.get(table.getConnectionId()); + if (abilityStatusAtomicReference != null) { + // try one time + // do nothing if AbilityStatus == Expired + // if ready + if(abilityStatusAtomicReference.compareAndSet(AbilityStatus.INITIALIZING, AbilityStatus.READY)) { + // publish event to subscriber + AbilityComeEvent updateEvent = new AbilityComeEvent(); + updateEvent.setConnectionId(table.getConnectionId()); + updateEvent.setTable(table); + NotifyCenter.publishEvent(updateEvent); + } + } else { + LOGGER.warn("[AbiityControlManager] Cannot get connection status after processing ability table, possible reason is that the network is unstable"); + } + } + + /** + * Remove a ability table + * + * @param connectionId the ability table which is removing. + */ + @Override + public final void removeTable(String connectionId) { + // if not exists + if(connectionId == null || !nodeAbilityTable.containsKey(connectionId)){ + return; + } + AbilityTable removingTable = null; + lockForAbilityTable.lock(); + try { + // check + if (!nodeAbilityTable.containsKey(connectionId)) { + return; + } + nodeAbilityTable.get(connectionId); + // update status + abilityStatus.computeIfPresent(connectionId, (k, v) -> { + v.set(AbilityStatus.EXPIRED); + return v; + }); + // hook method + remove(connectionId); + // remove + nodeAbilityTable.remove(connectionId); + } finally { + lockForAbilityTable.unlock(); + } + // remove status + abilityStatus.remove(connectionId); + // publish event + if (removingTable != null) { + AbilityExpiredEvent expiredEvent = new AbilityExpiredEvent(); + expiredEvent.setTable(removingTable); + expiredEvent.setConnectionId(connectionId); + NotifyCenter.publishEvent(expiredEvent); + } + } + + + /** + * Register a new ability table. This is a ThreadSafe method for {@link AbstractAbilityControlManager#remove(String)}. + * + * @param table the ability table. + */ + protected abstract void add(AbilityTable table); + + + /** + * Remove a ability table. This is a ThreadSafe method for {@link AbstractAbilityControlManager#add(AbilityTable)}. + * + * @param connectionId the ability table which is removing. + */ + protected abstract void remove(String connectionId); + + + /** + * wthether contains this ability table + * + * @return + */ + @Override + public boolean contains(String connectionId) { + return nodeAbilityTable.containsKey(connectionId); + } + + + /** + * Get the status of the ability table. + * + * @param connectionId connection id + * @return status of ability table {@link AbilityStatus} + */ + @Override + public AbilityStatus trace(String connectionId) { + if (connectionId == null) { + return AbilityStatus.NOT_EXIST; + } + return abilityStatus.getOrDefault(connectionId, new AtomicReference<>(AbilityStatus.NOT_EXIST)).get(); + } + + /** + * Trace the status of connection if

{@link AbilityStatus#INITIALIZING}

, wake up if

{@link AbilityStatus#READY}

+ * It will return if status is

{@link AbilityStatus#EXPIRED}

or

{@link AbilityStatus#NOT_EXIST}

+ * + * @param connectionId connection id + * @param source source status + * @param target target status + * @return if success + */ + @Override + public boolean traceReadySyn(String connectionId) { + AbilityStatus source = AbilityStatus.INITIALIZING; + AbilityStatus target = AbilityStatus.READY; + AtomicReference atomicReference = abilityStatus.get(connectionId); + // return if null + if (atomicReference == null || atomicReference.get().equals(AbilityStatus.EXPIRED)) { + return false; + } else if (target == atomicReference.get()) { + return true; + } + // try if status legal + while (!atomicReference.get().equals(target) && atomicReference.get().equals(source)) { + LockSupport.parkNanos(100L); + // if expired + if (atomicReference.get().equals(AbilityStatus.EXPIRED)) { + return false; + } + } + return atomicReference.get().equals(target); + } + + /**. + * Invoking {@link AbilityHandlePreProcessor} + * + * @param source source ability table + * @return result + */ + protected AbilityTable process(AbilityTable source) { + // do nothing if no processor + if (CollectionUtils.isEmpty(abilityHandlePreProcessors)) { + return source; + } + // copy to advoid error process + AbilityTable abilityTable = source; + AbilityTable copy = new AbilityTable(source.getConnectionId(), new HashMap<>(source.getAbility()), source.isServer(), source.getVersion()); + for (AbilityHandlePreProcessor handler : abilityHandlePreProcessors) { + try { + abilityTable = handler.handle(abilityTable); + } catch (Throwable t) { + LOGGER.warn("[AbilityHandlePostProcessor] Failed to invoke {} :{}", + handler.getClass().getSimpleName(), t.getLocalizedMessage()); + // ensure normal operation + abilityTable = copy; + } + } + return abilityTable; + } + + /**. + * They will be invoked before updating ability table, but the order in which + * they are called cannot be guaranteed + * + * @param postProcessor PostProcessor instance + */ + @Override + public void addPostProcessor(AbilityHandlePreProcessor postProcessor) { + lockForProcessors.lock(); + try { + abilityHandlePreProcessors.add(postProcessor); + } finally { + lockForProcessors.unlock(); + LOGGER.info("[AbilityHandlePostProcessor] registry handler: {}", + postProcessor.getClass().getSimpleName()); + } + } + + /** + * Initialize the manager + */ + @Override + public void init() { + // default init + // nothing to do + } + + /** + * It should be invoked before destroy + */ + @Override + public void destroy() { + // default destroy + // nothing to do + } + + /** + * Return ability table of current node + * + * @return ability table + */ + @Override + public Map getCurrentRunningAbility() { + return new HashMap<>(this.currentRunningAbility); + } + + /** + * base class for ability + */ + public abstract class AbilityEvent extends Event { + + private static final long serialVersionUID = -123241121302761L; + + protected AbilityEvent(){} + + /** + * connection id. + */ + private String connectionId; + + /** + * ability table + */ + private AbilityTable table; + + + public String getConnectionId() { + return connectionId; + } + + public void setConnectionId(String connectionId) { + this.connectionId = connectionId; + } + + public AbilityTable getTable() { + return table; + } + + public void setTable(AbilityTable table) { + this.table = table; + } + } + + /** + * when a connection connected. + */ + public class AbilityComeEvent extends AbilityEvent { + + private static final long serialVersionUID = -123241121302761L; + + private AbilityComeEvent(){} + } + + /** + * when a connection disconnected. + */ + public class AbilityExpiredEvent extends AbilityEvent { + + private static final long serialVersionUID = -123241121212127619L; + + private AbilityExpiredEvent(){} + + } +} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java new file mode 100644 index 00000000000..b3012392ed9 --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java @@ -0,0 +1,343 @@ +/* + * Copyright 1999-2022 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.ability; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.common.JustForTest; +import com.alibaba.nacos.common.ability.handler.HandlerMapping; +import com.alibaba.nacos.common.ability.inter.AbilityHandlerRegistry; +import com.alibaba.nacos.common.executor.ExecutorFactory; +import com.alibaba.nacos.common.notify.NotifyCenter; +import com.alibaba.nacos.common.utils.CollectionUtils; +import com.alibaba.nacos.common.utils.MapUtil; +import com.alibaba.nacos.common.utils.ThreadUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/**. + * @author Daydreamer + * @description It is a relatively complete capability control center implementation. + * @date 2022/7/12 19:18 + **/ +public abstract class DefaultAbilityControlManager extends AbstractAbilityControlManager + implements AbilityHandlerRegistry { + + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAbilityControlManager.class); + + /** + * . These handlers will be invoked when the flag of ability change key: ability key from {@link AbilityKey} value: + * componments who want to be invoked if its interested ability turn on/off + */ + private final Map> handlerMappings = new ConcurrentHashMap<>(); + + /**. + * run for HandlerMapping + */ + private final Executor simpleThreadPool = ExecutorFactory.newSingleExecutorService(); + + private final ReentrantLock lockForHandlerMappings = new ReentrantLock(); + + protected DefaultAbilityControlManager() { + ThreadUtils.addShutdownHook(this::destroy); + NotifyCenter.registerToPublisher(AbilityUpdateEvent.class, 16384); + } + + /** + * . Turn on the ability whose key is

abilityKey

+ * + * @param abilityKey ability key + * @return if turn success + */ + @Override + public boolean enableCurrentNodeAbility(String abilityKey) { + return doTurn(true, abilityKey); + } + + /** + * . Turn off the ability whose key is

abilityKey

+ * + * @param abilityKey ability key + * @return if turn success + */ + @Override + public boolean disableCurrentNodeAbility(String abilityKey) { + return doTurn(false, abilityKey); + } + + /** + * . Turn on/off the ability of current node + * + * @param isOn is on + * @param abilityKey ability key from {@link AbilityKey} + * @return if turn success + */ + private boolean doTurn(boolean isOn, String abilityKey) { + Boolean isEnabled = currentRunningAbility.get(abilityKey); + // if not supporting this key + if (isEnabled == null) { + LOGGER.warn("[AbilityControlManager] Attempt to turn on/off a not existed ability!"); + return false; + } else if (isOn == isEnabled) { + // if already turn on/off + return true; + } + // turn on/off + currentRunningAbility.put(abilityKey, isOn); + // handler mappings + triggerHandlerMappingAsyn(abilityKey, isOn, this.handlerMappings); + // notify event + AbilityUpdateEvent abilityUpdateEvent = new AbilityUpdateEvent(); + abilityUpdateEvent.setTable(new AbilityTable().setAbility(Collections.unmodifiableMap(currentRunningAbility))); + abilityUpdateEvent.isOn = isOn; + abilityUpdateEvent.abilityKey = abilityKey; + NotifyCenter.publishEvent(abilityUpdateEvent); + return true; + } + + /** + * Register the component which is managed by {@link AbstractAbilityControlManager}. if you are hoping that a + * component will be invoked when turn on/off the ability whose key is

abilityKey

. + * + * @param abilityKey component key. + * @param priority the higher the priority is, the faster it will be called. + * @param handlerMapping component instance. + */ + @Override + public void registerComponent(String abilityKey, HandlerMapping handlerMapping, int priority) { + doRegisterComponent(abilityKey, handlerMapping, this.handlerMappings, lockForHandlerMappings, priority, currentRunningAbility); + } + + @Override + public int removeComponent(String abilityKey, Class handlerMappingClazz) { + return doRemove(abilityKey, handlerMappingClazz, lockForHandlerMappings, handlerMappings); + } + + @Override + public final void destroy() { + LOGGER.warn("[DefaultAbilityControlManager] - Start destroying..."); + ((ThreadPoolExecutor) simpleThreadPool).shutdown(); + if (MapUtil.isNotEmpty(handlerMappings)) { + handlerMappings.keySet().forEach(key -> doTriggerSyn(key, false, handlerMappings)); + } + // hook + doDestroy(); + LOGGER.warn("[DefaultAbilityControlManager] - Destruction of the end"); + } + + /**. + * hook for subclass + */ + protected void doDestroy() { + // for server ability manager + } + + /** + * Remove the component instance of

handlerMappingClazz

. + * + * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param handlerMappingClazz implement of {@link HandlerMapping} + * @param lock lock for operation + * @param handlerMappingsMap handler collection map + * @return the count of components have removed + */ + protected int doRemove(String abilityKey, Class handlerMappingClazz, Lock lock, + Map> handlerMappingsMap) { + List handlerMappings = handlerMappingsMap.get(abilityKey); + if (CollectionUtils.isEmpty(handlerMappings)) { + return 0; + } + lock.lock(); + try { + AtomicInteger count = new AtomicInteger(); + handlerMappings.removeIf(item -> { + if (item.handlerMapping.getClass().equals(handlerMappingClazz)) { + count.getAndIncrement(); + return true; + } + return false; + }); + return count.get(); + } finally { + lock.unlock(); + } + } + + @Override + public int removeAll(String abilityKey) { + List remove = this.handlerMappings.remove(abilityKey); + return Optional.ofNullable(remove).orElse(Collections.emptyList()).size(); + } + + /**. + * Register the component into handlerMappings locking by lockForHandlerMappings to ensure concurrency security. + * + * @param abilityKey ability key + * @param handlerMapping component instance. + * @param handlerMappings container + * @param lockForHandlerMappings lock to ensure concurrency + * @param abilityTable behavioral basis of handler + */ + protected void doRegisterComponent(String abilityKey, HandlerMapping handlerMapping, + Map> handlerMappings, Lock lockForHandlerMappings, + int priority, Map abilityTable) { + if (!currentRunningAbility.containsKey(abilityKey)) { + LOGGER.warn("[AbilityHandlePostProcessor] Failed to register processor: {}, because illegal key!", + handlerMapping.getClass().getSimpleName()); + } + + // legal key + lockForHandlerMappings.lock(); + try { + List handlers = handlerMappings.getOrDefault(abilityKey, new CopyOnWriteArrayList<>()); + HandlerWithPriority handlerWithPriority = new HandlerWithPriority(handlerMapping, priority); + handlers.add(handlerWithPriority); + handlerMappings.put(abilityKey, handlers); + // choose behavior + // enable default + if (abilityTable.getOrDefault(abilityKey, false)) { + handlerMapping.enable(); + } else { + handlerMapping.disable(); + } + } catch (Exception e) { + e.printStackTrace(); + LOGGER.error("[DefaultAbilityControlManager] Fail to register handler: {}", handlerMapping.getClass().getSimpleName()); + } finally { + lockForHandlerMappings.unlock(); + LOGGER.info("[DefaultAbilityControlManager] Successfully registered processor: {}", + handlerMapping.getClass().getSimpleName()); + } + } + + /** + * Invoke componments which linked to ability key asyn. + * + * @param key ability key from {@link AbilityKey} + * @param isEnabled turn on/off + * @param handlerMappingsMap handler collection + */ + protected void triggerHandlerMappingAsyn(String key, boolean isEnabled, + Map> handlerMappingsMap) { + simpleThreadPool.execute(() -> doTriggerSyn(key, isEnabled, handlerMappingsMap)); + } + + /** + * Invoke componments which linked to ability key syn. + * + * @param key ability key from {@link AbilityKey} + * @param isEnabled turn on/off + * @param handlerMappingsMap handler collection + */ + protected void doTriggerSyn(String key, boolean isEnabled, + Map> handlerMappingsMap) { + List handlerWithPriorities = handlerMappingsMap.get(key); + // return if empty + if (CollectionUtils.isEmpty(handlerWithPriorities)) { + return; + } + Collections.sort(handlerWithPriorities); + // invoked all + handlerWithPriorities.forEach(handlerMappingWithPriorities -> { + // any error from current handler does not affect other handler + HandlerMapping handlerMapping = handlerMappingWithPriorities.handlerMapping; + try { + if (isEnabled) { + handlerMapping.enable(); + } else { + handlerMapping.disable(); + } + } catch (Throwable t) { + LOGGER.warn("[HandlerMapping] Failed to invoke {} :{}", handlerMapping.getClass().getSimpleName(), + t.getLocalizedMessage()); + } + }); + } + + @JustForTest + protected Map> handlerMapping() { + return this.handlerMappings; + } + + /** + * Support priority handler. + */ + protected class HandlerWithPriority implements Comparable { + + /**. + * Decorated + */ + public HandlerMapping handlerMapping; + + /**. + * the higher the priority, the faster it will be called + */ + public int priority; + + public HandlerWithPriority(HandlerMapping handlerMapping, int priority) { + this.handlerMapping = handlerMapping; + this.priority = priority; + } + + @Override + public int compareTo(HandlerWithPriority o) { + return o.priority - this.priority; + } + } + + /**. + * notify when current node ability changing + */ + public class AbilityUpdateEvent extends AbilityEvent { + + private static final long serialVersionUID = -1232411212311111L; + + private String abilityKey; + + private boolean isOn; + + private AbilityUpdateEvent(){} + + public String getAbilityKey() { + return abilityKey; + } + + public void setAbilityKey(String abilityKey) { + this.abilityKey = abilityKey; + } + + public boolean isOn() { + return isOn; + } + + public void setOn(boolean on) { + isOn = on; + } + } +} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/discover/AbilityHandleLoader.java b/common/src/main/java/com/alibaba/nacos/common/ability/discover/AbilityHandleLoader.java new file mode 100644 index 00000000000..feb07436a0b --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/discover/AbilityHandleLoader.java @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2022 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.ability.discover; + +import com.alibaba.nacos.common.ability.handler.AbilityHandlePreProcessor; +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.HashSet; + +/**. + * @author Daydreamer + * @description It is spi loader to load {@link AbilityHandlePreProcessor} + * @date 2022/8/25 18:24 + **/ +public class AbilityHandleLoader { + + private final Collection initializers; + + private static final Logger LOGGER = LoggerFactory.getLogger(AbilityHandleLoader.class); + + public AbilityHandleLoader() { + initializers = new HashSet<>(); + for (AbilityHandlePreProcessor preProcessor : NacosServiceLoader.load(AbilityHandlePreProcessor.class)) { + initializers.add(preProcessor); + LOGGER.info("Load {} for AbilityHandlePreProcessor", preProcessor.getClass().getCanonicalName()); + } + } + + public Collection getInitializers() { + return initializers; + } +} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java b/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java new file mode 100644 index 00000000000..fe7a0c7603c --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java @@ -0,0 +1,92 @@ +/* + * Copyright 1999-2022 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.ability.discover; + +import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; +import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; +import com.alibaba.nacos.common.ability.inter.AbilityControlManager; +import com.alibaba.nacos.common.spi.NacosServiceLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.ServiceConfigurationError; + +/** + * This class is used to discover {@link AbstractAbilityControlManager} implements. All the + * ability operation will be finish in this singleton. + * + * @author Daydreamer + * @date 2022/7/14 19:58 + **/ +public class NacosAbilityManagerHolder { + + /**. + * private constructor + */ + private NacosAbilityManagerHolder() { + } + + private static final Logger LOGGER = LoggerFactory.getLogger(NacosAbilityManagerHolder.class); + + /**. + * singleton + */ + private static DefaultAbilityControlManager abstractAbilityControlManager; + + static { + // spi discover implement + Collection load = null; + try { + // if server + load = NacosServiceLoader.load(DefaultAbilityControlManager.class); + } catch (ServiceConfigurationError e) { + // if client or not ability control manager + load = NacosServiceLoader.load(DefaultAbilityControlManager.class); + } + // the priority of the server is higher + if (load.size() > 0) { + load.forEach(clazz -> { + abstractAbilityControlManager = clazz; + }); + LOGGER.info("[AbilityControlManager] Successfully initialize AbilityControlManager"); + // init pre processor + AbilityHandleLoader loader = new AbilityHandleLoader(); + loader.getInitializers().forEach(processor -> abstractAbilityControlManager.addPostProcessor(processor)); + } + } + + /**. + * get nacos ability control manager + * + * @return BaseAbilityControlManager + */ + public static DefaultAbilityControlManager getInstance() { + return abstractAbilityControlManager; + } + + /**. + * Return the target type of ability manager + * + * @param clazz clazz + * @param target type + * @return AbilityControlManager + */ + public static T getInstance(Class clazz) { + return clazz.cast(abstractAbilityControlManager); + } +} From 427535897594f6b0effa04f2216a4cac430c5375 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 28 Aug 2022 17:40:08 +0800 Subject: [PATCH 003/181] Add the default implements for client and server. --- .../ability/ClientAbilityControlManager.java | 72 +++++ ...ommon.ability.DefaultAbilityControlManager | 19 ++ .../control/ServerAbilityControlManager.java | 268 ++++++++++++++++++ .../inte/ClusterAbilityControlSupport.java | 80 ++++++ 4 files changed, 439 insertions(+) create mode 100644 client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java create mode 100644 common/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager create mode 100644 core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java create mode 100644 core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java new file mode 100644 index 00000000000..0f3a6fcbef4 --- /dev/null +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2022 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.ability; + +import com.alibaba.nacos.api.ability.constant.AbilityStatus; +import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; +import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; + +import java.util.Collections; +import java.util.Optional; + +/**. + * @author Daydreamer + * @description {@link AbstractAbilityControlManager} for nacos-client. + * @date 2022/7/13 13:38 + **/ +public class ClientAbilityControlManager extends DefaultAbilityControlManager { + + public ClientAbilityControlManager() { + } + + @Override + public boolean isSupport(String connectionId, String abilityKey) { + Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); + if (!isRunning) { + return false; + } + AbilityTable abilityTable = nodeAbilityTable.get(connectionId); + // it is null, check if initialing + if (abilityTable == null && AbilityStatus.INITIALIZING.equals(trace(connectionId))) { + // wait for ready + boolean finish = traceReadySyn(connectionId); + // if expired + if (!finish) { + return false; + } else { + abilityTable = nodeAbilityTable.get(connectionId); + } + } + // false if null + return abilityTable != null + && Optional.ofNullable(abilityTable.getAbility()) + .orElse(Collections.emptyMap()) + .getOrDefault(abilityKey, false); + } + + @Override + protected void add(AbilityTable table) { + // nothing to do + } + + @Override + protected void remove(String connectionId) { + // nothing to do + } + +} diff --git a/common/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager b/common/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager new file mode 100644 index 00000000000..c5e3caeac2d --- /dev/null +++ b/common/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager @@ -0,0 +1,19 @@ +# +# Copyright 1999-2022 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. +# +# + +com.alibaba.nacos.client.ability.ClientAbilityControlManager +com.alibaba.nacos.core.ability.control.ServerAbilityControlManager \ No newline at end of file diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java new file mode 100644 index 00000000000..09faa79a43a --- /dev/null +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -0,0 +1,268 @@ +/* + * Copyright 1999-2022 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.core.ability.control; + +import com.alibaba.nacos.api.ability.constant.AbilityStatus; +import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.common.JustForTest; +import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; +import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; +import com.alibaba.nacos.common.ability.handler.HandlerMapping; +import com.alibaba.nacos.common.notify.NotifyCenter; +import com.alibaba.nacos.common.utils.MapUtil; +import com.alibaba.nacos.core.ability.inte.ClusterAbilityControlSupport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/**. + * @author Daydreamer + * @description {@link AbstractAbilityControlManager} for nacos-server. + * @date 2022/7/13 21:14 + **/ +public class ServerAbilityControlManager extends DefaultAbilityControlManager implements ClusterAbilityControlSupport { + + private static final Logger LOGGER = LoggerFactory.getLogger(ServerAbilityControlManager.class); + + /**. + * ability for cluster + */ + private final Map clusterAbilityTable = new ConcurrentHashMap<>(); + + /**. + * ability for server + */ + private final Map serversAbilityTable = new ConcurrentHashMap<>(); + + /** + * components for cluster. these will be invoked if cluster ability table changes. + */ + private final Map> clusterHandlerMapping = new ConcurrentHashMap<>(); + + private Lock lockForClusterComponents = new ReentrantLock(); + + public ServerAbilityControlManager() { + // add current node into + AbilityTable currentNodeAbility = new AbilityTable(); + currentNodeAbility.setAbility(super.currentRunningAbility); + currentNodeAbility.setConnectionId("current-node"); + serversAbilityTable.put(currentNodeAbility.getConnectionId(), currentNodeAbility); + clusterAbilityTable.putAll(currentNodeAbility.getAbility()); + NotifyCenter.registerToPublisher(ClusterAbilityUpdateEvent.class, 16384); + } + + @Override + public boolean isSupport(String connectionId, String abilityKey) { + Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); + if (!isRunning) { + return false; + } + AbilityTable abilityTable = nodeAbilityTable.get(connectionId); + // it is null, check if initialing + if (abilityTable == null && AbilityStatus.INITIALIZING.equals(trace(connectionId))) { + // wait for ready + boolean finish = traceReadySyn(connectionId); + // if expired + if (!finish) { + return false; + } else { + abilityTable = nodeAbilityTable.get(connectionId); + } + } + // false if null + return abilityTable != null + && Optional.ofNullable(abilityTable.getAbility()) + .orElse(Collections.emptyMap()) + .getOrDefault(abilityKey, false); + } + + /**. + * Whether current cluster supports ability + * + * @param abilityKey ability key + * @return whether it is turn on + */ + @Override + public boolean isClusterEnableAbility(String abilityKey) { + return clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE); + } + + @Override + public Map getClusterAbility() { + return Collections.unmodifiableMap(clusterAbilityTable); + } + + /**. + * Register components for cluster. These will be trigger when its interested ability changes + * + * @param abilityKey ability key + * @param priority the higher the priority, the faster it will be called + * @param handlerMapping component + */ + @Override + public void registerComponentForCluster(String abilityKey, HandlerMapping handlerMapping, int priority) { + doRegisterComponent(abilityKey, handlerMapping, this.clusterHandlerMapping, lockForClusterComponents, priority, clusterAbilityTable); + } + + @Override + public int removeClusterComponent(String abilityKey, Class handlerMappingClazz) { + return doRemove(abilityKey, handlerMappingClazz, lockForClusterComponents, clusterHandlerMapping); + } + + @Override + public int removeAllForCluster(String abilityKey) { + List remove = this.clusterHandlerMapping.remove(abilityKey); + return Optional.ofNullable(remove).orElse(Collections.emptyList()).size(); + } + + @Override + protected void add(AbilityTable table) { + // from which env + boolean isServer = table.isServer(); + // if not null + if (table.getConnectionId() != null && table.getAbility() != null) { + if (isServer) { + serversAbilityTable.put(table.getConnectionId(), table); + // enter cluster + Map nodeAbility = table.getAbility(); + Set keySet = clusterAbilityTable.keySet(); + keySet.forEach(abilityKey -> { + Boolean isEnabled = clusterAbilityTable.get(abilityKey); + Boolean val = nodeAbility.getOrDefault(abilityKey, Boolean.FALSE); + // new res + Boolean newRes = val && isEnabled; + // if ability changes + if (!newRes.equals(isEnabled)) { + triggerHandlerMappingAsyn(abilityKey, false, this.clusterHandlerMapping); + clusterAbilityTable.replace(abilityKey, false); + // notify + NotifyCenter.publishEvent(buildClusterEvent(abilityKey, false)); + } + }); + } + } + } + + private ClusterAbilityUpdateEvent buildClusterEvent(String abilityKey, boolean isOn) { + // notify + ClusterAbilityUpdateEvent event = new ClusterAbilityUpdateEvent(); + event.setAbilityKey(abilityKey); + event.setOn(isOn); + event.setTable(new AbilityTable().setAbility(Collections.unmodifiableMap(clusterAbilityTable))); + return event; + } + + @Override + protected void remove(String connectionId) { + // from which + AbilityTable abilityTable = nodeAbilityTable.get(connectionId); + // return if null + if (abilityTable == null) { + return; + } + // from which env + if (abilityTable.isServer()) { + // remove from server ability collection + serversAbilityTable.remove(connectionId); + // remove from cluster + if (MapUtil.isNotEmpty(serversAbilityTable)) { + Set keySet = clusterAbilityTable.keySet(); + keySet.forEach(abilityKey -> { + Boolean isEnabled = clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE); + // nothing to do if enabled + if (isEnabled) { + return; + } + // recalculate + Boolean newVal = serversAbilityTable.values() + .stream() + .map(AbilityTable::getAbility) + .map((map) -> map.getOrDefault(abilityKey, Boolean.FALSE)) + .reduce((a, b) -> a && b) + .orElse(Boolean.FALSE); + clusterAbilityTable.replace(abilityKey, newVal); + // if change + if (!isEnabled.equals(newVal)) { + triggerHandlerMappingAsyn(abilityKey, newVal, this.clusterHandlerMapping); + // notify + NotifyCenter.publishEvent(buildClusterEvent(abilityKey, newVal)); + } + }); + } + } + } + + @Override + protected void doDestroy() { + if (MapUtil.isNotEmpty(clusterHandlerMapping)) { + if (MapUtil.isNotEmpty(clusterHandlerMapping)) { + clusterHandlerMapping.keySet().forEach(key -> doTriggerSyn(key, false, clusterHandlerMapping)); + } + } + LOGGER.warn("[ServerAbilityControlManager] - Destruction of the end"); + } + + /**. + * notify when current node ability changing + */ + public class ClusterAbilityUpdateEvent extends AbilityEvent { + + private static final long serialVersionUID = -122222411212200111L; + + private String abilityKey; + + private boolean isOn; + + private ClusterAbilityUpdateEvent(){} + + public String getAbilityKey() { + return abilityKey; + } + + public void setAbilityKey(String abilityKey) { + this.abilityKey = abilityKey; + } + + public boolean isOn() { + return isOn; + } + + public void setOn(boolean on) { + isOn = on; + } + + } + + @JustForTest + protected void setClusterAbilityTable(Map map) { + clusterAbilityTable.putAll(map); + } + + @JustForTest + protected Map> clusterHandlerMapping() { + return this.clusterHandlerMapping; + } + +} diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java new file mode 100644 index 00000000000..1150b200516 --- /dev/null +++ b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java @@ -0,0 +1,80 @@ +/* + * Copyright 1999-2022 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.core.ability.inte; + +import com.alibaba.nacos.common.ability.handler.HandlerMapping; +import com.alibaba.nacos.common.ability.inter.AbilityControlManager; + +import java.util.Map; + +/**. + * @author Daydreamer + * @description It provides the capability to manage the AbilityTable in cluster for the {@link AbilityControlManager} + * @date 2022/8/10 23:18 + **/ +public interface ClusterAbilityControlSupport { + + /**. + * Return the cluster abilities. + * + * @return the cluster abilities. + */ + Map getClusterAbility(); + + /**. + * Register components for cluster. These will be trigger when its interested ability changes + * + * @param abilityKey ability key + * @param priority a positive number, the higher the priority, the faster it will be called + * @param handlerMapping component + */ + void registerComponentForCluster(String abilityKey, HandlerMapping handlerMapping, int priority); + + /**. + * Default method to register component + * + * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. + * @param handlerMapping component instance. + */ + default void registerComponentForCluster(String abilityKey, HandlerMapping handlerMapping) { + registerComponentForCluster(abilityKey, handlerMapping, 1); + } + + /** + * Remove the component instance of

handlerMappingClazz

. + * + * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param handlerMappingClazz implement of {@link HandlerMapping} + * @return the count of components have removed + */ + int removeClusterComponent(String abilityKey, Class handlerMappingClazz); + + /** + * Remove all {@link HandlerMapping} interested in the special ability. + * @param abilityKey abnility key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @return the count of components have removed + */ + int removeAllForCluster(String abilityKey); + + /**. + * Whether current cluster supports ability + * + * @param abilityKey ability key + * @return whether it is turn on + */ + boolean isClusterEnableAbility(String abilityKey); +} From 613335e763d78f572602f7be791600929b744b2e Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 28 Aug 2022 17:42:45 +0800 Subject: [PATCH 004/181] Add the junit test for AbilityControlManager. --- .../api/utils/AbilityTableUtilsTest.java | 56 +++ .../ability/AbilityControlManagerTest.java | 380 ++++++++++++++++++ .../TestClientAbilityControlManager.java | 30 ++ .../TestServerAbilityControlManager.java | 78 ++++ 4 files changed, 544 insertions(+) create mode 100644 api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java create mode 100644 test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java create mode 100644 test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java create mode 100644 test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java diff --git a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java new file mode 100644 index 00000000000..c2fea2c406c --- /dev/null +++ b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2022 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; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +public class AbilityTableUtilsTest { + + @Test + public void testGetByteArray() { + Map offset = new HashMap<>(); + offset.put("a", 1); + offset.put("b", 2); + offset.put("c", 10); + offset.put("d", 127); + byte[] abilityBitBy = AbilityTableUtils.getAbilityBitBy(offset.values()); + Assert.assertEquals(16, abilityBitBy.length); + Assert.assertEquals((byte) (3 << 6), abilityBitBy[0]); + Assert.assertEquals((byte) (1 << 6), abilityBitBy[1]); + } + + @Test + public void testGetAbilityTable() { + Map offset = new HashMap<>(); + offset.put("a", 1); + offset.put("b", 2); + offset.put("c", 10); + offset.put("d", 127); + byte[] abilityBitBy = AbilityTableUtils.getAbilityBitBy(offset.values()); + Map abilityTableBy = AbilityTableUtils.getAbilityTableBy(abilityBitBy, offset); + Assert.assertEquals(4, abilityTableBy.size()); + Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("a")); + Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("b")); + Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("c")); + Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("d")); + Assert.assertEquals(Boolean.FALSE, abilityTableBy.getOrDefault("asdasd", false)); + } +} diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java new file mode 100644 index 00000000000..e27009abe4d --- /dev/null +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java @@ -0,0 +1,380 @@ +/* + * Copyright 1999-2022 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.ability; + +import com.alibaba.nacos.api.ability.constant.AbilityStatus; +import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.common.ability.handler.AbilityHandlePreProcessor; +import com.alibaba.nacos.common.ability.handler.HandlerMapping; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +@SpringBootTest +public class AbilityControlManagerTest { + + private TestClientAbilityControlManager clientAbilityControlManager = new TestClientAbilityControlManager(); + + private TestServerAbilityControlManager serverAbilityControlManager = new TestServerAbilityControlManager(); + + private volatile int clusterEnabled = 0; + + private volatile int enabled = 0; + + private volatile LinkedList testPriority = new LinkedList<>(); + + @Before + public void inject() { + Map newTable = new HashMap<>(); + newTable.put("stop-raft", true); + clientAbilityControlManager.setCurrentSupportingAbility(newTable); + + Map table = new HashMap<>(); + table.put("stop-raft", true); + serverAbilityControlManager.setCurrentSupportingAbility(table); + + Map cluster = new HashMap<>(); + cluster.put("stop-raft", true); + serverAbilityControlManager.setClusterAbility(cluster); + serverAbilityControlManager.setCurrentSupportingAbility(newTable); + } + + @Test + public void testClientAdd() { + Map newTable = new HashMap<>(); + newTable.put("test-no-existed", true); + newTable.put("stop-raft", true); + AbilityTable table = new AbilityTable(); + table.setConnectionId("test-00001"); + table.setAbility(newTable); + table.setServer(true); + clientAbilityControlManager.addNewTable(table); + Assert.assertFalse(clientAbilityControlManager.isSupport("test-00001", "test-no-existed")); + Assert.assertTrue(clientAbilityControlManager.isSupport("test-00001", "stop-raft")); + } + + @Test + public void testServerAdd() { + Map newTable = new HashMap<>(); + newTable.put("test-no-existed", true); + newTable.put("stop-raft", true); + AbilityTable table = new AbilityTable(); + table.setConnectionId("test-00001"); + table.setAbility(newTable); + table.setServer(true); + serverAbilityControlManager.addNewTable(table); + Assert.assertFalse(serverAbilityControlManager.isSupport("test-00001", "test-no-existed")); + Assert.assertTrue(serverAbilityControlManager.isSupport("test-00001", "stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + + Map otherServer = new HashMap<>(); + otherServer.put("test-no-existed", true); + otherServer.put("stop-raft", false); + AbilityTable otherServerTable = new AbilityTable(); + otherServerTable.setConnectionId("test-00000"); + otherServerTable.setAbility(otherServer); + otherServerTable.setServer(true); + serverAbilityControlManager.addNewTable(otherServerTable); + Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + + Map clientTa = new HashMap<>(); + clientTa.put("test-no-existed", true); + clientTa.put("stop-raft", false); + AbilityTable clientTable = new AbilityTable(); + clientTable.setConnectionId("test-00002"); + clientTable.setAbility(clientTa); + clientTable.setServer(false); + serverAbilityControlManager.addNewTable(clientTable); + Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + } + + @Test + public void testClientRemove() { + Map clientTa = new HashMap<>(); + clientTa.put("test-no-existed", true); + clientTa.put("stop-raft", false); + AbilityTable clientTable = new AbilityTable(); + clientTable.setConnectionId("test-01111"); + clientTable.setAbility(clientTa); + clientTable.setServer(true); + clientAbilityControlManager.addNewTable(clientTable); + Assert.assertEquals(AbilityStatus.READY, clientAbilityControlManager.trace("test-01111")); + clientAbilityControlManager.removeTable("test-01111"); + Assert.assertEquals(AbilityStatus.NOT_EXIST, clientAbilityControlManager.trace("test-01111")); + } + + @Test + public void testComponent() throws InterruptedException { + enabled = 0; + // invoke enable() or disable() when registering + serverAbilityControlManager.registerComponent("stop-raft", new TestHandlerMapping(), -1); + Assert.assertEquals(1, serverAbilityControlManager.handlerMappingCount()); + + serverAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + // wait for invoking handler asyn + Thread.sleep(200L); + // nothing happens if it has enabled + Assert.assertEquals(enabled, 1); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + + // invoke disable() + serverAbilityControlManager.disableCurrentNodeAbility("stop-raft"); + // wait for invoking handler asyn + Thread.sleep(200L); + // disable will invoke handler + Assert.assertEquals(enabled, 0); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + + serverAbilityControlManager.disableCurrentNodeAbility("stop-raft"); + // wait for invoking handler asyn + Thread.sleep(200L); + // nothing to do because it has disable + Assert.assertEquals(enabled, 0); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + + serverAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + // wait for invoking handler asyn + Thread.sleep(200L); + Assert.assertEquals(enabled, 1); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + + serverAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + // wait for invoking handler asyn + Thread.sleep(200L); + Assert.assertEquals(enabled, 1); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + } + + @Test + public void testClusterComponent() throws InterruptedException { + clusterEnabled = 0; + // invoke enable() because it turn on + serverAbilityControlManager.registerComponentForCluster("stop-raft", new ClusterHandlerMapping(), -1); + Assert.assertEquals(1, serverAbilityControlManager.clusterHandlerMappingCount()); + Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertEquals(clusterEnabled, 1); + + Map serverAbility = new HashMap<>(); + serverAbility.put("test-no-existed", true); + serverAbility.put("stop-raft", false); + AbilityTable serverTable = new AbilityTable(); + serverTable.setConnectionId("test-01111"); + serverTable.setAbility(serverAbility); + serverTable.setServer(true); + serverAbilityControlManager.addNewTable(serverTable); + // wait for invoking handler asyn + Thread.sleep(200L); + + // disabled + Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertEquals(clusterEnabled, 0); + + // remove this table to enabled + serverAbilityControlManager.removeTable("test-01111"); + // wait for invoking handler asyn + Thread.sleep(200L); + Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertEquals(clusterEnabled, 1); + } + + @Test + public void testCurrentNodeAbility() { + Set keySet = serverAbilityControlManager.getCurrentRunningAbility().keySet(); + // diable all + keySet.forEach(key -> serverAbilityControlManager.disableCurrentNodeAbility(key)); + // get all + keySet.forEach(key -> { + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(key)); + }); + // enable all + keySet.forEach(key -> serverAbilityControlManager.enableCurrentNodeAbility(key)); + // get all + keySet.forEach(key -> { + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(key)); + }); + } + + @Test + public void testPre() { + clientAbilityControlManager.addPostProcessor(new TestPreHandler()); + clientAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + AbilityTable abilityTable = new AbilityTable(); + abilityTable.setConnectionId("1111"); + HashMap table = new HashMap<>(); + table.put("stop-raft", false); + abilityTable.setAbility(table); + clientAbilityControlManager.addNewTable(abilityTable); + Assert.assertFalse(clientAbilityControlManager.isSupport("1111", "stop-raft")); + } + + @Test + public void testStateSyn() { + // register a processing long time handler + AbilityTable abilityTable = new AbilityTable(); + abilityTable.setConnectionId("1111"); + HashMap table = new HashMap<>(); + table.put("stop-raft", false); + abilityTable.setAbility(table); + clientAbilityControlManager.addPostProcessor(new TestStatusPreHandler()); + // 追踪状态 + long begin = System.currentTimeMillis(); + clientAbilityControlManager.addNewTable(abilityTable); + Assert.assertTrue(clientAbilityControlManager.traceReadySyn("1111")); + long end = System.currentTimeMillis(); + Assert.assertTrue(end - begin > 5000); + } + + @Test + public void testPriority() throws InterruptedException { + TestServerAbilityControlManager testServerAbilityControlManager = new TestServerAbilityControlManager(); + String key = "key"; + TestPriority clusterHandlerMapping1 = new TestPriority("1"); + TestPriority clusterHandlerMapping2 = new TestPriority("2"); + TestPriority clusterHandlerMapping3 = new TestPriority("3"); + // first one, invoke enable() + testServerAbilityControlManager.registerComponentForCluster(key, clusterHandlerMapping2, 128); + // last one, invoke enable() + testServerAbilityControlManager.registerComponentForCluster(key, clusterHandlerMapping3); + // second one, invoke enable() + testServerAbilityControlManager.registerComponentForCluster(key, clusterHandlerMapping1, 12); + // trigger cluster + testServerAbilityControlManager.triggerCluster(key); + Assert.assertEquals(3, testServerAbilityControlManager.getClusterHandlerMapping(key).size()); + // wait for invoking + Thread.sleep(200L); + Assert.assertEquals("2", testPriority.poll()); + Assert.assertEquals("3", testPriority.poll()); + Assert.assertEquals("1", testPriority.poll()); + // here are priority + Assert.assertEquals("2", testPriority.poll()); + Assert.assertEquals("1", testPriority.poll()); + Assert.assertEquals("3", testPriority.poll()); + // remove + testServerAbilityControlManager.registerClusterHandlerMapping(key, new ClusterHandlerMapping(), -1); + Assert.assertEquals(4, testServerAbilityControlManager.getClusterHandlerMapping(key).size()); + Assert.assertEquals(1, testServerAbilityControlManager.removeClusterComponent(key, ClusterHandlerMapping.class)); + Assert.assertEquals(3, testServerAbilityControlManager.getClusterHandlerMapping(key).size()); + testServerAbilityControlManager.removeAllForCluster(key); + Assert.assertNull(testServerAbilityControlManager.getClusterHandlerMapping(key)); + + // first one + testServerAbilityControlManager.registerComponent(key, clusterHandlerMapping2, 128); + // last one + testServerAbilityControlManager.registerComponent(key, clusterHandlerMapping3); + // second one + testServerAbilityControlManager.registerComponent(key, clusterHandlerMapping1, 12); + Assert.assertEquals(3, testServerAbilityControlManager.getHandlerMapping(key).size()); + // wait for invoking + Thread.sleep(200L); + // trigger + testServerAbilityControlManager.trigger(key); + // wait for invoking + Thread.sleep(200L); + Assert.assertEquals("2", testPriority.poll()); + Assert.assertEquals("3", testPriority.poll()); + Assert.assertEquals("1", testPriority.poll()); + // here are priority + Assert.assertEquals("2", testPriority.poll()); + Assert.assertEquals("1", testPriority.poll()); + Assert.assertEquals("3", testPriority.poll()); + // remove + testServerAbilityControlManager.registerComponent(key, new ClusterHandlerMapping(), -1); + Assert.assertEquals(4, testServerAbilityControlManager.getHandlerMapping(key).size()); + Assert.assertEquals(1, testServerAbilityControlManager.removeComponent(key, ClusterHandlerMapping.class)); + Assert.assertEquals(3, testServerAbilityControlManager.getHandlerMapping(key).size()); + testServerAbilityControlManager.removeAll(key); + Assert.assertNull(testServerAbilityControlManager.getClusterHandlerMapping(key)); + } + + class TestPriority implements HandlerMapping { + + String mark; + + public TestPriority(String mark) { + // unique one + this.mark = mark.intern(); + } + + @Override + public void enable() { + testPriority.offer(mark); + } + + @Override + public void disable() { + testPriority.offer(mark); + } + } + + class ClusterHandlerMapping implements HandlerMapping { + + @Override + public void enable() { + clusterEnabled++; + } + + @Override + public void disable() { + clusterEnabled--; + } + } + + class TestHandlerMapping implements HandlerMapping { + + @Override + public void enable() { + enabled++; + } + + @Override + public void disable() { + enabled--; + } + + } + + class TestPreHandler implements AbilityHandlePreProcessor { + + @Override + public AbilityTable handle(AbilityTable source) { + source.setConnectionId("pre-handle"); + return source; + } + } + + class TestStatusPreHandler implements AbilityHandlePreProcessor { + + @Override + public AbilityTable handle(AbilityTable source) { + try { + // block + Thread.sleep(5000); + } catch (Exception e) { + e.printStackTrace(); + } + return source; + } + } +} + + diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java new file mode 100644 index 00000000000..5e9fc089923 --- /dev/null +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2022 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.ability; + +import com.alibaba.nacos.client.ability.ClientAbilityControlManager; +import com.alibaba.nacos.common.JustForTest; + +import java.util.Map; + +public class TestClientAbilityControlManager extends ClientAbilityControlManager { + + @JustForTest + public void setCurrentSupportingAbility(Map ability) { + currentRunningAbility.putAll(ability); + } +} diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java new file mode 100644 index 00000000000..2c48bc82112 --- /dev/null +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java @@ -0,0 +1,78 @@ +/* + * Copyright 1999-2022 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.ability; + +import com.alibaba.nacos.common.JustForTest; +import com.alibaba.nacos.common.ability.handler.HandlerMapping; +import com.alibaba.nacos.core.ability.control.ServerAbilityControlManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class TestServerAbilityControlManager extends ServerAbilityControlManager { + + @JustForTest + public void setCurrentSupportingAbility(Map ability) { + currentRunningAbility.putAll(ability); + } + + @JustForTest + public void setClusterAbility(Map ability) { + super.setClusterAbilityTable(ability); + } + + @JustForTest + public int handlerMappingCount() { + return super.handlerMapping().size(); + } + + @JustForTest + public List getHandlerMapping(String abilityKey) { + return super.handlerMapping().get(abilityKey); + } + + @JustForTest + public int clusterHandlerMappingCount() { + return super.clusterHandlerMapping().size(); + } + + @JustForTest + public List getClusterHandlerMapping(String abilityKey) { + return super.clusterHandlerMapping().get(abilityKey); + } + + /** + * Just a test method. + */ + @JustForTest + public void registerClusterHandlerMapping(String key, HandlerMapping handlerMapping, int priority) { + List orDefault = super.clusterHandlerMapping().getOrDefault(key, new ArrayList<>()); + orDefault.add(new HandlerWithPriority(handlerMapping, priority)); + clusterHandlerMapping().put(key, orDefault); + } + + @JustForTest + public void triggerCluster(String abilityKey) { + triggerHandlerMappingAsyn(abilityKey, true, clusterHandlerMapping()); + } + + @JustForTest + public void trigger(String abilityKey) { + triggerHandlerMappingAsyn(abilityKey, true, handlerMapping()); + } +} From ce4fb189b87ef46d6b1d72a92492240c87445a9b Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 28 Aug 2022 18:08:29 +0800 Subject: [PATCH 005/181] Fix the bug that cannot load AbilityControlManager. --- common/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/common/pom.xml b/common/pom.xml index b1c91f19d30..bda1fd571ab 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -84,6 +84,7 @@ true nacos-version.txt + META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager From 838c3d0ded82f16e3969a256e14b9425a3f87265 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 28 Aug 2022 18:20:35 +0800 Subject: [PATCH 006/181] Adapt the support of new ability control. --- .../request/ConnectionSetupRequest.java | 13 +-- .../remote/response/ServerCheckResponse.java | 13 ++- .../client/config/impl/ClientWorker.java | 10 +- .../AbstractAbilityControlManager.java | 2 +- .../nacos/common/remote/client/RpcClient.java | 103 +++++++++++++++++- .../remote/client/RpcClientFactory.java | 2 + .../common/remote/client/grpc/GrpcClient.java | 15 ++- .../alibaba/nacos/core/remote/Connection.java | 12 +- .../grpc/GrpcBiStreamRequestAcceptor.java | 6 +- .../core/remote/grpc/GrpcRequestAcceptor.java | 6 +- .../ServerAbilityConnectionListener.java | 45 ++++++++ 11 files changed, 202 insertions(+), 25 deletions(-) create mode 100644 core/src/main/java/com/alibaba/nacos/core/remote/listener/ServerAbilityConnectionListener.java diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java index 56e94dad21f..67e246ad6de 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.api.remote.request; -import com.alibaba.nacos.api.ability.ClientAbilities; import java.util.HashMap; import java.util.Map; @@ -31,12 +30,12 @@ public class ConnectionSetupRequest extends InternalRequest { private String clientVersion; - private ClientAbilities abilities; - private String tenant; private Map labels = new HashMap<>(); + private byte[] abilityTable; + public ConnectionSetupRequest() { } @@ -64,11 +63,11 @@ public void setTenant(String tenant) { this.tenant = tenant; } - public ClientAbilities getAbilities() { - return abilities; + public byte[] getAbilityTable() { + return abilityTable; } - public void setAbilities(ClientAbilities abilities) { - this.abilities = abilities; + public void setAbilityTable(byte[] abilityTable) { + this.abilityTable = abilityTable; } } diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java b/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java index fd3981cd18d..4f5092fc060 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java @@ -26,12 +26,15 @@ public class ServerCheckResponse extends Response { private String connectionId; + private byte[] abilities; + public ServerCheckResponse() { } - public ServerCheckResponse(String connectionId) { + public ServerCheckResponse(String connectionId, byte[] abilities) { this.connectionId = connectionId; + this.abilities = abilities; } public String getConnectionId() { @@ -41,4 +44,12 @@ public String getConnectionId() { public void setConnectionId(String connectionId) { this.connectionId = connectionId; } + + public byte[] getAbilities() { + return abilities; + } + + public void setAbilities(byte[] abilities) { + this.abilities = abilities; + } } diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index 7cb69a8f1b3..2d83a5a528e 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -18,6 +18,7 @@ import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.ability.ClientAbilities; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.config.ConfigType; import com.alibaba.nacos.api.config.listener.Listener; @@ -892,12 +893,9 @@ private RpcClient ensureRpcClient(String taskId) throws NacosException { } } - - private ClientAbilities initAbilities() { - ClientAbilities clientAbilities = new ClientAbilities(); - clientAbilities.getRemoteAbility().setSupportRemoteConnection(true); - clientAbilities.getConfigAbility().setSupportRemoteMetrics(true); - return clientAbilities; + + private byte[] initAbilities() { + return AbilityKey.getAbilityBitFlags(); } /** diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index f78fd0a2044..5b616a5885e 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -180,7 +180,7 @@ public final void removeTable(String connectionId) { // hook method remove(connectionId); // remove - nodeAbilityTable.remove(connectionId); + removingTable = nodeAbilityTable.remove(connectionId); } finally { lockForAbilityTable.unlock(); } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java index 8edb1110008..3a5d1bff992 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java @@ -17,6 +17,8 @@ package com.alibaba.nacos.common.remote.client; import com.alibaba.nacos.api.ability.ClientAbilities; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; +import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.remote.RequestCallBack; @@ -29,6 +31,8 @@ import com.alibaba.nacos.api.remote.response.ConnectResetResponse; import com.alibaba.nacos.api.remote.response.ErrorResponse; import com.alibaba.nacos.api.remote.response.Response; +import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.lifecycle.Closeable; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.PayloadRegistry; @@ -50,6 +54,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.LockSupport; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -77,6 +82,8 @@ public abstract class RpcClient implements Closeable { private final BlockingQueue reconnectionSignal = new ArrayBlockingQueue<>(1); + protected final BlockingQueue recServerAbilitySignal = new LinkedBlockingQueue<>(); + protected volatile Connection currentConnection; protected Map labels = new HashMap<>(); @@ -89,7 +96,7 @@ public abstract class RpcClient implements Closeable { private static final long DEFAULT_TIMEOUT_MILLS = 3000L; - protected ClientAbilities clientAbilities; + protected byte[] clientAbilities; /** * default keep alive time 5s. @@ -137,7 +144,7 @@ public RpcClient(String name, ServerListFactory serverListFactory) { * * @param clientAbilities clientAbilities. */ - public RpcClient clientAbilities(ClientAbilities clientAbilities) { + public RpcClient clientAbilities(byte[] clientAbilities) { this.clientAbilities = clientAbilities; return this; } @@ -279,7 +286,7 @@ public final void start() throws NacosException { return; } - clientEventExecutor = new ScheduledThreadPoolExecutor(2, r -> { + clientEventExecutor = new ScheduledThreadPoolExecutor(3, r -> { Thread t = new Thread(r); t.setName("com.alibaba.nacos.client.remote.worker"); t.setDaemon(true); @@ -302,6 +309,32 @@ public final void start() throws NacosException { } } }); + + // receive ability table + clientEventExecutor.submit(() -> { + // save server ability table or remove + while (!clientEventExecutor.isTerminated() && !clientEventExecutor.isShutdown()) { + try { + RecServerAbilityContext take = recServerAbilitySignal.take(); + // avoid interrupted should not null + if (take != null) { + DefaultAbilityControlManager manager = NacosAbilityManagerHolder.getInstance(); + // remove + manager.removeTable(take.oldConnectionId); + // and add + manager.addNewTable( + new AbilityTable() + .setAbility(take.abilityTable) + .setConnectionId(take.connectionId) + .setVersion(take.version) + .setServer(true) + ); + } + } catch (InterruptedException e) { + // do nothing + } + } + }); clientEventExecutor.submit(() -> { while (true) { @@ -395,6 +428,24 @@ public final void start() throws NacosException { } + // try to wait for the ability table to be added, but it will check three time at most + AbilityStatus status = AbilityStatus.NOT_EXIST; + int reCheckTimes = RETRY_TIMES; + while (!isShutdown() && connectToServer != null && status.equals(AbilityStatus.NOT_EXIST) && reCheckTimes > 0) { + LockSupport.parkNanos(100L); + status = NacosAbilityManagerHolder.getInstance().trace(connectToServer.getConnectionId()); + reCheckTimes--; + } + + // judge whether support ability table + // wait to get ability table if initializing, it will pass if server doesn't support ability table or table ready + boolean connected = true; + while (!isShutdown() && connectToServer != null && AbilityStatus.INITIALIZING.equals(status) && connected) { + // wait for complete + // return false if disconnect + connected = NacosAbilityManagerHolder.getInstance().traceReadySyn(connectToServer.getConnectionId()); + } + if (connectToServer != null) { LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to connect to server [{}] on start up, connectionId = {}", name, connectToServer.serverInfo.getAddress(), connectToServer.getConnectionId()); @@ -453,6 +504,9 @@ public void shutdown() throws NacosException { LOGGER.info("Shutdown rpc client, set status to shutdown"); rpcClientStatus.set(RpcClientStatus.SHUTDOWN); LOGGER.info("Shutdown client event executor " + clientEventExecutor); + if (currentConnection != null) { + NacosAbilityManagerHolder.getInstance().removeTable(currentConnection.getConnectionId()); + } if (clientEventExecutor != null) { clientEventExecutor.shutdownNow(); } @@ -522,7 +576,30 @@ protected void reconnect(final ServerInfo recommendServerInfo, boolean onRequest if (connectionNew != null) { LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to connect a server [{}], connectionId = {}", name, serverInfo.getAddress(), connectionNew.getConnectionId()); - // successfully create a new connect. + + // try to wait for the ability table to be added, but it will check three time at most + AbilityStatus status = AbilityStatus.NOT_EXIST; + int reCheckTimes = RETRY_TIMES; + while (status.equals(AbilityStatus.NOT_EXIST) && reCheckTimes > 0) { + LockSupport.parkNanos(100L); + status = NacosAbilityManagerHolder.getInstance().trace(connectionNew.getConnectionId()); + reCheckTimes--; + } + + // judge whether support ability table + // wait to get ability table if initializing, it will pass if server doesn't support ability table or table ready + boolean connected = true; + while (!isShutdown() && AbilityStatus.INITIALIZING.equals(status) && connected) { + // wait for complete + // return false if disconnect + connected = NacosAbilityManagerHolder.getInstance() + .traceReadySyn(connectionNew.getConnectionId()); + } + + LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to get server ability table, connectionId = {}", + name, connectionNew.getConnectionId()); + + // successfully create a new connect if (currentConnection != null) { LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Abandon prev connection, server is {}, connectionId is {}", name, @@ -1034,6 +1111,24 @@ public ReconnectContext(ServerInfo serverInfo, boolean onRequestFail) { ServerInfo serverInfo; } + protected class RecServerAbilityContext { + + public RecServerAbilityContext(String connectionId, Map abilityTable, String version, String oldConnectionId) { + this.connectionId = connectionId; + this.abilityTable = abilityTable; + this.version = version; + this.oldConnectionId = oldConnectionId; + } + + String connectionId; + + Map abilityTable; + + String version; + + String oldConnectionId; + } + public String getTenant() { return tenant; } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java index 2d71b9e46ed..8b40c9cfb8c 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.common.remote.client; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.grpc.GrpcClient; @@ -139,6 +140,7 @@ public static RpcClient createClusterClient(String clientName, ConnectionType co client.setThreadPoolCoreSize(threadPoolCoreSize); client.setThreadPoolMaxSize(threadPoolMaxSize); client.labels(labels); + client.clientAbilities(AbilityKey.getAbilityBitFlags()); return client; }); } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index d285583fbcd..0c81caf9782 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.common.remote.client.grpc; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -26,6 +27,7 @@ import com.alibaba.nacos.api.remote.response.ErrorResponse; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.remote.response.ServerCheckResponse; +import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.Connection; import com.alibaba.nacos.common.remote.client.RpcClient; @@ -43,6 +45,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -308,6 +311,16 @@ public Connection connectToServer(ServerInfo serverInfo) { shuntDownChannel(managedChannel); return null; } + + // submit ability table as soon as possible + // ability table will be null if server doesn't support ability table + ServerCheckResponse serverCheckResponse = (ServerCheckResponse) response; + Map abilityTable = AbilityTableUtils + .getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset()); + String oldConnId = currentConnection == null ? null : currentConnection.getConnectionId(); + RecServerAbilityContext recServerAbilityContext = new RecServerAbilityContext(serverCheckResponse.getConnectionId(), + abilityTable, null, oldConnId); + recServerAbilitySignal.offer(recServerAbilityContext); BiRequestStreamGrpc.BiRequestStreamStub biRequestStreamStub = BiRequestStreamGrpc .newStub(newChannelStubTemp.getChannel()); @@ -325,7 +338,7 @@ public Connection connectToServer(ServerInfo serverInfo) { ConnectionSetupRequest conSetupRequest = new ConnectionSetupRequest(); conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion()); conSetupRequest.setLabels(super.getLabels()); - conSetupRequest.setAbilities(super.clientAbilities); + conSetupRequest.setAbilityTable(super.clientAbilities == null ? AbilityKey.getAbilityBitFlags() : clientAbilities); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); //wait to register connection setup diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java index 96eace5e04c..2553d24a7d3 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java @@ -32,6 +32,8 @@ public abstract class Connection implements Requester { private boolean traced = false; + private Map abilityTable; + private ClientAbilities abilities; private final ConnectionMeta metaInfo; @@ -52,6 +54,14 @@ public void setTraced(boolean traced) { this.traced = traced; } + public Map getAbilityTable() { + return abilityTable; + } + + public void setAbilityTable(Map abilityTable) { + this.abilityTable = abilityTable; + } + /** * get abilities. * @@ -95,7 +105,7 @@ public ConnectionMeta getMetaInfo() { @Override public String toString() { - return "Connection{" + "traced=" + traced + ", abilities=" + abilities + ", metaInfo=" + metaInfo + '}'; + return "Connection{" + "traced=" + traced + ", abilities=" + abilityTable + ", metaInfo=" + metaInfo + '}'; } } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 15432c91e0d..6f2c32b7f92 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -16,12 +16,14 @@ package com.alibaba.nacos.core.remote.grpc; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; import com.alibaba.nacos.api.remote.request.ConnectResetRequest; import com.alibaba.nacos.api.remote.request.ConnectionSetupRequest; import com.alibaba.nacos.api.remote.response.Response; +import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.grpc.GrpcUtils; import com.alibaba.nacos.core.remote.Connection; @@ -114,13 +116,13 @@ public void onNext(Payload payload) { if (labels != null && labels.containsKey(Constants.APPNAME)) { appName = labels.get(Constants.APPNAME); } - + ConnectionMeta metaInfo = new ConnectionMeta(connectionId, payload.getMetadata().getClientIp(), remoteIp, remotePort, localPort, ConnectionType.GRPC.getType(), setUpRequest.getClientVersion(), appName, setUpRequest.getLabels()); metaInfo.setTenant(setUpRequest.getTenant()); Connection connection = new GrpcConnection(metaInfo, responseObserver, CONTEXT_KEY_CHANNEL.get()); - connection.setAbilities(setUpRequest.getAbilities()); + connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), AbilityKey.offset())); boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); if (rejectSdkOnStarting || !connectionManager.register(connectionId, connection)) { diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index 801d3d84ad9..d16ce16ab5e 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.core.remote.grpc; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.Payload; import com.alibaba.nacos.api.grpc.auto.RequestGrpc; @@ -85,10 +86,11 @@ public void request(Payload grpcRequest, StreamObserver responseObserve responseObserver.onCompleted(); return; } - + // server check. if (ServerCheckRequest.class.getSimpleName().equals(type)) { - Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get())); + Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(), + AbilityKey.getAbilityBitFlags())); traceIfNecessary(serverCheckResponseP, false); responseObserver.onNext(serverCheckResponseP); responseObserver.onCompleted(); diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/listener/ServerAbilityConnectionListener.java b/core/src/main/java/com/alibaba/nacos/core/remote/listener/ServerAbilityConnectionListener.java new file mode 100644 index 00000000000..7b581059258 --- /dev/null +++ b/core/src/main/java/com/alibaba/nacos/core/remote/listener/ServerAbilityConnectionListener.java @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2022 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.core.remote.listener; + +import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; +import com.alibaba.nacos.core.remote.ClientConnectionEventListener; +import com.alibaba.nacos.core.remote.Connection; +import org.springframework.stereotype.Component; + +/**. + * @author Daydreamer + * @description This listener is used to register or remove ability table. + * @date 2022/7/17 19:18 + **/ +@Component +public class ServerAbilityConnectionListener extends ClientConnectionEventListener { + + @Override + public void clientConnected(Connection connect) { + // it will be thought from client all + AbilityTable abilityTable = new AbilityTable(connect.getMetaInfo().getConnectionId(), connect.getAbilityTable(), + false, connect.getMetaInfo().getVersion()); + NacosAbilityManagerHolder.getInstance().addNewTable(abilityTable); + } + + @Override + public void clientDisConnected(Connection connect) { + NacosAbilityManagerHolder.getInstance().removeTable(connect.getMetaInfo().getConnectionId()); + } +} From 26bbc5780b8891f907936723dcaf77bb186c1029 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 28 Aug 2022 18:45:56 +0800 Subject: [PATCH 007/181] Adapt and replace old version ability api. --- .../nacos/api/ability/ClientAbilities.java | 1 + .../nacos/api/ability/ServerAbilities.java | 1 + .../com/alibaba/nacos/core/cluster/Member.java | 13 +++++++++++++ .../alibaba/nacos/core/cluster/MemberUtil.java | 10 +++++++--- .../nacos/core/cluster/ServerMemberManager.java | 17 ++++++++++++++--- .../listener/StartingApplicationListener.java | 2 ++ 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/ClientAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/ClientAbilities.java index ea4dd9aa7e4..fe9c80e950c 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/ClientAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/ClientAbilities.java @@ -28,6 +28,7 @@ * @author liuzunfei * @version $Id: ClientAbilities.java, v 0.1 2021年01月24日 00:09 AM liuzunfei Exp $ */ +@Deprecated public class ClientAbilities implements Serializable { private static final long serialVersionUID = -3590789441404549261L; diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/ServerAbilities.java index f6b8b5591b5..80d3f772d21 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/ServerAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/ServerAbilities.java @@ -29,6 +29,7 @@ * @author liuzunfei * @version $Id: ServerAbilities.java, v 0.1 2021年01月24日 00:09 AM liuzunfei Exp $ */ +@Deprecated public class ServerAbilities implements Serializable { private static final long serialVersionUID = -2120543002911304171L; diff --git a/core/src/main/java/com/alibaba/nacos/core/cluster/Member.java b/core/src/main/java/com/alibaba/nacos/core/cluster/Member.java index 090cf9f41a7..69b0cafd6f2 100644 --- a/core/src/main/java/com/alibaba/nacos/core/cluster/Member.java +++ b/core/src/main/java/com/alibaba/nacos/core/cluster/Member.java @@ -53,8 +53,11 @@ public class Member implements Comparable, Cloneable, Serializable { private transient int failAccessCnt = 0; + @Deprecated private ServerAbilities abilities = new ServerAbilities(); + private boolean supportRemoteConnection; + public Member() { String prefix = "nacos.core.member.meta."; extendInfo.put(MemberMetaDataConstants.SITE_KEY, @@ -65,10 +68,20 @@ public Member() { .put(MemberMetaDataConstants.WEIGHT, EnvUtil.getProperty(prefix + MemberMetaDataConstants.WEIGHT, "1")); } + public boolean isSupportRemoteConnection() { + return supportRemoteConnection; + } + + public void setSupportRemoteConnection(boolean supportRemoteConnection) { + this.supportRemoteConnection = supportRemoteConnection; + } + + @Deprecated public ServerAbilities getAbilities() { return abilities; } + @Deprecated public void setAbilities(ServerAbilities abilities) { this.abilities = abilities; } diff --git a/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java b/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java index 3a81aeb080a..07cf27b8aea 100644 --- a/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java +++ b/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java @@ -67,6 +67,7 @@ public static void copy(Member newMember, Member oldMember) { oldMember.setExtendInfo(newMember.getExtendInfo()); oldMember.setAddress(newMember.getAddress()); oldMember.setAbilities(newMember.getAbilities()); + oldMember.setSupportRemoteConnection(newMember.isSupportRemoteConnection()); } /** @@ -108,7 +109,10 @@ public static boolean isSupportedLongCon(Member member) { if (member.getAbilities() == null || member.getAbilities().getRemoteAbility() == null) { return false; } - return member.getAbilities().getRemoteAbility().isSupportRemoteConnection(); + + boolean oldVerJudge = member.getAbilities().getRemoteAbility().isSupportRemoteConnection(); + + return member.isSupportRemoteConnection() || oldVerJudge; } public static int calculateRaftPort(Member member) { @@ -279,8 +283,8 @@ public static boolean isBasicInfoChanged(Member actual, Member expected) { if (!expected.getState().equals(actual.getState())) { return true; } - - if (!expected.getAbilities().equals(actual.getAbilities())) { + + if (!(expected.isSupportRemoteConnection() && actual.isSupportRemoteConnection())) { return true; } diff --git a/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java b/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java index 16c6824a562..d90653996bc 100644 --- a/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java @@ -152,6 +152,7 @@ protected void init() throws NacosException { this.localAddress = InetUtils.getSelfIP() + ":" + port; this.self = MemberUtil.singleParse(this.localAddress); this.self.setExtendVal(MemberMetaDataConstants.VERSION, VersionUtils.version); + this.self.setSupportRemoteConnection(true); // init abilities. this.self.setAbilities(initMemberAbilities()); @@ -171,6 +172,12 @@ protected void init() throws NacosException { Loggers.CORE.info("The cluster resource is initialized"); } + /**. + * Init the ability of current node + * + * @return ServerAbilities + * @deprecated ability of current node and event cluster can be managed by {@link com.alibaba.nacos.core.ability.control.ServerAbilityControlManager} + */ private ServerAbilities initMemberAbilities() { ServerAbilities serverAbilities = new ServerAbilities(); for (ServerAbilityInitializer each : ServerAbilityInitializerHolder.getInstance().getInitializers()) { @@ -550,13 +557,17 @@ public void onReceive(RestResult result) { Loggers.CLUSTER.warn("{} : Clean up version info," + " target has been downgrade to old version.", memberNew); } - if (target.getAbilities() != null - && target.getAbilities().getRemoteAbility() != null && target.getAbilities() - .getRemoteAbility().isSupportRemoteConnection()) { + // adapt old version + boolean oldVersionJudge = target.getAbilities() != null + && target.getAbilities().getRemoteAbility() != null + && target.getAbilities().getRemoteAbility().isSupportRemoteConnection(); + boolean newVersionJudge = target.isSupportRemoteConnection(); + if (oldVersionJudge || newVersionJudge) { if (memberNew == null) { memberNew = target.copy(); } memberNew.getAbilities().getRemoteAbility().setSupportRemoteConnection(false); + target.setSupportRemoteConnection(false); Loggers.CLUSTER .warn("{} : Clear support remote connection flag,target may rollback version ", memberNew); diff --git a/core/src/main/java/com/alibaba/nacos/core/listener/StartingApplicationListener.java b/core/src/main/java/com/alibaba/nacos/core/listener/StartingApplicationListener.java index fa1e21b6130..7be65bbc08a 100644 --- a/core/src/main/java/com/alibaba/nacos/core/listener/StartingApplicationListener.java +++ b/core/src/main/java/com/alibaba/nacos/core/listener/StartingApplicationListener.java @@ -18,6 +18,7 @@ import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.exception.runtime.NacosRuntimeException; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.executor.ExecutorFactory; import com.alibaba.nacos.common.executor.NameThreadFactory; import com.alibaba.nacos.common.executor.ThreadPoolManager; @@ -138,6 +139,7 @@ public void failed(ConfigurableApplicationContext context, Throwable exception) ThreadPoolManager.shutdown(); WatchFileCenter.shutdown(); NotifyCenter.shutdown(); + NacosAbilityManagerHolder.getInstance().destroy(); closeExecutor(); From 679b0e018483ea4639a810b3a7fc6a7ce6d543d6 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 28 Aug 2022 18:48:48 +0800 Subject: [PATCH 008/181] Example for new ability. --- .../java/com/alibaba/nacos/api/ability/constant/AbilityKey.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java index 0971ca7af6f..cf194cccaff 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java @@ -51,7 +51,7 @@ private AbilityKey() { * This field can be used outside. * * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: - * CURRENT_NODE_ABILITY_TABLE.put("compression", 1); means that is the first bit from left to right in the table. + * CURRENT_SERVER_ABILITY_OFFSET.put("compression", 1); means that is the first bit from left to right in the table. * */ From de9e113e24571aa6f9f6b8b905dc01759dff1829 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 28 Aug 2022 19:10:55 +0800 Subject: [PATCH 009/181] Fix checkstyle --- .../nacos/api/remote/request/ConnectionSetupRequest.java | 1 - .../com/alibaba/nacos/client/config/impl/ClientWorker.java | 1 - .../java/com/alibaba/nacos/common/remote/client/RpcClient.java | 1 - .../com/alibaba/nacos/core/cluster/ServerMemberManager.java | 3 ++- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java index 67e246ad6de..046a897a447 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.api.remote.request; - import java.util.HashMap; import java.util.Map; diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index 2d83a5a528e..fad43fc4cea 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.client.config.impl; import com.alibaba.nacos.api.PropertyKeyConst; -import com.alibaba.nacos.api.ability.ClientAbilities; import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.config.ConfigType; diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java index 3a5d1bff992..c4107c480f2 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.common.remote.client; -import com.alibaba.nacos.api.ability.ClientAbilities; import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.common.Constants; diff --git a/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java b/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java index d90653996bc..3c4e28b1924 100644 --- a/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java @@ -60,6 +60,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentSkipListMap; +import com.alibaba.nacos.core.ability.control.ServerAbilityControlManager; /** * Cluster node management in Nacos. @@ -176,7 +177,7 @@ protected void init() throws NacosException { * Init the ability of current node * * @return ServerAbilities - * @deprecated ability of current node and event cluster can be managed by {@link com.alibaba.nacos.core.ability.control.ServerAbilityControlManager} + * @deprecated ability of current node and event cluster can be managed by {@link ServerAbilityControlManager} */ private ServerAbilities initMemberAbilities() { ServerAbilities serverAbilities = new ServerAbilities(); From a47f052c904a7f46121059fcdb0e44f881ec96b7 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Tue, 30 Aug 2022 21:36:24 +0800 Subject: [PATCH 010/181] Remove the AbilityHandlePreProcessor and AbilityStatus. Change the way to get or remove AbilityTable for RpcClient. --- .../api/ability/constant/AbilityStatus.java | 46 ------ .../ability/ClientAbilityControlManager.java | 12 -- .../client/config/impl/ClientWorker.java | 5 +- .../gprc/redo/NamingGrpcRedoService.java | 5 +- .../client/naming/remote/TestConnection.java | 36 +++++ .../gprc/redo/NamingGrpcRedoServiceTest.java | 8 +- .../AbstractAbilityControlManager.java | 149 +----------------- .../ability/discover/AbilityHandleLoader.java | 49 ------ .../discover/NacosAbilityManagerHolder.java | 3 - .../handler/AbilityHandlePreProcessor.java | 36 ----- .../ability/inter/AbilityControlManager.java | 9 -- .../inter/TraceableAbilityControlManager.java | 44 ------ .../listener/ClientAbilityEventListener.java | 24 +++ .../client/ConnectionEventListener.java | 8 +- .../nacos/common/remote/client/RpcClient.java | 105 +++--------- .../common/remote/client/grpc/GrpcClient.java | 11 +- .../control/ServerAbilityControlManager.java | 12 -- .../ability/AbilityControlManagerTest.java | 58 +------ 18 files changed, 116 insertions(+), 504 deletions(-) delete mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java create mode 100644 client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java delete mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/discover/AbilityHandleLoader.java delete mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/handler/AbilityHandlePreProcessor.java delete mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/inter/TraceableAbilityControlManager.java create mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java deleted file mode 100644 index 825e99a0a1a..00000000000 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 1999-2022 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.ability.constant; - -/**. - * @author Daydreamer - * @description This enum is used to track the status of the ability table. - * @date 2022/7/13 14:11 - **/ -public enum AbilityStatus { - - /** - * It means that the ability table does not exist in the current node. - */ - NOT_EXIST, - - /** - * It means that current node has received the ability table and the table is initializing by AbilityPostProcessor. - */ - INITIALIZING, - - /** - * It means that the ability table is ready. - */ - READY, - - /** - * It means that the ability table will be removed soon. - */ - EXPIRED - -} diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index 0f3a6fcbef4..9d39574f8b3 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.client.ability; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; @@ -41,17 +40,6 @@ public boolean isSupport(String connectionId, String abilityKey) { return false; } AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - // it is null, check if initialing - if (abilityTable == null && AbilityStatus.INITIALIZING.equals(trace(connectionId))) { - // wait for ready - boolean finish = traceReadySyn(connectionId); - // if expired - if (!finish) { - return false; - } else { - abilityTable = nodeAbilityTable.get(connectionId); - } - } // false if null return abilityTable != null && Optional.ofNullable(abilityTable.getAbility()) diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index fad43fc4cea..fc450b990a5 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -37,6 +37,7 @@ import com.alibaba.nacos.api.remote.RemoteConstants; import com.alibaba.nacos.api.remote.request.Request; import com.alibaba.nacos.api.remote.response.Response; +import com.alibaba.nacos.common.remote.client.Connection; import com.alibaba.nacos.plugin.auth.api.RequestResource; import com.alibaba.nacos.client.config.common.GroupKey; import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager; @@ -629,13 +630,13 @@ private void initRpcClientHandler(final RpcClient rpcClientInner) { rpcClientInner.registerConnectionListener(new ConnectionEventListener() { @Override - public void onConnected() { + public void onConnected(Connection connection) { LOGGER.info("[{}] Connected,notify listen context...", rpcClientInner.getName()); notifyListenConfig(); } @Override - public void onDisConnect() { + public void onDisConnect(Connection connection) { String taskId = rpcClientInner.getLabels().get("taskId"); LOGGER.info("[{}] DisConnected,clear listen context...", rpcClientInner.getName()); Collection values = cacheMap.get().values(); diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java index 4b68b6e3bc0..d715a357813 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoService.java @@ -25,6 +25,7 @@ import com.alibaba.nacos.client.naming.remote.gprc.redo.data.SubscriberRedoData; import com.alibaba.nacos.client.utils.LogUtils; import com.alibaba.nacos.common.executor.NameThreadFactory; +import com.alibaba.nacos.common.remote.client.Connection; import com.alibaba.nacos.common.remote.client.ConnectionEventListener; import java.util.HashSet; @@ -73,13 +74,13 @@ public boolean isConnected() { } @Override - public void onConnected() { + public void onConnected(Connection connection) { connected = true; LogUtils.NAMING_LOGGER.info("Grpc connection connect"); } @Override - public void onDisConnect() { + public void onDisConnect(Connection connection) { connected = false; LogUtils.NAMING_LOGGER.warn("Grpc connection disconnect, mark to redo"); synchronized (registeredInstances) { diff --git a/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java b/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java new file mode 100644 index 00000000000..6d02c962da0 --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java @@ -0,0 +1,36 @@ +package com.alibaba.nacos.client.naming.remote; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.remote.RequestCallBack; +import com.alibaba.nacos.api.remote.RequestFuture; +import com.alibaba.nacos.api.remote.request.Request; +import com.alibaba.nacos.api.remote.response.Response; +import com.alibaba.nacos.common.remote.client.Connection; +import com.alibaba.nacos.common.remote.client.RpcClient; + +public class TestConnection extends Connection { + + public TestConnection(RpcClient.ServerInfo serverInfo) { + super(serverInfo); + } + + @Override + public Response request(Request request, long timeoutMills) throws NacosException { + return null; + } + + @Override + public RequestFuture requestFuture(Request request) throws NacosException { + return null; + } + + @Override + public void asyncRequest(Request request, RequestCallBack requestCallBack) throws NacosException { + + } + + @Override + public void close() { + + } +} diff --git a/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoServiceTest.java b/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoServiceTest.java index 150ff5d87c2..cc204b4012a 100644 --- a/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoServiceTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/redo/NamingGrpcRedoServiceTest.java @@ -17,10 +17,12 @@ package com.alibaba.nacos.client.naming.remote.gprc.redo; import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.client.naming.remote.TestConnection; import com.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy; import com.alibaba.nacos.client.naming.remote.gprc.redo.data.BatchInstanceRedoData; import com.alibaba.nacos.client.naming.remote.gprc.redo.data.InstanceRedoData; import com.alibaba.nacos.client.naming.remote.gprc.redo.data.SubscriberRedoData; +import com.alibaba.nacos.common.remote.client.RpcClient; import com.alibaba.nacos.common.utils.ReflectUtils; import org.junit.After; import org.junit.Before; @@ -68,13 +70,13 @@ public void tearDown() throws Exception { @Test public void testOnConnected() { assertFalse(redoService.isConnected()); - redoService.onConnected(); + redoService.onConnected(new TestConnection(new RpcClient.ServerInfo())); assertTrue(redoService.isConnected()); } @Test public void testOnDisConnect() { - redoService.onConnected(); + redoService.onConnected(new TestConnection(new RpcClient.ServerInfo())); redoService.cacheInstanceForRedo(SERVICE, GROUP, new Instance()); redoService.instanceRegistered(SERVICE, GROUP); redoService.cacheSubscriberForRedo(SERVICE, GROUP, CLUSTER); @@ -82,7 +84,7 @@ public void testOnDisConnect() { assertTrue(redoService.isConnected()); assertTrue(redoService.findInstanceRedoData().isEmpty()); assertTrue(redoService.findSubscriberRedoData().isEmpty()); - redoService.onDisConnect(); + redoService.onDisConnect(new TestConnection(new RpcClient.ServerInfo())); assertFalse(redoService.isConnected()); assertFalse(redoService.findInstanceRedoData().isEmpty()); assertFalse(redoService.findSubscriberRedoData().isEmpty()); diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 5b616a5885e..e1723a9e228 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -17,23 +17,16 @@ package com.alibaba.nacos.common.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; -import com.alibaba.nacos.common.ability.handler.AbilityHandlePreProcessor; -import com.alibaba.nacos.common.ability.inter.TraceableAbilityControlManager; +import com.alibaba.nacos.common.ability.inter.AbilityControlManager; import com.alibaba.nacos.common.notify.Event; import com.alibaba.nacos.common.notify.NotifyCenter; -import com.alibaba.nacos.common.utils.CollectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.ReentrantLock; /**. @@ -42,7 +35,7 @@ * @date 2022/7/12 19:18 **/ @SuppressWarnings("all") -public abstract class AbstractAbilityControlManager implements TraceableAbilityControlManager { +public abstract class AbstractAbilityControlManager implements AbilityControlManager { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAbilityControlManager.class); @@ -63,17 +56,6 @@ public abstract class AbstractAbilityControlManager implements TraceableAbilityC */ protected final Map nodeAbilityTable = new ConcurrentHashMap<>(); - /**. - * These handlers will be invoke before combine the ability table - */ - private final List abilityHandlePreProcessors = new ArrayList<>(); - - /** - * This map is used to trace the status of ability table. - * Its status should be update after {@link #addNewTable(AbilityTable)} and {@link #removeTable(String)} - */ - protected final Map> abilityStatus = new ConcurrentHashMap<>(); - private final ReentrantLock lockForProcessors = new ReentrantLock(); private final ReentrantLock lockForAbilityTable = new ReentrantLock(); @@ -124,33 +106,18 @@ public final void addNewTable(AbilityTable table) { if (contains(connectionId)) { return; } - // update status - abilityStatus.put(connectionId, new AtomicReference<>(AbilityStatus.INITIALIZING)); - // handle ability table before joining current node - AbilityTable processed = process(table); // hook method - add(processed); + add(table); // add to node nodeAbilityTable.put(connectionId, table); } finally { lockForAbilityTable.unlock(); } - // update status - AtomicReference abilityStatusAtomicReference = abilityStatus.get(table.getConnectionId()); - if (abilityStatusAtomicReference != null) { - // try one time - // do nothing if AbilityStatus == Expired - // if ready - if(abilityStatusAtomicReference.compareAndSet(AbilityStatus.INITIALIZING, AbilityStatus.READY)) { - // publish event to subscriber - AbilityComeEvent updateEvent = new AbilityComeEvent(); - updateEvent.setConnectionId(table.getConnectionId()); - updateEvent.setTable(table); - NotifyCenter.publishEvent(updateEvent); - } - } else { - LOGGER.warn("[AbiityControlManager] Cannot get connection status after processing ability table, possible reason is that the network is unstable"); - } + // publish event to subscriber + AbilityComeEvent updateEvent = new AbilityComeEvent(); + updateEvent.setConnectionId(table.getConnectionId()); + updateEvent.setTable(table); + NotifyCenter.publishEvent(updateEvent); } /** @@ -171,12 +138,6 @@ public final void removeTable(String connectionId) { if (!nodeAbilityTable.containsKey(connectionId)) { return; } - nodeAbilityTable.get(connectionId); - // update status - abilityStatus.computeIfPresent(connectionId, (k, v) -> { - v.set(AbilityStatus.EXPIRED); - return v; - }); // hook method remove(connectionId); // remove @@ -184,8 +145,6 @@ public final void removeTable(String connectionId) { } finally { lockForAbilityTable.unlock(); } - // remove status - abilityStatus.remove(connectionId); // publish event if (removingTable != null) { AbilityExpiredEvent expiredEvent = new AbilityExpiredEvent(); @@ -195,7 +154,6 @@ public final void removeTable(String connectionId) { } } - /** * Register a new ability table. This is a ThreadSafe method for {@link AbstractAbilityControlManager#remove(String)}. * @@ -221,97 +179,6 @@ public final void removeTable(String connectionId) { public boolean contains(String connectionId) { return nodeAbilityTable.containsKey(connectionId); } - - - /** - * Get the status of the ability table. - * - * @param connectionId connection id - * @return status of ability table {@link AbilityStatus} - */ - @Override - public AbilityStatus trace(String connectionId) { - if (connectionId == null) { - return AbilityStatus.NOT_EXIST; - } - return abilityStatus.getOrDefault(connectionId, new AtomicReference<>(AbilityStatus.NOT_EXIST)).get(); - } - - /** - * Trace the status of connection if

{@link AbilityStatus#INITIALIZING}

, wake up if

{@link AbilityStatus#READY}

- * It will return if status is

{@link AbilityStatus#EXPIRED}

or

{@link AbilityStatus#NOT_EXIST}

- * - * @param connectionId connection id - * @param source source status - * @param target target status - * @return if success - */ - @Override - public boolean traceReadySyn(String connectionId) { - AbilityStatus source = AbilityStatus.INITIALIZING; - AbilityStatus target = AbilityStatus.READY; - AtomicReference atomicReference = abilityStatus.get(connectionId); - // return if null - if (atomicReference == null || atomicReference.get().equals(AbilityStatus.EXPIRED)) { - return false; - } else if (target == atomicReference.get()) { - return true; - } - // try if status legal - while (!atomicReference.get().equals(target) && atomicReference.get().equals(source)) { - LockSupport.parkNanos(100L); - // if expired - if (atomicReference.get().equals(AbilityStatus.EXPIRED)) { - return false; - } - } - return atomicReference.get().equals(target); - } - - /**. - * Invoking {@link AbilityHandlePreProcessor} - * - * @param source source ability table - * @return result - */ - protected AbilityTable process(AbilityTable source) { - // do nothing if no processor - if (CollectionUtils.isEmpty(abilityHandlePreProcessors)) { - return source; - } - // copy to advoid error process - AbilityTable abilityTable = source; - AbilityTable copy = new AbilityTable(source.getConnectionId(), new HashMap<>(source.getAbility()), source.isServer(), source.getVersion()); - for (AbilityHandlePreProcessor handler : abilityHandlePreProcessors) { - try { - abilityTable = handler.handle(abilityTable); - } catch (Throwable t) { - LOGGER.warn("[AbilityHandlePostProcessor] Failed to invoke {} :{}", - handler.getClass().getSimpleName(), t.getLocalizedMessage()); - // ensure normal operation - abilityTable = copy; - } - } - return abilityTable; - } - - /**. - * They will be invoked before updating ability table, but the order in which - * they are called cannot be guaranteed - * - * @param postProcessor PostProcessor instance - */ - @Override - public void addPostProcessor(AbilityHandlePreProcessor postProcessor) { - lockForProcessors.lock(); - try { - abilityHandlePreProcessors.add(postProcessor); - } finally { - lockForProcessors.unlock(); - LOGGER.info("[AbilityHandlePostProcessor] registry handler: {}", - postProcessor.getClass().getSimpleName()); - } - } /** * Initialize the manager diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/discover/AbilityHandleLoader.java b/common/src/main/java/com/alibaba/nacos/common/ability/discover/AbilityHandleLoader.java deleted file mode 100644 index feb07436a0b..00000000000 --- a/common/src/main/java/com/alibaba/nacos/common/ability/discover/AbilityHandleLoader.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 1999-2022 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.ability.discover; - -import com.alibaba.nacos.common.ability.handler.AbilityHandlePreProcessor; -import com.alibaba.nacos.common.spi.NacosServiceLoader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.HashSet; - -/**. - * @author Daydreamer - * @description It is spi loader to load {@link AbilityHandlePreProcessor} - * @date 2022/8/25 18:24 - **/ -public class AbilityHandleLoader { - - private final Collection initializers; - - private static final Logger LOGGER = LoggerFactory.getLogger(AbilityHandleLoader.class); - - public AbilityHandleLoader() { - initializers = new HashSet<>(); - for (AbilityHandlePreProcessor preProcessor : NacosServiceLoader.load(AbilityHandlePreProcessor.class)) { - initializers.add(preProcessor); - LOGGER.info("Load {} for AbilityHandlePreProcessor", preProcessor.getClass().getCanonicalName()); - } - } - - public Collection getInitializers() { - return initializers; - } -} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java b/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java index fe7a0c7603c..dc3fe479d00 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java @@ -64,9 +64,6 @@ private NacosAbilityManagerHolder() { abstractAbilityControlManager = clazz; }); LOGGER.info("[AbilityControlManager] Successfully initialize AbilityControlManager"); - // init pre processor - AbilityHandleLoader loader = new AbilityHandleLoader(); - loader.getInitializers().forEach(processor -> abstractAbilityControlManager.addPostProcessor(processor)); } } diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/handler/AbilityHandlePreProcessor.java b/common/src/main/java/com/alibaba/nacos/common/ability/handler/AbilityHandlePreProcessor.java deleted file mode 100644 index 252f8112359..00000000000 --- a/common/src/main/java/com/alibaba/nacos/common/ability/handler/AbilityHandlePreProcessor.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 1999-2022 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.ability.handler; - -import com.alibaba.nacos.api.ability.entity.AbilityTable; - -/**. - * @author Daydreamer - * @description This handler will should be invoked before ability table joining current node. - * @date 2022/7/12 19:24 - **/ -public interface AbilityHandlePreProcessor { - - /** - * Handling before joining current node. - * - * @param source source ability handler - * @return result table - */ - AbilityTable handle(AbilityTable source); - -} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java index 15adf7fc924..75aac889380 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java @@ -18,7 +18,6 @@ import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.entity.AbilityTable; -import com.alibaba.nacos.common.ability.handler.AbilityHandlePreProcessor; import java.util.Map; @@ -75,14 +74,6 @@ public interface AbilityControlManager { */ Map getCurrentRunningAbility(); - /**. - * They will be invoked before updating ability table, but the order in which - * they are called cannot be guaranteed - * - * @param postProcessor PostProcessor instance - */ - void addPostProcessor(AbilityHandlePreProcessor postProcessor); - /**. * Initialize the manager */ diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/TraceableAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/TraceableAbilityControlManager.java deleted file mode 100644 index 6b87b9b38fc..00000000000 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/TraceableAbilityControlManager.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 1999-2022 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.ability.inter; - -import com.alibaba.nacos.api.ability.constant.AbilityStatus; - -/**. - * @author Daydreamer - * @description It provides the capability to trace the state of AbilityTable for the {@link AbilityControlManager} - * @date 2022/8/10 23:30 - **/ -public interface TraceableAbilityControlManager extends AbilityControlManager { - - /** - * Get the status of the ability table. - * - * @param connectionId connection id - * @return status of ability table {@link AbilityStatus} - */ - AbilityStatus trace(String connectionId); - - /**. - * Trace the status of connection if {@link AbilityStatus#INITIALIZING}, wake up if {@link AbilityStatus#READY} - * It will return if status is {@link AbilityStatus#EXPIRED} or {@link AbilityStatus#NOT_EXIST} - * - * @param connectionId connection id - * @return if success to {@link AbilityStatus#READY} - */ - boolean traceReadySyn(String connectionId); -} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java b/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java new file mode 100644 index 00000000000..0c20043655d --- /dev/null +++ b/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java @@ -0,0 +1,24 @@ +package com.alibaba.nacos.common.ability.listener; + + +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; +import com.alibaba.nacos.common.remote.client.Connection; +import com.alibaba.nacos.common.remote.client.ConnectionEventListener; + +/**. + * @author Daydreamer + * @description This listener is used for remove ability table if disconnected. + * @date 2022/8/30 22:00 + **/ +public class ClientAbilityEventListener implements ConnectionEventListener { + + @Override + public void onConnected(Connection connection) { + // nothing to do + } + + @Override + public void onDisConnect(Connection connection) { + NacosAbilityManagerHolder.getInstance().removeTable(connection.getConnectionId()); + } +} diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/ConnectionEventListener.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/ConnectionEventListener.java index f3f15bf24e4..d411a62a9ed 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/ConnectionEventListener.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/ConnectionEventListener.java @@ -25,11 +25,15 @@ public interface ConnectionEventListener { /** * notify when connected to server. + * + * @param connection connection has connected */ - public void onConnected(); + public void onConnected(Connection connection); /** * notify when disconnected to server. + * + * @param connection connection has disconnected */ - public void onDisConnect(); + public void onDisConnect(Connection connection); } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java index c4107c480f2..9db2e1e8487 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java @@ -16,8 +16,6 @@ package com.alibaba.nacos.common.remote.client; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; -import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.remote.RequestCallBack; @@ -30,8 +28,8 @@ import com.alibaba.nacos.api.remote.response.ConnectResetResponse; import com.alibaba.nacos.api.remote.response.ErrorResponse; import com.alibaba.nacos.api.remote.response.Response; -import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; +import com.alibaba.nacos.common.ability.listener.ClientAbilityEventListener; import com.alibaba.nacos.common.lifecycle.Closeable; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.PayloadRegistry; @@ -53,7 +51,6 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.LockSupport; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -81,8 +78,6 @@ public abstract class RpcClient implements Closeable { private final BlockingQueue reconnectionSignal = new ArrayBlockingQueue<>(1); - protected final BlockingQueue recServerAbilitySignal = new LinkedBlockingQueue<>(); - protected volatile Connection currentConnection; protected Map labels = new HashMap<>(); @@ -191,15 +186,17 @@ public RpcClient keepAlive(long keepAliveTime, TimeUnit timeUnit) { /** * Notify when client disconnected. + * + * @param connection connection has disconnected */ - protected void notifyDisConnected() { + protected void notifyDisConnected(Connection connection) { if (connectionEventListeners.isEmpty()) { return; } LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Notify disconnected event to listeners", name); for (ConnectionEventListener connectionEventListener : connectionEventListeners) { try { - connectionEventListener.onDisConnect(); + connectionEventListener.onDisConnect(connection); } catch (Throwable throwable) { LoggerUtils.printIfErrorEnabled(LOGGER, "[{}] Notify disconnect listener error, listener = {}", name, connectionEventListener.getClass().getName()); @@ -209,15 +206,17 @@ protected void notifyDisConnected() { /** * Notify when client new connected. + * + * @param connection connection has connected */ - protected void notifyConnected() { + protected void notifyConnected(Connection connection) { if (connectionEventListeners.isEmpty()) { return; } LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Notify connected event to listeners.", name); for (ConnectionEventListener connectionEventListener : connectionEventListeners) { try { - connectionEventListener.onConnected(); + connectionEventListener.onConnected(connection); } catch (Throwable throwable) { LoggerUtils.printIfErrorEnabled(LOGGER, "[{}] Notify connect listener error, listener = {}", name, connectionEventListener.getClass().getName()); @@ -285,7 +284,10 @@ public final void start() throws NacosException { return; } - clientEventExecutor = new ScheduledThreadPoolExecutor(3, r -> { + // add listener to remove expired ability table + registerConnectionListener(new ClientAbilityEventListener()); + + clientEventExecutor = new ScheduledThreadPoolExecutor(2, r -> { Thread t = new Thread(r); t.setName("com.alibaba.nacos.client.remote.worker"); t.setDaemon(true); @@ -299,41 +301,15 @@ public final void start() throws NacosException { try { take = eventLinkedBlockingQueue.take(); if (take.isConnected()) { - notifyConnected(); + notifyConnected(take.connection); } else if (take.isDisConnected()) { - notifyDisConnected(); + notifyDisConnected(take.connection); } } catch (Throwable e) { // Do nothing } } }); - - // receive ability table - clientEventExecutor.submit(() -> { - // save server ability table or remove - while (!clientEventExecutor.isTerminated() && !clientEventExecutor.isShutdown()) { - try { - RecServerAbilityContext take = recServerAbilitySignal.take(); - // avoid interrupted should not null - if (take != null) { - DefaultAbilityControlManager manager = NacosAbilityManagerHolder.getInstance(); - // remove - manager.removeTable(take.oldConnectionId); - // and add - manager.addNewTable( - new AbilityTable() - .setAbility(take.abilityTable) - .setConnectionId(take.connectionId) - .setVersion(take.version) - .setServer(true) - ); - } - } catch (InterruptedException e) { - // do nothing - } - } - }); clientEventExecutor.submit(() -> { while (true) { @@ -427,30 +403,12 @@ public final void start() throws NacosException { } - // try to wait for the ability table to be added, but it will check three time at most - AbilityStatus status = AbilityStatus.NOT_EXIST; - int reCheckTimes = RETRY_TIMES; - while (!isShutdown() && connectToServer != null && status.equals(AbilityStatus.NOT_EXIST) && reCheckTimes > 0) { - LockSupport.parkNanos(100L); - status = NacosAbilityManagerHolder.getInstance().trace(connectToServer.getConnectionId()); - reCheckTimes--; - } - - // judge whether support ability table - // wait to get ability table if initializing, it will pass if server doesn't support ability table or table ready - boolean connected = true; - while (!isShutdown() && connectToServer != null && AbilityStatus.INITIALIZING.equals(status) && connected) { - // wait for complete - // return false if disconnect - connected = NacosAbilityManagerHolder.getInstance().traceReadySyn(connectToServer.getConnectionId()); - } - if (connectToServer != null) { LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to connect to server [{}] on start up, connectionId = {}", name, connectToServer.serverInfo.getAddress(), connectToServer.getConnectionId()); this.currentConnection = connectToServer; rpcClientStatus.set(RpcClientStatus.RUNNING); - eventLinkedBlockingQueue.offer(new ConnectionEvent(ConnectionEvent.CONNECTED)); + eventLinkedBlockingQueue.offer(new ConnectionEvent(ConnectionEvent.CONNECTED, currentConnection)); } else { switchServerAsync(); } @@ -576,28 +534,6 @@ protected void reconnect(final ServerInfo recommendServerInfo, boolean onRequest LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to connect a server [{}], connectionId = {}", name, serverInfo.getAddress(), connectionNew.getConnectionId()); - // try to wait for the ability table to be added, but it will check three time at most - AbilityStatus status = AbilityStatus.NOT_EXIST; - int reCheckTimes = RETRY_TIMES; - while (status.equals(AbilityStatus.NOT_EXIST) && reCheckTimes > 0) { - LockSupport.parkNanos(100L); - status = NacosAbilityManagerHolder.getInstance().trace(connectionNew.getConnectionId()); - reCheckTimes--; - } - - // judge whether support ability table - // wait to get ability table if initializing, it will pass if server doesn't support ability table or table ready - boolean connected = true; - while (!isShutdown() && AbilityStatus.INITIALIZING.equals(status) && connected) { - // wait for complete - // return false if disconnect - connected = NacosAbilityManagerHolder.getInstance() - .traceReadySyn(connectionNew.getConnectionId()); - } - - LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Success to get server ability table, connectionId = {}", - name, connectionNew.getConnectionId()); - // successfully create a new connect if (currentConnection != null) { LoggerUtils.printIfInfoEnabled(LOGGER, @@ -610,7 +546,7 @@ protected void reconnect(final ServerInfo recommendServerInfo, boolean onRequest currentConnection = connectionNew; rpcClientStatus.set(RpcClientStatus.RUNNING); switchSuccess = true; - eventLinkedBlockingQueue.add(new ConnectionEvent(ConnectionEvent.CONNECTED)); + eventLinkedBlockingQueue.add(new ConnectionEvent(ConnectionEvent.CONNECTED, currentConnection)); return; } @@ -671,7 +607,7 @@ private void closeConnection(Connection connection) { if (connection != null) { LOGGER.info("Close current connection " + connection.getConnectionId()); connection.close(); - eventLinkedBlockingQueue.add(new ConnectionEvent(ConnectionEvent.DISCONNECTED)); + eventLinkedBlockingQueue.add(new ConnectionEvent(ConnectionEvent.DISCONNECTED, connection)); } } @@ -1076,8 +1012,11 @@ public class ConnectionEvent { int eventType; - public ConnectionEvent(int eventType) { + Connection connection; + + public ConnectionEvent(int eventType, Connection connection) { this.eventType = eventType; + this.connection = connection; } public boolean isConnected() { diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 0c81caf9782..a68c81e5847 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.common.remote.client.grpc; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -28,6 +29,7 @@ import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.remote.response.ServerCheckResponse; import com.alibaba.nacos.api.utils.AbilityTableUtils; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.Connection; import com.alibaba.nacos.common.remote.client.RpcClient; @@ -317,10 +319,11 @@ public Connection connectToServer(ServerInfo serverInfo) { ServerCheckResponse serverCheckResponse = (ServerCheckResponse) response; Map abilityTable = AbilityTableUtils .getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset()); - String oldConnId = currentConnection == null ? null : currentConnection.getConnectionId(); - RecServerAbilityContext recServerAbilityContext = new RecServerAbilityContext(serverCheckResponse.getConnectionId(), - abilityTable, null, oldConnId); - recServerAbilitySignal.offer(recServerAbilityContext); + AbilityTable table = new AbilityTable(); + table.setServer(true) + .setConnectionId(serverCheckResponse.getConnectionId()) + .setAbility(abilityTable); + NacosAbilityManagerHolder.getInstance().addNewTable(table); BiRequestStreamGrpc.BiRequestStreamStub biRequestStreamStub = BiRequestStreamGrpc .newStub(newChannelStubTemp.getChannel()); diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 09faa79a43a..44a01258ffa 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.core.ability.control; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; @@ -80,17 +79,6 @@ public boolean isSupport(String connectionId, String abilityKey) { return false; } AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - // it is null, check if initialing - if (abilityTable == null && AbilityStatus.INITIALIZING.equals(trace(connectionId))) { - // wait for ready - boolean finish = traceReadySyn(connectionId); - // if expired - if (!finish) { - return false; - } else { - abilityTable = nodeAbilityTable.get(connectionId); - } - } // false if null return abilityTable != null && Optional.ofNullable(abilityTable.getAbility()) diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java index e27009abe4d..99d7cced7da 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java @@ -16,9 +16,7 @@ package com.alibaba.nacos.test.ability; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; -import com.alibaba.nacos.common.ability.handler.AbilityHandlePreProcessor; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import org.junit.Assert; import org.junit.Before; @@ -118,9 +116,9 @@ public void testClientRemove() { clientTable.setAbility(clientTa); clientTable.setServer(true); clientAbilityControlManager.addNewTable(clientTable); - Assert.assertEquals(AbilityStatus.READY, clientAbilityControlManager.trace("test-01111")); + Assert.assertTrue(clientAbilityControlManager.contains(clientTable.getConnectionId())); clientAbilityControlManager.removeTable("test-01111"); - Assert.assertEquals(AbilityStatus.NOT_EXIST, clientAbilityControlManager.trace("test-01111")); + Assert.assertFalse(clientAbilityControlManager.contains(clientTable.getConnectionId())); } @Test @@ -214,36 +212,6 @@ public void testCurrentNodeAbility() { }); } - @Test - public void testPre() { - clientAbilityControlManager.addPostProcessor(new TestPreHandler()); - clientAbilityControlManager.enableCurrentNodeAbility("stop-raft"); - AbilityTable abilityTable = new AbilityTable(); - abilityTable.setConnectionId("1111"); - HashMap table = new HashMap<>(); - table.put("stop-raft", false); - abilityTable.setAbility(table); - clientAbilityControlManager.addNewTable(abilityTable); - Assert.assertFalse(clientAbilityControlManager.isSupport("1111", "stop-raft")); - } - - @Test - public void testStateSyn() { - // register a processing long time handler - AbilityTable abilityTable = new AbilityTable(); - abilityTable.setConnectionId("1111"); - HashMap table = new HashMap<>(); - table.put("stop-raft", false); - abilityTable.setAbility(table); - clientAbilityControlManager.addPostProcessor(new TestStatusPreHandler()); - // 追踪状态 - long begin = System.currentTimeMillis(); - clientAbilityControlManager.addNewTable(abilityTable); - Assert.assertTrue(clientAbilityControlManager.traceReadySyn("1111")); - long end = System.currentTimeMillis(); - Assert.assertTrue(end - begin > 5000); - } - @Test public void testPriority() throws InterruptedException { TestServerAbilityControlManager testServerAbilityControlManager = new TestServerAbilityControlManager(); @@ -352,29 +320,7 @@ public void disable() { } } - - class TestPreHandler implements AbilityHandlePreProcessor { - - @Override - public AbilityTable handle(AbilityTable source) { - source.setConnectionId("pre-handle"); - return source; - } - } - class TestStatusPreHandler implements AbilityHandlePreProcessor { - - @Override - public AbilityTable handle(AbilityTable source) { - try { - // block - Thread.sleep(5000); - } catch (Exception e) { - e.printStackTrace(); - } - return source; - } - } } From 92add6e833d38bac1b0453b081b8f90230911866 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Wed, 31 Aug 2022 16:59:43 +0800 Subject: [PATCH 011/181] Separate client capability and server capability: ClientAbilities and ServerAbilities. --- .../api/ability/constant/AbilityKey.java | 92 ++---------------- .../api/ability/entity/AbilityTable.java | 11 ++- .../ability/register/AbilityBitOperate.java | 61 ++++++++++++ .../register/impl/ClientAbilities.java | 72 ++++++++++++++ .../register/impl/ServerAbilities.java | 73 ++++++++++++++ .../request/ConnectionSetupRequest.java | 13 +++ .../nacos/api/utils/AbilityTableUtils.java | 13 +-- .../api/utils/AbilityTableUtilsTest.java | 56 ----------- .../ability/ClientAbilityControlManager.java | 11 ++- .../client/config/impl/ClientWorker.java | 7 +- .../AbstractAbilityControlManager.java | 18 +++- .../ability/DefaultAbilityControlManager.java | 51 +++++----- .../ability/inter/AbilityControlManager.java | 9 +- .../ability/inter/AbilityHandlerRegistry.java | 22 +++-- .../nacos/common/remote/client/RpcClient.java | 12 --- .../remote/client/RpcClientFactory.java | 3 +- .../common/remote/client/grpc/GrpcClient.java | 24 ++++- .../remote/client/grpc/GrpcClusterClient.java | 11 +++ .../remote/client/grpc/GrpcSdkClient.java | 11 +++ .../remote/client/grpc/GrpcClientTest.java | 10 ++ .../control/ServerAbilityControlManager.java | 42 ++++---- .../inte/ClusterAbilityControlSupport.java | 18 ++-- .../alibaba/nacos/core/remote/Connection.java | 7 +- .../grpc/GrpcBiStreamRequestAcceptor.java | 14 ++- .../core/remote/grpc/GrpcRequestAcceptor.java | 4 +- .../ability/AbilityControlManagerTest.java | 97 ++++++++++--------- .../TestClientAbilityControlManager.java | 3 +- .../TestServerAbilityControlManager.java | 15 +-- 28 files changed, 471 insertions(+), 309 deletions(-) create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/register/AbilityBitOperate.java create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java delete mode 100644 api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java index cf194cccaff..71e1e1435f9 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java @@ -16,96 +16,16 @@ package com.alibaba.nacos.api.ability.constant; -import com.alibaba.nacos.api.utils.AbilityTableUtils; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - /**. * @author Daydreamer - * @description Ability table key. It can be a replacement of {@link com.alibaba.nacos.api.ability.ServerAbilities} - * and {@link com.alibaba.nacos.api.ability.ClientAbilities}. - * @date 2022/7/12 19:23 + * @description Ability key constant. + * @date 2022/8/31 12:27 **/ -@SuppressWarnings("unchecked") -public class AbilityKey { - - private static final HashMap CURRENT_SERVER_SUPPORT_ABILITY = new HashMap<>(); - - private static final HashMap CURRENT_SERVER_ABILITY_OFFSET = new HashMap<>(); - - private static final byte[] ABILITY_BIT_FLAGS; - - private AbilityKey() { - } - - static { - /* - * example: - * There is a function named "compression". - * The key is "compression", the value is the offset of the flag bit of this ability in the ability table. The value should be unique. - * - * You can add a new public static field like: - * public static final String COMPRESSION = "compression"; - * This field can be used outside. - * - * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: - * CURRENT_SERVER_ABILITY_OFFSET.put("compression", 1); means that is the first bit from left to right in the table. - * - */ - - // put ability here, which you want current server supports - - } +public enum AbilityKey { - /**. - * Return ability table of current node - * But this ability is static which means that this ability table is all function this node supports if no one to ask it to close some functions. - * If you want to get what function current node is supporting, you should call AbilityControlManager#getCurrentAbility - * By the way, AbilityControlManager is singleton, you can get it by static method - * - * @return ability table + /** + * just for junit test */ - public static Map getCurrentNodeSupportAbility() { - return Collections.unmodifiableMap(CURRENT_SERVER_SUPPORT_ABILITY); - } + TEST_1, TEST_2, - /**. - * Return the static ability bit table - * - * @return ability bit table - */ - public static byte[] getAbilityBitFlags() { - return ABILITY_BIT_FLAGS.clone(); - } - - /**. - * Is it a legal key - * - * @param key input - * @return whether a legal key - */ - public static boolean isLegal(String key) { - return CURRENT_SERVER_SUPPORT_ABILITY.containsKey(key); - } - - static { - // init the bits table - ABILITY_BIT_FLAGS = AbilityTableUtils.getAbilityBitBy(CURRENT_SERVER_ABILITY_OFFSET.values()); - // init the ability table, default all true - CURRENT_SERVER_ABILITY_OFFSET.forEach((k, v) -> { - CURRENT_SERVER_SUPPORT_ABILITY.put(k, Boolean.TRUE); - }); - } - - /**. - * Return the ability bit offsets - * - * @return bit offset - */ - public static Map offset() { - return CURRENT_SERVER_ABILITY_OFFSET; - } - } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java index 921a092a773..67eb663ddef 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.api.ability.entity; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import java.util.Map; @@ -34,10 +35,10 @@ public class AbilityTable implements Cloneable { /**. * ability table - * key: name from {@link AbilityKey} + * key: name from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} * value: whether to turn on */ - private Map ability; + private Map ability; /**. * whether it from a server node @@ -70,7 +71,7 @@ public AbilityTable setVersion(String version) { return this; } - public AbilityTable(String connectionId, Map ability, boolean isServer, String version) { + public AbilityTable(String connectionId, Map ability, boolean isServer, String version) { this.connectionId = connectionId; this.ability = ability; this.isServer = isServer; @@ -86,11 +87,11 @@ public AbilityTable setConnectionId(String connectionId) { return this; } - public Map getAbility() { + public Map getAbility() { return ability; } - public AbilityTable setAbility(Map ability) { + public AbilityTable setAbility(Map ability) { this.ability = ability; return this; } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbilityBitOperate.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbilityBitOperate.java new file mode 100644 index 00000000000..e16165e7491 --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbilityBitOperate.java @@ -0,0 +1,61 @@ +/* + * Copyright 1999-2022 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.ability.register; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.utils.AbilityTableUtils; + +import java.util.HashMap; +import java.util.Map; + +/**. + * @author Daydreamer + * @description Operation for bit table. + * @date 2022/7/12 19:23 + **/ +public abstract class AbilityBitOperate { + + protected final HashMap abilityOffset = new HashMap<>(); + + private byte[] abilityBitFlag; + + /**. + * Return the static ability bit table + * + * @return ability bit table + */ + public byte[] getAbilityBitFlags() { + return abilityBitFlag.clone(); + } + + /**. + * Return the ability bit offsets + * + * @return bit offset + */ + public Map offset() { + return abilityOffset; + } + + /** + * put the bit offset to {@link AbilityBitOperate#abilityBitFlag} + */ + protected void init() { + // init the bits table + abilityBitFlag = AbilityTableUtils.getAbilityBitBy(abilityOffset.values()); + } +} diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java new file mode 100644 index 00000000000..ba1a7496d6f --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2022 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.ability.register.impl; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; + +import java.util.Map; + +/**. + * @author Daydreamer + * @description It is used to register client abilities. + * @date 2022/8/31 12:32 + **/ +public class ClientAbilities extends AbilityBitOperate { + + private static final ClientAbilities INSTANCE = new ClientAbilities(); + + { + /* + * example: + * There is a function named "compression". + * The key is "compression", the value is the offset of the flag bit of this ability in the ability table. The value should be unique. + * + * You can add a new public static field in

AbilityKeyConstant

like: + * public static final String COMPRESSION = "compression"; + * This field can be used outside. + * + * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: + * abilityOffset.put("compression", 1); means that is the first bit from left to right in the table. + * + */ + // put ability here, which you want current server supports + } + + private ClientAbilities() { + // put key to bit offset + init(); + } + + /** + * get the ability offset for server + * + * @return ability offset + */ + public static byte[] getBitFlags() { + return INSTANCE.getAbilityBitFlags(); + } + + /** + * get the ability offset for server + * + * @return ability offset + */ + public static Map getOffset() { + return INSTANCE.offset(); + } +} diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java new file mode 100644 index 00000000000..842591587fb --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java @@ -0,0 +1,73 @@ +/* + * Copyright 1999-2022 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.ability.register.impl; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; + +import java.util.Map; + +/**. + * @author Daydreamer + * @description It is used to register server abilities. + * @date 2022/8/31 12:32 + **/ +public class ServerAbilities extends AbilityBitOperate { + + private static final ServerAbilities INSTANCE = new ServerAbilities(); + + { + /* + * example: + * There is a function named "compression". + * The key is "compression", the value is the offset of the flag bit of this ability in the ability table. The value should be unique. + * + * You can add a new public static field like: + * public static final String COMPRESSION = "compression"; + * This field can be used outside. + * + * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: + * CURRENT_SERVER_ABILITY_OFFSET.put("compression", 1); means that is the first bit from left to right in the table. + * + */ + // put ability here, which you want current server supports + } + + private ServerAbilities() { + // put key to bit offset + init(); + } + + /** + * get bit table + * + * @return ability offset + */ + public static byte[] getBitFlags() { + return INSTANCE.getAbilityBitFlags(); + } + + /** + * get the ability offset for server + * + * @return ability offset + */ + public static Map getOffset() { + return INSTANCE.offset(); + } + +} diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java index 046a897a447..d2fbd704a37 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java @@ -35,6 +35,19 @@ public class ConnectionSetupRequest extends InternalRequest { private byte[] abilityTable; + /** + * server will resolve {@link ConnectionSetupRequest#abilityTable} to server abilities, or to client abilities + */ + private boolean isServer; + + public boolean isServer() { + return isServer; + } + + public void setServer(boolean server) { + isServer = server; + } + public ConnectionSetupRequest() { } diff --git a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java index 11ad28cc054..aa74be70d43 100644 --- a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java +++ b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.api.utils; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import java.util.Collection; import java.util.Collections; @@ -67,18 +68,18 @@ public static byte[] getAbilityBitBy(Collection bitCollection) { * get ability table by bits * * @param bits bit flag - * @param offsetMap offset from {@link AbilityKey} + * @param offsetMap offset from {@link AbilityBitOperate} * @return Return the Map containing AbilityTableKey and isRunning. */ - public static Map getAbilityTableBy(byte[] bits, Map offsetMap) { + public static Map getAbilityTableBy(byte[] bits, Map offsetMap) { if (bits == null || offsetMap.size() == 0) { return Collections.emptyMap(); } int length = bits.length; - Set> entries = offsetMap.entrySet(); - Map res = new HashMap<>(offsetMap.size()); - for (Map.Entry entry : entries) { - String abilityKey = entry.getKey(); + Set> entries = offsetMap.entrySet(); + Map res = new HashMap<>(offsetMap.size()); + for (Map.Entry entry : entries) { + AbilityKey abilityKey = entry.getKey(); Integer offset = entry.getValue(); // if not exists int index = offset / 8 + (offset % 8 == 0 ? -1 : 0); diff --git a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java deleted file mode 100644 index c2fea2c406c..00000000000 --- a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 1999-2022 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; - -import org.junit.Assert; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -public class AbilityTableUtilsTest { - - @Test - public void testGetByteArray() { - Map offset = new HashMap<>(); - offset.put("a", 1); - offset.put("b", 2); - offset.put("c", 10); - offset.put("d", 127); - byte[] abilityBitBy = AbilityTableUtils.getAbilityBitBy(offset.values()); - Assert.assertEquals(16, abilityBitBy.length); - Assert.assertEquals((byte) (3 << 6), abilityBitBy[0]); - Assert.assertEquals((byte) (1 << 6), abilityBitBy[1]); - } - - @Test - public void testGetAbilityTable() { - Map offset = new HashMap<>(); - offset.put("a", 1); - offset.put("b", 2); - offset.put("c", 10); - offset.put("d", 127); - byte[] abilityBitBy = AbilityTableUtils.getAbilityBitBy(offset.values()); - Map abilityTableBy = AbilityTableUtils.getAbilityTableBy(abilityBitBy, offset); - Assert.assertEquals(4, abilityTableBy.size()); - Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("a")); - Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("b")); - Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("c")); - Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("d")); - Assert.assertEquals(Boolean.FALSE, abilityTableBy.getOrDefault("asdasd", false)); - } -} diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index 9d39574f8b3..9e859b3b2f4 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -16,11 +16,15 @@ package com.alibaba.nacos.client.ability; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; +import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; import java.util.Collections; +import java.util.Map; import java.util.Optional; /**. @@ -34,7 +38,12 @@ public ClientAbilityControlManager() { } @Override - public boolean isSupport(String connectionId, String abilityKey) { + protected Map getCurrentNodeSupportAbility() { + return AbilityTableUtils.getAbilityTableBy(ClientAbilities.getBitFlags(), ClientAbilities.getOffset()); + } + + @Override + public boolean isSupport(String connectionId, AbilityKey abilityKey) { Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); if (!isRunning) { return false; diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index fc450b990a5..d56b23a7cdf 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.client.config.impl; import com.alibaba.nacos.api.PropertyKeyConst; -import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.config.ConfigType; import com.alibaba.nacos.api.config.listener.Listener; @@ -885,7 +885,6 @@ private RpcClient ensureRpcClient(String taskId) throws NacosException { if (rpcClient.isWaitInitiated()) { initRpcClientHandler(rpcClient); rpcClient.setTenant(getTenant()); - rpcClient.clientAbilities(initAbilities()); rpcClient.start(); } @@ -893,10 +892,6 @@ private RpcClient ensureRpcClient(String taskId) throws NacosException { } } - - private byte[] initAbilities() { - return AbilityKey.getAbilityBitFlags(); - } /** * build config string. diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index e1723a9e228..c72e6a9e2bd 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.common.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.inter.AbilityControlManager; import com.alibaba.nacos.common.notify.Event; @@ -43,10 +44,10 @@ public abstract class AbstractAbilityControlManager implements AbilityControlMan /** * Abilities current supporting *

- * key: ability key from {@link AbilityKey} + * key: ability key from {@link AbilityBitOperate} * value: whether to turn on */ - protected final Map currentRunningAbility = new ConcurrentHashMap<>(); + protected final Map currentRunningAbility = new ConcurrentHashMap<>(); /** * Ability table collections @@ -64,10 +65,17 @@ protected AbstractAbilityControlManager() { // register events registerAbilityEvent(); // put abilities - currentRunningAbility.putAll(AbilityKey.getCurrentNodeSupportAbility()); + currentRunningAbility.putAll(getCurrentNodeSupportAbility()); // initialize init(); } + + /** + * This is a hook for subclass to init current node ability + * + * @return current node ability + */ + protected abstract Map getCurrentNodeSupportAbility(); private void registerAbilityEvent(){ @@ -83,7 +91,7 @@ private void registerAbilityEvent(){ * @return is running */ @Override - public boolean isCurrentNodeAbilityRunning(String abilityKey) { + public boolean isCurrentNodeAbilityRunning(AbilityKey abilityKey) { return currentRunningAbility.getOrDefault(abilityKey, false); } @@ -204,7 +212,7 @@ public void destroy() { * @return ability table */ @Override - public Map getCurrentRunningAbility() { + public Map getCurrentRunningAbility() { return new HashMap<>(this.currentRunningAbility); } diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java index b3012392ed9..9d7dbfe36e5 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.common.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.handler.HandlerMapping; @@ -52,10 +53,10 @@ public abstract class DefaultAbilityControlManager extends AbstractAbilityContro private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAbilityControlManager.class); /** - * . These handlers will be invoked when the flag of ability change key: ability key from {@link AbilityKey} value: - * componments who want to be invoked if its interested ability turn on/off + * These handlers will be invoked when the flag of ability change key: ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} value: + * components who want to be invoked if its interested ability turn on/off */ - private final Map> handlerMappings = new ConcurrentHashMap<>(); + private final Map> handlerMappings = new ConcurrentHashMap<>(); /**. * run for HandlerMapping @@ -76,7 +77,7 @@ protected DefaultAbilityControlManager() { * @return if turn success */ @Override - public boolean enableCurrentNodeAbility(String abilityKey) { + public boolean enableCurrentNodeAbility(AbilityKey abilityKey) { return doTurn(true, abilityKey); } @@ -87,7 +88,7 @@ public boolean enableCurrentNodeAbility(String abilityKey) { * @return if turn success */ @Override - public boolean disableCurrentNodeAbility(String abilityKey) { + public boolean disableCurrentNodeAbility(AbilityKey abilityKey) { return doTurn(false, abilityKey); } @@ -98,7 +99,7 @@ public boolean disableCurrentNodeAbility(String abilityKey) { * @param abilityKey ability key from {@link AbilityKey} * @return if turn success */ - private boolean doTurn(boolean isOn, String abilityKey) { + private boolean doTurn(boolean isOn, AbilityKey abilityKey) { Boolean isEnabled = currentRunningAbility.get(abilityKey); // if not supporting this key if (isEnabled == null) { @@ -130,12 +131,12 @@ private boolean doTurn(boolean isOn, String abilityKey) { * @param handlerMapping component instance. */ @Override - public void registerComponent(String abilityKey, HandlerMapping handlerMapping, int priority) { + public void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority) { doRegisterComponent(abilityKey, handlerMapping, this.handlerMappings, lockForHandlerMappings, priority, currentRunningAbility); } @Override - public int removeComponent(String abilityKey, Class handlerMappingClazz) { + public int removeComponent(AbilityKey abilityKey, Class handlerMappingClazz) { return doRemove(abilityKey, handlerMappingClazz, lockForHandlerMappings, handlerMappings); } @@ -161,14 +162,14 @@ protected void doDestroy() { /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey ability key from {@link AbilityBitOperate} * @param handlerMappingClazz implement of {@link HandlerMapping} * @param lock lock for operation * @param handlerMappingsMap handler collection map * @return the count of components have removed */ - protected int doRemove(String abilityKey, Class handlerMappingClazz, Lock lock, - Map> handlerMappingsMap) { + protected int doRemove(AbilityKey abilityKey, Class handlerMappingClazz, Lock lock, + Map> handlerMappingsMap) { List handlerMappings = handlerMappingsMap.get(abilityKey); if (CollectionUtils.isEmpty(handlerMappings)) { return 0; @@ -190,7 +191,7 @@ protected int doRemove(String abilityKey, Class handle } @Override - public int removeAll(String abilityKey) { + public int removeAll(AbilityKey abilityKey) { List remove = this.handlerMappings.remove(abilityKey); return Optional.ofNullable(remove).orElse(Collections.emptyList()).size(); } @@ -204,9 +205,9 @@ public int removeAll(String abilityKey) { * @param lockForHandlerMappings lock to ensure concurrency * @param abilityTable behavioral basis of handler */ - protected void doRegisterComponent(String abilityKey, HandlerMapping handlerMapping, - Map> handlerMappings, Lock lockForHandlerMappings, - int priority, Map abilityTable) { + protected void doRegisterComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, + Map> handlerMappings, Lock lockForHandlerMappings, + int priority, Map abilityTable) { if (!currentRunningAbility.containsKey(abilityKey)) { LOGGER.warn("[AbilityHandlePostProcessor] Failed to register processor: {}, because illegal key!", handlerMapping.getClass().getSimpleName()); @@ -239,24 +240,24 @@ protected void doRegisterComponent(String abilityKey, HandlerMapping handlerMapp /** * Invoke componments which linked to ability key asyn. * - * @param key ability key from {@link AbilityKey} + * @param key ability key from {@link AbilityBitOperate} * @param isEnabled turn on/off * @param handlerMappingsMap handler collection */ - protected void triggerHandlerMappingAsyn(String key, boolean isEnabled, - Map> handlerMappingsMap) { + protected void triggerHandlerMappingAsyn(AbilityKey key, boolean isEnabled, + Map> handlerMappingsMap) { simpleThreadPool.execute(() -> doTriggerSyn(key, isEnabled, handlerMappingsMap)); } /** * Invoke componments which linked to ability key syn. * - * @param key ability key from {@link AbilityKey} + * @param key ability key from {@link AbilityBitOperate} * @param isEnabled turn on/off * @param handlerMappingsMap handler collection */ - protected void doTriggerSyn(String key, boolean isEnabled, - Map> handlerMappingsMap) { + protected void doTriggerSyn(AbilityKey key, boolean isEnabled, + Map> handlerMappingsMap) { List handlerWithPriorities = handlerMappingsMap.get(key); // return if empty if (CollectionUtils.isEmpty(handlerWithPriorities)) { @@ -281,7 +282,7 @@ protected void doTriggerSyn(String key, boolean isEnabled, } @JustForTest - protected Map> handlerMapping() { + protected Map> handlerMapping() { return this.handlerMappings; } @@ -318,17 +319,17 @@ public class AbilityUpdateEvent extends AbilityEvent { private static final long serialVersionUID = -1232411212311111L; - private String abilityKey; + private AbilityKey abilityKey; private boolean isOn; private AbilityUpdateEvent(){} - public String getAbilityKey() { + public AbilityKey getAbilityKey() { return abilityKey; } - public void setAbilityKey(String abilityKey) { + public void setAbilityKey(AbilityKey abilityKey) { this.abilityKey = abilityKey; } diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java index 75aac889380..22bbfd85afd 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.common.ability.inter; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.api.ability.entity.AbilityTable; import java.util.Map; @@ -32,10 +33,10 @@ public interface AbilityControlManager { * Whether the ability is supported for Connection. If the ability of current node is closed, it will return false. * * @param connectionId the connection range of ability table. - * @param abilityKey key name which comes from {@link AbilityKey}. + * @param abilityKey key name which comes from {@link AbilityBitOperate}. * @return whether the ability is supported in certain connection. */ - boolean isSupport(String connectionId, String abilityKey); + boolean isSupport(String connectionId, AbilityKey abilityKey); /** * Whether the ability current node supporting is running. Return false if current node doesn't support. @@ -43,7 +44,7 @@ public interface AbilityControlManager { * @param abilityKey ability key * @return is running */ - boolean isCurrentNodeAbilityRunning(String abilityKey); + boolean isCurrentNodeAbilityRunning(AbilityKey abilityKey); /** * Register a new ability table. @@ -72,7 +73,7 @@ public interface AbilityControlManager { * * @return ability table */ - Map getCurrentRunningAbility(); + Map getCurrentRunningAbility(); /**. * Initialize the manager diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java index c2725478466..77d2e847c62 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.common.ability.inter; +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.handler.HandlerMapping; @@ -32,7 +34,7 @@ public interface AbilityHandlerRegistry { * @param abilityKey ability key * @return if turn success */ - boolean enableCurrentNodeAbility(String abilityKey); + boolean enableCurrentNodeAbility(AbilityKey abilityKey); /**. * Turn off the ability whose key is

abilityKey

@@ -40,42 +42,42 @@ public interface AbilityHandlerRegistry { * @param abilityKey ability key * @return if turn success */ - boolean disableCurrentNodeAbility(String abilityKey); + boolean disableCurrentNodeAbility(AbilityKey abilityKey); /**. * Register the component which is managed by {@link AbstractAbilityControlManager}. * if you are hoping that a component will be invoked when turn on/off the ability whose key is

abilityKey

. * - * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey component key from {@link AbilityBitOperate} * @param priority a positive number, the higher the priority is, the faster it will be called. `1` is the lowest priority. * @param handlerMapping component instance. */ - void registerComponent(String abilityKey, HandlerMapping handlerMapping, int priority); + void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority); /**. * Default method to register component with the lowest priority. * - * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey component key from {@link AbilityBitOperate} * @param handlerMapping component instance. */ - default void registerComponent(String abilityKey, HandlerMapping handlerMapping) { + default void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping) { registerComponent(abilityKey, handlerMapping, 1); } /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey ability key from {@link AbilityBitOperate} * @param handlerMappingClazz implement of {@link HandlerMapping} * @return the count of components have removed */ - int removeComponent(String abilityKey, Class handlerMappingClazz); + int removeComponent(AbilityKey abilityKey, Class handlerMappingClazz); /** * Remove all {@link HandlerMapping} interested in the special ability. - * @param abilityKey abnility key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey abnility key from {@link AbilityBitOperate} * @return the count of components have removed */ - int removeAll(String abilityKey); + int removeAll(AbilityKey abilityKey); } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java index 9db2e1e8487..59d8134ecb6 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java @@ -90,8 +90,6 @@ public abstract class RpcClient implements Closeable { private static final long DEFAULT_TIMEOUT_MILLS = 3000L; - protected byte[] clientAbilities; - /** * default keep alive time 5s. */ @@ -133,16 +131,6 @@ public RpcClient(String name, ServerListFactory serverListFactory) { } } - /** - * init client abilities. - * - * @param clientAbilities clientAbilities. - */ - public RpcClient clientAbilities(byte[] clientAbilities) { - this.clientAbilities = clientAbilities; - return this; - } - /** * init server list factory. only can init once. * diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java index 8b40c9cfb8c..8293f019230 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java @@ -16,7 +16,7 @@ package com.alibaba.nacos.common.remote.client; -import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.grpc.GrpcClient; @@ -140,7 +140,6 @@ public static RpcClient createClusterClient(String clientName, ConnectionType co client.setThreadPoolCoreSize(threadPoolCoreSize); client.setThreadPoolMaxSize(threadPoolMaxSize); client.labels(labels); - client.clientAbilities(AbilityKey.getAbilityBitFlags()); return client; }); } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index a68c81e5847..d4c61452e98 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -17,7 +17,9 @@ package com.alibaba.nacos.common.remote.client.grpc; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -317,8 +319,8 @@ public Connection connectToServer(ServerInfo serverInfo) { // submit ability table as soon as possible // ability table will be null if server doesn't support ability table ServerCheckResponse serverCheckResponse = (ServerCheckResponse) response; - Map abilityTable = AbilityTableUtils - .getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset()); + Map abilityTable = AbilityTableUtils + .getAbilityTableBy(serverCheckResponse.getAbilities(), ServerAbilities.getOffset()); AbilityTable table = new AbilityTable(); table.setServer(true) .setConnectionId(serverCheckResponse.getConnectionId()) @@ -341,7 +343,8 @@ public Connection connectToServer(ServerInfo serverInfo) { ConnectionSetupRequest conSetupRequest = new ConnectionSetupRequest(); conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion()); conSetupRequest.setLabels(super.getLabels()); - conSetupRequest.setAbilityTable(super.clientAbilities == null ? AbilityKey.getAbilityBitFlags() : clientAbilities); + conSetupRequest.setAbilityTable(getAbilityBit()); + conSetupRequest.setServer(isServer()); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); //wait to register connection setup @@ -355,6 +358,21 @@ public Connection connectToServer(ServerInfo serverInfo) { return null; } + /** + * get ability, server or client + * + * @return bit table + */ + protected abstract byte[] getAbilityBit(); + + /** + * Return whether server environment + * The same offset may refer to different functions in the client capability table and the server capability table. + * + * @return whether server environment + */ + protected abstract boolean isServer(); + } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java index 7b63653b659..67cd0cd7ce0 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.common.remote.client.grpc; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.common.Constants; /** @@ -35,6 +36,16 @@ public GrpcClusterClient(String name) { super(name); } + @Override + public byte[] getAbilityBit() { + return ServerAbilities.getBitFlags(); + } + + @Override + protected boolean isServer() { + return true; + } + @Override public int rpcPortOffset() { return Integer.parseInt(System.getProperty(NACOS_SERVER_GRPC_PORT_OFFSET_KEY, diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java index 34cf408243a..8cbc9fcc3ec 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.common.remote.client.grpc; +import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; import com.alibaba.nacos.api.common.Constants; /** @@ -35,6 +36,16 @@ public GrpcSdkClient(String name) { super(name); } + @Override + public byte[] getAbilityBit() { + return ClientAbilities.getBitFlags(); + } + + @Override + protected boolean isServer() { + return false; + } + @Override public int rpcPortOffset() { return Integer.parseInt(System.getProperty(NACOS_SERVER_GRPC_PORT_OFFSET_KEY, diff --git a/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java b/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java index 5a81ab3ed4d..dd6f8f965f2 100644 --- a/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java +++ b/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java @@ -47,6 +47,16 @@ public class GrpcClientTest { @Before public void setUp() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { grpcClient = spy(new GrpcClient("testClient") { + @Override + public byte[] getAbilityBit() { + return new byte[1]; + } + + @Override + protected boolean isServer() { + return false; + } + @Override public int rpcPortOffset() { return 1000; diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 44a01258ffa..6a6d5effabc 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -16,7 +16,10 @@ package com.alibaba.nacos.core.ability.control; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; +import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; @@ -48,7 +51,7 @@ public class ServerAbilityControlManager extends DefaultAbilityControlManager im /**. * ability for cluster */ - private final Map clusterAbilityTable = new ConcurrentHashMap<>(); + private final Map clusterAbilityTable = new ConcurrentHashMap<>(); /**. * ability for server @@ -58,7 +61,7 @@ public class ServerAbilityControlManager extends DefaultAbilityControlManager im /** * components for cluster. these will be invoked if cluster ability table changes. */ - private final Map> clusterHandlerMapping = new ConcurrentHashMap<>(); + private final Map> clusterHandlerMapping = new ConcurrentHashMap<>(); private Lock lockForClusterComponents = new ReentrantLock(); @@ -73,7 +76,12 @@ public ServerAbilityControlManager() { } @Override - public boolean isSupport(String connectionId, String abilityKey) { + protected Map getCurrentNodeSupportAbility() { + return AbilityTableUtils.getAbilityTableBy(ServerAbilities.getBitFlags(), ServerAbilities.getOffset()); + } + + @Override + public boolean isSupport(String connectionId, AbilityKey abilityKey) { Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); if (!isRunning) { return false; @@ -93,12 +101,12 @@ public boolean isSupport(String connectionId, String abilityKey) { * @return whether it is turn on */ @Override - public boolean isClusterEnableAbility(String abilityKey) { + public boolean isClusterEnableAbility(AbilityKey abilityKey) { return clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE); } @Override - public Map getClusterAbility() { + public Map getClusterAbility() { return Collections.unmodifiableMap(clusterAbilityTable); } @@ -110,17 +118,17 @@ public Map getClusterAbility() { * @param handlerMapping component */ @Override - public void registerComponentForCluster(String abilityKey, HandlerMapping handlerMapping, int priority) { + public void registerComponentForCluster(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority) { doRegisterComponent(abilityKey, handlerMapping, this.clusterHandlerMapping, lockForClusterComponents, priority, clusterAbilityTable); } @Override - public int removeClusterComponent(String abilityKey, Class handlerMappingClazz) { + public int removeClusterComponent(AbilityKey abilityKey, Class handlerMappingClazz) { return doRemove(abilityKey, handlerMappingClazz, lockForClusterComponents, clusterHandlerMapping); } @Override - public int removeAllForCluster(String abilityKey) { + public int removeAllForCluster(AbilityKey abilityKey) { List remove = this.clusterHandlerMapping.remove(abilityKey); return Optional.ofNullable(remove).orElse(Collections.emptyList()).size(); } @@ -134,8 +142,8 @@ protected void add(AbilityTable table) { if (isServer) { serversAbilityTable.put(table.getConnectionId(), table); // enter cluster - Map nodeAbility = table.getAbility(); - Set keySet = clusterAbilityTable.keySet(); + Map nodeAbility = table.getAbility(); + Set keySet = clusterAbilityTable.keySet(); keySet.forEach(abilityKey -> { Boolean isEnabled = clusterAbilityTable.get(abilityKey); Boolean val = nodeAbility.getOrDefault(abilityKey, Boolean.FALSE); @@ -153,7 +161,7 @@ protected void add(AbilityTable table) { } } - private ClusterAbilityUpdateEvent buildClusterEvent(String abilityKey, boolean isOn) { + private ClusterAbilityUpdateEvent buildClusterEvent(AbilityKey abilityKey, boolean isOn) { // notify ClusterAbilityUpdateEvent event = new ClusterAbilityUpdateEvent(); event.setAbilityKey(abilityKey); @@ -176,7 +184,7 @@ protected void remove(String connectionId) { serversAbilityTable.remove(connectionId); // remove from cluster if (MapUtil.isNotEmpty(serversAbilityTable)) { - Set keySet = clusterAbilityTable.keySet(); + Set keySet = clusterAbilityTable.keySet(); keySet.forEach(abilityKey -> { Boolean isEnabled = clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE); // nothing to do if enabled @@ -219,17 +227,17 @@ public class ClusterAbilityUpdateEvent extends AbilityEvent { private static final long serialVersionUID = -122222411212200111L; - private String abilityKey; + private AbilityKey abilityKey; private boolean isOn; private ClusterAbilityUpdateEvent(){} - public String getAbilityKey() { + public AbilityKey getAbilityKey() { return abilityKey; } - public void setAbilityKey(String abilityKey) { + public void setAbilityKey(AbilityKey abilityKey) { this.abilityKey = abilityKey; } @@ -244,12 +252,12 @@ public void setOn(boolean on) { } @JustForTest - protected void setClusterAbilityTable(Map map) { + protected void setClusterAbilityTable(Map map) { clusterAbilityTable.putAll(map); } @JustForTest - protected Map> clusterHandlerMapping() { + protected Map> clusterHandlerMapping() { return this.clusterHandlerMapping; } diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java index 1150b200516..5b79e6b6b4b 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.core.ability.inte; +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import com.alibaba.nacos.common.ability.inter.AbilityControlManager; @@ -33,7 +35,7 @@ public interface ClusterAbilityControlSupport { * * @return the cluster abilities. */ - Map getClusterAbility(); + Map getClusterAbility(); /**. * Register components for cluster. These will be trigger when its interested ability changes @@ -42,7 +44,7 @@ public interface ClusterAbilityControlSupport { * @param priority a positive number, the higher the priority, the faster it will be called * @param handlerMapping component */ - void registerComponentForCluster(String abilityKey, HandlerMapping handlerMapping, int priority); + void registerComponentForCluster(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority); /**. * Default method to register component @@ -50,25 +52,25 @@ public interface ClusterAbilityControlSupport { * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. * @param handlerMapping component instance. */ - default void registerComponentForCluster(String abilityKey, HandlerMapping handlerMapping) { + default void registerComponentForCluster(AbilityKey abilityKey, HandlerMapping handlerMapping) { registerComponentForCluster(abilityKey, handlerMapping, 1); } /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. * @param handlerMappingClazz implement of {@link HandlerMapping} * @return the count of components have removed */ - int removeClusterComponent(String abilityKey, Class handlerMappingClazz); + int removeClusterComponent(AbilityKey abilityKey, Class handlerMappingClazz); /** * Remove all {@link HandlerMapping} interested in the special ability. - * @param abilityKey abnility key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey abnility key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. * @return the count of components have removed */ - int removeAllForCluster(String abilityKey); + int removeAllForCluster(AbilityKey abilityKey); /**. * Whether current cluster supports ability @@ -76,5 +78,5 @@ default void registerComponentForCluster(String abilityKey, HandlerMapping handl * @param abilityKey ability key * @return whether it is turn on */ - boolean isClusterEnableAbility(String abilityKey); + boolean isClusterEnableAbility(AbilityKey abilityKey); } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java index 2553d24a7d3..2e159bce16b 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.core.remote; import com.alibaba.nacos.api.ability.ClientAbilities; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.remote.Requester; import java.util.Map; @@ -32,7 +33,7 @@ public abstract class Connection implements Requester { private boolean traced = false; - private Map abilityTable; + private Map abilityTable; private ClientAbilities abilities; @@ -54,11 +55,11 @@ public void setTraced(boolean traced) { this.traced = traced; } - public Map getAbilityTable() { + public Map getAbilityTable() { return abilityTable; } - public void setAbilityTable(Map abilityTable) { + public void setAbilityTable(Map abilityTable) { this.abilityTable = abilityTable; } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 6f2c32b7f92..39edc93c3cf 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -16,7 +16,8 @@ package com.alibaba.nacos.core.remote.grpc; -import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -122,7 +123,16 @@ public void onNext(Payload payload) { setUpRequest.getClientVersion(), appName, setUpRequest.getLabels()); metaInfo.setTenant(setUpRequest.getTenant()); Connection connection = new GrpcConnection(metaInfo, responseObserver, CONTEXT_KEY_CHANNEL.get()); - connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), AbilityKey.offset())); + if (setUpRequest.isServer()) { + // if from server + connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), + ServerAbilities.getOffset())); + } else { + // if from client + connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), + ClientAbilities.getOffset())); + } + System.out.println(connection.getAbilityTable()); boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); if (rejectSdkOnStarting || !connectionManager.register(connectionId, connection)) { diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index d16ce16ab5e..a2869d6cdf5 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -16,7 +16,7 @@ package com.alibaba.nacos.core.remote.grpc; -import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.Payload; import com.alibaba.nacos.api.grpc.auto.RequestGrpc; @@ -90,7 +90,7 @@ public void request(Payload grpcRequest, StreamObserver responseObserve // server check. if (ServerCheckRequest.class.getSimpleName().equals(type)) { Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(), - AbilityKey.getAbilityBitFlags())); + ServerAbilities.getBitFlags())); traceIfNecessary(serverCheckResponseP, false); responseObserver.onNext(serverCheckResponseP); responseObserver.onCompleted(); diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java index 99d7cced7da..16d753d4f38 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.test.ability; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import org.junit.Assert; @@ -43,74 +44,74 @@ public class AbilityControlManagerTest { @Before public void inject() { - Map newTable = new HashMap<>(); - newTable.put("stop-raft", true); + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_1, true); clientAbilityControlManager.setCurrentSupportingAbility(newTable); - Map table = new HashMap<>(); - table.put("stop-raft", true); + Map table = new HashMap<>(); + table.put(AbilityKey.TEST_1, true); serverAbilityControlManager.setCurrentSupportingAbility(table); - Map cluster = new HashMap<>(); - cluster.put("stop-raft", true); + Map cluster = new HashMap<>(); + cluster.put(AbilityKey.TEST_1, true); serverAbilityControlManager.setClusterAbility(cluster); serverAbilityControlManager.setCurrentSupportingAbility(newTable); } @Test public void testClientAdd() { - Map newTable = new HashMap<>(); - newTable.put("test-no-existed", true); - newTable.put("stop-raft", true); + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_2, true); + newTable.put(AbilityKey.TEST_1, true); AbilityTable table = new AbilityTable(); table.setConnectionId("test-00001"); table.setAbility(newTable); table.setServer(true); clientAbilityControlManager.addNewTable(table); - Assert.assertFalse(clientAbilityControlManager.isSupport("test-00001", "test-no-existed")); - Assert.assertTrue(clientAbilityControlManager.isSupport("test-00001", "stop-raft")); + Assert.assertFalse(clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); + Assert.assertTrue(clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); } @Test public void testServerAdd() { - Map newTable = new HashMap<>(); - newTable.put("test-no-existed", true); - newTable.put("stop-raft", true); + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_2, true); + newTable.put(AbilityKey.TEST_1, true); AbilityTable table = new AbilityTable(); table.setConnectionId("test-00001"); table.setAbility(newTable); table.setServer(true); serverAbilityControlManager.addNewTable(table); - Assert.assertFalse(serverAbilityControlManager.isSupport("test-00001", "test-no-existed")); - Assert.assertTrue(serverAbilityControlManager.isSupport("test-00001", "stop-raft")); - Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); + Assert.assertTrue(serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); + Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); - Map otherServer = new HashMap<>(); - otherServer.put("test-no-existed", true); - otherServer.put("stop-raft", false); + Map otherServer = new HashMap<>(); + otherServer.put(AbilityKey.TEST_2, true); + otherServer.put(AbilityKey.TEST_1, false); AbilityTable otherServerTable = new AbilityTable(); otherServerTable.setConnectionId("test-00000"); otherServerTable.setAbility(otherServer); otherServerTable.setServer(true); serverAbilityControlManager.addNewTable(otherServerTable); - Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); - Map clientTa = new HashMap<>(); - clientTa.put("test-no-existed", true); - clientTa.put("stop-raft", false); + Map clientTa = new HashMap<>(); + clientTa.put(AbilityKey.TEST_2, true); + clientTa.put(AbilityKey.TEST_1, false); AbilityTable clientTable = new AbilityTable(); clientTable.setConnectionId("test-00002"); clientTable.setAbility(clientTa); clientTable.setServer(false); serverAbilityControlManager.addNewTable(clientTable); - Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); } @Test public void testClientRemove() { - Map clientTa = new HashMap<>(); - clientTa.put("test-no-existed", true); - clientTa.put("stop-raft", false); + Map clientTa = new HashMap<>(); + clientTa.put(AbilityKey.TEST_2, true); + clientTa.put(AbilityKey.TEST_1, false); AbilityTable clientTable = new AbilityTable(); clientTable.setConnectionId("test-01111"); clientTable.setAbility(clientTa); @@ -125,56 +126,56 @@ public void testClientRemove() { public void testComponent() throws InterruptedException { enabled = 0; // invoke enable() or disable() when registering - serverAbilityControlManager.registerComponent("stop-raft", new TestHandlerMapping(), -1); + serverAbilityControlManager.registerComponent(AbilityKey.TEST_1, new TestHandlerMapping(), -1); Assert.assertEquals(1, serverAbilityControlManager.handlerMappingCount()); - serverAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); // nothing happens if it has enabled Assert.assertEquals(enabled, 1); - Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); // invoke disable() - serverAbilityControlManager.disableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.disableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); // disable will invoke handler Assert.assertEquals(enabled, 0); - Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - serverAbilityControlManager.disableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.disableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); // nothing to do because it has disable Assert.assertEquals(enabled, 0); - Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - serverAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); Assert.assertEquals(enabled, 1); - Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - serverAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); Assert.assertEquals(enabled, 1); - Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); } @Test public void testClusterComponent() throws InterruptedException { clusterEnabled = 0; // invoke enable() because it turn on - serverAbilityControlManager.registerComponentForCluster("stop-raft", new ClusterHandlerMapping(), -1); + serverAbilityControlManager.registerComponentForCluster(AbilityKey.TEST_1, new ClusterHandlerMapping(), -1); Assert.assertEquals(1, serverAbilityControlManager.clusterHandlerMappingCount()); - Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); Assert.assertEquals(clusterEnabled, 1); - Map serverAbility = new HashMap<>(); - serverAbility.put("test-no-existed", true); - serverAbility.put("stop-raft", false); + Map serverAbility = new HashMap<>(); + serverAbility.put(AbilityKey.TEST_2, true); + serverAbility.put(AbilityKey.TEST_1, false); AbilityTable serverTable = new AbilityTable(); serverTable.setConnectionId("test-01111"); serverTable.setAbility(serverAbility); @@ -184,20 +185,20 @@ public void testClusterComponent() throws InterruptedException { Thread.sleep(200L); // disabled - Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); Assert.assertEquals(clusterEnabled, 0); // remove this table to enabled serverAbilityControlManager.removeTable("test-01111"); // wait for invoking handler asyn Thread.sleep(200L); - Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); Assert.assertEquals(clusterEnabled, 1); } @Test public void testCurrentNodeAbility() { - Set keySet = serverAbilityControlManager.getCurrentRunningAbility().keySet(); + Set keySet = serverAbilityControlManager.getCurrentRunningAbility().keySet(); // diable all keySet.forEach(key -> serverAbilityControlManager.disableCurrentNodeAbility(key)); // get all @@ -215,7 +216,7 @@ public void testCurrentNodeAbility() { @Test public void testPriority() throws InterruptedException { TestServerAbilityControlManager testServerAbilityControlManager = new TestServerAbilityControlManager(); - String key = "key"; + AbilityKey key = AbilityKey.TEST_1; TestPriority clusterHandlerMapping1 = new TestPriority("1"); TestPriority clusterHandlerMapping2 = new TestPriority("2"); TestPriority clusterHandlerMapping3 = new TestPriority("3"); diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java index 5e9fc089923..e506e295254 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.test.ability; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.client.ability.ClientAbilityControlManager; import com.alibaba.nacos.common.JustForTest; @@ -24,7 +25,7 @@ public class TestClientAbilityControlManager extends ClientAbilityControlManager { @JustForTest - public void setCurrentSupportingAbility(Map ability) { + public void setCurrentSupportingAbility(Map ability) { currentRunningAbility.putAll(ability); } } diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java index 2c48bc82112..3571c6060f9 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.test.ability; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import com.alibaba.nacos.core.ability.control.ServerAbilityControlManager; @@ -27,12 +28,12 @@ public class TestServerAbilityControlManager extends ServerAbilityControlManager { @JustForTest - public void setCurrentSupportingAbility(Map ability) { + public void setCurrentSupportingAbility(Map ability) { currentRunningAbility.putAll(ability); } @JustForTest - public void setClusterAbility(Map ability) { + public void setClusterAbility(Map ability) { super.setClusterAbilityTable(ability); } @@ -42,7 +43,7 @@ public int handlerMappingCount() { } @JustForTest - public List getHandlerMapping(String abilityKey) { + public List getHandlerMapping(AbilityKey abilityKey) { return super.handlerMapping().get(abilityKey); } @@ -52,7 +53,7 @@ public int clusterHandlerMappingCount() { } @JustForTest - public List getClusterHandlerMapping(String abilityKey) { + public List getClusterHandlerMapping(AbilityKey abilityKey) { return super.clusterHandlerMapping().get(abilityKey); } @@ -60,19 +61,19 @@ public List getClusterHandlerMapping(String abilityKey) { * Just a test method. */ @JustForTest - public void registerClusterHandlerMapping(String key, HandlerMapping handlerMapping, int priority) { + public void registerClusterHandlerMapping(AbilityKey key, HandlerMapping handlerMapping, int priority) { List orDefault = super.clusterHandlerMapping().getOrDefault(key, new ArrayList<>()); orDefault.add(new HandlerWithPriority(handlerMapping, priority)); clusterHandlerMapping().put(key, orDefault); } @JustForTest - public void triggerCluster(String abilityKey) { + public void triggerCluster(AbilityKey abilityKey) { triggerHandlerMappingAsyn(abilityKey, true, clusterHandlerMapping()); } @JustForTest - public void trigger(String abilityKey) { + public void trigger(AbilityKey abilityKey) { triggerHandlerMappingAsyn(abilityKey, true, handlerMapping()); } } From 4560d88327aabe7d39859fa8a47c0d801184da00 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Wed, 31 Aug 2022 19:05:00 +0800 Subject: [PATCH 012/181] Tell unknown if it cannot find AbilityTable. --- .../api/ability/constant/AbilityStatus.java | 40 +++++++++++++++++++ .../ability/ClientAbilityControlManager.java | 17 ++++---- .../ability/inter/AbilityControlManager.java | 3 +- .../control/ServerAbilityControlManager.java | 16 ++++---- 4 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java new file mode 100644 index 00000000000..bf788bc8ad9 --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2022 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.ability.constant; + +/**. + * @author Daydreamer + * @description It is used to know a certain ability whether supporting. + * @date 2022/8/31 12:27 + **/ +public enum AbilityStatus { + + /** + * Support a certain ability + */ + SUPPORTED, + + /** + * Not support a certain ability + */ + NOT_SUPPORTED, + + /** + * Cannot find ability table, unknown + */ + UNKNOWN +} diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index 9e859b3b2f4..1ecdb41df94 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.client.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; import com.alibaba.nacos.api.utils.AbilityTableUtils; @@ -43,17 +44,19 @@ protected Map getCurrentNodeSupportAbility() { } @Override - public boolean isSupport(String connectionId, AbilityKey abilityKey) { + public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); if (!isRunning) { - return false; + return AbilityStatus.NOT_SUPPORTED; } AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - // false if null - return abilityTable != null - && Optional.ofNullable(abilityTable.getAbility()) - .orElse(Collections.emptyMap()) - .getOrDefault(abilityKey, false); + if(abilityTable == null) { + return AbilityStatus.UNKNOWN; + } + Boolean isSupport = Optional.ofNullable(abilityTable.getAbility()) + .orElse(Collections.emptyMap()) + .getOrDefault(abilityKey, false); + return isSupport ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; } @Override diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java index 22bbfd85afd..a40cfca63cd 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.common.ability.inter; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.api.ability.entity.AbilityTable; @@ -36,7 +37,7 @@ public interface AbilityControlManager { * @param abilityKey key name which comes from {@link AbilityBitOperate}. * @return whether the ability is supported in certain connection. */ - boolean isSupport(String connectionId, AbilityKey abilityKey); + AbilityStatus isSupport(String connectionId, AbilityKey abilityKey); /** * Whether the ability current node supporting is running. Return false if current node doesn't support. diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 6a6d5effabc..16da67df91f 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.core.ability.control; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.utils.AbilityTableUtils; @@ -81,17 +82,18 @@ protected Map getCurrentNodeSupportAbility() { } @Override - public boolean isSupport(String connectionId, AbilityKey abilityKey) { + public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); if (!isRunning) { - return false; + return AbilityStatus.NOT_SUPPORTED; } AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - // false if null - return abilityTable != null - && Optional.ofNullable(abilityTable.getAbility()) - .orElse(Collections.emptyMap()) - .getOrDefault(abilityKey, false); + if(abilityTable == null) { + return AbilityStatus.UNKNOWN; + } + Boolean isSupport = Optional.ofNullable(abilityTable.getAbility()).orElse(Collections.emptyMap()) + .getOrDefault(abilityKey, false); + return isSupport ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; } /**. From 22ace653fcdc29c7b28ed76855ab112fb90467fd Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Wed, 31 Aug 2022 21:22:24 +0800 Subject: [PATCH 013/181] The abilities of stock connection abilities remains unchanged and the abilities of incremental connection changes. --- .../nacos/api/ability/entity/AbilityTable.java | 7 ++++++- .../nacos/api/utils/AbilityTableUtils.java | 15 +++++++++++++++ .../ability/ClientAbilityControlManager.java | 4 ---- .../ability/AbstractAbilityControlManager.java | 9 +++++++++ .../remote/client/grpc/GrpcClusterClient.java | 5 ++++- .../common/remote/client/grpc/GrpcSdkClient.java | 5 ++++- .../control/ServerAbilityControlManager.java | 4 ---- 7 files changed, 38 insertions(+), 11 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java index 67eb663ddef..f35f30826d0 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java @@ -95,5 +95,10 @@ public AbilityTable setAbility(Map ability) { this.ability = ability; return this; } - + + @Override + public String toString() { + return "AbilityTable{" + "connectionId='" + connectionId + '\'' + ", ability=" + ability + ", isServer=" + + isServer + ", version='" + version + '\'' + '}'; + } } diff --git a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java index aa74be70d43..e6d4c9d013f 100644 --- a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java +++ b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /**. * @author Daydreamer @@ -98,4 +99,18 @@ public static Map getAbilityTableBy(byte[] bits, Map offsetMap, Map abilityTable) { + // filter the element which abilityTable don't have or value is false + Map res = offsetMap.entrySet().stream() + .filter(item -> abilityTable.getOrDefault(item.getKey(), false)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + return getAbilityBitBy(res.values()); + } } diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index 1ecdb41df94..da37ab6382f 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -45,10 +45,6 @@ protected Map getCurrentNodeSupportAbility() { @Override public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { - Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); - if (!isRunning) { - return AbilityStatus.NOT_SUPPORTED; - } AbilityTable abilityTable = nodeAbilityTable.get(connectionId); if(abilityTable == null) { return AbilityStatus.UNKNOWN; diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index c72e6a9e2bd..28efd20dcf5 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; @@ -117,6 +118,14 @@ public final void addNewTable(AbilityTable table) { // hook method add(table); // add to node + Set abilityKeys = table.getAbility().keySet(); + Map clientAbilities = table.getAbility(); + abilityKeys.forEach(abilityKey -> { + Boolean res = currentRunningAbility.getOrDefault(abilityKey, false); + Boolean coming = clientAbilities.getOrDefault(abilityKey, false); + clientAbilities.put(abilityKey, res && coming); + }); + System.out.println(table); nodeAbilityTable.put(connectionId, table); } finally { lockForAbilityTable.unlock(); diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java index 67cd0cd7ce0..fdae2aa2fb0 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java @@ -18,6 +18,8 @@ import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.common.Constants; +import com.alibaba.nacos.api.utils.AbilityTableUtils; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; /** * gRPC client for cluster. @@ -38,7 +40,8 @@ public GrpcClusterClient(String name) { @Override public byte[] getAbilityBit() { - return ServerAbilities.getBitFlags(); + // calculate the ability bit table based on ability of current client + return AbilityTableUtils.getAbilityBiTableBy(ServerAbilities.getOffset(), NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()); } @Override diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java index 8cbc9fcc3ec..9c85b2b3c58 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java @@ -18,6 +18,8 @@ import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; import com.alibaba.nacos.api.common.Constants; +import com.alibaba.nacos.api.utils.AbilityTableUtils; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; /** * gRPC client for sdk. @@ -38,7 +40,8 @@ public GrpcSdkClient(String name) { @Override public byte[] getAbilityBit() { - return ClientAbilities.getBitFlags(); + // calculate the ability bit table based on ability of current client + return AbilityTableUtils.getAbilityBiTableBy(ClientAbilities.getOffset(), NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()); } @Override diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 16da67df91f..1ee0577e3fc 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -83,10 +83,6 @@ protected Map getCurrentNodeSupportAbility() { @Override public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { - Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); - if (!isRunning) { - return AbilityStatus.NOT_SUPPORTED; - } AbilityTable abilityTable = nodeAbilityTable.get(connectionId); if(abilityTable == null) { return AbilityStatus.UNKNOWN; From dd6c565e65e8692cfd5cd063c7128d1f76d960f2 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Wed, 31 Aug 2022 21:26:13 +0800 Subject: [PATCH 014/181] Fix note --- .../nacos/api/ability/register/impl/ClientAbilities.java | 8 ++++---- .../nacos/api/ability/register/impl/ServerAbilities.java | 6 +++--- .../core/remote/grpc/GrpcBiStreamRequestAcceptor.java | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java index ba1a7496d6f..df065f653ad 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java @@ -36,15 +36,15 @@ public class ClientAbilities extends AbilityBitOperate { * There is a function named "compression". * The key is "compression", the value is the offset of the flag bit of this ability in the ability table. The value should be unique. * - * You can add a new public static field in

AbilityKeyConstant

like: - * public static final String COMPRESSION = "compression"; + * You can add a new public field in

AbilityKey

like: + * DATA_COMPRESSION * This field can be used outside. * * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: - * abilityOffset.put("compression", 1); means that is the first bit from left to right in the table. + * abilityOffset.put(AbilityKey.DATA_COMPRESSION, 1); means that is the first bit from left to right in the table. * */ - // put ability here, which you want current server supports + // put ability here, which you want current client supports } private ClientAbilities() { diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java index 842591587fb..facf2525cdb 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java @@ -36,12 +36,12 @@ public class ServerAbilities extends AbilityBitOperate { * There is a function named "compression". * The key is "compression", the value is the offset of the flag bit of this ability in the ability table. The value should be unique. * - * You can add a new public static field like: - * public static final String COMPRESSION = "compression"; + * You can add a new public field in

AbilityKey

like: + * DATA_COMPRESSION * This field can be used outside. * * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: - * CURRENT_SERVER_ABILITY_OFFSET.put("compression", 1); means that is the first bit from left to right in the table. + * abilityOffset.put(AbilityKey.DATA_COMPRESSION, 1); means that is the first bit from left to right in the table. * */ // put ability here, which you want current server supports diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 39edc93c3cf..b143834ba00 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -132,7 +132,6 @@ public void onNext(Payload payload) { connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), ClientAbilities.getOffset())); } - System.out.println(connection.getAbilityTable()); boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); if (rejectSdkOnStarting || !connectionManager.register(connectionId, connection)) { From 37cf6c47d8b2efdeb2f162d8ecf844e3ffc021d5 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Thu, 1 Sep 2022 12:33:34 +0800 Subject: [PATCH 015/181] Fix checkstyle. --- .../api/ability/constant/AbilityKey.java | 21 +++++++++++++++++-- .../api/ability/constant/AbilityStatus.java | 6 +++--- .../api/ability/entity/AbilityTable.java | 1 - ...te.java => AbstractAbilityBitOperate.java} | 9 ++++---- .../register/impl/ClientAbilities.java | 8 +++---- .../register/impl/ServerAbilities.java | 8 +++---- .../request/ConnectionSetupRequest.java | 2 +- .../nacos/api/utils/AbilityTableUtils.java | 6 +++--- .../ability/ClientAbilityControlManager.java | 2 +- .../client/config/impl/ClientWorker.java | 1 - .../client/naming/remote/TestConnection.java | 16 ++++++++++++++ .../AbstractAbilityControlManager.java | 5 ++--- .../ability/DefaultAbilityControlManager.java | 14 +++++++------ .../ability/inter/AbilityControlManager.java | 4 ++-- .../ability/inter/AbilityHandlerRegistry.java | 10 ++++----- .../listener/ClientAbilityEventListener.java | 17 ++++++++++++++- .../remote/client/RpcClientFactory.java | 1 - .../common/remote/client/grpc/GrpcClient.java | 3 +-- .../control/ServerAbilityControlManager.java | 2 +- .../inte/ClusterAbilityControlSupport.java | 1 - 20 files changed, 91 insertions(+), 46 deletions(-) rename api/src/main/java/com/alibaba/nacos/api/ability/register/{AbilityBitOperate.java => AbstractAbilityBitOperate.java} (87%) diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java index 71e1e1435f9..8a9b8f8c16e 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java @@ -23,9 +23,26 @@ **/ public enum AbilityKey { - /** + /**. * just for junit test */ - TEST_1, TEST_2, + TEST_1("test_1"), + /**. + * just for junit test + */ + TEST_2("test_2"); + + + + + + + + + private final String name; + + AbilityKey(String name) { + this.name = name; + } } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java index bf788bc8ad9..a762c037300 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java @@ -23,17 +23,17 @@ **/ public enum AbilityStatus { - /** + /**. * Support a certain ability */ SUPPORTED, - /** + /**. * Not support a certain ability */ NOT_SUPPORTED, - /** + /**. * Cannot find ability table, unknown */ UNKNOWN diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java index f35f30826d0..63fda78da96 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.api.ability.entity; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import java.util.Map; diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbilityBitOperate.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityBitOperate.java similarity index 87% rename from api/src/main/java/com/alibaba/nacos/api/ability/register/AbilityBitOperate.java rename to api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityBitOperate.java index e16165e7491..3218426724d 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbilityBitOperate.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityBitOperate.java @@ -19,6 +19,7 @@ import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.utils.AbilityTableUtils; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -27,7 +28,7 @@ * @description Operation for bit table. * @date 2022/7/12 19:23 **/ -public abstract class AbilityBitOperate { +public abstract class AbstractAbilityBitOperate { protected final HashMap abilityOffset = new HashMap<>(); @@ -48,11 +49,11 @@ public byte[] getAbilityBitFlags() { * @return bit offset */ public Map offset() { - return abilityOffset; + return Collections.unmodifiableMap(abilityOffset); } - /** - * put the bit offset to {@link AbilityBitOperate#abilityBitFlag} + /**. + * put the bit offset to {@link AbstractAbilityBitOperate#abilityBitFlag} */ protected void init() { // init the bits table diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java index df065f653ad..8df95956082 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.api.ability.register.impl; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; import java.util.Map; @@ -26,7 +26,7 @@ * @description It is used to register client abilities. * @date 2022/8/31 12:32 **/ -public class ClientAbilities extends AbilityBitOperate { +public class ClientAbilities extends AbstractAbilityBitOperate { private static final ClientAbilities INSTANCE = new ClientAbilities(); @@ -52,7 +52,7 @@ private ClientAbilities() { init(); } - /** + /**. * get the ability offset for server * * @return ability offset @@ -61,7 +61,7 @@ public static byte[] getBitFlags() { return INSTANCE.getAbilityBitFlags(); } - /** + /**. * get the ability offset for server * * @return ability offset diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java index facf2525cdb..2f959087d62 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.api.ability.register.impl; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; import java.util.Map; @@ -26,7 +26,7 @@ * @description It is used to register server abilities. * @date 2022/8/31 12:32 **/ -public class ServerAbilities extends AbilityBitOperate { +public class ServerAbilities extends AbstractAbilityBitOperate { private static final ServerAbilities INSTANCE = new ServerAbilities(); @@ -52,7 +52,7 @@ private ServerAbilities() { init(); } - /** + /**. * get bit table * * @return ability offset @@ -61,7 +61,7 @@ public static byte[] getBitFlags() { return INSTANCE.getAbilityBitFlags(); } - /** + /**. * get the ability offset for server * * @return ability offset diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java index d2fbd704a37..15b3c35d5ec 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java @@ -35,7 +35,7 @@ public class ConnectionSetupRequest extends InternalRequest { private byte[] abilityTable; - /** + /**. * server will resolve {@link ConnectionSetupRequest#abilityTable} to server abilities, or to client abilities */ private boolean isServer; diff --git a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java index e6d4c9d013f..a97d2a2c2e6 100644 --- a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java +++ b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.api.utils; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; import java.util.Collection; import java.util.Collections; @@ -69,7 +69,7 @@ public static byte[] getAbilityBitBy(Collection bitCollection) { * get ability table by bits * * @param bits bit flag - * @param offsetMap offset from {@link AbilityBitOperate} + * @param offsetMap offset from {@link AbstractAbilityBitOperate} * @return Return the Map containing AbilityTableKey and isRunning. */ public static Map getAbilityTableBy(byte[] bits, Map offsetMap) { @@ -103,7 +103,7 @@ public static Map getAbilityTableBy(byte[] bits, Map offsetMap, Map abilityTable) { diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index da37ab6382f..534b3b202a4 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -46,7 +46,7 @@ protected Map getCurrentNodeSupportAbility() { @Override public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - if(abilityTable == null) { + if (abilityTable == null) { return AbilityStatus.UNKNOWN; } Boolean isSupport = Optional.ofNullable(abilityTable.getAbility()) diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index d56b23a7cdf..a227d537e9c 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.client.config.impl; import com.alibaba.nacos.api.PropertyKeyConst; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.config.ConfigType; import com.alibaba.nacos.api.config.listener.Listener; diff --git a/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java b/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java index 6d02c962da0..43fc088fde2 100644 --- a/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java +++ b/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java @@ -1,3 +1,19 @@ +/* + * Copyright 1999-2022 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.naming.remote; import com.alibaba.nacos.api.exception.NacosException; diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 28efd20dcf5..51e77b837b5 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.common.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.inter.AbilityControlManager; import com.alibaba.nacos.common.notify.Event; @@ -45,7 +45,7 @@ public abstract class AbstractAbilityControlManager implements AbilityControlMan /** * Abilities current supporting *

- * key: ability key from {@link AbilityBitOperate} + * key: ability key from {@link AbstractAbilityBitOperate} * value: whether to turn on */ protected final Map currentRunningAbility = new ConcurrentHashMap<>(); @@ -125,7 +125,6 @@ public final void addNewTable(AbilityTable table) { Boolean coming = clientAbilities.getOrDefault(abilityKey, false); clientAbilities.put(abilityKey, res && coming); }); - System.out.println(table); nodeAbilityTable.put(connectionId, table); } finally { lockForAbilityTable.unlock(); diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java index 9d7dbfe36e5..46268198f17 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.common.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.handler.HandlerMapping; @@ -47,13 +47,15 @@ * @description It is a relatively complete capability control center implementation. * @date 2022/7/12 19:18 **/ +@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule") public abstract class DefaultAbilityControlManager extends AbstractAbilityControlManager implements AbilityHandlerRegistry { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAbilityControlManager.class); - /** - * These handlers will be invoked when the flag of ability change key: ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} value: + /**. + * These handlers will be invoked when the flag of ability change key: + * ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} value: * components who want to be invoked if its interested ability turn on/off */ private final Map> handlerMappings = new ConcurrentHashMap<>(); @@ -162,7 +164,7 @@ protected void doDestroy() { /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link AbilityBitOperate} + * @param abilityKey ability key from {@link AbstractAbilityBitOperate} * @param handlerMappingClazz implement of {@link HandlerMapping} * @param lock lock for operation * @param handlerMappingsMap handler collection map @@ -240,7 +242,7 @@ protected void doRegisterComponent(AbilityKey abilityKey, HandlerMapping handler /** * Invoke componments which linked to ability key asyn. * - * @param key ability key from {@link AbilityBitOperate} + * @param key ability key from {@link AbstractAbilityBitOperate} * @param isEnabled turn on/off * @param handlerMappingsMap handler collection */ @@ -252,7 +254,7 @@ protected void triggerHandlerMappingAsyn(AbilityKey key, boolean isEnabled, /** * Invoke componments which linked to ability key syn. * - * @param key ability key from {@link AbilityBitOperate} + * @param key ability key from {@link AbstractAbilityBitOperate} * @param isEnabled turn on/off * @param handlerMappingsMap handler collection */ diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java index a40cfca63cd..0972ff980f7 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java @@ -18,7 +18,7 @@ import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.constant.AbilityStatus; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; import com.alibaba.nacos.api.ability.entity.AbilityTable; import java.util.Map; @@ -34,7 +34,7 @@ public interface AbilityControlManager { * Whether the ability is supported for Connection. If the ability of current node is closed, it will return false. * * @param connectionId the connection range of ability table. - * @param abilityKey key name which comes from {@link AbilityBitOperate}. + * @param abilityKey key name which comes from {@link AbstractAbilityBitOperate}. * @return whether the ability is supported in certain connection. */ AbilityStatus isSupport(String connectionId, AbilityKey abilityKey); diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java index 77d2e847c62..52d1b432fb4 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.common.ability.inter; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.handler.HandlerMapping; @@ -48,7 +48,7 @@ public interface AbilityHandlerRegistry { * Register the component which is managed by {@link AbstractAbilityControlManager}. * if you are hoping that a component will be invoked when turn on/off the ability whose key is

abilityKey

. * - * @param abilityKey component key from {@link AbilityBitOperate} + * @param abilityKey component key from {@link AbstractAbilityBitOperate} * @param priority a positive number, the higher the priority is, the faster it will be called. `1` is the lowest priority. * @param handlerMapping component instance. */ @@ -57,7 +57,7 @@ public interface AbilityHandlerRegistry { /**. * Default method to register component with the lowest priority. * - * @param abilityKey component key from {@link AbilityBitOperate} + * @param abilityKey component key from {@link AbstractAbilityBitOperate} * @param handlerMapping component instance. */ default void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping) { @@ -67,7 +67,7 @@ default void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapp /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link AbilityBitOperate} + * @param abilityKey ability key from {@link AbstractAbilityBitOperate} * @param handlerMappingClazz implement of {@link HandlerMapping} * @return the count of components have removed */ @@ -75,7 +75,7 @@ default void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapp /** * Remove all {@link HandlerMapping} interested in the special ability. - * @param abilityKey abnility key from {@link AbilityBitOperate} + * @param abilityKey abnility key from {@link AbstractAbilityBitOperate} * @return the count of components have removed */ int removeAll(AbilityKey abilityKey); diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java b/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java index 0c20043655d..0093709c5b4 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java @@ -1,5 +1,20 @@ -package com.alibaba.nacos.common.ability.listener; +/* + * Copyright 1999-2022 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.ability.listener; import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.client.Connection; diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java index 8293f019230..2d71b9e46ed 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.common.remote.client; -import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.grpc.GrpcClient; diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index d4c61452e98..c6771ab760d 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.common.remote.client.grpc; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; @@ -358,7 +357,7 @@ public Connection connectToServer(ServerInfo serverInfo) { return null; } - /** + /**. * get ability, server or client * * @return bit table diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 1ee0577e3fc..e61d39553e7 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -84,7 +84,7 @@ protected Map getCurrentNodeSupportAbility() { @Override public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - if(abilityTable == null) { + if (abilityTable == null) { return AbilityStatus.UNKNOWN; } Boolean isSupport = Optional.ofNullable(abilityTable.getAbility()).orElse(Collections.emptyMap()) diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java index 5b79e6b6b4b..9b989a07840 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.core.ability.inte; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbilityBitOperate; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import com.alibaba.nacos.common.ability.inter.AbilityControlManager; From 6273cce1df1b3177903f09ab563f8621f04952d7 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Thu, 1 Sep 2022 17:42:01 +0800 Subject: [PATCH 016/181] Separate client capability and server capability: ClientAbilities and ServerAbilities. --- .../api/ability/constant/AbilityKey.java | 38 ++++++++++++++++--- ...rate.java => AbstractAbilityRegistry.java} | 26 ++++++------- .../register/impl/ClientAbilities.java | 22 +++++------ .../register/impl/ServerAbilities.java | 22 +++++------ .../nacos/api/utils/AbilityTableUtils.java | 22 +++++++++-- .../ability/ClientAbilityControlManager.java | 3 +- .../AbstractAbilityControlManager.java | 4 +- .../ability/DefaultAbilityControlManager.java | 8 ++-- .../ability/inter/AbilityControlManager.java | 4 +- .../ability/inter/AbilityHandlerRegistry.java | 10 ++--- .../common/remote/client/grpc/GrpcClient.java | 15 +++----- .../remote/client/grpc/GrpcClusterClient.java | 9 ----- .../remote/client/grpc/GrpcSdkClient.java | 9 ----- .../remote/client/grpc/GrpcClientTest.java | 4 -- .../control/ServerAbilityControlManager.java | 3 +- .../grpc/GrpcBiStreamRequestAcceptor.java | 14 ++----- .../ability/AbilityControlManagerTest.java | 9 +++-- 17 files changed, 115 insertions(+), 107 deletions(-) rename api/src/main/java/com/alibaba/nacos/api/ability/register/{AbstractAbilityBitOperate.java => AbstractAbilityRegistry.java} (70%) diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java index 8a9b8f8c16e..11a26e54ac9 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java @@ -16,6 +16,11 @@ package com.alibaba.nacos.api.ability.constant; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + /**. * @author Daydreamer * @description Ability key constant. @@ -26,23 +31,44 @@ public enum AbilityKey { /**. * just for junit test */ - TEST_1("test_1"), + TEST_1("test_1", 1), /**. * just for junit test */ - TEST_2("test_2"); - + TEST_2("test_2", 2); + /**. + * the name of a certain ability + */ + private final String name; + /**. + * the offset in ability table + */ + private final int offset; + AbilityKey(String name, int offset) { + this.name = name; + this.offset = offset; + } + public String getName() { + return name; + } + public int getOffset() { + return offset; + } + private static final Map OFFSET_MAP; - private final String name; + public static Map offset() { + return OFFSET_MAP; + } - AbilityKey(String name) { - this.name = name; + static { + OFFSET_MAP = Arrays.stream(AbilityKey.values()) + .collect(Collectors.toMap(Function.identity(), AbilityKey::getOffset)); } } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityBitOperate.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java similarity index 70% rename from api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityBitOperate.java rename to api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java index 3218426724d..4ad0df43d32 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityBitOperate.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java @@ -28,9 +28,9 @@ * @description Operation for bit table. * @date 2022/7/12 19:23 **/ -public abstract class AbstractAbilityBitOperate { +public abstract class AbstractAbilityRegistry { - protected final HashMap abilityOffset = new HashMap<>(); + protected final Map supportedAbilities = new HashMap<>(); private byte[] abilityBitFlag; @@ -42,21 +42,21 @@ public abstract class AbstractAbilityBitOperate { public byte[] getAbilityBitFlags() { return abilityBitFlag.clone(); } - - /**. - * Return the ability bit offsets - * - * @return bit offset - */ - public Map offset() { - return Collections.unmodifiableMap(abilityOffset); - } /**. - * put the bit offset to {@link AbstractAbilityBitOperate#abilityBitFlag} + * put the bit offset to {@link AbstractAbilityRegistry#abilityBitFlag} */ protected void init() { // init the bits table - abilityBitFlag = AbilityTableUtils.getAbilityBitBy(abilityOffset.values()); + abilityBitFlag = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), supportedAbilities); + } + + /** + * get static ability current server supports + * + * @return static ability + */ + public Map getSupportedAbilities() { + return Collections.unmodifiableMap(supportedAbilities); } } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java index 8df95956082..c4ec32be5a0 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.api.ability.register.impl; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import java.util.Map; @@ -26,7 +26,7 @@ * @description It is used to register client abilities. * @date 2022/8/31 12:32 **/ -public class ClientAbilities extends AbstractAbilityBitOperate { +public class ClientAbilities extends AbstractAbilityRegistry { private static final ClientAbilities INSTANCE = new ClientAbilities(); @@ -34,14 +34,14 @@ public class ClientAbilities extends AbstractAbilityBitOperate { /* * example: * There is a function named "compression". - * The key is "compression", the value is the offset of the flag bit of this ability in the ability table. The value should be unique. + * The key is from

AbilityKey

, the value is whether turn on. * * You can add a new public field in

AbilityKey

like: - * DATA_COMPRESSION - * This field can be used outside. + * DATA_COMPRESSION("compression", 1) + * This field can be used outside, and the offset should be unique. * * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: - * abilityOffset.put(AbilityKey.DATA_COMPRESSION, 1); means that is the first bit from left to right in the table. + * supportedAbilities.put(AbilityKey.DATA_COMPRESSION, true); means that is the first bit from left to right in the table. * */ // put ability here, which you want current client supports @@ -61,12 +61,12 @@ public static byte[] getBitFlags() { return INSTANCE.getAbilityBitFlags(); } - /**. - * get the ability offset for server + /** + * get static ability current server supports * - * @return ability offset + * @return static ability */ - public static Map getOffset() { - return INSTANCE.offset(); + public static Map getStaticAbilities(){ + return INSTANCE.getSupportedAbilities(); } } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java index 2f959087d62..bd01a53b8bd 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.api.ability.register.impl; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import java.util.Map; @@ -26,7 +26,7 @@ * @description It is used to register server abilities. * @date 2022/8/31 12:32 **/ -public class ServerAbilities extends AbstractAbilityBitOperate { +public class ServerAbilities extends AbstractAbilityRegistry { private static final ServerAbilities INSTANCE = new ServerAbilities(); @@ -34,14 +34,14 @@ public class ServerAbilities extends AbstractAbilityBitOperate { /* * example: * There is a function named "compression". - * The key is "compression", the value is the offset of the flag bit of this ability in the ability table. The value should be unique. + * The key is from

AbilityKey

, the value is whether turn on. * * You can add a new public field in

AbilityKey

like: - * DATA_COMPRESSION - * This field can be used outside. + * DATA_COMPRESSION("compression", 1) + * This field can be used outside, and the offset should be unique. * * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: - * abilityOffset.put(AbilityKey.DATA_COMPRESSION, 1); means that is the first bit from left to right in the table. + * supportedAbilities.put(AbilityKey.DATA_COMPRESSION, true); means that is the first bit from left to right in the table. * */ // put ability here, which you want current server supports @@ -61,13 +61,13 @@ public static byte[] getBitFlags() { return INSTANCE.getAbilityBitFlags(); } - /**. - * get the ability offset for server + /** + * get static ability current server supports * - * @return ability offset + * @return static ability */ - public static Map getOffset() { - return INSTANCE.offset(); + public static Map getStaticAbilities(){ + return INSTANCE.getSupportedAbilities(); } } diff --git a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java index a97d2a2c2e6..fe75aab2c36 100644 --- a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java +++ b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java @@ -17,11 +17,13 @@ package com.alibaba.nacos.api.utils; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -69,7 +71,7 @@ public static byte[] getAbilityBitBy(Collection bitCollection) { * get ability table by bits * * @param bits bit flag - * @param offsetMap offset from {@link AbstractAbilityBitOperate} + * @param offsetMap offset from {@link AbstractAbilityRegistry} * @return Return the Map containing AbilityTableKey and isRunning. */ public static Map getAbilityTableBy(byte[] bits, Map offsetMap) { @@ -103,7 +105,7 @@ public static Map getAbilityTableBy(byte[] bits, Map offsetMap, Map abilityTable) { @@ -113,4 +115,18 @@ public static byte[] getAbilityBiTableBy(Map offsetMap, Map .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); return getAbilityBitBy(res.values()); } + + /** + * get ability bit table by existed ability table and abilityKeys array + * + * @param abilityKeys abilityKeys array + * @param abilityTable existed ability table + * @return filter ability which value is false in abilityTable + */ + public static byte[] getAbilityBiTableBy(AbilityKey[] abilityKeys, Map abilityTable) { + // filter the element which abilityTable don't have or value is false + List keyList = Arrays.stream(abilityKeys).collect(Collectors.toList()); + keyList.removeIf(key -> !abilityTable.getOrDefault(key, false)); + return getAbilityBitBy(keyList.stream().map(AbilityKey::getOffset).collect(Collectors.toList())); + } } diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index 534b3b202a4..eef2427a54a 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -20,7 +20,6 @@ import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; -import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; @@ -40,7 +39,7 @@ public ClientAbilityControlManager() { @Override protected Map getCurrentNodeSupportAbility() { - return AbilityTableUtils.getAbilityTableBy(ClientAbilities.getBitFlags(), ClientAbilities.getOffset()); + return ClientAbilities.getStaticAbilities(); } @Override diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 51e77b837b5..96c5e1c45e4 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.common.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.inter.AbilityControlManager; import com.alibaba.nacos.common.notify.Event; @@ -45,7 +45,7 @@ public abstract class AbstractAbilityControlManager implements AbilityControlMan /** * Abilities current supporting *

- * key: ability key from {@link AbstractAbilityBitOperate} + * key: ability key from {@link AbstractAbilityRegistry} * value: whether to turn on */ protected final Map currentRunningAbility = new ConcurrentHashMap<>(); diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java index 46268198f17..01fc7a60bb6 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.common.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.handler.HandlerMapping; @@ -164,7 +164,7 @@ protected void doDestroy() { /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link AbstractAbilityBitOperate} + * @param abilityKey ability key from {@link AbstractAbilityRegistry} * @param handlerMappingClazz implement of {@link HandlerMapping} * @param lock lock for operation * @param handlerMappingsMap handler collection map @@ -242,7 +242,7 @@ protected void doRegisterComponent(AbilityKey abilityKey, HandlerMapping handler /** * Invoke componments which linked to ability key asyn. * - * @param key ability key from {@link AbstractAbilityBitOperate} + * @param key ability key from {@link AbstractAbilityRegistry} * @param isEnabled turn on/off * @param handlerMappingsMap handler collection */ @@ -254,7 +254,7 @@ protected void triggerHandlerMappingAsyn(AbilityKey key, boolean isEnabled, /** * Invoke componments which linked to ability key syn. * - * @param key ability key from {@link AbstractAbilityBitOperate} + * @param key ability key from {@link AbstractAbilityRegistry} * @param isEnabled turn on/off * @param handlerMappingsMap handler collection */ diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java index 0972ff980f7..304d673d4d1 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java @@ -18,7 +18,7 @@ import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.constant.AbilityStatus; -import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import com.alibaba.nacos.api.ability.entity.AbilityTable; import java.util.Map; @@ -34,7 +34,7 @@ public interface AbilityControlManager { * Whether the ability is supported for Connection. If the ability of current node is closed, it will return false. * * @param connectionId the connection range of ability table. - * @param abilityKey key name which comes from {@link AbstractAbilityBitOperate}. + * @param abilityKey key name which comes from {@link AbstractAbilityRegistry}. * @return whether the ability is supported in certain connection. */ AbilityStatus isSupport(String connectionId, AbilityKey abilityKey); diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java index 52d1b432fb4..5cbc2a8a506 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.common.ability.inter; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbstractAbilityBitOperate; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.handler.HandlerMapping; @@ -48,7 +48,7 @@ public interface AbilityHandlerRegistry { * Register the component which is managed by {@link AbstractAbilityControlManager}. * if you are hoping that a component will be invoked when turn on/off the ability whose key is

abilityKey

. * - * @param abilityKey component key from {@link AbstractAbilityBitOperate} + * @param abilityKey component key from {@link AbstractAbilityRegistry} * @param priority a positive number, the higher the priority is, the faster it will be called. `1` is the lowest priority. * @param handlerMapping component instance. */ @@ -57,7 +57,7 @@ public interface AbilityHandlerRegistry { /**. * Default method to register component with the lowest priority. * - * @param abilityKey component key from {@link AbstractAbilityBitOperate} + * @param abilityKey component key from {@link AbstractAbilityRegistry} * @param handlerMapping component instance. */ default void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping) { @@ -67,7 +67,7 @@ default void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapp /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link AbstractAbilityBitOperate} + * @param abilityKey ability key from {@link AbstractAbilityRegistry} * @param handlerMappingClazz implement of {@link HandlerMapping} * @return the count of components have removed */ @@ -75,7 +75,7 @@ default void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapp /** * Remove all {@link HandlerMapping} interested in the special ability. - * @param abilityKey abnility key from {@link AbstractAbilityBitOperate} + * @param abilityKey abnility key from {@link AbstractAbilityRegistry} * @return the count of components have removed */ int removeAll(AbilityKey abilityKey); diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index c6771ab760d..7519de40f17 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -48,6 +48,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Arrays; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -319,7 +320,7 @@ public Connection connectToServer(ServerInfo serverInfo) { // ability table will be null if server doesn't support ability table ServerCheckResponse serverCheckResponse = (ServerCheckResponse) response; Map abilityTable = AbilityTableUtils - .getAbilityTableBy(serverCheckResponse.getAbilities(), ServerAbilities.getOffset()); + .getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset()); AbilityTable table = new AbilityTable(); table.setServer(true) .setConnectionId(serverCheckResponse.getConnectionId()) @@ -342,7 +343,10 @@ public Connection connectToServer(ServerInfo serverInfo) { ConnectionSetupRequest conSetupRequest = new ConnectionSetupRequest(); conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion()); conSetupRequest.setLabels(super.getLabels()); - conSetupRequest.setAbilityTable(getAbilityBit()); + // set ability table + byte[] bitTable = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), + NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()); + conSetupRequest.setAbilityTable(bitTable); conSetupRequest.setServer(isServer()); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); @@ -357,13 +361,6 @@ public Connection connectToServer(ServerInfo serverInfo) { return null; } - /**. - * get ability, server or client - * - * @return bit table - */ - protected abstract byte[] getAbilityBit(); - /** * Return whether server environment * The same offset may refer to different functions in the client capability table and the server capability table. diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java index fdae2aa2fb0..74919ba078b 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java @@ -16,10 +16,7 @@ package com.alibaba.nacos.common.remote.client.grpc; -import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.common.Constants; -import com.alibaba.nacos.api.utils.AbilityTableUtils; -import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; /** * gRPC client for cluster. @@ -38,12 +35,6 @@ public GrpcClusterClient(String name) { super(name); } - @Override - public byte[] getAbilityBit() { - // calculate the ability bit table based on ability of current client - return AbilityTableUtils.getAbilityBiTableBy(ServerAbilities.getOffset(), NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()); - } - @Override protected boolean isServer() { return true; diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java index 9c85b2b3c58..46cd691f65e 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java @@ -16,10 +16,7 @@ package com.alibaba.nacos.common.remote.client.grpc; -import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; import com.alibaba.nacos.api.common.Constants; -import com.alibaba.nacos.api.utils.AbilityTableUtils; -import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; /** * gRPC client for sdk. @@ -38,12 +35,6 @@ public GrpcSdkClient(String name) { super(name); } - @Override - public byte[] getAbilityBit() { - // calculate the ability bit table based on ability of current client - return AbilityTableUtils.getAbilityBiTableBy(ClientAbilities.getOffset(), NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()); - } - @Override protected boolean isServer() { return false; diff --git a/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java b/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java index dd6f8f965f2..af7104d1333 100644 --- a/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java +++ b/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java @@ -47,10 +47,6 @@ public class GrpcClientTest { @Before public void setUp() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { grpcClient = spy(new GrpcClient("testClient") { - @Override - public byte[] getAbilityBit() { - return new byte[1]; - } @Override protected boolean isServer() { diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index e61d39553e7..825faa807c1 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -20,7 +20,6 @@ import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; -import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; @@ -78,7 +77,7 @@ public ServerAbilityControlManager() { @Override protected Map getCurrentNodeSupportAbility() { - return AbilityTableUtils.getAbilityTableBy(ServerAbilities.getBitFlags(), ServerAbilities.getOffset()); + return ServerAbilities.getStaticAbilities(); } @Override diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index b143834ba00..b8cf7508bb7 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -16,8 +16,7 @@ package com.alibaba.nacos.core.remote.grpc; -import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; -import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -123,15 +122,8 @@ public void onNext(Payload payload) { setUpRequest.getClientVersion(), appName, setUpRequest.getLabels()); metaInfo.setTenant(setUpRequest.getTenant()); Connection connection = new GrpcConnection(metaInfo, responseObserver, CONTEXT_KEY_CHANNEL.get()); - if (setUpRequest.isServer()) { - // if from server - connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), - ServerAbilities.getOffset())); - } else { - // if from client - connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), - ClientAbilities.getOffset())); - } + connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), + AbilityKey.offset())); boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); if (rejectSdkOnStarting || !connectionManager.register(connectionId, connection)) { diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java index 16d753d4f38..038cd0f8294 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.test.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import org.junit.Assert; @@ -68,8 +69,8 @@ public void testClientAdd() { table.setAbility(newTable); table.setServer(true); clientAbilityControlManager.addNewTable(table); - Assert.assertFalse(clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); - Assert.assertTrue(clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); + Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); + Assert.assertEquals(AbilityStatus.SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); } @Test @@ -82,8 +83,8 @@ public void testServerAdd() { table.setAbility(newTable); table.setServer(true); serverAbilityControlManager.addNewTable(table); - Assert.assertFalse(serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); - Assert.assertTrue(serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); + Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); + Assert.assertEquals(AbilityStatus.SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); Map otherServer = new HashMap<>(); From 118cde52e7432277b1c3733ed7d5a1622691a73c Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Wed, 31 Aug 2022 16:59:43 +0800 Subject: [PATCH 017/181] Separate client capability and server capability: ClientAbilities and ServerAbilities. --- .../api/ability/constant/AbilityKey.java | 111 ++++++------------ .../api/ability/constant/AbilityStatus.java | 40 +++++++ .../api/ability/entity/AbilityTable.java | 17 ++- .../register/AbstractAbilityRegistry.java | 62 ++++++++++ .../register/impl/ClientAbilities.java | 72 ++++++++++++ .../register/impl/ServerAbilities.java | 73 ++++++++++++ .../request/ConnectionSetupRequest.java | 13 ++ .../nacos/api/utils/AbilityTableUtils.java | 44 ++++++- .../api/utils/AbilityTableUtilsTest.java | 56 --------- .../ability/ClientAbilityControlManager.java | 27 +++-- .../client/config/impl/ClientWorker.java | 6 - .../client/naming/remote/TestConnection.java | 16 +++ .../AbstractAbilityControlManager.java | 26 +++- .../ability/DefaultAbilityControlManager.java | 55 +++++---- .../ability/inter/AbilityControlManager.java | 10 +- .../ability/inter/AbilityHandlerRegistry.java | 22 ++-- .../listener/ClientAbilityEventListener.java | 17 ++- .../nacos/common/remote/client/RpcClient.java | 12 -- .../remote/client/RpcClientFactory.java | 2 - .../common/remote/client/grpc/GrpcClient.java | 18 ++- .../remote/client/grpc/GrpcClusterClient.java | 5 + .../remote/client/grpc/GrpcSdkClient.java | 5 + .../remote/client/grpc/GrpcClientTest.java | 6 + .../control/ServerAbilityControlManager.java | 57 +++++---- .../inte/ClusterAbilityControlSupport.java | 17 +-- .../alibaba/nacos/core/remote/Connection.java | 7 +- .../grpc/GrpcBiStreamRequestAcceptor.java | 3 +- .../core/remote/grpc/GrpcRequestAcceptor.java | 4 +- .../ability/AbilityControlManagerTest.java | 98 ++++++++-------- .../TestClientAbilityControlManager.java | 3 +- .../TestServerAbilityControlManager.java | 15 +-- 31 files changed, 603 insertions(+), 316 deletions(-) create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java create mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java delete mode 100644 api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java index cf194cccaff..11a26e54ac9 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java @@ -16,96 +16,59 @@ package com.alibaba.nacos.api.ability.constant; -import com.alibaba.nacos.api.utils.AbilityTableUtils; - -import java.util.Collections; -import java.util.HashMap; +import java.util.Arrays; import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; /**. * @author Daydreamer - * @description Ability table key. It can be a replacement of {@link com.alibaba.nacos.api.ability.ServerAbilities} - * and {@link com.alibaba.nacos.api.ability.ClientAbilities}. - * @date 2022/7/12 19:23 + * @description Ability key constant. + * @date 2022/8/31 12:27 **/ -@SuppressWarnings("unchecked") -public class AbilityKey { - - private static final HashMap CURRENT_SERVER_SUPPORT_ABILITY = new HashMap<>(); - - private static final HashMap CURRENT_SERVER_ABILITY_OFFSET = new HashMap<>(); - - private static final byte[] ABILITY_BIT_FLAGS; - - private AbilityKey() { - } +public enum AbilityKey { - static { - /* - * example: - * There is a function named "compression". - * The key is "compression", the value is the offset of the flag bit of this ability in the ability table. The value should be unique. - * - * You can add a new public static field like: - * public static final String COMPRESSION = "compression"; - * This field can be used outside. - * - * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: - * CURRENT_SERVER_ABILITY_OFFSET.put("compression", 1); means that is the first bit from left to right in the table. - * - */ - - // put ability here, which you want current server supports - - } + /**. + * just for junit test + */ + TEST_1("test_1", 1), /**. - * Return ability table of current node - * But this ability is static which means that this ability table is all function this node supports if no one to ask it to close some functions. - * If you want to get what function current node is supporting, you should call AbilityControlManager#getCurrentAbility - * By the way, AbilityControlManager is singleton, you can get it by static method - * - * @return ability table + * just for junit test */ - public static Map getCurrentNodeSupportAbility() { - return Collections.unmodifiableMap(CURRENT_SERVER_SUPPORT_ABILITY); - } + TEST_2("test_2", 2); /**. - * Return the static ability bit table - * - * @return ability bit table + * the name of a certain ability */ - public static byte[] getAbilityBitFlags() { - return ABILITY_BIT_FLAGS.clone(); - } - + private final String name; + /**. - * Is it a legal key - * - * @param key input - * @return whether a legal key + * the offset in ability table */ - public static boolean isLegal(String key) { - return CURRENT_SERVER_SUPPORT_ABILITY.containsKey(key); + private final int offset; + + AbilityKey(String name, int offset) { + this.name = name; + this.offset = offset; } - static { - // init the bits table - ABILITY_BIT_FLAGS = AbilityTableUtils.getAbilityBitBy(CURRENT_SERVER_ABILITY_OFFSET.values()); - // init the ability table, default all true - CURRENT_SERVER_ABILITY_OFFSET.forEach((k, v) -> { - CURRENT_SERVER_SUPPORT_ABILITY.put(k, Boolean.TRUE); - }); + public String getName() { + return name; } - - /**. - * Return the ability bit offsets - * - * @return bit offset - */ - public static Map offset() { - return CURRENT_SERVER_ABILITY_OFFSET; + + public int getOffset() { + return offset; + } + + private static final Map OFFSET_MAP; + + public static Map offset() { + return OFFSET_MAP; + } + + static { + OFFSET_MAP = Arrays.stream(AbilityKey.values()) + .collect(Collectors.toMap(Function.identity(), AbilityKey::getOffset)); } - } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java new file mode 100644 index 00000000000..a762c037300 --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityStatus.java @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2022 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.ability.constant; + +/**. + * @author Daydreamer + * @description It is used to know a certain ability whether supporting. + * @date 2022/8/31 12:27 + **/ +public enum AbilityStatus { + + /**. + * Support a certain ability + */ + SUPPORTED, + + /**. + * Not support a certain ability + */ + NOT_SUPPORTED, + + /**. + * Cannot find ability table, unknown + */ + UNKNOWN +} diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java index 921a092a773..63fda78da96 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java @@ -34,10 +34,10 @@ public class AbilityTable implements Cloneable { /**. * ability table - * key: name from {@link AbilityKey} + * key: name from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} * value: whether to turn on */ - private Map ability; + private Map ability; /**. * whether it from a server node @@ -70,7 +70,7 @@ public AbilityTable setVersion(String version) { return this; } - public AbilityTable(String connectionId, Map ability, boolean isServer, String version) { + public AbilityTable(String connectionId, Map ability, boolean isServer, String version) { this.connectionId = connectionId; this.ability = ability; this.isServer = isServer; @@ -86,13 +86,18 @@ public AbilityTable setConnectionId(String connectionId) { return this; } - public Map getAbility() { + public Map getAbility() { return ability; } - public AbilityTable setAbility(Map ability) { + public AbilityTable setAbility(Map ability) { this.ability = ability; return this; } - + + @Override + public String toString() { + return "AbilityTable{" + "connectionId='" + connectionId + '\'' + ", ability=" + ability + ", isServer=" + + isServer + ", version='" + version + '\'' + '}'; + } } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java new file mode 100644 index 00000000000..4ad0df43d32 --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java @@ -0,0 +1,62 @@ +/* + * Copyright 1999-2022 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.ability.register; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.utils.AbilityTableUtils; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/**. + * @author Daydreamer + * @description Operation for bit table. + * @date 2022/7/12 19:23 + **/ +public abstract class AbstractAbilityRegistry { + + protected final Map supportedAbilities = new HashMap<>(); + + private byte[] abilityBitFlag; + + /**. + * Return the static ability bit table + * + * @return ability bit table + */ + public byte[] getAbilityBitFlags() { + return abilityBitFlag.clone(); + } + + /**. + * put the bit offset to {@link AbstractAbilityRegistry#abilityBitFlag} + */ + protected void init() { + // init the bits table + abilityBitFlag = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), supportedAbilities); + } + + /** + * get static ability current server supports + * + * @return static ability + */ + public Map getSupportedAbilities() { + return Collections.unmodifiableMap(supportedAbilities); + } +} diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java new file mode 100644 index 00000000000..c4ec32be5a0 --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2022 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.ability.register.impl; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; + +import java.util.Map; + +/**. + * @author Daydreamer + * @description It is used to register client abilities. + * @date 2022/8/31 12:32 + **/ +public class ClientAbilities extends AbstractAbilityRegistry { + + private static final ClientAbilities INSTANCE = new ClientAbilities(); + + { + /* + * example: + * There is a function named "compression". + * The key is from

AbilityKey

, the value is whether turn on. + * + * You can add a new public field in

AbilityKey

like: + * DATA_COMPRESSION("compression", 1) + * This field can be used outside, and the offset should be unique. + * + * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: + * supportedAbilities.put(AbilityKey.DATA_COMPRESSION, true); means that is the first bit from left to right in the table. + * + */ + // put ability here, which you want current client supports + } + + private ClientAbilities() { + // put key to bit offset + init(); + } + + /**. + * get the ability offset for server + * + * @return ability offset + */ + public static byte[] getBitFlags() { + return INSTANCE.getAbilityBitFlags(); + } + + /** + * get static ability current server supports + * + * @return static ability + */ + public static Map getStaticAbilities(){ + return INSTANCE.getSupportedAbilities(); + } +} diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java new file mode 100644 index 00000000000..bd01a53b8bd --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java @@ -0,0 +1,73 @@ +/* + * Copyright 1999-2022 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.ability.register.impl; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; + +import java.util.Map; + +/**. + * @author Daydreamer + * @description It is used to register server abilities. + * @date 2022/8/31 12:32 + **/ +public class ServerAbilities extends AbstractAbilityRegistry { + + private static final ServerAbilities INSTANCE = new ServerAbilities(); + + { + /* + * example: + * There is a function named "compression". + * The key is from

AbilityKey

, the value is whether turn on. + * + * You can add a new public field in

AbilityKey

like: + * DATA_COMPRESSION("compression", 1) + * This field can be used outside, and the offset should be unique. + * + * And then you need to declare the offset of the flag bit of this ability in the ability table, you can: + * supportedAbilities.put(AbilityKey.DATA_COMPRESSION, true); means that is the first bit from left to right in the table. + * + */ + // put ability here, which you want current server supports + } + + private ServerAbilities() { + // put key to bit offset + init(); + } + + /**. + * get bit table + * + * @return ability offset + */ + public static byte[] getBitFlags() { + return INSTANCE.getAbilityBitFlags(); + } + + /** + * get static ability current server supports + * + * @return static ability + */ + public static Map getStaticAbilities(){ + return INSTANCE.getSupportedAbilities(); + } + +} diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java index 046a897a447..15b3c35d5ec 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java @@ -35,6 +35,19 @@ public class ConnectionSetupRequest extends InternalRequest { private byte[] abilityTable; + /**. + * server will resolve {@link ConnectionSetupRequest#abilityTable} to server abilities, or to client abilities + */ + private boolean isServer; + + public boolean isServer() { + return isServer; + } + + public void setServer(boolean server) { + isServer = server; + } + public ConnectionSetupRequest() { } diff --git a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java index 11ad28cc054..fe75aab2c36 100644 --- a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java +++ b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java @@ -17,12 +17,16 @@ package com.alibaba.nacos.api.utils; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /**. * @author Daydreamer @@ -67,18 +71,18 @@ public static byte[] getAbilityBitBy(Collection bitCollection) { * get ability table by bits * * @param bits bit flag - * @param offsetMap offset from {@link AbilityKey} + * @param offsetMap offset from {@link AbstractAbilityRegistry} * @return Return the Map containing AbilityTableKey and isRunning. */ - public static Map getAbilityTableBy(byte[] bits, Map offsetMap) { + public static Map getAbilityTableBy(byte[] bits, Map offsetMap) { if (bits == null || offsetMap.size() == 0) { return Collections.emptyMap(); } int length = bits.length; - Set> entries = offsetMap.entrySet(); - Map res = new HashMap<>(offsetMap.size()); - for (Map.Entry entry : entries) { - String abilityKey = entry.getKey(); + Set> entries = offsetMap.entrySet(); + Map res = new HashMap<>(offsetMap.size()); + for (Map.Entry entry : entries) { + AbilityKey abilityKey = entry.getKey(); Integer offset = entry.getValue(); // if not exists int index = offset / 8 + (offset % 8 == 0 ? -1 : 0); @@ -97,4 +101,32 @@ public static Map getAbilityTableBy(byte[] bits, Map offsetMap, Map abilityTable) { + // filter the element which abilityTable don't have or value is false + Map res = offsetMap.entrySet().stream() + .filter(item -> abilityTable.getOrDefault(item.getKey(), false)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + return getAbilityBitBy(res.values()); + } + + /** + * get ability bit table by existed ability table and abilityKeys array + * + * @param abilityKeys abilityKeys array + * @param abilityTable existed ability table + * @return filter ability which value is false in abilityTable + */ + public static byte[] getAbilityBiTableBy(AbilityKey[] abilityKeys, Map abilityTable) { + // filter the element which abilityTable don't have or value is false + List keyList = Arrays.stream(abilityKeys).collect(Collectors.toList()); + keyList.removeIf(key -> !abilityTable.getOrDefault(key, false)); + return getAbilityBitBy(keyList.stream().map(AbilityKey::getOffset).collect(Collectors.toList())); + } } diff --git a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java deleted file mode 100644 index c2fea2c406c..00000000000 --- a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 1999-2022 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; - -import org.junit.Assert; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -public class AbilityTableUtilsTest { - - @Test - public void testGetByteArray() { - Map offset = new HashMap<>(); - offset.put("a", 1); - offset.put("b", 2); - offset.put("c", 10); - offset.put("d", 127); - byte[] abilityBitBy = AbilityTableUtils.getAbilityBitBy(offset.values()); - Assert.assertEquals(16, abilityBitBy.length); - Assert.assertEquals((byte) (3 << 6), abilityBitBy[0]); - Assert.assertEquals((byte) (1 << 6), abilityBitBy[1]); - } - - @Test - public void testGetAbilityTable() { - Map offset = new HashMap<>(); - offset.put("a", 1); - offset.put("b", 2); - offset.put("c", 10); - offset.put("d", 127); - byte[] abilityBitBy = AbilityTableUtils.getAbilityBitBy(offset.values()); - Map abilityTableBy = AbilityTableUtils.getAbilityTableBy(abilityBitBy, offset); - Assert.assertEquals(4, abilityTableBy.size()); - Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("a")); - Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("b")); - Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("c")); - Assert.assertEquals(Boolean.TRUE, abilityTableBy.get("d")); - Assert.assertEquals(Boolean.FALSE, abilityTableBy.getOrDefault("asdasd", false)); - } -} diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index 9d39574f8b3..eef2427a54a 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -16,11 +16,15 @@ package com.alibaba.nacos.client.ability; +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; import java.util.Collections; +import java.util.Map; import java.util.Optional; /**. @@ -34,17 +38,20 @@ public ClientAbilityControlManager() { } @Override - public boolean isSupport(String connectionId, String abilityKey) { - Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); - if (!isRunning) { - return false; - } + protected Map getCurrentNodeSupportAbility() { + return ClientAbilities.getStaticAbilities(); + } + + @Override + public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - // false if null - return abilityTable != null - && Optional.ofNullable(abilityTable.getAbility()) - .orElse(Collections.emptyMap()) - .getOrDefault(abilityKey, false); + if (abilityTable == null) { + return AbilityStatus.UNKNOWN; + } + Boolean isSupport = Optional.ofNullable(abilityTable.getAbility()) + .orElse(Collections.emptyMap()) + .getOrDefault(abilityKey, false); + return isSupport ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; } @Override diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index fc450b990a5..a227d537e9c 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.client.config.impl; import com.alibaba.nacos.api.PropertyKeyConst; -import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.config.ConfigType; import com.alibaba.nacos.api.config.listener.Listener; @@ -885,7 +884,6 @@ private RpcClient ensureRpcClient(String taskId) throws NacosException { if (rpcClient.isWaitInitiated()) { initRpcClientHandler(rpcClient); rpcClient.setTenant(getTenant()); - rpcClient.clientAbilities(initAbilities()); rpcClient.start(); } @@ -893,10 +891,6 @@ private RpcClient ensureRpcClient(String taskId) throws NacosException { } } - - private byte[] initAbilities() { - return AbilityKey.getAbilityBitFlags(); - } /** * build config string. diff --git a/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java b/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java index 6d02c962da0..43fc088fde2 100644 --- a/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java +++ b/client/src/test/java/com/alibaba/nacos/client/naming/remote/TestConnection.java @@ -1,3 +1,19 @@ +/* + * Copyright 1999-2022 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.naming.remote; import com.alibaba.nacos.api.exception.NacosException; diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index e1723a9e228..96c5e1c45e4 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.common.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.inter.AbilityControlManager; import com.alibaba.nacos.common.notify.Event; @@ -26,6 +27,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; @@ -43,10 +45,10 @@ public abstract class AbstractAbilityControlManager implements AbilityControlMan /** * Abilities current supporting *

- * key: ability key from {@link AbilityKey} + * key: ability key from {@link AbstractAbilityRegistry} * value: whether to turn on */ - protected final Map currentRunningAbility = new ConcurrentHashMap<>(); + protected final Map currentRunningAbility = new ConcurrentHashMap<>(); /** * Ability table collections @@ -64,10 +66,17 @@ protected AbstractAbilityControlManager() { // register events registerAbilityEvent(); // put abilities - currentRunningAbility.putAll(AbilityKey.getCurrentNodeSupportAbility()); + currentRunningAbility.putAll(getCurrentNodeSupportAbility()); // initialize init(); } + + /** + * This is a hook for subclass to init current node ability + * + * @return current node ability + */ + protected abstract Map getCurrentNodeSupportAbility(); private void registerAbilityEvent(){ @@ -83,7 +92,7 @@ private void registerAbilityEvent(){ * @return is running */ @Override - public boolean isCurrentNodeAbilityRunning(String abilityKey) { + public boolean isCurrentNodeAbilityRunning(AbilityKey abilityKey) { return currentRunningAbility.getOrDefault(abilityKey, false); } @@ -109,6 +118,13 @@ public final void addNewTable(AbilityTable table) { // hook method add(table); // add to node + Set abilityKeys = table.getAbility().keySet(); + Map clientAbilities = table.getAbility(); + abilityKeys.forEach(abilityKey -> { + Boolean res = currentRunningAbility.getOrDefault(abilityKey, false); + Boolean coming = clientAbilities.getOrDefault(abilityKey, false); + clientAbilities.put(abilityKey, res && coming); + }); nodeAbilityTable.put(connectionId, table); } finally { lockForAbilityTable.unlock(); @@ -204,7 +220,7 @@ public void destroy() { * @return ability table */ @Override - public Map getCurrentRunningAbility() { + public Map getCurrentRunningAbility() { return new HashMap<>(this.currentRunningAbility); } diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java index b3012392ed9..01fc7a60bb6 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.common.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.handler.HandlerMapping; @@ -46,16 +47,18 @@ * @description It is a relatively complete capability control center implementation. * @date 2022/7/12 19:18 **/ +@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule") public abstract class DefaultAbilityControlManager extends AbstractAbilityControlManager implements AbilityHandlerRegistry { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAbilityControlManager.class); - /** - * . These handlers will be invoked when the flag of ability change key: ability key from {@link AbilityKey} value: - * componments who want to be invoked if its interested ability turn on/off + /**. + * These handlers will be invoked when the flag of ability change key: + * ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} value: + * components who want to be invoked if its interested ability turn on/off */ - private final Map> handlerMappings = new ConcurrentHashMap<>(); + private final Map> handlerMappings = new ConcurrentHashMap<>(); /**. * run for HandlerMapping @@ -76,7 +79,7 @@ protected DefaultAbilityControlManager() { * @return if turn success */ @Override - public boolean enableCurrentNodeAbility(String abilityKey) { + public boolean enableCurrentNodeAbility(AbilityKey abilityKey) { return doTurn(true, abilityKey); } @@ -87,7 +90,7 @@ public boolean enableCurrentNodeAbility(String abilityKey) { * @return if turn success */ @Override - public boolean disableCurrentNodeAbility(String abilityKey) { + public boolean disableCurrentNodeAbility(AbilityKey abilityKey) { return doTurn(false, abilityKey); } @@ -98,7 +101,7 @@ public boolean disableCurrentNodeAbility(String abilityKey) { * @param abilityKey ability key from {@link AbilityKey} * @return if turn success */ - private boolean doTurn(boolean isOn, String abilityKey) { + private boolean doTurn(boolean isOn, AbilityKey abilityKey) { Boolean isEnabled = currentRunningAbility.get(abilityKey); // if not supporting this key if (isEnabled == null) { @@ -130,12 +133,12 @@ private boolean doTurn(boolean isOn, String abilityKey) { * @param handlerMapping component instance. */ @Override - public void registerComponent(String abilityKey, HandlerMapping handlerMapping, int priority) { + public void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority) { doRegisterComponent(abilityKey, handlerMapping, this.handlerMappings, lockForHandlerMappings, priority, currentRunningAbility); } @Override - public int removeComponent(String abilityKey, Class handlerMappingClazz) { + public int removeComponent(AbilityKey abilityKey, Class handlerMappingClazz) { return doRemove(abilityKey, handlerMappingClazz, lockForHandlerMappings, handlerMappings); } @@ -161,14 +164,14 @@ protected void doDestroy() { /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey ability key from {@link AbstractAbilityRegistry} * @param handlerMappingClazz implement of {@link HandlerMapping} * @param lock lock for operation * @param handlerMappingsMap handler collection map * @return the count of components have removed */ - protected int doRemove(String abilityKey, Class handlerMappingClazz, Lock lock, - Map> handlerMappingsMap) { + protected int doRemove(AbilityKey abilityKey, Class handlerMappingClazz, Lock lock, + Map> handlerMappingsMap) { List handlerMappings = handlerMappingsMap.get(abilityKey); if (CollectionUtils.isEmpty(handlerMappings)) { return 0; @@ -190,7 +193,7 @@ protected int doRemove(String abilityKey, Class handle } @Override - public int removeAll(String abilityKey) { + public int removeAll(AbilityKey abilityKey) { List remove = this.handlerMappings.remove(abilityKey); return Optional.ofNullable(remove).orElse(Collections.emptyList()).size(); } @@ -204,9 +207,9 @@ public int removeAll(String abilityKey) { * @param lockForHandlerMappings lock to ensure concurrency * @param abilityTable behavioral basis of handler */ - protected void doRegisterComponent(String abilityKey, HandlerMapping handlerMapping, - Map> handlerMappings, Lock lockForHandlerMappings, - int priority, Map abilityTable) { + protected void doRegisterComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, + Map> handlerMappings, Lock lockForHandlerMappings, + int priority, Map abilityTable) { if (!currentRunningAbility.containsKey(abilityKey)) { LOGGER.warn("[AbilityHandlePostProcessor] Failed to register processor: {}, because illegal key!", handlerMapping.getClass().getSimpleName()); @@ -239,24 +242,24 @@ protected void doRegisterComponent(String abilityKey, HandlerMapping handlerMapp /** * Invoke componments which linked to ability key asyn. * - * @param key ability key from {@link AbilityKey} + * @param key ability key from {@link AbstractAbilityRegistry} * @param isEnabled turn on/off * @param handlerMappingsMap handler collection */ - protected void triggerHandlerMappingAsyn(String key, boolean isEnabled, - Map> handlerMappingsMap) { + protected void triggerHandlerMappingAsyn(AbilityKey key, boolean isEnabled, + Map> handlerMappingsMap) { simpleThreadPool.execute(() -> doTriggerSyn(key, isEnabled, handlerMappingsMap)); } /** * Invoke componments which linked to ability key syn. * - * @param key ability key from {@link AbilityKey} + * @param key ability key from {@link AbstractAbilityRegistry} * @param isEnabled turn on/off * @param handlerMappingsMap handler collection */ - protected void doTriggerSyn(String key, boolean isEnabled, - Map> handlerMappingsMap) { + protected void doTriggerSyn(AbilityKey key, boolean isEnabled, + Map> handlerMappingsMap) { List handlerWithPriorities = handlerMappingsMap.get(key); // return if empty if (CollectionUtils.isEmpty(handlerWithPriorities)) { @@ -281,7 +284,7 @@ protected void doTriggerSyn(String key, boolean isEnabled, } @JustForTest - protected Map> handlerMapping() { + protected Map> handlerMapping() { return this.handlerMappings; } @@ -318,17 +321,17 @@ public class AbilityUpdateEvent extends AbilityEvent { private static final long serialVersionUID = -1232411212311111L; - private String abilityKey; + private AbilityKey abilityKey; private boolean isOn; private AbilityUpdateEvent(){} - public String getAbilityKey() { + public AbilityKey getAbilityKey() { return abilityKey; } - public void setAbilityKey(String abilityKey) { + public void setAbilityKey(AbilityKey abilityKey) { this.abilityKey = abilityKey; } diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java index 75aac889380..304d673d4d1 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java @@ -17,6 +17,8 @@ package com.alibaba.nacos.common.ability.inter; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import com.alibaba.nacos.api.ability.entity.AbilityTable; import java.util.Map; @@ -32,10 +34,10 @@ public interface AbilityControlManager { * Whether the ability is supported for Connection. If the ability of current node is closed, it will return false. * * @param connectionId the connection range of ability table. - * @param abilityKey key name which comes from {@link AbilityKey}. + * @param abilityKey key name which comes from {@link AbstractAbilityRegistry}. * @return whether the ability is supported in certain connection. */ - boolean isSupport(String connectionId, String abilityKey); + AbilityStatus isSupport(String connectionId, AbilityKey abilityKey); /** * Whether the ability current node supporting is running. Return false if current node doesn't support. @@ -43,7 +45,7 @@ public interface AbilityControlManager { * @param abilityKey ability key * @return is running */ - boolean isCurrentNodeAbilityRunning(String abilityKey); + boolean isCurrentNodeAbilityRunning(AbilityKey abilityKey); /** * Register a new ability table. @@ -72,7 +74,7 @@ public interface AbilityControlManager { * * @return ability table */ - Map getCurrentRunningAbility(); + Map getCurrentRunningAbility(); /**. * Initialize the manager diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java index c2725478466..5cbc2a8a506 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.common.ability.inter; +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.handler.HandlerMapping; @@ -32,7 +34,7 @@ public interface AbilityHandlerRegistry { * @param abilityKey ability key * @return if turn success */ - boolean enableCurrentNodeAbility(String abilityKey); + boolean enableCurrentNodeAbility(AbilityKey abilityKey); /**. * Turn off the ability whose key is

abilityKey

@@ -40,42 +42,42 @@ public interface AbilityHandlerRegistry { * @param abilityKey ability key * @return if turn success */ - boolean disableCurrentNodeAbility(String abilityKey); + boolean disableCurrentNodeAbility(AbilityKey abilityKey); /**. * Register the component which is managed by {@link AbstractAbilityControlManager}. * if you are hoping that a component will be invoked when turn on/off the ability whose key is

abilityKey

. * - * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey component key from {@link AbstractAbilityRegistry} * @param priority a positive number, the higher the priority is, the faster it will be called. `1` is the lowest priority. * @param handlerMapping component instance. */ - void registerComponent(String abilityKey, HandlerMapping handlerMapping, int priority); + void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority); /**. * Default method to register component with the lowest priority. * - * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey component key from {@link AbstractAbilityRegistry} * @param handlerMapping component instance. */ - default void registerComponent(String abilityKey, HandlerMapping handlerMapping) { + default void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping) { registerComponent(abilityKey, handlerMapping, 1); } /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey ability key from {@link AbstractAbilityRegistry} * @param handlerMappingClazz implement of {@link HandlerMapping} * @return the count of components have removed */ - int removeComponent(String abilityKey, Class handlerMappingClazz); + int removeComponent(AbilityKey abilityKey, Class handlerMappingClazz); /** * Remove all {@link HandlerMapping} interested in the special ability. - * @param abilityKey abnility key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey abnility key from {@link AbstractAbilityRegistry} * @return the count of components have removed */ - int removeAll(String abilityKey); + int removeAll(AbilityKey abilityKey); } diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java b/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java index 0c20043655d..0093709c5b4 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java @@ -1,5 +1,20 @@ -package com.alibaba.nacos.common.ability.listener; +/* + * Copyright 1999-2022 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.ability.listener; import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.client.Connection; diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java index 9db2e1e8487..59d8134ecb6 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java @@ -90,8 +90,6 @@ public abstract class RpcClient implements Closeable { private static final long DEFAULT_TIMEOUT_MILLS = 3000L; - protected byte[] clientAbilities; - /** * default keep alive time 5s. */ @@ -133,16 +131,6 @@ public RpcClient(String name, ServerListFactory serverListFactory) { } } - /** - * init client abilities. - * - * @param clientAbilities clientAbilities. - */ - public RpcClient clientAbilities(byte[] clientAbilities) { - this.clientAbilities = clientAbilities; - return this; - } - /** * init server list factory. only can init once. * diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java index 8b40c9cfb8c..2d71b9e46ed 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClientFactory.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.common.remote.client; -import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.grpc.GrpcClient; @@ -140,7 +139,6 @@ public static RpcClient createClusterClient(String clientName, ConnectionType co client.setThreadPoolCoreSize(threadPoolCoreSize); client.setThreadPoolMaxSize(threadPoolMaxSize); client.labels(labels); - client.clientAbilities(AbilityKey.getAbilityBitFlags()); return client; }); } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index a68c81e5847..7519de40f17 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -18,6 +18,7 @@ import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -47,6 +48,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Arrays; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -317,7 +319,7 @@ public Connection connectToServer(ServerInfo serverInfo) { // submit ability table as soon as possible // ability table will be null if server doesn't support ability table ServerCheckResponse serverCheckResponse = (ServerCheckResponse) response; - Map abilityTable = AbilityTableUtils + Map abilityTable = AbilityTableUtils .getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset()); AbilityTable table = new AbilityTable(); table.setServer(true) @@ -341,7 +343,11 @@ public Connection connectToServer(ServerInfo serverInfo) { ConnectionSetupRequest conSetupRequest = new ConnectionSetupRequest(); conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion()); conSetupRequest.setLabels(super.getLabels()); - conSetupRequest.setAbilityTable(super.clientAbilities == null ? AbilityKey.getAbilityBitFlags() : clientAbilities); + // set ability table + byte[] bitTable = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), + NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()); + conSetupRequest.setAbilityTable(bitTable); + conSetupRequest.setServer(isServer()); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); //wait to register connection setup @@ -355,6 +361,14 @@ public Connection connectToServer(ServerInfo serverInfo) { return null; } + /** + * Return whether server environment + * The same offset may refer to different functions in the client capability table and the server capability table. + * + * @return whether server environment + */ + protected abstract boolean isServer(); + } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java index 7b63653b659..74919ba078b 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java @@ -35,6 +35,11 @@ public GrpcClusterClient(String name) { super(name); } + @Override + protected boolean isServer() { + return true; + } + @Override public int rpcPortOffset() { return Integer.parseInt(System.getProperty(NACOS_SERVER_GRPC_PORT_OFFSET_KEY, diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java index 34cf408243a..46cd691f65e 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java @@ -35,6 +35,11 @@ public GrpcSdkClient(String name) { super(name); } + @Override + protected boolean isServer() { + return false; + } + @Override public int rpcPortOffset() { return Integer.parseInt(System.getProperty(NACOS_SERVER_GRPC_PORT_OFFSET_KEY, diff --git a/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java b/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java index 5a81ab3ed4d..af7104d1333 100644 --- a/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java +++ b/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java @@ -47,6 +47,12 @@ public class GrpcClientTest { @Before public void setUp() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { grpcClient = spy(new GrpcClient("testClient") { + + @Override + protected boolean isServer() { + return false; + } + @Override public int rpcPortOffset() { return 1000; diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 44a01258ffa..825faa807c1 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -16,7 +16,10 @@ package com.alibaba.nacos.core.ability.control; +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; @@ -48,7 +51,7 @@ public class ServerAbilityControlManager extends DefaultAbilityControlManager im /**. * ability for cluster */ - private final Map clusterAbilityTable = new ConcurrentHashMap<>(); + private final Map clusterAbilityTable = new ConcurrentHashMap<>(); /**. * ability for server @@ -58,7 +61,7 @@ public class ServerAbilityControlManager extends DefaultAbilityControlManager im /** * components for cluster. these will be invoked if cluster ability table changes. */ - private final Map> clusterHandlerMapping = new ConcurrentHashMap<>(); + private final Map> clusterHandlerMapping = new ConcurrentHashMap<>(); private Lock lockForClusterComponents = new ReentrantLock(); @@ -73,17 +76,19 @@ public ServerAbilityControlManager() { } @Override - public boolean isSupport(String connectionId, String abilityKey) { - Boolean isRunning = currentRunningAbility.getOrDefault(abilityKey, false); - if (!isRunning) { - return false; - } + protected Map getCurrentNodeSupportAbility() { + return ServerAbilities.getStaticAbilities(); + } + + @Override + public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - // false if null - return abilityTable != null - && Optional.ofNullable(abilityTable.getAbility()) - .orElse(Collections.emptyMap()) - .getOrDefault(abilityKey, false); + if (abilityTable == null) { + return AbilityStatus.UNKNOWN; + } + Boolean isSupport = Optional.ofNullable(abilityTable.getAbility()).orElse(Collections.emptyMap()) + .getOrDefault(abilityKey, false); + return isSupport ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; } /**. @@ -93,12 +98,12 @@ public boolean isSupport(String connectionId, String abilityKey) { * @return whether it is turn on */ @Override - public boolean isClusterEnableAbility(String abilityKey) { + public boolean isClusterEnableAbility(AbilityKey abilityKey) { return clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE); } @Override - public Map getClusterAbility() { + public Map getClusterAbility() { return Collections.unmodifiableMap(clusterAbilityTable); } @@ -110,17 +115,17 @@ public Map getClusterAbility() { * @param handlerMapping component */ @Override - public void registerComponentForCluster(String abilityKey, HandlerMapping handlerMapping, int priority) { + public void registerComponentForCluster(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority) { doRegisterComponent(abilityKey, handlerMapping, this.clusterHandlerMapping, lockForClusterComponents, priority, clusterAbilityTable); } @Override - public int removeClusterComponent(String abilityKey, Class handlerMappingClazz) { + public int removeClusterComponent(AbilityKey abilityKey, Class handlerMappingClazz) { return doRemove(abilityKey, handlerMappingClazz, lockForClusterComponents, clusterHandlerMapping); } @Override - public int removeAllForCluster(String abilityKey) { + public int removeAllForCluster(AbilityKey abilityKey) { List remove = this.clusterHandlerMapping.remove(abilityKey); return Optional.ofNullable(remove).orElse(Collections.emptyList()).size(); } @@ -134,8 +139,8 @@ protected void add(AbilityTable table) { if (isServer) { serversAbilityTable.put(table.getConnectionId(), table); // enter cluster - Map nodeAbility = table.getAbility(); - Set keySet = clusterAbilityTable.keySet(); + Map nodeAbility = table.getAbility(); + Set keySet = clusterAbilityTable.keySet(); keySet.forEach(abilityKey -> { Boolean isEnabled = clusterAbilityTable.get(abilityKey); Boolean val = nodeAbility.getOrDefault(abilityKey, Boolean.FALSE); @@ -153,7 +158,7 @@ protected void add(AbilityTable table) { } } - private ClusterAbilityUpdateEvent buildClusterEvent(String abilityKey, boolean isOn) { + private ClusterAbilityUpdateEvent buildClusterEvent(AbilityKey abilityKey, boolean isOn) { // notify ClusterAbilityUpdateEvent event = new ClusterAbilityUpdateEvent(); event.setAbilityKey(abilityKey); @@ -176,7 +181,7 @@ protected void remove(String connectionId) { serversAbilityTable.remove(connectionId); // remove from cluster if (MapUtil.isNotEmpty(serversAbilityTable)) { - Set keySet = clusterAbilityTable.keySet(); + Set keySet = clusterAbilityTable.keySet(); keySet.forEach(abilityKey -> { Boolean isEnabled = clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE); // nothing to do if enabled @@ -219,17 +224,17 @@ public class ClusterAbilityUpdateEvent extends AbilityEvent { private static final long serialVersionUID = -122222411212200111L; - private String abilityKey; + private AbilityKey abilityKey; private boolean isOn; private ClusterAbilityUpdateEvent(){} - public String getAbilityKey() { + public AbilityKey getAbilityKey() { return abilityKey; } - public void setAbilityKey(String abilityKey) { + public void setAbilityKey(AbilityKey abilityKey) { this.abilityKey = abilityKey; } @@ -244,12 +249,12 @@ public void setOn(boolean on) { } @JustForTest - protected void setClusterAbilityTable(Map map) { + protected void setClusterAbilityTable(Map map) { clusterAbilityTable.putAll(map); } @JustForTest - protected Map> clusterHandlerMapping() { + protected Map> clusterHandlerMapping() { return this.clusterHandlerMapping; } diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java index 1150b200516..9b989a07840 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.core.ability.inte; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import com.alibaba.nacos.common.ability.inter.AbilityControlManager; @@ -33,7 +34,7 @@ public interface ClusterAbilityControlSupport { * * @return the cluster abilities. */ - Map getClusterAbility(); + Map getClusterAbility(); /**. * Register components for cluster. These will be trigger when its interested ability changes @@ -42,7 +43,7 @@ public interface ClusterAbilityControlSupport { * @param priority a positive number, the higher the priority, the faster it will be called * @param handlerMapping component */ - void registerComponentForCluster(String abilityKey, HandlerMapping handlerMapping, int priority); + void registerComponentForCluster(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority); /**. * Default method to register component @@ -50,25 +51,25 @@ public interface ClusterAbilityControlSupport { * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. * @param handlerMapping component instance. */ - default void registerComponentForCluster(String abilityKey, HandlerMapping handlerMapping) { + default void registerComponentForCluster(AbilityKey abilityKey, HandlerMapping handlerMapping) { registerComponentForCluster(abilityKey, handlerMapping, 1); } /** * Remove the component instance of

handlerMappingClazz

. * - * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. * @param handlerMappingClazz implement of {@link HandlerMapping} * @return the count of components have removed */ - int removeClusterComponent(String abilityKey, Class handlerMappingClazz); + int removeClusterComponent(AbilityKey abilityKey, Class handlerMappingClazz); /** * Remove all {@link HandlerMapping} interested in the special ability. - * @param abilityKey abnility key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} + * @param abilityKey abnility key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. * @return the count of components have removed */ - int removeAllForCluster(String abilityKey); + int removeAllForCluster(AbilityKey abilityKey); /**. * Whether current cluster supports ability @@ -76,5 +77,5 @@ default void registerComponentForCluster(String abilityKey, HandlerMapping handl * @param abilityKey ability key * @return whether it is turn on */ - boolean isClusterEnableAbility(String abilityKey); + boolean isClusterEnableAbility(AbilityKey abilityKey); } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java index 2553d24a7d3..2e159bce16b 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.core.remote; import com.alibaba.nacos.api.ability.ClientAbilities; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.remote.Requester; import java.util.Map; @@ -32,7 +33,7 @@ public abstract class Connection implements Requester { private boolean traced = false; - private Map abilityTable; + private Map abilityTable; private ClientAbilities abilities; @@ -54,11 +55,11 @@ public void setTraced(boolean traced) { this.traced = traced; } - public Map getAbilityTable() { + public Map getAbilityTable() { return abilityTable; } - public void setAbilityTable(Map abilityTable) { + public void setAbilityTable(Map abilityTable) { this.abilityTable = abilityTable; } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 6f2c32b7f92..b8cf7508bb7 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -122,7 +122,8 @@ public void onNext(Payload payload) { setUpRequest.getClientVersion(), appName, setUpRequest.getLabels()); metaInfo.setTenant(setUpRequest.getTenant()); Connection connection = new GrpcConnection(metaInfo, responseObserver, CONTEXT_KEY_CHANNEL.get()); - connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), AbilityKey.offset())); + connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), + AbilityKey.offset())); boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); if (rejectSdkOnStarting || !connectionManager.register(connectionId, connection)) { diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index d16ce16ab5e..a2869d6cdf5 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -16,7 +16,7 @@ package com.alibaba.nacos.core.remote.grpc; -import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.Payload; import com.alibaba.nacos.api.grpc.auto.RequestGrpc; @@ -90,7 +90,7 @@ public void request(Payload grpcRequest, StreamObserver responseObserve // server check. if (ServerCheckRequest.class.getSimpleName().equals(type)) { Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(), - AbilityKey.getAbilityBitFlags())); + ServerAbilities.getBitFlags())); traceIfNecessary(serverCheckResponseP, false); responseObserver.onNext(serverCheckResponseP); responseObserver.onCompleted(); diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java index 99d7cced7da..038cd0f8294 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.test.ability; +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import org.junit.Assert; @@ -43,74 +45,74 @@ public class AbilityControlManagerTest { @Before public void inject() { - Map newTable = new HashMap<>(); - newTable.put("stop-raft", true); + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_1, true); clientAbilityControlManager.setCurrentSupportingAbility(newTable); - Map table = new HashMap<>(); - table.put("stop-raft", true); + Map table = new HashMap<>(); + table.put(AbilityKey.TEST_1, true); serverAbilityControlManager.setCurrentSupportingAbility(table); - Map cluster = new HashMap<>(); - cluster.put("stop-raft", true); + Map cluster = new HashMap<>(); + cluster.put(AbilityKey.TEST_1, true); serverAbilityControlManager.setClusterAbility(cluster); serverAbilityControlManager.setCurrentSupportingAbility(newTable); } @Test public void testClientAdd() { - Map newTable = new HashMap<>(); - newTable.put("test-no-existed", true); - newTable.put("stop-raft", true); + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_2, true); + newTable.put(AbilityKey.TEST_1, true); AbilityTable table = new AbilityTable(); table.setConnectionId("test-00001"); table.setAbility(newTable); table.setServer(true); clientAbilityControlManager.addNewTable(table); - Assert.assertFalse(clientAbilityControlManager.isSupport("test-00001", "test-no-existed")); - Assert.assertTrue(clientAbilityControlManager.isSupport("test-00001", "stop-raft")); + Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); + Assert.assertEquals(AbilityStatus.SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); } @Test public void testServerAdd() { - Map newTable = new HashMap<>(); - newTable.put("test-no-existed", true); - newTable.put("stop-raft", true); + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_2, true); + newTable.put(AbilityKey.TEST_1, true); AbilityTable table = new AbilityTable(); table.setConnectionId("test-00001"); table.setAbility(newTable); table.setServer(true); serverAbilityControlManager.addNewTable(table); - Assert.assertFalse(serverAbilityControlManager.isSupport("test-00001", "test-no-existed")); - Assert.assertTrue(serverAbilityControlManager.isSupport("test-00001", "stop-raft")); - Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); + Assert.assertEquals(AbilityStatus.SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); + Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); - Map otherServer = new HashMap<>(); - otherServer.put("test-no-existed", true); - otherServer.put("stop-raft", false); + Map otherServer = new HashMap<>(); + otherServer.put(AbilityKey.TEST_2, true); + otherServer.put(AbilityKey.TEST_1, false); AbilityTable otherServerTable = new AbilityTable(); otherServerTable.setConnectionId("test-00000"); otherServerTable.setAbility(otherServer); otherServerTable.setServer(true); serverAbilityControlManager.addNewTable(otherServerTable); - Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); - Map clientTa = new HashMap<>(); - clientTa.put("test-no-existed", true); - clientTa.put("stop-raft", false); + Map clientTa = new HashMap<>(); + clientTa.put(AbilityKey.TEST_2, true); + clientTa.put(AbilityKey.TEST_1, false); AbilityTable clientTable = new AbilityTable(); clientTable.setConnectionId("test-00002"); clientTable.setAbility(clientTa); clientTable.setServer(false); serverAbilityControlManager.addNewTable(clientTable); - Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); } @Test public void testClientRemove() { - Map clientTa = new HashMap<>(); - clientTa.put("test-no-existed", true); - clientTa.put("stop-raft", false); + Map clientTa = new HashMap<>(); + clientTa.put(AbilityKey.TEST_2, true); + clientTa.put(AbilityKey.TEST_1, false); AbilityTable clientTable = new AbilityTable(); clientTable.setConnectionId("test-01111"); clientTable.setAbility(clientTa); @@ -125,56 +127,56 @@ public void testClientRemove() { public void testComponent() throws InterruptedException { enabled = 0; // invoke enable() or disable() when registering - serverAbilityControlManager.registerComponent("stop-raft", new TestHandlerMapping(), -1); + serverAbilityControlManager.registerComponent(AbilityKey.TEST_1, new TestHandlerMapping(), -1); Assert.assertEquals(1, serverAbilityControlManager.handlerMappingCount()); - serverAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); // nothing happens if it has enabled Assert.assertEquals(enabled, 1); - Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); // invoke disable() - serverAbilityControlManager.disableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.disableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); // disable will invoke handler Assert.assertEquals(enabled, 0); - Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - serverAbilityControlManager.disableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.disableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); // nothing to do because it has disable Assert.assertEquals(enabled, 0); - Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - serverAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); Assert.assertEquals(enabled, 1); - Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - serverAbilityControlManager.enableCurrentNodeAbility("stop-raft"); + serverAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); // wait for invoking handler asyn Thread.sleep(200L); Assert.assertEquals(enabled, 1); - Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); } @Test public void testClusterComponent() throws InterruptedException { clusterEnabled = 0; // invoke enable() because it turn on - serverAbilityControlManager.registerComponentForCluster("stop-raft", new ClusterHandlerMapping(), -1); + serverAbilityControlManager.registerComponentForCluster(AbilityKey.TEST_1, new ClusterHandlerMapping(), -1); Assert.assertEquals(1, serverAbilityControlManager.clusterHandlerMappingCount()); - Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); Assert.assertEquals(clusterEnabled, 1); - Map serverAbility = new HashMap<>(); - serverAbility.put("test-no-existed", true); - serverAbility.put("stop-raft", false); + Map serverAbility = new HashMap<>(); + serverAbility.put(AbilityKey.TEST_2, true); + serverAbility.put(AbilityKey.TEST_1, false); AbilityTable serverTable = new AbilityTable(); serverTable.setConnectionId("test-01111"); serverTable.setAbility(serverAbility); @@ -184,20 +186,20 @@ public void testClusterComponent() throws InterruptedException { Thread.sleep(200L); // disabled - Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); Assert.assertEquals(clusterEnabled, 0); // remove this table to enabled serverAbilityControlManager.removeTable("test-01111"); // wait for invoking handler asyn Thread.sleep(200L); - Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility("stop-raft")); + Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); Assert.assertEquals(clusterEnabled, 1); } @Test public void testCurrentNodeAbility() { - Set keySet = serverAbilityControlManager.getCurrentRunningAbility().keySet(); + Set keySet = serverAbilityControlManager.getCurrentRunningAbility().keySet(); // diable all keySet.forEach(key -> serverAbilityControlManager.disableCurrentNodeAbility(key)); // get all @@ -215,7 +217,7 @@ public void testCurrentNodeAbility() { @Test public void testPriority() throws InterruptedException { TestServerAbilityControlManager testServerAbilityControlManager = new TestServerAbilityControlManager(); - String key = "key"; + AbilityKey key = AbilityKey.TEST_1; TestPriority clusterHandlerMapping1 = new TestPriority("1"); TestPriority clusterHandlerMapping2 = new TestPriority("2"); TestPriority clusterHandlerMapping3 = new TestPriority("3"); diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java index 5e9fc089923..e506e295254 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.test.ability; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.client.ability.ClientAbilityControlManager; import com.alibaba.nacos.common.JustForTest; @@ -24,7 +25,7 @@ public class TestClientAbilityControlManager extends ClientAbilityControlManager { @JustForTest - public void setCurrentSupportingAbility(Map ability) { + public void setCurrentSupportingAbility(Map ability) { currentRunningAbility.putAll(ability); } } diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java index 2c48bc82112..3571c6060f9 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.test.ability; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import com.alibaba.nacos.core.ability.control.ServerAbilityControlManager; @@ -27,12 +28,12 @@ public class TestServerAbilityControlManager extends ServerAbilityControlManager { @JustForTest - public void setCurrentSupportingAbility(Map ability) { + public void setCurrentSupportingAbility(Map ability) { currentRunningAbility.putAll(ability); } @JustForTest - public void setClusterAbility(Map ability) { + public void setClusterAbility(Map ability) { super.setClusterAbilityTable(ability); } @@ -42,7 +43,7 @@ public int handlerMappingCount() { } @JustForTest - public List getHandlerMapping(String abilityKey) { + public List getHandlerMapping(AbilityKey abilityKey) { return super.handlerMapping().get(abilityKey); } @@ -52,7 +53,7 @@ public int clusterHandlerMappingCount() { } @JustForTest - public List getClusterHandlerMapping(String abilityKey) { + public List getClusterHandlerMapping(AbilityKey abilityKey) { return super.clusterHandlerMapping().get(abilityKey); } @@ -60,19 +61,19 @@ public List getClusterHandlerMapping(String abilityKey) { * Just a test method. */ @JustForTest - public void registerClusterHandlerMapping(String key, HandlerMapping handlerMapping, int priority) { + public void registerClusterHandlerMapping(AbilityKey key, HandlerMapping handlerMapping, int priority) { List orDefault = super.clusterHandlerMapping().getOrDefault(key, new ArrayList<>()); orDefault.add(new HandlerWithPriority(handlerMapping, priority)); clusterHandlerMapping().put(key, orDefault); } @JustForTest - public void triggerCluster(String abilityKey) { + public void triggerCluster(AbilityKey abilityKey) { triggerHandlerMappingAsyn(abilityKey, true, clusterHandlerMapping()); } @JustForTest - public void trigger(String abilityKey) { + public void trigger(AbilityKey abilityKey) { triggerHandlerMappingAsyn(abilityKey, true, handlerMapping()); } } From 41d278d6f1db8aa2e08f88944e37aee0099ab379 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Thu, 1 Sep 2022 20:31:48 +0800 Subject: [PATCH 018/181] Add junit test --- .../api/utils/AbilityTableUtilsTest.java | 118 +++++++++++ .../ability/AbilityControlManagerTest.java | 189 ++++++++++++++++++ .../TestClientAbilityControlManager.java | 19 +- .../ability/AbilityControlManagerTest.java | 20 +- .../TestServerAbilityControlManager.java | 2 +- 5 files changed, 334 insertions(+), 14 deletions(-) create mode 100644 api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java create mode 100644 client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java rename {test/core-test/src/test/java/com/alibaba/nacos/test => client/src/test/java/com/alibaba/nacos/client}/ability/TestClientAbilityControlManager.java (66%) rename {test/core-test/src/test/java/com/alibaba/nacos/test => core/src/test/java/com/alibaba/nacos/core}/ability/AbilityControlManagerTest.java (95%) rename {test/core-test/src/test/java/com/alibaba/nacos/test => core/src/test/java/com/alibaba/nacos/core}/ability/TestServerAbilityControlManager.java (98%) diff --git a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java new file mode 100644 index 00000000000..8d3e6ce3276 --- /dev/null +++ b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 1999-2022 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; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class AbilityTableUtilsTest { + + @Test + public void testGetAbilityBitBy() { + byte[] abilityBitBy = AbilityTableUtils.getAbilityBitBy(Arrays.asList(1, 8, 9, 17)); + Assert.assertEquals(abilityBitBy[0], -127); + Assert.assertEquals(abilityBitBy[1], -128); + Assert.assertEquals(abilityBitBy[2], -128); + // clear + byte[] abilityBits = AbilityTableUtils.getAbilityBitBy(Collections.emptyList()); + Assert.assertEquals(abilityBits.length , 1); + Assert.assertEquals(abilityBits[0] , 0); + } + + @Test + public void testGetAbilityTableBy() { + byte[] bytes = new byte[]{0}; + Map abilityTableBy = + AbilityTableUtils.getAbilityTableBy(bytes, AbilityKey.offset()); + Assert.assertEquals(abilityTableBy.getOrDefault(AbilityKey.TEST_1, false), false); + Assert.assertEquals(abilityTableBy.getOrDefault(AbilityKey.TEST_2, false), false); + + byte[] bytes1 = new byte[]{-64}; + Map abilityTableBy1 = + AbilityTableUtils.getAbilityTableBy(bytes1, AbilityKey.offset()); + Assert.assertEquals(abilityTableBy1.get(AbilityKey.TEST_1), true); + Assert.assertEquals(abilityTableBy1.get(AbilityKey.TEST_2), true); + + byte[] bytes2 = new byte[]{-128}; + Map abilityTableBy2 = + AbilityTableUtils.getAbilityTableBy(bytes2, AbilityKey.offset()); + Assert.assertEquals(abilityTableBy2.getOrDefault(AbilityKey.TEST_1, false), true); + Assert.assertEquals(abilityTableBy2.getOrDefault(AbilityKey.TEST_2, false), false); + + byte[] bytes3 = new byte[]{64}; + Map abilityTableBy3 = + AbilityTableUtils.getAbilityTableBy(bytes3, AbilityKey.offset()); + Assert.assertEquals(abilityTableBy3.getOrDefault(AbilityKey.TEST_1, false), false); + Assert.assertEquals(abilityTableBy3.getOrDefault(AbilityKey.TEST_2, false), true); + } + + @Test + public void testGetAbilityBiTableBy() { + Map map = new HashMap<>(); + byte[] bytes1 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map); + Assert.assertEquals(1, bytes1.length); + Assert.assertEquals(bytes1[0], 0); + + map.put(AbilityKey.TEST_1, true); + byte[] bytes2 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map); + Assert.assertEquals(1, bytes1.length); + Assert.assertEquals(bytes2[0], -128); + + map.put(AbilityKey.TEST_1, false); + map.put(AbilityKey.TEST_2, true); + byte[] bytes3 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map); + Assert.assertEquals(1, bytes3.length); + Assert.assertEquals(bytes3[0], 64); + + map.put(AbilityKey.TEST_1, true); + byte[] bytes4 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map); + Assert.assertEquals(1, bytes4.length); + Assert.assertEquals(bytes4[0], -64); + } + + @Test + public void testGetAbilityBiTable() { + Map offset = AbilityKey.offset(); + Map abilities = new HashMap<>(); + byte[] bytes1 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities); + Assert.assertEquals(1, bytes1.length); + Assert.assertEquals(bytes1[0], 0); + + abilities.put(AbilityKey.TEST_1, true); + byte[] bytes2 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities); + Assert.assertEquals(1, bytes2.length); + Assert.assertEquals(bytes2[0], -128); + + abilities.put(AbilityKey.TEST_2, true); + byte[] bytes3 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities); + Assert.assertEquals(1, bytes3.length); + Assert.assertEquals(bytes3[0], -64); + + offset = new HashMap<>(); + offset.put(AbilityKey.TEST_1, 2); + byte[] bytes4 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities); + Assert.assertEquals(1, bytes4.length); + Assert.assertEquals(bytes4[0], 64); + } + +} diff --git a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java new file mode 100644 index 00000000000..b60abf7ff16 --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java @@ -0,0 +1,189 @@ +/* + * Copyright 1999-2022 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.ability; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; +import com.alibaba.nacos.api.ability.entity.AbilityTable; +import com.alibaba.nacos.common.ability.handler.HandlerMapping; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +public class AbilityControlManagerTest { + + private TestClientAbilityControlManager clientAbilityControlManager = new TestClientAbilityControlManager(); + + private volatile int enabled = 0; + + private volatile LinkedList testPriority = new LinkedList<>(); + + @Before + public void inject() { + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_1, true); + clientAbilityControlManager.setCurrentSupportingAbility(newTable); + } + + @Test + public void testClientAdd() { + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_2, true); + newTable.put(AbilityKey.TEST_1, true); + AbilityTable table = new AbilityTable(); + table.setConnectionId("test-00001"); + table.setAbility(newTable); + table.setServer(true); + clientAbilityControlManager.addNewTable(table); + Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); + Assert.assertEquals(AbilityStatus.SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); + } + + @Test + public void testClientRemove() { + Map clientTa = new HashMap<>(); + clientTa.put(AbilityKey.TEST_2, true); + clientTa.put(AbilityKey.TEST_1, false); + AbilityTable clientTable = new AbilityTable(); + clientTable.setConnectionId("test-01111"); + clientTable.setAbility(clientTa); + clientTable.setServer(true); + clientAbilityControlManager.addNewTable(clientTable); + Assert.assertTrue(clientAbilityControlManager.contains(clientTable.getConnectionId())); + clientAbilityControlManager.removeTable("test-01111"); + Assert.assertFalse(clientAbilityControlManager.contains(clientTable.getConnectionId())); + } + + @Test + public void testComponent() throws InterruptedException { + enabled = 0; + // invoke enable() or disable() when registering + clientAbilityControlManager.registerComponent(AbilityKey.TEST_1, new TestHandlerMapping(), -1); + Assert.assertEquals(1, clientAbilityControlManager.handlerMappingCount()); + + clientAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); + // wait for invoking handler asyn + Thread.sleep(200L); + // nothing happens if it has enabled + Assert.assertEquals(enabled, 1); + Assert.assertTrue(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + + // invoke disable() + clientAbilityControlManager.disableCurrentNodeAbility(AbilityKey.TEST_1); + // wait for invoking handler asyn + Thread.sleep(200L); + // disable will invoke handler + Assert.assertEquals(enabled, 0); + Assert.assertFalse(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + + clientAbilityControlManager.disableCurrentNodeAbility(AbilityKey.TEST_1); + // wait for invoking handler asyn + Thread.sleep(200L); + // nothing to do because it has disable + Assert.assertEquals(enabled, 0); + Assert.assertFalse(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + + clientAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); + // wait for invoking handler asyn + Thread.sleep(200L); + Assert.assertEquals(enabled, 1); + Assert.assertTrue(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + + clientAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); + // wait for invoking handler asyn + Thread.sleep(200L); + Assert.assertEquals(enabled, 1); + Assert.assertTrue(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + } + + @Test + public void testPriority() throws InterruptedException { + TestClientAbilityControlManager testClientAbilityControlManager = new TestClientAbilityControlManager(); + AbilityKey key = AbilityKey.TEST_1; + TestPriority clusterHandlerMapping1 = new TestPriority("1"); + TestPriority clusterHandlerMapping2 = new TestPriority("2"); + TestPriority clusterHandlerMapping3 = new TestPriority("3"); + // first one, invoke enable() + testClientAbilityControlManager.registerComponent(key, clusterHandlerMapping2, 128); + // last one, invoke enable() + testClientAbilityControlManager.registerComponent(key, clusterHandlerMapping3); + // second one, invoke enable() + testClientAbilityControlManager.registerComponent(key, clusterHandlerMapping1, 12); + // trigger cluster + testClientAbilityControlManager.trigger(key); + Assert.assertEquals(3, testClientAbilityControlManager.getHandlerMapping(key).size()); + // wait for invoking + Thread.sleep(200L); + Assert.assertEquals("2", testPriority.poll()); + Assert.assertEquals("3", testPriority.poll()); + Assert.assertEquals("1", testPriority.poll()); + // here are priority + Assert.assertEquals("2", testPriority.poll()); + Assert.assertEquals("1", testPriority.poll()); + Assert.assertEquals("3", testPriority.poll()); + + // remove + testClientAbilityControlManager.registerComponent(key, new TestHandlerMapping(), -1); + Assert.assertEquals(4, testClientAbilityControlManager.getHandlerMapping(key).size()); + Assert.assertEquals(1, testClientAbilityControlManager.removeComponent(key, TestHandlerMapping.class)); + Assert.assertEquals(3, testClientAbilityControlManager.getHandlerMapping(key).size()); + testClientAbilityControlManager.removeAll(key); + Assert.assertNull(testClientAbilityControlManager.getHandlerMapping(key)); + } + + class TestPriority implements HandlerMapping { + + String mark; + + public TestPriority(String mark) { + // unique one + this.mark = mark.intern(); + } + + @Override + public void enable() { + testPriority.offer(mark); + } + + @Override + public void disable() { + testPriority.offer(mark); + } + } + + + class TestHandlerMapping implements HandlerMapping { + + @Override + public void enable() { + enabled++; + } + + @Override + public void disable() { + enabled--; + } + + } + +} + + diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java b/client/src/test/java/com/alibaba/nacos/client/ability/TestClientAbilityControlManager.java similarity index 66% rename from test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java rename to client/src/test/java/com/alibaba/nacos/client/ability/TestClientAbilityControlManager.java index e506e295254..df52b85f3ea 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestClientAbilityControlManager.java +++ b/client/src/test/java/com/alibaba/nacos/client/ability/TestClientAbilityControlManager.java @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.alibaba.nacos.test.ability; +package com.alibaba.nacos.client.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.client.ability.ClientAbilityControlManager; import com.alibaba.nacos.common.JustForTest; +import java.util.List; import java.util.Map; public class TestClientAbilityControlManager extends ClientAbilityControlManager { @@ -28,4 +28,19 @@ public class TestClientAbilityControlManager extends ClientAbilityControlManager public void setCurrentSupportingAbility(Map ability) { currentRunningAbility.putAll(ability); } + + @JustForTest + public int handlerMappingCount() { + return super.handlerMapping().size(); + } + + @JustForTest + public List getHandlerMapping(AbilityKey abilityKey) { + return super.handlerMapping().get(abilityKey); + } + + @JustForTest + public void trigger(AbilityKey abilityKey) { + triggerHandlerMappingAsyn(abilityKey, true, handlerMapping()); + } } diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java similarity index 95% rename from test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java rename to core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java index 038cd0f8294..cd9d062c622 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityControlManagerTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.alibaba.nacos.test.ability; +package com.alibaba.nacos.core.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.constant.AbilityStatus; @@ -33,8 +33,6 @@ @SpringBootTest public class AbilityControlManagerTest { - private TestClientAbilityControlManager clientAbilityControlManager = new TestClientAbilityControlManager(); - private TestServerAbilityControlManager serverAbilityControlManager = new TestServerAbilityControlManager(); private volatile int clusterEnabled = 0; @@ -47,7 +45,7 @@ public class AbilityControlManagerTest { public void inject() { Map newTable = new HashMap<>(); newTable.put(AbilityKey.TEST_1, true); - clientAbilityControlManager.setCurrentSupportingAbility(newTable); + serverAbilityControlManager.setCurrentSupportingAbility(newTable); Map table = new HashMap<>(); table.put(AbilityKey.TEST_1, true); @@ -68,9 +66,9 @@ public void testClientAdd() { table.setConnectionId("test-00001"); table.setAbility(newTable); table.setServer(true); - clientAbilityControlManager.addNewTable(table); - Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); - Assert.assertEquals(AbilityStatus.SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); + serverAbilityControlManager.addNewTable(table); + Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); + Assert.assertEquals(AbilityStatus.SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); } @Test @@ -117,10 +115,10 @@ public void testClientRemove() { clientTable.setConnectionId("test-01111"); clientTable.setAbility(clientTa); clientTable.setServer(true); - clientAbilityControlManager.addNewTable(clientTable); - Assert.assertTrue(clientAbilityControlManager.contains(clientTable.getConnectionId())); - clientAbilityControlManager.removeTable("test-01111"); - Assert.assertFalse(clientAbilityControlManager.contains(clientTable.getConnectionId())); + serverAbilityControlManager.addNewTable(clientTable); + Assert.assertTrue(serverAbilityControlManager.contains(clientTable.getConnectionId())); + serverAbilityControlManager.removeTable("test-01111"); + Assert.assertFalse(serverAbilityControlManager.contains(clientTable.getConnectionId())); } @Test diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java similarity index 98% rename from test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java rename to core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java index 3571c6060f9..e5d7a002bca 100644 --- a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/TestServerAbilityControlManager.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.alibaba.nacos.test.ability; +package com.alibaba.nacos.core.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.common.JustForTest; From 182b821938d322a4b75d12ec3d1984cc97c60d31 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Fri, 2 Sep 2022 21:56:03 +0800 Subject: [PATCH 019/181] Remove the component listening to cluster ability, disable the cluster capability table when the connected server does not support capability negotiation. --- .../register/AbstractAbilityRegistry.java | 2 +- .../register/impl/ClientAbilities.java | 4 +- .../register/impl/ServerAbilities.java | 4 +- .../nacos/api/utils/AbilityTableUtils.java | 4 +- .../api/utils/AbilityTableUtilsTest.java | 4 +- .../ability/AbilityControlManagerTest.java | 1 - .../AbstractAbilityControlManager.java | 27 ++- .../common/remote/client/grpc/GrpcClient.java | 13 +- .../control/ServerAbilityControlManager.java | 76 +++------ .../inte/ClusterAbilityControlSupport.java | 41 +---- .../grpc/GrpcBiStreamRequestAcceptor.java | 7 +- .../ability/AbilityControlManagerTest.java | 160 +++--------------- .../TestServerAbilityControlManager.java | 37 +--- 13 files changed, 83 insertions(+), 297 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java index 4ad0df43d32..60be843faea 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java @@ -51,7 +51,7 @@ protected void init() { abilityBitFlag = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), supportedAbilities); } - /** + /**. * get static ability current server supports * * @return static ability diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java index c4ec32be5a0..39a4f7232cb 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java @@ -61,12 +61,12 @@ public static byte[] getBitFlags() { return INSTANCE.getAbilityBitFlags(); } - /** + /**. * get static ability current server supports * * @return static ability */ - public static Map getStaticAbilities(){ + public static Map getStaticAbilities() { return INSTANCE.getSupportedAbilities(); } } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java index bd01a53b8bd..ca5fecdef74 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java @@ -61,12 +61,12 @@ public static byte[] getBitFlags() { return INSTANCE.getAbilityBitFlags(); } - /** + /**. * get static ability current server supports * * @return static ability */ - public static Map getStaticAbilities(){ + public static Map getStaticAbilities() { return INSTANCE.getSupportedAbilities(); } diff --git a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java index fe75aab2c36..d995870758a 100644 --- a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java +++ b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java @@ -116,12 +116,12 @@ public static byte[] getAbilityBiTableBy(Map offsetMap, Map return getAbilityBitBy(res.values()); } - /** + /**. * get ability bit table by existed ability table and abilityKeys array * * @param abilityKeys abilityKeys array * @param abilityTable existed ability table - * @return filter ability which value is false in abilityTable + * @return filter ability which value is false in abilityTable */ public static byte[] getAbilityBiTableBy(AbilityKey[] abilityKeys, Map abilityTable) { // filter the element which abilityTable don't have or value is false diff --git a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java index 8d3e6ce3276..bbd2ce77047 100644 --- a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java +++ b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java @@ -35,8 +35,8 @@ public void testGetAbilityBitBy() { Assert.assertEquals(abilityBitBy[2], -128); // clear byte[] abilityBits = AbilityTableUtils.getAbilityBitBy(Collections.emptyList()); - Assert.assertEquals(abilityBits.length , 1); - Assert.assertEquals(abilityBits[0] , 0); + Assert.assertEquals(abilityBits.length, 1); + Assert.assertEquals(abilityBits[0], 0); } @Test diff --git a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java index b60abf7ff16..c18cbaf7547 100644 --- a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java @@ -169,7 +169,6 @@ public void disable() { } } - class TestHandlerMapping implements HandlerMapping { @Override diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 96c5e1c45e4..66d4c8f7e97 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -117,15 +117,18 @@ public final void addNewTable(AbilityTable table) { } // hook method add(table); - // add to node - Set abilityKeys = table.getAbility().keySet(); + // null if not support ability table Map clientAbilities = table.getAbility(); - abilityKeys.forEach(abilityKey -> { - Boolean res = currentRunningAbility.getOrDefault(abilityKey, false); - Boolean coming = clientAbilities.getOrDefault(abilityKey, false); - clientAbilities.put(abilityKey, res && coming); - }); - nodeAbilityTable.put(connectionId, table); + if (clientAbilities != null) { + // add to nod + Set abilityKeys = table.getAbility().keySet(); + abilityKeys.forEach(abilityKey -> { + Boolean res = currentRunningAbility.getOrDefault(abilityKey, false); + Boolean coming = clientAbilities.getOrDefault(abilityKey, false); + clientAbilities.put(abilityKey, res && coming); + }); + nodeAbilityTable.put(connectionId, table); + } } finally { lockForAbilityTable.unlock(); } @@ -143,17 +146,9 @@ public final void addNewTable(AbilityTable table) { */ @Override public final void removeTable(String connectionId) { - // if not exists - if(connectionId == null || !nodeAbilityTable.containsKey(connectionId)){ - return; - } AbilityTable removingTable = null; lockForAbilityTable.lock(); try { - // check - if (!nodeAbilityTable.containsKey(connectionId)) { - return; - } // hook method remove(connectionId); // remove diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 7519de40f17..73ae05692c7 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -18,7 +18,6 @@ import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.entity.AbilityTable; -import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -48,7 +47,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Arrays; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -319,12 +317,15 @@ public Connection connectToServer(ServerInfo serverInfo) { // submit ability table as soon as possible // ability table will be null if server doesn't support ability table ServerCheckResponse serverCheckResponse = (ServerCheckResponse) response; - Map abilityTable = AbilityTableUtils - .getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset()); AbilityTable table = new AbilityTable(); table.setServer(true) - .setConnectionId(serverCheckResponse.getConnectionId()) - .setAbility(abilityTable); + .setConnectionId(serverCheckResponse.getConnectionId()); + // if not supported, it will be null + if (serverCheckResponse.getAbilities() != null) { + Map abilityTable = AbilityTableUtils + .getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset()); + table.setAbility(abilityTable); + } NacosAbilityManagerHolder.getInstance().addNewTable(table); BiRequestStreamGrpc.BiRequestStreamStub biRequestStreamStub = BiRequestStreamGrpc diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 825faa807c1..12ddc7885b6 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -23,21 +23,16 @@ import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; -import com.alibaba.nacos.common.ability.handler.HandlerMapping; import com.alibaba.nacos.common.notify.NotifyCenter; +import com.alibaba.nacos.common.utils.ConcurrentHashSet; import com.alibaba.nacos.common.utils.MapUtil; import com.alibaba.nacos.core.ability.inte.ClusterAbilityControlSupport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; /**. * @author Daydreamer @@ -46,8 +41,6 @@ **/ public class ServerAbilityControlManager extends DefaultAbilityControlManager implements ClusterAbilityControlSupport { - private static final Logger LOGGER = LoggerFactory.getLogger(ServerAbilityControlManager.class); - /**. * ability for cluster */ @@ -57,13 +50,11 @@ public class ServerAbilityControlManager extends DefaultAbilityControlManager im * ability for server */ private final Map serversAbilityTable = new ConcurrentHashMap<>(); - - /** - * components for cluster. these will be invoked if cluster ability table changes. - */ - private final Map> clusterHandlerMapping = new ConcurrentHashMap<>(); - private Lock lockForClusterComponents = new ReentrantLock(); + /**. + * Number of servers that do not support capability negotiation + */ + private final ConcurrentHashSet serverNoAbilityNegotiation = new ConcurrentHashSet<>(); public ServerAbilityControlManager() { // add current node into @@ -92,14 +83,17 @@ public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { } /**. - * Whether current cluster supports ability + * Whether all the servers currently connected support a certain capability * * @param abilityKey ability key * @return whether it is turn on */ @Override - public boolean isClusterEnableAbility(AbilityKey abilityKey) { - return clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE); + public AbilityStatus isClusterEnableAbilityNow(AbilityKey abilityKey) { + if (serverNoAbilityNegotiation.size() > 0) { + return AbilityStatus.UNKNOWN; + } + return clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; } @Override @@ -107,29 +101,6 @@ public Map getClusterAbility() { return Collections.unmodifiableMap(clusterAbilityTable); } - /**. - * Register components for cluster. These will be trigger when its interested ability changes - * - * @param abilityKey ability key - * @param priority the higher the priority, the faster it will be called - * @param handlerMapping component - */ - @Override - public void registerComponentForCluster(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority) { - doRegisterComponent(abilityKey, handlerMapping, this.clusterHandlerMapping, lockForClusterComponents, priority, clusterAbilityTable); - } - - @Override - public int removeClusterComponent(AbilityKey abilityKey, Class handlerMappingClazz) { - return doRemove(abilityKey, handlerMappingClazz, lockForClusterComponents, clusterHandlerMapping); - } - - @Override - public int removeAllForCluster(AbilityKey abilityKey) { - List remove = this.clusterHandlerMapping.remove(abilityKey); - return Optional.ofNullable(remove).orElse(Collections.emptyList()).size(); - } - @Override protected void add(AbilityTable table) { // from which env @@ -148,13 +119,15 @@ protected void add(AbilityTable table) { Boolean newRes = val && isEnabled; // if ability changes if (!newRes.equals(isEnabled)) { - triggerHandlerMappingAsyn(abilityKey, false, this.clusterHandlerMapping); clusterAbilityTable.replace(abilityKey, false); // notify NotifyCenter.publishEvent(buildClusterEvent(abilityKey, false)); } }); } + } else if (isServer && table.getAbility() == null) { + // add mark if server doesn't support ability table + serverNoAbilityNegotiation.add(table.getConnectionId()); } } @@ -171,13 +144,15 @@ private ClusterAbilityUpdateEvent buildClusterEvent(AbilityKey abilityKey, boole protected void remove(String connectionId) { // from which AbilityTable abilityTable = nodeAbilityTable.get(connectionId); + // if not support + serverNoAbilityNegotiation.remove(connectionId); // return if null if (abilityTable == null) { return; } // from which env if (abilityTable.isServer()) { - // remove from server ability collection + // remove from server ability collection if support serversAbilityTable.remove(connectionId); // remove from cluster if (MapUtil.isNotEmpty(serversAbilityTable)) { @@ -198,7 +173,6 @@ protected void remove(String connectionId) { clusterAbilityTable.replace(abilityKey, newVal); // if change if (!isEnabled.equals(newVal)) { - triggerHandlerMappingAsyn(abilityKey, newVal, this.clusterHandlerMapping); // notify NotifyCenter.publishEvent(buildClusterEvent(abilityKey, newVal)); } @@ -207,16 +181,6 @@ protected void remove(String connectionId) { } } - @Override - protected void doDestroy() { - if (MapUtil.isNotEmpty(clusterHandlerMapping)) { - if (MapUtil.isNotEmpty(clusterHandlerMapping)) { - clusterHandlerMapping.keySet().forEach(key -> doTriggerSyn(key, false, clusterHandlerMapping)); - } - } - LOGGER.warn("[ServerAbilityControlManager] - Destruction of the end"); - } - /**. * notify when current node ability changing */ @@ -252,10 +216,10 @@ public void setOn(boolean on) { protected void setClusterAbilityTable(Map map) { clusterAbilityTable.putAll(map); } - + @JustForTest - protected Map> clusterHandlerMapping() { - return this.clusterHandlerMapping; + protected Set serverNotSupport() { + return serverNoAbilityNegotiation; } } diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java index 9b989a07840..71f32488f71 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java @@ -17,7 +17,7 @@ package com.alibaba.nacos.core.ability.inte; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.common.ability.handler.HandlerMapping; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.common.ability.inter.AbilityControlManager; import java.util.Map; @@ -37,45 +37,10 @@ public interface ClusterAbilityControlSupport { Map getClusterAbility(); /**. - * Register components for cluster. These will be trigger when its interested ability changes - * - * @param abilityKey ability key - * @param priority a positive number, the higher the priority, the faster it will be called - * @param handlerMapping component - */ - void registerComponentForCluster(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority); - - /**. - * Default method to register component - * - * @param abilityKey component key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. - * @param handlerMapping component instance. - */ - default void registerComponentForCluster(AbilityKey abilityKey, HandlerMapping handlerMapping) { - registerComponentForCluster(abilityKey, handlerMapping, 1); - } - - /** - * Remove the component instance of

handlerMappingClazz

. - * - * @param abilityKey ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. - * @param handlerMappingClazz implement of {@link HandlerMapping} - * @return the count of components have removed - */ - int removeClusterComponent(AbilityKey abilityKey, Class handlerMappingClazz); - - /** - * Remove all {@link HandlerMapping} interested in the special ability. - * @param abilityKey abnility key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey}. - * @return the count of components have removed - */ - int removeAllForCluster(AbilityKey abilityKey); - - /**. - * Whether current cluster supports ability + * Whether all the servers currently connected support a certain capability * * @param abilityKey ability key * @return whether it is turn on */ - boolean isClusterEnableAbility(AbilityKey abilityKey); + AbilityStatus isClusterEnableAbilityNow(AbilityKey abilityKey); } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index b8cf7508bb7..4a550d80b2e 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -122,8 +122,11 @@ public void onNext(Payload payload) { setUpRequest.getClientVersion(), appName, setUpRequest.getLabels()); metaInfo.setTenant(setUpRequest.getTenant()); Connection connection = new GrpcConnection(metaInfo, responseObserver, CONTEXT_KEY_CHANNEL.get()); - connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), - AbilityKey.offset())); + // null if supported + if (setUpRequest.getAbilityTable() != null) { + connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), + AbilityKey.offset())); + } boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); if (rejectSdkOnStarting || !connectionManager.register(connectionId, connection)) { diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java index cd9d062c622..b15dce4c7a5 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java @@ -26,7 +26,6 @@ import org.springframework.boot.test.context.SpringBootTest; import java.util.HashMap; -import java.util.LinkedList; import java.util.Map; import java.util.Set; @@ -35,11 +34,7 @@ public class AbilityControlManagerTest { private TestServerAbilityControlManager serverAbilityControlManager = new TestServerAbilityControlManager(); - private volatile int clusterEnabled = 0; - private volatile int enabled = 0; - - private volatile LinkedList testPriority = new LinkedList<>(); @Before public void inject() { @@ -83,7 +78,6 @@ public void testServerAdd() { serverAbilityControlManager.addNewTable(table); Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); Assert.assertEquals(AbilityStatus.SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); - Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); Map otherServer = new HashMap<>(); otherServer.put(AbilityKey.TEST_2, true); @@ -93,7 +87,6 @@ public void testServerAdd() { otherServerTable.setAbility(otherServer); otherServerTable.setServer(true); serverAbilityControlManager.addNewTable(otherServerTable); - Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); Map clientTa = new HashMap<>(); clientTa.put(AbilityKey.TEST_2, true); @@ -103,7 +96,31 @@ public void testServerAdd() { clientTable.setAbility(clientTa); clientTable.setServer(false); serverAbilityControlManager.addNewTable(clientTable); - Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); + + // if not support + AbilityTable serverTable = new AbilityTable(); + serverTable.setConnectionId("test-001231"); + serverTable.setServer(true); + serverAbilityControlManager.addNewTable(serverTable); + // unknown because not support + Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); + Assert.assertEquals(serverAbilityControlManager.getServerNotSupportAbility().size(), 1); + Assert.assertTrue(serverAbilityControlManager.getServerNotSupportAbility().contains("test-001231")); + + AbilityTable serverTable1 = new AbilityTable(); + serverTable1.setConnectionId("test-001231231"); + serverTable1.setServer(true); + serverAbilityControlManager.addNewTable(serverTable1); + // unknown because not support + Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); + Assert.assertEquals(serverAbilityControlManager.getServerNotSupportAbility().size(), 2); + Assert.assertTrue(serverAbilityControlManager.getServerNotSupportAbility().contains("test-001231231")); + + // remove then support + serverAbilityControlManager.removeTable("test-001231"); + Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); + serverAbilityControlManager.removeTable("test-001231231"); + Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.NOT_SUPPORTED); } @Test @@ -162,38 +179,6 @@ public void testComponent() throws InterruptedException { Assert.assertEquals(enabled, 1); Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); } - - @Test - public void testClusterComponent() throws InterruptedException { - clusterEnabled = 0; - // invoke enable() because it turn on - serverAbilityControlManager.registerComponentForCluster(AbilityKey.TEST_1, new ClusterHandlerMapping(), -1); - Assert.assertEquals(1, serverAbilityControlManager.clusterHandlerMappingCount()); - Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); - Assert.assertEquals(clusterEnabled, 1); - - Map serverAbility = new HashMap<>(); - serverAbility.put(AbilityKey.TEST_2, true); - serverAbility.put(AbilityKey.TEST_1, false); - AbilityTable serverTable = new AbilityTable(); - serverTable.setConnectionId("test-01111"); - serverTable.setAbility(serverAbility); - serverTable.setServer(true); - serverAbilityControlManager.addNewTable(serverTable); - // wait for invoking handler asyn - Thread.sleep(200L); - - // disabled - Assert.assertFalse(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); - Assert.assertEquals(clusterEnabled, 0); - - // remove this table to enabled - serverAbilityControlManager.removeTable("test-01111"); - // wait for invoking handler asyn - Thread.sleep(200L); - Assert.assertTrue(serverAbilityControlManager.isClusterEnableAbility(AbilityKey.TEST_1)); - Assert.assertEquals(clusterEnabled, 1); - } @Test public void testCurrentNodeAbility() { @@ -212,101 +197,6 @@ public void testCurrentNodeAbility() { }); } - @Test - public void testPriority() throws InterruptedException { - TestServerAbilityControlManager testServerAbilityControlManager = new TestServerAbilityControlManager(); - AbilityKey key = AbilityKey.TEST_1; - TestPriority clusterHandlerMapping1 = new TestPriority("1"); - TestPriority clusterHandlerMapping2 = new TestPriority("2"); - TestPriority clusterHandlerMapping3 = new TestPriority("3"); - // first one, invoke enable() - testServerAbilityControlManager.registerComponentForCluster(key, clusterHandlerMapping2, 128); - // last one, invoke enable() - testServerAbilityControlManager.registerComponentForCluster(key, clusterHandlerMapping3); - // second one, invoke enable() - testServerAbilityControlManager.registerComponentForCluster(key, clusterHandlerMapping1, 12); - // trigger cluster - testServerAbilityControlManager.triggerCluster(key); - Assert.assertEquals(3, testServerAbilityControlManager.getClusterHandlerMapping(key).size()); - // wait for invoking - Thread.sleep(200L); - Assert.assertEquals("2", testPriority.poll()); - Assert.assertEquals("3", testPriority.poll()); - Assert.assertEquals("1", testPriority.poll()); - // here are priority - Assert.assertEquals("2", testPriority.poll()); - Assert.assertEquals("1", testPriority.poll()); - Assert.assertEquals("3", testPriority.poll()); - // remove - testServerAbilityControlManager.registerClusterHandlerMapping(key, new ClusterHandlerMapping(), -1); - Assert.assertEquals(4, testServerAbilityControlManager.getClusterHandlerMapping(key).size()); - Assert.assertEquals(1, testServerAbilityControlManager.removeClusterComponent(key, ClusterHandlerMapping.class)); - Assert.assertEquals(3, testServerAbilityControlManager.getClusterHandlerMapping(key).size()); - testServerAbilityControlManager.removeAllForCluster(key); - Assert.assertNull(testServerAbilityControlManager.getClusterHandlerMapping(key)); - - // first one - testServerAbilityControlManager.registerComponent(key, clusterHandlerMapping2, 128); - // last one - testServerAbilityControlManager.registerComponent(key, clusterHandlerMapping3); - // second one - testServerAbilityControlManager.registerComponent(key, clusterHandlerMapping1, 12); - Assert.assertEquals(3, testServerAbilityControlManager.getHandlerMapping(key).size()); - // wait for invoking - Thread.sleep(200L); - // trigger - testServerAbilityControlManager.trigger(key); - // wait for invoking - Thread.sleep(200L); - Assert.assertEquals("2", testPriority.poll()); - Assert.assertEquals("3", testPriority.poll()); - Assert.assertEquals("1", testPriority.poll()); - // here are priority - Assert.assertEquals("2", testPriority.poll()); - Assert.assertEquals("1", testPriority.poll()); - Assert.assertEquals("3", testPriority.poll()); - // remove - testServerAbilityControlManager.registerComponent(key, new ClusterHandlerMapping(), -1); - Assert.assertEquals(4, testServerAbilityControlManager.getHandlerMapping(key).size()); - Assert.assertEquals(1, testServerAbilityControlManager.removeComponent(key, ClusterHandlerMapping.class)); - Assert.assertEquals(3, testServerAbilityControlManager.getHandlerMapping(key).size()); - testServerAbilityControlManager.removeAll(key); - Assert.assertNull(testServerAbilityControlManager.getClusterHandlerMapping(key)); - } - - class TestPriority implements HandlerMapping { - - String mark; - - public TestPriority(String mark) { - // unique one - this.mark = mark.intern(); - } - - @Override - public void enable() { - testPriority.offer(mark); - } - - @Override - public void disable() { - testPriority.offer(mark); - } - } - - class ClusterHandlerMapping implements HandlerMapping { - - @Override - public void enable() { - clusterEnabled++; - } - - @Override - public void disable() { - clusterEnabled--; - } - } - class TestHandlerMapping implements HandlerMapping { @Override diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java index e5d7a002bca..f53f9e1cd66 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java @@ -18,12 +18,10 @@ import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.common.JustForTest; -import com.alibaba.nacos.common.ability.handler.HandlerMapping; import com.alibaba.nacos.core.ability.control.ServerAbilityControlManager; -import java.util.ArrayList; -import java.util.List; import java.util.Map; +import java.util.Set; public class TestServerAbilityControlManager extends ServerAbilityControlManager { @@ -43,37 +41,8 @@ public int handlerMappingCount() { } @JustForTest - public List getHandlerMapping(AbilityKey abilityKey) { - return super.handlerMapping().get(abilityKey); - } - - @JustForTest - public int clusterHandlerMappingCount() { - return super.clusterHandlerMapping().size(); - } - - @JustForTest - public List getClusterHandlerMapping(AbilityKey abilityKey) { - return super.clusterHandlerMapping().get(abilityKey); - } - - /** - * Just a test method. - */ - @JustForTest - public void registerClusterHandlerMapping(AbilityKey key, HandlerMapping handlerMapping, int priority) { - List orDefault = super.clusterHandlerMapping().getOrDefault(key, new ArrayList<>()); - orDefault.add(new HandlerWithPriority(handlerMapping, priority)); - clusterHandlerMapping().put(key, orDefault); + public Set getServerNotSupportAbility() { + return super.serverNotSupport(); } - @JustForTest - public void triggerCluster(AbilityKey abilityKey) { - triggerHandlerMappingAsyn(abilityKey, true, clusterHandlerMapping()); - } - - @JustForTest - public void trigger(AbilityKey abilityKey) { - triggerHandlerMappingAsyn(abilityKey, true, handlerMapping()); - } } From ac2523ab7de44e5cdabc27933ed65339dc6546a0 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 3 Sep 2022 14:11:55 +0800 Subject: [PATCH 020/181] Add the priority to AbilityControlManager. --- .../ability/ClientAbilityControlManager.java | 8 +++++++- ...common.ability.DefaultAbilityControlManager | 18 ++++++++++++++++++ common/pom.xml | 1 - .../ability/AbstractAbilityControlManager.java | 8 ++++++++ .../discover/NacosAbilityManagerHolder.java | 14 +++++++++----- .../control/ServerAbilityControlManager.java | 5 +++++ ...common.ability.DefaultAbilityControlManager | 1 - 7 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 client/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager rename {common => core}/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager (91%) diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index eef2427a54a..cd3e38f66a7 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -63,5 +63,11 @@ protected void add(AbilityTable table) { protected void remove(String connectionId) { // nothing to do } - + + @Override + public int getPriority() { + // if server ability manager exist, you should choose the server one + return 0; + } + } diff --git a/client/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager b/client/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager new file mode 100644 index 00000000000..6434f25b1df --- /dev/null +++ b/client/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager @@ -0,0 +1,18 @@ +# +# Copyright 1999-2022 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. +# +# + +com.alibaba.nacos.client.ability.ClientAbilityControlManager \ No newline at end of file diff --git a/common/pom.xml b/common/pom.xml index bda1fd571ab..b1c91f19d30 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -84,7 +84,6 @@ true nacos-version.txt - META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 66d4c8f7e97..7b523e9beb6 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -208,6 +208,14 @@ public void destroy() { // default destroy // nothing to do } + + /** + * A Nacos application can only have one {@link AbilityControlManager}. + * When multiple control centers exist, it is used to determine which one is preferred + * + * @return priority + */ + public abstract int getPriority(); /** * Return ability table of current node diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java b/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java index dc3fe479d00..668e96b9d77 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java @@ -24,7 +24,10 @@ import org.slf4j.LoggerFactory; import java.util.Collection; +import java.util.Comparator; +import java.util.List; import java.util.ServiceConfigurationError; +import java.util.stream.Collectors; /** * This class is used to discover {@link AbstractAbilityControlManager} implements. All the @@ -55,14 +58,15 @@ private NacosAbilityManagerHolder() { // if server load = NacosServiceLoader.load(DefaultAbilityControlManager.class); } catch (ServiceConfigurationError e) { - // if client or not ability control manager - load = NacosServiceLoader.load(DefaultAbilityControlManager.class); + throw new RuntimeException("[AbilityControlManager] Cannot find AbilityControlManger"); } // the priority of the server is higher + List collect = load.stream() + .sorted(Comparator.comparingInt(AbstractAbilityControlManager::getPriority)) + .collect(Collectors.toList()); + // get the highest priority one if (load.size() > 0) { - load.forEach(clazz -> { - abstractAbilityControlManager = clazz; - }); + abstractAbilityControlManager = collect.get(collect.size() - 1); LOGGER.info("[AbilityControlManager] Successfully initialize AbilityControlManager"); } } diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 12ddc7885b6..32d7ae97548 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -181,6 +181,11 @@ protected void remove(String connectionId) { } } + @Override + public int getPriority() { + return 1; + } + /**. * notify when current node ability changing */ diff --git a/common/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager b/core/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager similarity index 91% rename from common/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager rename to core/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager index c5e3caeac2d..f2545ddc3df 100644 --- a/common/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager +++ b/core/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager @@ -15,5 +15,4 @@ # # -com.alibaba.nacos.client.ability.ClientAbilityControlManager com.alibaba.nacos.core.ability.control.ServerAbilityControlManager \ No newline at end of file From 4de709cc0a51567caca3157bd5b56b6b8d1fafde Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 3 Sep 2022 14:27:41 +0800 Subject: [PATCH 021/181] Supports server change ability by editing config. --- .../core/ability/config/AbilityConfigs.java | 107 +++++++++++++++ .../ability/config/AbilityConfigsTest.java | 129 ++++++++++++++++++ .../ability/config/TestAbilityConfig.java | 19 +++ 3 files changed, 255 insertions(+) create mode 100644 core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java create mode 100644 core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java create mode 100644 core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java b/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java new file mode 100644 index 00000000000..084dc7f6ae8 --- /dev/null +++ b/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java @@ -0,0 +1,107 @@ +/* + * Copyright 1999-2022 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.core.ability.config; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; +import com.alibaba.nacos.common.JustForTest; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; +import com.alibaba.nacos.common.ability.inter.AbilityHandlerRegistry; +import com.alibaba.nacos.common.event.ServerConfigChangeEvent; +import com.alibaba.nacos.common.notify.Event; +import com.alibaba.nacos.common.notify.NotifyCenter; +import com.alibaba.nacos.common.notify.listener.Subscriber; +import com.alibaba.nacos.common.utils.ConcurrentHashSet; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Configuration; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/**. + * @author Daydreamer + * @description Dynamically load ability from config + * @date 2022/8/31 12:27 + **/ +@Configuration +public class AbilityConfigs extends Subscriber { + + public static final String PREFIX = "nacos.core.ability."; + + private static final Logger LOGGER = LoggerFactory.getLogger(AbilityConfigs.class); + + private final Set serverAbilityKeys = new ConcurrentHashSet<>(); + + private AbilityHandlerRegistry abilityHandlerRegistry = NacosAbilityManagerHolder.getInstance(); + + public AbilityConfigs() { + // load ability + serverAbilityKeys.addAll(ServerAbilities.getStaticAbilities().keySet()); + NotifyCenter.registerSubscriber(this); + } + + @Override + public void onEvent(ServerConfigChangeEvent event) { + // load config + Map newValues = new HashMap<>(serverAbilityKeys.size()); + serverAbilityKeys.forEach(abilityKey -> { + String key = PREFIX + abilityKey.getName(); + try { + // default true + Boolean property = EnvUtil.getProperty(key, Boolean.class, true); + newValues.put(abilityKey, property); + } catch (Exception e) { + LOGGER.warn("Update ability config from env failed, use old val, ability : {} , because : {}", key, e); + } + }); + // update + refresh(newValues); + } + + /**. + * refresh ability + */ + private void refresh(Map newValues) { + newValues.forEach((abilityKey, val) -> { + // do nothing if has turned on/off + if (val) { + abilityHandlerRegistry.enableCurrentNodeAbility(abilityKey); + } else { + abilityHandlerRegistry.disableCurrentNodeAbility(abilityKey); + } + }); + } + + @Override + public Class subscribeType() { + return ServerConfigChangeEvent.class; + } + + @JustForTest + protected Set getServerAbilityKeys() { + return serverAbilityKeys; + } + + @JustForTest + protected void setAbilityHandlerRegistry(AbilityHandlerRegistry abilityHandlerRegistry) { + this.abilityHandlerRegistry = abilityHandlerRegistry; + } + +} diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java new file mode 100644 index 00000000000..edb2fde21eb --- /dev/null +++ b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java @@ -0,0 +1,129 @@ +/* + * Copyright 1999-2022 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.core.ability.config; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.common.ability.handler.HandlerMapping; +import com.alibaba.nacos.common.event.ServerConfigChangeEvent; +import com.alibaba.nacos.core.ability.TestServerAbilityControlManager; +import com.alibaba.nacos.core.ability.control.ServerAbilityControlManager; +import com.alibaba.nacos.sys.env.EnvUtil; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.env.MockEnvironment; + +import java.util.HashMap; +import java.util.Map; + +/**. + * @author Daydreamer + * @description + * @date 2022/9/3 12:27 + **/ +public class AbilityConfigsTest { + + private MockEnvironment environment; + + private TestAbilityConfig abilityConfigs; + + private int tmp; + + private ServerAbilityControlManager serverAbilityControlManager; + + @Before + public void setUp() throws Exception { + environment = new MockEnvironment(); + EnvUtil.setEnvironment(environment); + abilityConfigs = new TestAbilityConfig(); + inject(abilityConfigs); + serverAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); + serverAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_2); + serverAbilityControlManager.registerComponent(AbilityKey.TEST_1, new TestHandler()); + serverAbilityControlManager.registerComponent(AbilityKey.TEST_2, new TestHandler()); + // tmp is 2 now + } + + void inject(AbilityConfigs abilityConfigs) { + TestServerAbilityControlManager serverAbilityControlManager = new TestServerAbilityControlManager(); + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_1, true); + newTable.put(AbilityKey.TEST_2, true); + serverAbilityControlManager.setCurrentSupportingAbility(newTable); + abilityConfigs.setAbilityHandlerRegistry(serverAbilityControlManager); + this.serverAbilityControlManager = serverAbilityControlManager; + } + + @Test + public void testInit() { + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_2)); + } + + @Test + public void testConfigChange() throws InterruptedException { + // test no change + environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_1.getName(), Boolean.TRUE.toString()); + environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_2.getName(), Boolean.TRUE.toString()); + abilityConfigs.onEvent(new ServerConfigChangeEvent()); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_2)); + //wait for invoke + Thread.sleep(100); + Assert.assertEquals(tmp, 2); + + // test change + environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_1.getName(), Boolean.FALSE.toString()); + abilityConfigs.onEvent(new ServerConfigChangeEvent()); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_2)); + //wait for invoke + Thread.sleep(100); + Assert.assertEquals(tmp, 1); + + environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_1.getName(), Boolean.TRUE.toString()); + abilityConfigs.onEvent(new ServerConfigChangeEvent()); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + //wait for invoke + Thread.sleep(100); + Assert.assertEquals(tmp, 2); + + environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_1.getName(), Boolean.FALSE.toString()); + environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_2.getName(), Boolean.FALSE.toString()); + abilityConfigs.onEvent(new ServerConfigChangeEvent()); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_2)); + //wait for invoke + Thread.sleep(100); + Assert.assertEquals(tmp, 0); + } + + + class TestHandler implements HandlerMapping { + + @Override + public void enable() { + tmp++; + } + + @Override + public void disable() { + tmp--; + } + } + +} diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java b/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java new file mode 100644 index 00000000000..072d43bc218 --- /dev/null +++ b/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java @@ -0,0 +1,19 @@ +package com.alibaba.nacos.core.ability.config; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.common.ability.inter.AbilityHandlerRegistry; + +import java.util.Set; + +public class TestAbilityConfig extends AbilityConfigs { + + public TestAbilityConfig() { + Set serverAbilityKeys = super.getServerAbilityKeys(); + serverAbilityKeys.add(AbilityKey.TEST_1); + serverAbilityKeys.add(AbilityKey.TEST_2); + } + + public void setAbilityControlManager(AbilityHandlerRegistry abilityHandlerRegistry) { + super.setAbilityHandlerRegistry(abilityHandlerRegistry); + } +} From eada63e8d076a1d0db1879d1d3e240e727ed9992 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 3 Sep 2022 16:01:24 +0800 Subject: [PATCH 022/181] Fix checkstyle and support server ability manager load config. --- .../control/ServerAbilityControlManager.java | 18 +++++++++++++++- .../ability/config/AbilityConfigsTest.java | 1 - .../ability/config/TestAbilityConfig.java | 21 +++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 32d7ae97548..d47cc50ad6d 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -26,9 +26,12 @@ import com.alibaba.nacos.common.notify.NotifyCenter; import com.alibaba.nacos.common.utils.ConcurrentHashSet; import com.alibaba.nacos.common.utils.MapUtil; +import com.alibaba.nacos.core.ability.config.AbilityConfigs; import com.alibaba.nacos.core.ability.inte.ClusterAbilityControlSupport; +import com.alibaba.nacos.sys.env.EnvUtil; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -68,7 +71,20 @@ public ServerAbilityControlManager() { @Override protected Map getCurrentNodeSupportAbility() { - return ServerAbilities.getStaticAbilities(); + Set abilityKeys = ServerAbilities.getStaticAbilities().keySet(); + Map abilityTable = new HashMap<>(abilityKeys.size()); + abilityKeys.forEach(abilityKey -> { + String key = AbilityConfigs.PREFIX + abilityKey.getName(); + try { + // default true + Boolean property = EnvUtil.getProperty(key, Boolean.class, true); + abilityTable.put(abilityKey, property); + } catch (Exception e) { + // default true + abilityTable.put(abilityKey, true); + } + }); + return abilityTable; } @Override diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java index edb2fde21eb..3a5ba7d6cfa 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java @@ -112,7 +112,6 @@ public void testConfigChange() throws InterruptedException { Assert.assertEquals(tmp, 0); } - class TestHandler implements HandlerMapping { @Override diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java b/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java index 072d43bc218..d24b1677cb7 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java @@ -1,3 +1,19 @@ +/* + * Copyright 1999-2022 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.core.ability.config; import com.alibaba.nacos.api.ability.constant.AbilityKey; @@ -5,6 +21,11 @@ import java.util.Set; +/**. + * @author Daydreamer + * @description Dynamically load ability from config. just for test + * @date 2022/8/31 12:27 + **/ public class TestAbilityConfig extends AbilityConfigs { public TestAbilityConfig() { From 138f0758eb60f69f24de75960c5773f6a98cf49d Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 3 Sep 2022 16:12:25 +0800 Subject: [PATCH 023/181] Remove dead code. --- .../nacos/common/ability/AbstractAbilityControlManager.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 7b523e9beb6..469f1b99d1d 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -58,8 +58,6 @@ public abstract class AbstractAbilityControlManager implements AbilityControlMan */ protected final Map nodeAbilityTable = new ConcurrentHashMap<>(); - private final ReentrantLock lockForProcessors = new ReentrantLock(); - private final ReentrantLock lockForAbilityTable = new ReentrantLock(); protected AbstractAbilityControlManager() { From 6b2d3b1f3aa3385a13c275814f49f62a36f04046 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 4 Sep 2022 16:31:45 +0800 Subject: [PATCH 024/181] Return nothing if existed connection from other cluster node doesn't support ability table. --- .../nacos/core/ability/control/ServerAbilityControlManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index d47cc50ad6d..23a511e1501 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -114,7 +114,7 @@ public AbilityStatus isClusterEnableAbilityNow(AbilityKey abilityKey) { @Override public Map getClusterAbility() { - return Collections.unmodifiableMap(clusterAbilityTable); + return serverNoAbilityNegotiation.size() > 0 ? null : Collections.unmodifiableMap(clusterAbilityTable); } @Override From fd6938566f1653781a389ce30a8979cd78371fc2 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 4 Sep 2022 16:50:25 +0800 Subject: [PATCH 025/181] Add junit test --- .../ability/AbilityControlManagerTest.java | 41 ++++++++++++++++--- .../TestServerAbilityControlManager.java | 1 + 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java index b15dce4c7a5..8a01dbc2de7 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java @@ -40,11 +40,6 @@ public class AbilityControlManagerTest { public void inject() { Map newTable = new HashMap<>(); newTable.put(AbilityKey.TEST_1, true); - serverAbilityControlManager.setCurrentSupportingAbility(newTable); - - Map table = new HashMap<>(); - table.put(AbilityKey.TEST_1, true); - serverAbilityControlManager.setCurrentSupportingAbility(table); Map cluster = new HashMap<>(); cluster.put(AbilityKey.TEST_1, true); @@ -195,6 +190,42 @@ public void testCurrentNodeAbility() { keySet.forEach(key -> { Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(key)); }); + + // add node doesn't support ability table + AbilityTable abilityTable = new AbilityTable(); + abilityTable.setServer(true); + abilityTable.setConnectionId("adsadsa1"); + serverAbilityControlManager.addNewTable(abilityTable); + // cluster abilities close + Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); + + AbilityTable abilityTable1 = new AbilityTable(); + abilityTable1.setServer(true); + abilityTable1.setConnectionId("adsadsa2"); + serverAbilityControlManager.addNewTable(abilityTable1); + // cluster abilities still close + Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); + Assert.assertNull(serverAbilityControlManager.getClusterAbility()); + + AbilityTable abilityTable2 = new AbilityTable(); + abilityTable2.setServer(true); + abilityTable2.setConnectionId("adsadsa3"); + Map clientTa = new HashMap<>(); + clientTa.put(AbilityKey.TEST_2, true); + clientTa.put(AbilityKey.TEST_1, false); + abilityTable2.setAbility(clientTa); + serverAbilityControlManager.addNewTable(abilityTable2); + // cluster abilities still close + Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); + Assert.assertNull(serverAbilityControlManager.getClusterAbility()); + + // remove + serverAbilityControlManager.removeTable("adsadsa3"); + serverAbilityControlManager.removeTable("adsadsa2"); + serverAbilityControlManager.removeTable("adsadsa1"); + // cluster abilities open + Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.SUPPORTED); + Assert.assertNotNull(serverAbilityControlManager.getClusterAbility()); } class TestHandlerMapping implements HandlerMapping { diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java index f53f9e1cd66..3953cf54e7a 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java @@ -27,6 +27,7 @@ public class TestServerAbilityControlManager extends ServerAbilityControlManager @JustForTest public void setCurrentSupportingAbility(Map ability) { + currentRunningAbility.clear(); currentRunningAbility.putAll(ability); } From eb6ea55fef20cf76f6da870d3b6f00c63befe5dc Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sun, 4 Sep 2022 17:11:26 +0800 Subject: [PATCH 026/181] load server abilities from ServerAbilities if config doesn't define --- .../control/ServerAbilityControlManager.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 23a511e1501..61d32bc6451 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -32,6 +32,7 @@ import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -71,19 +72,30 @@ public ServerAbilityControlManager() { @Override protected Map getCurrentNodeSupportAbility() { - Set abilityKeys = ServerAbilities.getStaticAbilities().keySet(); + // static abilities + Map staticAbilities = ServerAbilities.getStaticAbilities(); + // all function server can support + Set abilityKeys = staticAbilities.keySet(); Map abilityTable = new HashMap<>(abilityKeys.size()); + // if not define in config, then load from ServerAbilities + Set unIncludedInConfig = new HashSet<>(); abilityKeys.forEach(abilityKey -> { String key = AbilityConfigs.PREFIX + abilityKey.getName(); try { - // default true - Boolean property = EnvUtil.getProperty(key, Boolean.class, true); - abilityTable.put(abilityKey, property); + Boolean property = EnvUtil.getProperty(key, Boolean.class); + // if not null + if (property != null) { + abilityTable.put(abilityKey, property); + } else { + unIncludedInConfig.add(abilityKey); + } } catch (Exception e) { - // default true - abilityTable.put(abilityKey, true); + // from ServerAbilities + unIncludedInConfig.add(abilityKey); } }); + // load from ServerAbilities + unIncludedInConfig.forEach(abilityKey -> abilityTable.put(abilityKey, staticAbilities.get(abilityKey))); return abilityTable; } From eedb84f2a197a88e436c69b6b0aa34ff347a2dc1 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Mon, 5 Sep 2022 16:22:42 +0800 Subject: [PATCH 027/181] Send the newest abilities to client. --- .../alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index a2869d6cdf5..9318408f623 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -16,6 +16,7 @@ package com.alibaba.nacos.core.remote.grpc; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -26,6 +27,8 @@ import com.alibaba.nacos.api.remote.response.ErrorResponse; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.remote.response.ServerCheckResponse; +import com.alibaba.nacos.api.utils.AbilityTableUtils; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.client.grpc.GrpcUtils; import com.alibaba.nacos.core.remote.Connection; import com.alibaba.nacos.core.remote.ConnectionManager; @@ -90,7 +93,8 @@ public void request(Payload grpcRequest, StreamObserver responseObserve // server check. if (ServerCheckRequest.class.getSimpleName().equals(type)) { Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(), - ServerAbilities.getBitFlags())); + AbilityTableUtils.getAbilityBiTableBy(AbilityKey.offset(), + NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()))); traceIfNecessary(serverCheckResponseP, false); responseObserver.onNext(serverCheckResponseP); responseObserver.onCompleted(); From 89b450537e8a6f7af87bc9cc03e87b38290b5951 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Thu, 8 Sep 2022 18:23:35 +0800 Subject: [PATCH 028/181] Add the response to setup request. --- .../register/impl/ServerAbilities.java | 2 + .../remote/request/ConnectResetRequest.java | 20 ++++++ .../api/remote/request/SetupAckRequest.java | 49 +++++++++++++++ .../api/remote/response/SetupAckResponse.java | 26 ++++++++ .../nacos/common/remote/client/RpcClient.java | 10 +++ .../common/remote/client/grpc/GrpcClient.java | 61 ++++++++++++++++++- .../core/ability/config/AbilityConfigs.java | 8 ++- .../nacos/core/remote/ConnectionManager.java | 1 + .../grpc/GrpcBiStreamRequestAcceptor.java | 13 +++- .../core/remote/grpc/GrpcRequestAcceptor.java | 1 - 10 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 api/src/main/java/com/alibaba/nacos/api/remote/request/SetupAckRequest.java create mode 100644 api/src/main/java/com/alibaba/nacos/api/remote/response/SetupAckResponse.java diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java index ca5fecdef74..f3a098b4bbc 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java @@ -45,6 +45,8 @@ public class ServerAbilities extends AbstractAbilityRegistry { * */ // put ability here, which you want current server supports + supportedAbilities.put(AbilityKey.TEST_1, true); + supportedAbilities.put(AbilityKey.TEST_2, true); } private ServerAbilities() { diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectResetRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectResetRequest.java index 1a2e14424be..75c6fa0cade 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectResetRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectResetRequest.java @@ -30,11 +30,31 @@ public class ConnectResetRequest extends ServerRequest { String serverPort; + String connectionId; + @Override public String getModule() { return INTERNAL_MODULE; } + /** + * Getter method for property connectionId. + * + * @return property value of connectionId + */ + public String getConnectionId() { + return connectionId; + } + + /** + * Setter method for property connectionId. + * + * @param connectionId value to be assigned to property connectionId + */ + public void setConnectionId(String connectionId) { + this.connectionId = connectionId; + } + /** * Getter method for property serverIp. * diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/SetupAckRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/SetupAckRequest.java new file mode 100644 index 00000000000..66f6eb2385b --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/SetupAckRequest.java @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2022 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.remote.request; + +import static com.alibaba.nacos.api.common.Constants.Remote.INTERNAL_MODULE; + +/**. + * @author Daydreamer + * @description Server tells the client that the connection is established + * @date 2022/7/12 19:21 + **/ +public class SetupAckRequest extends ServerRequest { + + private String connectionId; + + public SetupAckRequest() { + } + + public SetupAckRequest(String connectionId) { + this.connectionId = connectionId; + } + + public String getConnectionId() { + return connectionId; + } + + public void setConnectionId(String connectionId) { + this.connectionId = connectionId; + } + + @Override + public String getModule() { + return INTERNAL_MODULE; + } +} diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/response/SetupAckResponse.java b/api/src/main/java/com/alibaba/nacos/api/remote/response/SetupAckResponse.java new file mode 100644 index 00000000000..ce4abcb943f --- /dev/null +++ b/api/src/main/java/com/alibaba/nacos/api/remote/response/SetupAckResponse.java @@ -0,0 +1,26 @@ +/* + * Copyright 1999-2022 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.remote.response; + +/**. + * @author Daydreamer + * @description Server tells the client that the connection is established + * @date 2022/7/12 19:21 + **/ +public class SetupAckResponse extends Response { + +} diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java index 59d8134ecb6..6a65ae14676 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java @@ -433,6 +433,7 @@ public Response requestReply(Request request) { } else { switchServerAsync(); } + afterReset(connectResetRequest); } } } catch (Exception e) { @@ -444,6 +445,15 @@ public Response requestReply(Request request) { } } + /**. + * invoke after receiving reset request + * + * @param request request for resetting + */ + protected void afterReset(ConnectResetRequest request) { + // hook for GrpcClient + } + @Override public void shutdown() throws NacosException { LOGGER.info("Shutdown rpc client, set status to shutdown"); diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 73ae05692c7..0fe29f41c79 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -22,12 +22,15 @@ import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; import com.alibaba.nacos.api.grpc.auto.RequestGrpc; +import com.alibaba.nacos.api.remote.request.ConnectResetRequest; import com.alibaba.nacos.api.remote.request.ConnectionSetupRequest; import com.alibaba.nacos.api.remote.request.Request; import com.alibaba.nacos.api.remote.request.ServerCheckRequest; +import com.alibaba.nacos.api.remote.request.SetupAckRequest; import com.alibaba.nacos.api.remote.response.ErrorResponse; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.remote.response.ServerCheckResponse; +import com.alibaba.nacos.api.remote.response.SetupAckResponse; import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.ConnectionType; @@ -48,6 +51,9 @@ import org.slf4j.LoggerFactory; import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -75,6 +81,11 @@ public abstract class GrpcClient extends RpcClient { private static final long DEFAULT_KEEP_ALIVE_TIME = 6 * 60 * 1000; + /**. + * Block to wait setup success response + */ + private final Map markForSetup = new ConcurrentHashMap<>(); + @Override public ConnectionType getConnectionType() { return ConnectionType.GRPC; @@ -85,6 +96,19 @@ public ConnectionType getConnectionType() { */ public GrpcClient(String name) { super(name); + + // register to handler setup request + registerServerRequestHandler((request) -> { + // if finish setup + if (request instanceof SetupAckRequest) { + SetupAckRequest setupAckRequest = (SetupAckRequest) request; + // remove and count down + Optional.ofNullable(markForSetup.remove((setupAckRequest.getConnectionId()))) + .orElse(new CountDownLatch(1)) + .countDown(); + } + return new SetupAckResponse(); + }); } /** @@ -247,6 +271,10 @@ public void onNext(Payload payload) { LoggerUtils.printIfErrorEnabled(LOGGER, "[{}]Error to process server push response: {}", grpcConn.getConnectionId(), payload.getBody().getValue().toStringUtf8()); + // remove and notify + Optional.ofNullable(markForSetup.remove(grpcConn.getConnectionId())) + .orElse(new CountDownLatch(1)) + .countDown(); } } @@ -299,6 +327,8 @@ private void sendResponse(Response response) { @Override public Connection connectToServer(ServerInfo serverInfo) { + // the newest connection id + String connectionId = ""; try { if (grpcExecutor == null) { this.grpcExecutor = createGrpcExecutor(serverInfo.getServerIp()); @@ -317,21 +347,25 @@ public Connection connectToServer(ServerInfo serverInfo) { // submit ability table as soon as possible // ability table will be null if server doesn't support ability table ServerCheckResponse serverCheckResponse = (ServerCheckResponse) response; + connectionId = serverCheckResponse.getConnectionId(); AbilityTable table = new AbilityTable(); table.setServer(true) - .setConnectionId(serverCheckResponse.getConnectionId()); + .setConnectionId(connectionId); + // if not supported, it will be null if (serverCheckResponse.getAbilities() != null) { Map abilityTable = AbilityTableUtils .getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset()); table.setAbility(abilityTable); + // mark + markForSetup.put(serverCheckResponse.getConnectionId(), new CountDownLatch(1)); } NacosAbilityManagerHolder.getInstance().addNewTable(table); BiRequestStreamGrpc.BiRequestStreamStub biRequestStreamStub = BiRequestStreamGrpc .newStub(newChannelStubTemp.getChannel()); GrpcConnection grpcConn = new GrpcConnection(serverInfo, grpcExecutor); - grpcConn.setConnectionId(((ServerCheckResponse) response).getConnectionId()); + grpcConn.setConnectionId(connectionId); //create stream request and bind connection event to this connection. StreamObserver payloadStreamObserver = bindRequestStream(biRequestStreamStub, grpcConn); @@ -351,6 +385,14 @@ public Connection connectToServer(ServerInfo serverInfo) { conSetupRequest.setServer(isServer()); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); + // wait for response + CountDownLatch synResponse = markForSetup.get(connectionId); + if (synResponse != null) { + synResponse.await(2000L, TimeUnit.MICROSECONDS); + // ensure remove, it may being reset + markForSetup.remove(connectionId); + } + // leave for adapting old version server //wait to register connection setup Thread.sleep(100L); return grpcConn; @@ -358,10 +400,25 @@ public Connection connectToServer(ServerInfo serverInfo) { return null; } catch (Exception e) { LOGGER.error("[{}]Fail to connect to server!,error={}", GrpcClient.this.getName(), e); + // remove and notify + Optional.ofNullable(markForSetup.remove(connectionId)) + .orElse(new CountDownLatch(1)) + .countDown(); } return null; } + @Override + protected void afterReset(ConnectResetRequest request) { + String connectionId = request.getConnectionId(); + if (connectionId != null) { + // remove and notify + Optional.ofNullable(markForSetup.remove(connectionId)) + .orElse(new CountDownLatch(1)) + .countDown(); + } + } + /** * Return whether server environment * The same offset may refer to different functions in the client capability table and the server capability table. diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java b/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java index 084dc7f6ae8..1b49e8e190c 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java @@ -64,9 +64,11 @@ public void onEvent(ServerConfigChangeEvent event) { serverAbilityKeys.forEach(abilityKey -> { String key = PREFIX + abilityKey.getName(); try { - // default true - Boolean property = EnvUtil.getProperty(key, Boolean.class, true); - newValues.put(abilityKey, property); + // scan + Boolean property = EnvUtil.getProperty(key, Boolean.class); + if (property != null) { + newValues.put(abilityKey, property); + } } catch (Exception e) { LOGGER.warn("Update ability config from env failed, use old val, ability : {} , because : {}", key, e); } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/ConnectionManager.java b/core/src/main/java/com/alibaba/nacos/core/remote/ConnectionManager.java index c3ae2393fa0..f51427ea88e 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/ConnectionManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/ConnectionManager.java @@ -511,6 +511,7 @@ public void loadSingle(String connectionId, String redirectAddress) { String[] split = redirectAddress.split(Constants.COLON); connectResetRequest.setServerIp(split[0]); connectResetRequest.setServerPort(split[1]); + connectResetRequest.setConnectionId(connectionId); } try { connection.request(connectResetRequest, 3000L); diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 4a550d80b2e..4dbb4d4142a 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -22,6 +22,7 @@ import com.alibaba.nacos.api.grpc.auto.Payload; import com.alibaba.nacos.api.remote.request.ConnectResetRequest; import com.alibaba.nacos.api.remote.request.ConnectionSetupRequest; +import com.alibaba.nacos.api.remote.request.SetupAckRequest; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.remote.ConnectionType; @@ -134,7 +135,9 @@ public void onNext(Payload payload) { try { Loggers.REMOTE_DIGEST.warn("[{}]Connection register fail,reason:{}", connectionId, rejectSdkOnStarting ? " server is not started" : " server is over limited."); - connection.request(new ConnectResetRequest(), 3000L); + ConnectResetRequest connectResetRequest = new ConnectResetRequest(); + connectResetRequest.setConnectionId(connectionId); + connection.request(connectResetRequest, 3000L); connection.close(); } catch (Exception e) { //Do nothing. @@ -143,6 +146,14 @@ public void onNext(Payload payload) { .warn("[{}]Send connect reset request error,error={}", connectionId, e); } } + } else { + try { + // finish register, tell client has set up successfully + connection.request(new SetupAckRequest(connectionId), 3000L); + } catch (Exception e) { + // nothing to do + + } } } else if (parseObj instanceof Response) { diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index 9318408f623..261713558ae 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.core.remote.grpc; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.Payload; import com.alibaba.nacos.api.grpc.auto.RequestGrpc; From afbfed295488048df1759d5e7c366ba5c0735500 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Thu, 8 Sep 2022 18:34:03 +0800 Subject: [PATCH 029/181] Remove the unused filed. --- .../api/remote/request/ConnectionSetupRequest.java | 13 ------------- .../nacos/common/remote/client/grpc/GrpcClient.java | 9 --------- .../remote/client/grpc/GrpcClusterClient.java | 5 ----- .../common/remote/client/grpc/GrpcSdkClient.java | 5 ----- .../common/remote/client/grpc/GrpcClientTest.java | 5 ----- 5 files changed, 37 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java index 15b3c35d5ec..046a897a447 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java @@ -35,19 +35,6 @@ public class ConnectionSetupRequest extends InternalRequest { private byte[] abilityTable; - /**. - * server will resolve {@link ConnectionSetupRequest#abilityTable} to server abilities, or to client abilities - */ - private boolean isServer; - - public boolean isServer() { - return isServer; - } - - public void setServer(boolean server) { - isServer = server; - } - public ConnectionSetupRequest() { } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 0fe29f41c79..40125405966 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -382,7 +382,6 @@ public Connection connectToServer(ServerInfo serverInfo) { byte[] bitTable = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()); conSetupRequest.setAbilityTable(bitTable); - conSetupRequest.setServer(isServer()); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); // wait for response @@ -419,14 +418,6 @@ protected void afterReset(ConnectResetRequest request) { } } - /** - * Return whether server environment - * The same offset may refer to different functions in the client capability table and the server capability table. - * - * @return whether server environment - */ - protected abstract boolean isServer(); - } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java index 74919ba078b..7b63653b659 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClusterClient.java @@ -35,11 +35,6 @@ public GrpcClusterClient(String name) { super(name); } - @Override - protected boolean isServer() { - return true; - } - @Override public int rpcPortOffset() { return Integer.parseInt(System.getProperty(NACOS_SERVER_GRPC_PORT_OFFSET_KEY, diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java index 46cd691f65e..34cf408243a 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcSdkClient.java @@ -35,11 +35,6 @@ public GrpcSdkClient(String name) { super(name); } - @Override - protected boolean isServer() { - return false; - } - @Override public int rpcPortOffset() { return Integer.parseInt(System.getProperty(NACOS_SERVER_GRPC_PORT_OFFSET_KEY, diff --git a/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java b/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java index af7104d1333..9e3c17f7fc6 100644 --- a/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java +++ b/common/src/test/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClientTest.java @@ -48,11 +48,6 @@ public class GrpcClientTest { public void setUp() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { grpcClient = spy(new GrpcClient("testClient") { - @Override - protected boolean isServer() { - return false; - } - @Override public int rpcPortOffset() { return 1000; From 02bd4872cac42756db7fd11ad5ea2d1360743909 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Fri, 9 Sep 2022 18:41:04 +0800 Subject: [PATCH 030/181] Change the way to transport ability table. --- .../api/ability/constant/AbilityKey.java | 93 +++++++++--- .../register/AbstractAbilityRegistry.java | 20 --- .../register/impl/ClientAbilities.java | 14 -- .../register/impl/ServerAbilities.java | 14 -- .../request/ConnectionSetupRequest.java | 6 +- .../remote/response/ServerCheckResponse.java | 10 +- .../nacos/api/utils/AbilityTableUtils.java | 132 ------------------ .../nacos/api/utils/AbilityKeyTest.java | 75 ++++++++++ .../api/utils/AbilityTableUtilsTest.java | 118 ---------------- .../common/remote/client/grpc/GrpcClient.java | 8 +- .../grpc/GrpcBiStreamRequestAcceptor.java | 5 +- .../core/remote/grpc/GrpcRequestAcceptor.java | 5 +- 12 files changed, 166 insertions(+), 334 deletions(-) delete mode 100644 api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java create mode 100644 api/src/test/java/com/alibaba/nacos/api/utils/AbilityKeyTest.java delete mode 100644 api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java index 11a26e54ac9..6857e73e434 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java @@ -17,6 +17,8 @@ package com.alibaba.nacos.api.ability.constant; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; @@ -31,44 +33,101 @@ public enum AbilityKey { /**. * just for junit test */ - TEST_1("test_1", 1), + TEST_1("test_1"), /**. * just for junit test */ - TEST_2("test_2", 2); + TEST_2("test_2"); /**. * the name of a certain ability */ - private final String name; + private final String keyName; + + AbilityKey(String name) { + this.keyName = name; + } + + public String getName() { + return keyName; + } /**. - * the offset in ability table + * All key set */ - private final int offset; + private static final Map ALL_ABILITIES; - AbilityKey(String name, int offset) { - this.name = name; - this.offset = offset; + /**. + * Get all keys + * + * @return all keys + */ + public static Collection getAllValues() { + return Collections.unmodifiableCollection(ALL_ABILITIES.values()); } - public String getName() { - return name; + /**. + * Get all names + * + * @return all names + */ + public static Collection getAllNames() { + return Collections.unmodifiableCollection(ALL_ABILITIES.keySet()); } - public int getOffset() { - return offset; + /**. + * Whether contains this name + * + * @param name key name + * @return whether contains + */ + public static boolean isLegalKey(String name) { + return ALL_ABILITIES.containsKey(name); + } + + /**. + * Map the string key to enum + * + * @param abilities map + * @return enum map + */ + public static Map mapEnum(Map abilities) { + if (abilities == null || abilities.isEmpty()) { + return Collections.emptyMap(); + } + return abilities.entrySet() + .stream() + .filter(entry -> isLegalKey(entry.getKey())) + .collect(Collectors.toMap((entry) -> getEnum(entry.getKey()), Map.Entry::getValue)); } - private static final Map OFFSET_MAP; + /**. + * Map the string key to enum + * + * @param abilities map + * @return enum map + */ + public static Map mapStr(Map abilities) { + if (abilities == null || abilities.isEmpty()) { + return Collections.emptyMap(); + } + return abilities.entrySet() + .stream() + .collect(Collectors.toMap((entry) -> entry.getKey().getName(), Map.Entry::getValue)); + } - public static Map offset() { - return OFFSET_MAP; + /** + * getter to obtain enum + * + * @param key string key + * @return enum + */ + public static AbilityKey getEnum(String key) { + return ALL_ABILITIES.get(key); } static { - OFFSET_MAP = Arrays.stream(AbilityKey.values()) - .collect(Collectors.toMap(Function.identity(), AbilityKey::getOffset)); + ALL_ABILITIES = Arrays.stream(AbilityKey.values()).collect(Collectors.toMap(AbilityKey::getName, Function.identity())); } } diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java index 60be843faea..40af9087cfe 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/AbstractAbilityRegistry.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.api.ability.register; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.utils.AbilityTableUtils; import java.util.Collections; import java.util.HashMap; @@ -31,25 +30,6 @@ public abstract class AbstractAbilityRegistry { protected final Map supportedAbilities = new HashMap<>(); - - private byte[] abilityBitFlag; - - /**. - * Return the static ability bit table - * - * @return ability bit table - */ - public byte[] getAbilityBitFlags() { - return abilityBitFlag.clone(); - } - - /**. - * put the bit offset to {@link AbstractAbilityRegistry#abilityBitFlag} - */ - protected void init() { - // init the bits table - abilityBitFlag = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), supportedAbilities); - } /**. * get static ability current server supports diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java index 39a4f7232cb..533f4ecdd2b 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ClientAbilities.java @@ -47,20 +47,6 @@ public class ClientAbilities extends AbstractAbilityRegistry { // put ability here, which you want current client supports } - private ClientAbilities() { - // put key to bit offset - init(); - } - - /**. - * get the ability offset for server - * - * @return ability offset - */ - public static byte[] getBitFlags() { - return INSTANCE.getAbilityBitFlags(); - } - /**. * get static ability current server supports * diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java index f3a098b4bbc..480861c0e00 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java @@ -49,20 +49,6 @@ public class ServerAbilities extends AbstractAbilityRegistry { supportedAbilities.put(AbilityKey.TEST_2, true); } - private ServerAbilities() { - // put key to bit offset - init(); - } - - /**. - * get bit table - * - * @return ability offset - */ - public static byte[] getBitFlags() { - return INSTANCE.getAbilityBitFlags(); - } - /**. * get static ability current server supports * diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java index 046a897a447..3409728f576 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequest.java @@ -33,7 +33,7 @@ public class ConnectionSetupRequest extends InternalRequest { private Map labels = new HashMap<>(); - private byte[] abilityTable; + private Map abilityTable; public ConnectionSetupRequest() { } @@ -62,11 +62,11 @@ public void setTenant(String tenant) { this.tenant = tenant; } - public byte[] getAbilityTable() { + public Map getAbilityTable() { return abilityTable; } - public void setAbilityTable(byte[] abilityTable) { + public void setAbilityTable(Map abilityTable) { this.abilityTable = abilityTable; } } diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java b/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java index 4f5092fc060..d3c2ee44914 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.api.remote.response; +import java.util.Map; + /** * response of server check. * @@ -26,13 +28,13 @@ public class ServerCheckResponse extends Response { private String connectionId; - private byte[] abilities; + private Map abilities; public ServerCheckResponse() { } - public ServerCheckResponse(String connectionId, byte[] abilities) { + public ServerCheckResponse(String connectionId, Map abilities) { this.connectionId = connectionId; this.abilities = abilities; } @@ -45,11 +47,11 @@ public void setConnectionId(String connectionId) { this.connectionId = connectionId; } - public byte[] getAbilities() { + public Map getAbilities() { return abilities; } - public void setAbilities(byte[] abilities) { + public void setAbilities(Map abilities) { this.abilities = abilities; } } diff --git a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java b/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java deleted file mode 100644 index d995870758a..00000000000 --- a/api/src/main/java/com/alibaba/nacos/api/utils/AbilityTableUtils.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 1999-2022 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; - -import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -/**. - * @author Daydreamer - * @description It is used to operate ability table. - * @date 2022/7/12 19:23 - **/ -public class AbilityTableUtils { - - private static final int BASE = 128; - - private AbilityTableUtils() { - } - - /**. - * get ability bit table from Collection - * - * @param bitCollection bit offset - * @return bit table - */ - public static byte[] getAbilityBitBy(Collection bitCollection) { - if (bitCollection.size() == 0) { - return new byte[1]; - } - Integer max = Collections.max(bitCollection); - // calculate byte[] - int mark = max % 8; - int length = max / 8 + (mark == 0 ? 0 : 1); - byte[] res = new byte[length]; - bitCollection.forEach(offset -> { - int index = offset / 8 + (offset % 8 == 0 ? -1 : 0); - int flag = offset % 8; - if (flag == 0) { - flag = 8; - } - byte x = (byte) (BASE >>> (flag - 1)); - res[index] = (byte) (res[index] | x); - }); - return res; - } - - /**. - * get ability table by bits - * - * @param bits bit flag - * @param offsetMap offset from {@link AbstractAbilityRegistry} - * @return Return the Map containing AbilityTableKey and isRunning. - */ - public static Map getAbilityTableBy(byte[] bits, Map offsetMap) { - if (bits == null || offsetMap.size() == 0) { - return Collections.emptyMap(); - } - int length = bits.length; - Set> entries = offsetMap.entrySet(); - Map res = new HashMap<>(offsetMap.size()); - for (Map.Entry entry : entries) { - AbilityKey abilityKey = entry.getKey(); - Integer offset = entry.getValue(); - // if not exists - int index = offset / 8 + (offset % 8 == 0 ? -1 : 0); - if (index + 1 > length) { - res.put(abilityKey, Boolean.FALSE); - continue; - } - // find - int flag = offset % 8; - if (flag == 0) { - flag = 8; - } - byte x = (byte) (BASE >>> (flag - 1)); - byte tmp = (byte) (x & bits[index]); - res.put(abilityKey, x == tmp); - } - return res; - } - - /**. - * get ability bit table by existed ability table and offset map - * - * @param offsetMap offset from {@link AbstractAbilityRegistry} - * @return Return the Map containing AbilityTableKey and isRunning. - */ - public static byte[] getAbilityBiTableBy(Map offsetMap, Map abilityTable) { - // filter the element which abilityTable don't have or value is false - Map res = offsetMap.entrySet().stream() - .filter(item -> abilityTable.getOrDefault(item.getKey(), false)) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - return getAbilityBitBy(res.values()); - } - - /**. - * get ability bit table by existed ability table and abilityKeys array - * - * @param abilityKeys abilityKeys array - * @param abilityTable existed ability table - * @return filter ability which value is false in abilityTable - */ - public static byte[] getAbilityBiTableBy(AbilityKey[] abilityKeys, Map abilityTable) { - // filter the element which abilityTable don't have or value is false - List keyList = Arrays.stream(abilityKeys).collect(Collectors.toList()); - keyList.removeIf(key -> !abilityTable.getOrDefault(key, false)); - return getAbilityBitBy(keyList.stream().map(AbilityKey::getOffset).collect(Collectors.toList())); - } -} diff --git a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityKeyTest.java b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityKeyTest.java new file mode 100644 index 00000000000..baf0d1c2d86 --- /dev/null +++ b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityKeyTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 1999-2022 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; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/**. + * @author Daydreamer + * @description Ability key test + * @date 2022/9/8 12:27 + **/ +public class AbilityKeyTest { + + @Test + public void testMapStr() { + Map enumMap = new HashMap<>(); + Map stringBooleanMap = AbilityKey.mapStr(enumMap); + Assert.assertEquals(0, stringBooleanMap.size()); + + enumMap.put(AbilityKey.TEST_1, true); + enumMap.put(AbilityKey.TEST_2, false); + stringBooleanMap = AbilityKey.mapStr(enumMap); + Assert.assertEquals(2, stringBooleanMap.size()); + Assert.assertTrue(stringBooleanMap.get(AbilityKey.TEST_1.getName())); + Assert.assertFalse(stringBooleanMap.get(AbilityKey.TEST_2.getName())); + + enumMap.put(AbilityKey.TEST_2, true); + stringBooleanMap = AbilityKey.mapStr(enumMap); + Assert.assertEquals(2, stringBooleanMap.size()); + Assert.assertTrue(stringBooleanMap.get(AbilityKey.TEST_1.getName())); + Assert.assertTrue(stringBooleanMap.get(AbilityKey.TEST_2.getName())); + } + + @Test + public void testMapEnum() { + Map mapStr = new HashMap<>(); + mapStr.put("test-no-existed", true); + Map enumMap = AbilityKey.mapEnum(mapStr); + Assert.assertEquals(0, enumMap.size()); + + mapStr.put(AbilityKey.TEST_2.getName(), false); + mapStr.put(AbilityKey.TEST_1.getName(), true); + enumMap = AbilityKey.mapEnum(mapStr); + Assert.assertFalse(enumMap.get(AbilityKey.TEST_2)); + Assert.assertTrue(enumMap.get(AbilityKey.TEST_1)); + + mapStr.clear(); + mapStr.put(AbilityKey.TEST_2.getName(), true); + mapStr.put(AbilityKey.TEST_1.getName(), true); + enumMap = AbilityKey.mapEnum(mapStr); + Assert.assertTrue(enumMap.get(AbilityKey.TEST_2)); + Assert.assertTrue(enumMap.get(AbilityKey.TEST_1)); + + } + +} diff --git a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java b/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java deleted file mode 100644 index bbd2ce77047..00000000000 --- a/api/src/test/java/com/alibaba/nacos/api/utils/AbilityTableUtilsTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 1999-2022 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; - -import com.alibaba.nacos.api.ability.constant.AbilityKey; -import org.junit.Assert; -import org.junit.Test; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class AbilityTableUtilsTest { - - @Test - public void testGetAbilityBitBy() { - byte[] abilityBitBy = AbilityTableUtils.getAbilityBitBy(Arrays.asList(1, 8, 9, 17)); - Assert.assertEquals(abilityBitBy[0], -127); - Assert.assertEquals(abilityBitBy[1], -128); - Assert.assertEquals(abilityBitBy[2], -128); - // clear - byte[] abilityBits = AbilityTableUtils.getAbilityBitBy(Collections.emptyList()); - Assert.assertEquals(abilityBits.length, 1); - Assert.assertEquals(abilityBits[0], 0); - } - - @Test - public void testGetAbilityTableBy() { - byte[] bytes = new byte[]{0}; - Map abilityTableBy = - AbilityTableUtils.getAbilityTableBy(bytes, AbilityKey.offset()); - Assert.assertEquals(abilityTableBy.getOrDefault(AbilityKey.TEST_1, false), false); - Assert.assertEquals(abilityTableBy.getOrDefault(AbilityKey.TEST_2, false), false); - - byte[] bytes1 = new byte[]{-64}; - Map abilityTableBy1 = - AbilityTableUtils.getAbilityTableBy(bytes1, AbilityKey.offset()); - Assert.assertEquals(abilityTableBy1.get(AbilityKey.TEST_1), true); - Assert.assertEquals(abilityTableBy1.get(AbilityKey.TEST_2), true); - - byte[] bytes2 = new byte[]{-128}; - Map abilityTableBy2 = - AbilityTableUtils.getAbilityTableBy(bytes2, AbilityKey.offset()); - Assert.assertEquals(abilityTableBy2.getOrDefault(AbilityKey.TEST_1, false), true); - Assert.assertEquals(abilityTableBy2.getOrDefault(AbilityKey.TEST_2, false), false); - - byte[] bytes3 = new byte[]{64}; - Map abilityTableBy3 = - AbilityTableUtils.getAbilityTableBy(bytes3, AbilityKey.offset()); - Assert.assertEquals(abilityTableBy3.getOrDefault(AbilityKey.TEST_1, false), false); - Assert.assertEquals(abilityTableBy3.getOrDefault(AbilityKey.TEST_2, false), true); - } - - @Test - public void testGetAbilityBiTableBy() { - Map map = new HashMap<>(); - byte[] bytes1 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map); - Assert.assertEquals(1, bytes1.length); - Assert.assertEquals(bytes1[0], 0); - - map.put(AbilityKey.TEST_1, true); - byte[] bytes2 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map); - Assert.assertEquals(1, bytes1.length); - Assert.assertEquals(bytes2[0], -128); - - map.put(AbilityKey.TEST_1, false); - map.put(AbilityKey.TEST_2, true); - byte[] bytes3 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map); - Assert.assertEquals(1, bytes3.length); - Assert.assertEquals(bytes3[0], 64); - - map.put(AbilityKey.TEST_1, true); - byte[] bytes4 = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), map); - Assert.assertEquals(1, bytes4.length); - Assert.assertEquals(bytes4[0], -64); - } - - @Test - public void testGetAbilityBiTable() { - Map offset = AbilityKey.offset(); - Map abilities = new HashMap<>(); - byte[] bytes1 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities); - Assert.assertEquals(1, bytes1.length); - Assert.assertEquals(bytes1[0], 0); - - abilities.put(AbilityKey.TEST_1, true); - byte[] bytes2 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities); - Assert.assertEquals(1, bytes2.length); - Assert.assertEquals(bytes2[0], -128); - - abilities.put(AbilityKey.TEST_2, true); - byte[] bytes3 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities); - Assert.assertEquals(1, bytes3.length); - Assert.assertEquals(bytes3[0], -64); - - offset = new HashMap<>(); - offset.put(AbilityKey.TEST_1, 2); - byte[] bytes4 = AbilityTableUtils.getAbilityBiTableBy(offset, abilities); - Assert.assertEquals(1, bytes4.length); - Assert.assertEquals(bytes4[0], 64); - } - -} diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 40125405966..308ead43b1a 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -31,7 +31,6 @@ import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.remote.response.ServerCheckResponse; import com.alibaba.nacos.api.remote.response.SetupAckResponse; -import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.Connection; @@ -354,8 +353,7 @@ public Connection connectToServer(ServerInfo serverInfo) { // if not supported, it will be null if (serverCheckResponse.getAbilities() != null) { - Map abilityTable = AbilityTableUtils - .getAbilityTableBy(serverCheckResponse.getAbilities(), AbilityKey.offset()); + Map abilityTable = AbilityKey.mapEnum(serverCheckResponse.getAbilities()); table.setAbility(abilityTable); // mark markForSetup.put(serverCheckResponse.getConnectionId(), new CountDownLatch(1)); @@ -379,9 +377,7 @@ public Connection connectToServer(ServerInfo serverInfo) { conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion()); conSetupRequest.setLabels(super.getLabels()); // set ability table - byte[] bitTable = AbilityTableUtils.getAbilityBiTableBy(AbilityKey.values(), - NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()); - conSetupRequest.setAbilityTable(bitTable); + conSetupRequest.setAbilityTable(AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility())); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); // wait for response diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 4dbb4d4142a..61f82ba644c 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -24,7 +24,6 @@ import com.alibaba.nacos.api.remote.request.ConnectionSetupRequest; import com.alibaba.nacos.api.remote.request.SetupAckRequest; import com.alibaba.nacos.api.remote.response.Response; -import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.grpc.GrpcUtils; import com.alibaba.nacos.core.remote.Connection; @@ -125,8 +124,8 @@ public void onNext(Payload payload) { Connection connection = new GrpcConnection(metaInfo, responseObserver, CONTEXT_KEY_CHANNEL.get()); // null if supported if (setUpRequest.getAbilityTable() != null) { - connection.setAbilityTable(AbilityTableUtils.getAbilityTableBy(setUpRequest.getAbilityTable(), - AbilityKey.offset())); + // map to table + connection.setAbilityTable(AbilityKey.mapEnum(setUpRequest.getAbilityTable())); } boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index 261713558ae..fc9aff20bd3 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -26,7 +26,6 @@ import com.alibaba.nacos.api.remote.response.ErrorResponse; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.remote.response.ServerCheckResponse; -import com.alibaba.nacos.api.utils.AbilityTableUtils; import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.client.grpc.GrpcUtils; import com.alibaba.nacos.core.remote.Connection; @@ -92,8 +91,8 @@ public void request(Payload grpcRequest, StreamObserver responseObserve // server check. if (ServerCheckRequest.class.getSimpleName().equals(type)) { Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(), - AbilityTableUtils.getAbilityBiTableBy(AbilityKey.offset(), - NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()))); + // to str map + AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()))); traceIfNecessary(serverCheckResponseP, false); responseObserver.onNext(serverCheckResponseP); responseObserver.onCompleted(); From e3a3139c33bb9b3cc28e0645e0d64a8b1ad63994 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 10 Sep 2022 13:53:48 +0800 Subject: [PATCH 031/181] Save the ability table to Connection. --- .../ability/ClientAbilityControlManager.java | 31 +- ...mon.ability.AbstractAbilityControlManager} | 0 .../ability/AbilityControlManagerTest.java | 45 +- .../AbstractAbilityControlManager.java | 483 +++++++++++------- .../ability/DefaultAbilityControlManager.java | 346 ------------- .../discover/NacosAbilityManagerHolder.java | 14 +- .../ability/inter/AbilityControlManager.java | 88 ---- .../ability/inter/AbilityHandlerRegistry.java | 83 --- .../listener/ClientAbilityEventListener.java | 39 -- .../common/remote/client/Connection.java | 13 + .../nacos/common/remote/client/RpcClient.java | 8 - .../common/remote/client/grpc/GrpcClient.java | 19 +- .../core/ability/config/AbilityConfigs.java | 6 +- .../control/ServerAbilityControlManager.java | 188 +------ .../inte/ClusterAbilityControlSupport.java | 46 -- .../alibaba/nacos/core/remote/Connection.java | 4 + .../core/remote/grpc/GrpcRequestAcceptor.java | 2 +- .../ServerAbilityConnectionListener.java | 45 -- ...mon.ability.AbstractAbilityControlManager} | 0 .../ability/AbilityControlManagerTest.java | 130 +---- .../TestServerAbilityControlManager.java | 10 - .../ability/config/TestAbilityConfig.java | 5 - 22 files changed, 344 insertions(+), 1261 deletions(-) rename client/src/main/resources/META-INF/services/{com.alibaba.nacos.common.ability.DefaultAbilityControlManager => com.alibaba.nacos.common.ability.AbstractAbilityControlManager} (100%) delete mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java delete mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java delete mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java delete mode 100644 common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java delete mode 100644 core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java delete mode 100644 core/src/main/java/com/alibaba/nacos/core/remote/listener/ServerAbilityConnectionListener.java rename core/src/main/resources/META-INF/services/{com.alibaba.nacos.common.ability.DefaultAbilityControlManager => com.alibaba.nacos.common.ability.AbstractAbilityControlManager} (100%) diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index cd3e38f66a7..f1cb6cf7d8a 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -17,53 +17,26 @@ package com.alibaba.nacos.client.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; -import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.ability.register.impl.ClientAbilities; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; -import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; -import java.util.Collections; import java.util.Map; -import java.util.Optional; /**. * @author Daydreamer * @description {@link AbstractAbilityControlManager} for nacos-client. * @date 2022/7/13 13:38 **/ -public class ClientAbilityControlManager extends DefaultAbilityControlManager { +public class ClientAbilityControlManager extends AbstractAbilityControlManager { public ClientAbilityControlManager() { } @Override - protected Map getCurrentNodeSupportAbility() { + protected Map initCurrentNodeAbilities() { return ClientAbilities.getStaticAbilities(); } - @Override - public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { - AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - if (abilityTable == null) { - return AbilityStatus.UNKNOWN; - } - Boolean isSupport = Optional.ofNullable(abilityTable.getAbility()) - .orElse(Collections.emptyMap()) - .getOrDefault(abilityKey, false); - return isSupport ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; - } - - @Override - protected void add(AbilityTable table) { - // nothing to do - } - - @Override - protected void remove(String connectionId) { - // nothing to do - } - @Override public int getPriority() { // if server ability manager exist, you should choose the server one diff --git a/client/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager b/client/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.AbstractAbilityControlManager similarity index 100% rename from client/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager rename to client/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.AbstractAbilityControlManager diff --git a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java index c18cbaf7547..b0994fa596e 100644 --- a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java @@ -17,8 +17,6 @@ package com.alibaba.nacos.client.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; -import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import org.junit.Assert; import org.junit.Before; @@ -43,35 +41,6 @@ public void inject() { clientAbilityControlManager.setCurrentSupportingAbility(newTable); } - @Test - public void testClientAdd() { - Map newTable = new HashMap<>(); - newTable.put(AbilityKey.TEST_2, true); - newTable.put(AbilityKey.TEST_1, true); - AbilityTable table = new AbilityTable(); - table.setConnectionId("test-00001"); - table.setAbility(newTable); - table.setServer(true); - clientAbilityControlManager.addNewTable(table); - Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); - Assert.assertEquals(AbilityStatus.SUPPORTED, clientAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); - } - - @Test - public void testClientRemove() { - Map clientTa = new HashMap<>(); - clientTa.put(AbilityKey.TEST_2, true); - clientTa.put(AbilityKey.TEST_1, false); - AbilityTable clientTable = new AbilityTable(); - clientTable.setConnectionId("test-01111"); - clientTable.setAbility(clientTa); - clientTable.setServer(true); - clientAbilityControlManager.addNewTable(clientTable); - Assert.assertTrue(clientAbilityControlManager.contains(clientTable.getConnectionId())); - clientAbilityControlManager.removeTable("test-01111"); - Assert.assertFalse(clientAbilityControlManager.contains(clientTable.getConnectionId())); - } - @Test public void testComponent() throws InterruptedException { enabled = 0; @@ -118,16 +87,16 @@ public void testComponent() throws InterruptedException { public void testPriority() throws InterruptedException { TestClientAbilityControlManager testClientAbilityControlManager = new TestClientAbilityControlManager(); AbilityKey key = AbilityKey.TEST_1; - TestPriority clusterHandlerMapping1 = new TestPriority("1"); - TestPriority clusterHandlerMapping2 = new TestPriority("2"); - TestPriority clusterHandlerMapping3 = new TestPriority("3"); + TestPriority handlerMapping1 = new TestPriority("1"); + TestPriority handlerMapping2 = new TestPriority("2"); + TestPriority handlerMapping3 = new TestPriority("3"); // first one, invoke enable() - testClientAbilityControlManager.registerComponent(key, clusterHandlerMapping2, 128); + testClientAbilityControlManager.registerComponent(key, handlerMapping2, 128); // last one, invoke enable() - testClientAbilityControlManager.registerComponent(key, clusterHandlerMapping3); + testClientAbilityControlManager.registerComponent(key, handlerMapping3); // second one, invoke enable() - testClientAbilityControlManager.registerComponent(key, clusterHandlerMapping1, 12); - // trigger cluster + testClientAbilityControlManager.registerComponent(key, handlerMapping1, 12); + // trigger testClientAbilityControlManager.trigger(key); Assert.assertEquals(3, testClientAbilityControlManager.getHandlerMapping(key).size()); // wait for invoking diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 469f1b99d1d..4b1271fc8da 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -18,268 +18,381 @@ import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; -import com.alibaba.nacos.api.ability.entity.AbilityTable; -import com.alibaba.nacos.common.ability.inter.AbilityControlManager; +import com.alibaba.nacos.common.JustForTest; +import com.alibaba.nacos.common.ability.handler.HandlerMapping; +import com.alibaba.nacos.common.executor.ExecutorFactory; import com.alibaba.nacos.common.notify.Event; import com.alibaba.nacos.common.notify.NotifyCenter; +import com.alibaba.nacos.common.utils.CollectionUtils; +import com.alibaba.nacos.common.utils.MapUtil; +import com.alibaba.nacos.common.utils.ThreadUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; +import java.util.Collections; +import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /**. * @author Daydreamer - * @description Base class for ability control. It can only be used internally by Nacos.It showld be sington. + * @description It is a capability control center, manager current node abilities or other control. * @date 2022/7/12 19:18 **/ -@SuppressWarnings("all") -public abstract class AbstractAbilityControlManager implements AbilityControlManager { - - +public abstract class AbstractAbilityControlManager { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAbilityControlManager.class); - - /** - * Abilities current supporting - *

- * key: ability key from {@link AbstractAbilityRegistry} - * value: whether to turn on + + /**. + * These handlers will be invoked when the flag of ability change key: + * ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} value: + * components who want to be invoked if its interested ability turn on/off */ - protected final Map currentRunningAbility = new ConcurrentHashMap<>(); - - /** - * Ability table collections - *

- * key: connectionId - * value: AbilityTable + private final Map> handlerMappings = new ConcurrentHashMap<>(); + + /**. + * run for HandlerMapping + */ + private final Executor simpleThreadPool = ExecutorFactory.newSingleExecutorService(); + + /**. + * ability current node running */ - protected final Map nodeAbilityTable = new ConcurrentHashMap<>(); + protected final Map currentRunningAbility = new ConcurrentHashMap<>(); - private final ReentrantLock lockForAbilityTable = new ReentrantLock(); + private final ReentrantLock lockForHandlerMappings = new ReentrantLock(); protected AbstractAbilityControlManager() { - // register events - registerAbilityEvent(); - // put abilities - currentRunningAbility.putAll(getCurrentNodeSupportAbility()); - // initialize - init(); + ThreadUtils.addShutdownHook(this::destroy); + NotifyCenter.registerToPublisher(AbilityUpdateEvent.class, 16384); + currentRunningAbility.putAll(initCurrentNodeAbilities()); } /** - * This is a hook for subclass to init current node ability + * . Turn on the ability whose key is

abilityKey

* - * @return current node ability + * @param abilityKey ability key + * @return if turn success */ - protected abstract Map getCurrentNodeSupportAbility(); - - - private void registerAbilityEvent(){ - // register events - NotifyCenter.registerToPublisher(AbilityComeEvent.class, 16384); - NotifyCenter.registerToPublisher(AbilityExpiredEvent.class, 16384); + public boolean enableCurrentNodeAbility(AbilityKey abilityKey) { + return doTurn(true, abilityKey); } - + /** - * Whether the ability current node supporting is running. Return false if current node doesn't support. + * . Turn off the ability whose key is

abilityKey

* * @param abilityKey ability key - * @return is running + * @return if turn success */ - @Override + public boolean disableCurrentNodeAbility(AbilityKey abilityKey) { + return doTurn(false, abilityKey); + } + public boolean isCurrentNodeAbilityRunning(AbilityKey abilityKey) { return currentRunningAbility.getOrDefault(abilityKey, false); } - + /** - * Register a new ability table. + * Init current node abilities * - * @param table the ability table. + * @return current node abilities */ - @Override - public final void addNewTable(AbilityTable table) { - // id should not be null - String connectionId = table.getConnectionId(); - // if exists - if (contains(connectionId) || connectionId == null) { - return; - } - lockForAbilityTable.lock(); - try { - // check - if (contains(connectionId)) { - return; - } - // hook method - add(table); - // null if not support ability table - Map clientAbilities = table.getAbility(); - if (clientAbilities != null) { - // add to nod - Set abilityKeys = table.getAbility().keySet(); - abilityKeys.forEach(abilityKey -> { - Boolean res = currentRunningAbility.getOrDefault(abilityKey, false); - Boolean coming = clientAbilities.getOrDefault(abilityKey, false); - clientAbilities.put(abilityKey, res && coming); - }); - nodeAbilityTable.put(connectionId, table); - } - } finally { - lockForAbilityTable.unlock(); - } - // publish event to subscriber - AbilityComeEvent updateEvent = new AbilityComeEvent(); - updateEvent.setConnectionId(table.getConnectionId()); - updateEvent.setTable(table); - NotifyCenter.publishEvent(updateEvent); + protected abstract Map initCurrentNodeAbilities(); + + /** + * Return the abilities current node + * + * @return current abilities + */ + public Map getCurrentNodeAbilities() { + return Collections.unmodifiableMap(currentRunningAbility); } - + /** - * Remove a ability table + * . Turn on/off the ability of current node * - * @param connectionId the ability table which is removing. + * @param isOn is on + * @param abilityKey ability key from {@link AbilityKey} + * @return if turn success */ - @Override - public final void removeTable(String connectionId) { - AbilityTable removingTable = null; - lockForAbilityTable.lock(); - try { - // hook method - remove(connectionId); - // remove - removingTable = nodeAbilityTable.remove(connectionId); - } finally { - lockForAbilityTable.unlock(); - } - // publish event - if (removingTable != null) { - AbilityExpiredEvent expiredEvent = new AbilityExpiredEvent(); - expiredEvent.setTable(removingTable); - expiredEvent.setConnectionId(connectionId); - NotifyCenter.publishEvent(expiredEvent); + private boolean doTurn(boolean isOn, AbilityKey abilityKey) { + Boolean isEnabled = currentRunningAbility.get(abilityKey); + // if not supporting this key + if (isEnabled == null) { + LOGGER.warn("[AbilityControlManager] Attempt to turn on/off a not existed ability!"); + return false; + } else if (isOn == isEnabled) { + // if already turn on/off + return true; } + // turn on/off + currentRunningAbility.put(abilityKey, isOn); + // handler mappings + triggerHandlerMappingAsyn(abilityKey, isOn, this.handlerMappings); + // notify event + AbilityUpdateEvent abilityUpdateEvent = new AbilityUpdateEvent(); + abilityUpdateEvent.setTable(Collections.unmodifiableMap(currentRunningAbility)); + abilityUpdateEvent.isOn = isOn; + abilityUpdateEvent.abilityKey = abilityKey; + NotifyCenter.publishEvent(abilityUpdateEvent); + return true; } - + /** - * Register a new ability table. This is a ThreadSafe method for {@link AbstractAbilityControlManager#remove(String)}. + * Register the component which is managed by {@link AbstractAbilityControlManager}. if you are hoping that a + * component will be invoked when turn on/off the ability whose key is

abilityKey

. * - * @param table the ability table. + * @param abilityKey component key. + * @param priority the higher the priority is, the faster it will be called. + * @param handlerMapping component instance. */ - protected abstract void add(AbilityTable table); - - + public void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority) { + doRegisterComponent(abilityKey, handlerMapping, this.handlerMappings, lockForHandlerMappings, priority, currentRunningAbility); + } + /** - * Remove a ability table. This is a ThreadSafe method for {@link AbstractAbilityControlManager#add(AbilityTable)}. + * Register component with the lowest priority * - * @param connectionId the ability table which is removing. + * @param abilityKey ability key + * @param handlerMapping handler */ - protected abstract void remove(String connectionId); - - + public void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping) { + registerComponent(abilityKey, handlerMapping, -1); + } + /** - * wthether contains this ability table + * Remove the specific type handler for a certain ability * - * @return + * @param abilityKey ability key + * @param handlerMappingClazz type + * @return the count of handlers are removed + */ + public int removeComponent(AbilityKey abilityKey, Class handlerMappingClazz) { + return doRemove(abilityKey, handlerMappingClazz, lockForHandlerMappings, handlerMappings); + } + + public final void destroy() { + LOGGER.warn("[DefaultAbilityControlManager] - Start destroying..."); + ((ThreadPoolExecutor) simpleThreadPool).shutdown(); + if (MapUtil.isNotEmpty(handlerMappings)) { + handlerMappings.keySet().forEach(key -> doTriggerSyn(key, false, handlerMappings)); + } + // hook + doDestroy(); + LOGGER.warn("[DefaultAbilityControlManager] - Destruction of the end"); + } + + /**. + * hook for subclass */ - @Override - public boolean contains(String connectionId) { - return nodeAbilityTable.containsKey(connectionId); + protected void doDestroy() { + // for server ability manager } /** - * Initialize the manager + * Remove the component instance of

handlerMappingClazz

. + * + * @param abilityKey ability key from {@link AbstractAbilityRegistry} + * @param handlerMappingClazz implement of {@link HandlerMapping} + * @param lock lock for operation + * @param handlerMappingsMap handler collection map + * @return the count of components have removed */ - @Override - public void init() { - // default init - // nothing to do + protected int doRemove(AbilityKey abilityKey, Class handlerMappingClazz, Lock lock, + Map> handlerMappingsMap) { + List handlerMappings = handlerMappingsMap.get(abilityKey); + if (CollectionUtils.isEmpty(handlerMappings)) { + return 0; + } + lock.lock(); + try { + AtomicInteger count = new AtomicInteger(); + handlerMappings.removeIf(item -> { + if (item.handlerMapping.getClass().equals(handlerMappingClazz)) { + count.getAndIncrement(); + return true; + } + return false; + }); + return count.get(); + } finally { + lock.unlock(); + } + } + + public int removeAll(AbilityKey abilityKey) { + List remove = this.handlerMappings.remove(abilityKey); + return Optional.ofNullable(remove).orElse(Collections.emptyList()).size(); + } + + /**. + * Register the component into handlerMappings locking by lockForHandlerMappings to ensure concurrency security. + * + * @param abilityKey ability key + * @param handlerMapping component instance. + * @param handlerMappings container + * @param lockForHandlerMappings lock to ensure concurrency + * @param abilityTable behavioral basis of handler + */ + protected void doRegisterComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, + Map> handlerMappings, Lock lockForHandlerMappings, + int priority, Map abilityTable) { + if (!currentRunningAbility.containsKey(abilityKey)) { + LOGGER.warn("[AbilityHandlePostProcessor] Failed to register processor: {}, because illegal key!", + handlerMapping.getClass().getSimpleName()); + } + + // legal key + lockForHandlerMappings.lock(); + try { + List handlers = handlerMappings.getOrDefault(abilityKey, new CopyOnWriteArrayList<>()); + HandlerWithPriority handlerWithPriority = new HandlerWithPriority(handlerMapping, priority); + handlers.add(handlerWithPriority); + handlerMappings.put(abilityKey, handlers); + // choose behavior + // enable default + if (abilityTable.getOrDefault(abilityKey, false)) { + handlerMapping.enable(); + } else { + handlerMapping.disable(); + } + } catch (Exception e) { + e.printStackTrace(); + LOGGER.error("[DefaultAbilityControlManager] Fail to register handler: {}", handlerMapping.getClass().getSimpleName()); + } finally { + lockForHandlerMappings.unlock(); + LOGGER.info("[DefaultAbilityControlManager] Successfully registered processor: {}", + handlerMapping.getClass().getSimpleName()); + } } /** - * It should be invoked before destroy + * Invoke componments which linked to ability key asyn. + * + * @param key ability key from {@link AbstractAbilityRegistry} + * @param isEnabled turn on/off + * @param handlerMappingsMap handler collection */ - @Override - public void destroy() { - // default destroy - // nothing to do + protected void triggerHandlerMappingAsyn(AbilityKey key, boolean isEnabled, + Map> handlerMappingsMap) { + simpleThreadPool.execute(() -> doTriggerSyn(key, isEnabled, handlerMappingsMap)); } /** - * A Nacos application can only have one {@link AbilityControlManager}. - * When multiple control centers exist, it is used to determine which one is preferred + * Invoke componments which linked to ability key syn. * - * @return priority + * @param key ability key from {@link AbstractAbilityRegistry} + * @param isEnabled turn on/off + * @param handlerMappingsMap handler collection */ - public abstract int getPriority(); - + protected void doTriggerSyn(AbilityKey key, boolean isEnabled, + Map> handlerMappingsMap) { + List handlerWithPriorities = handlerMappingsMap.get(key); + // return if empty + if (CollectionUtils.isEmpty(handlerWithPriorities)) { + return; + } + Collections.sort(handlerWithPriorities); + // invoked all + handlerWithPriorities.forEach(handlerMappingWithPriorities -> { + // any error from current handler does not affect other handler + HandlerMapping handlerMapping = handlerMappingWithPriorities.handlerMapping; + try { + if (isEnabled) { + handlerMapping.enable(); + } else { + handlerMapping.disable(); + } + } catch (Throwable t) { + LOGGER.warn("[HandlerMapping] Failed to invoke {} :{}", handlerMapping.getClass().getSimpleName(), + t.getLocalizedMessage()); + } + }); + } + /** - * Return ability table of current node + * A legal nacos application has a ability control manager. + * If there are more than one, the one with higher priority is preferred * - * @return ability table + * @return priority */ - @Override - public Map getCurrentRunningAbility() { - return new HashMap<>(this.currentRunningAbility); + public abstract int getPriority(); + + @JustForTest + protected Map> handlerMapping() { + return this.handlerMappings; } - + /** - * base class for ability + * Support priority handler. */ - public abstract class AbilityEvent extends Event { - - private static final long serialVersionUID = -123241121302761L; - - protected AbilityEvent(){} - - /** - * connection id. + protected class HandlerWithPriority implements Comparable { + + /**. + * Decorated */ - private String connectionId; - - /** - * ability table + public HandlerMapping handlerMapping; + + /**. + * the higher the priority, the faster it will be called */ - private AbilityTable table; - - - public String getConnectionId() { - return connectionId; - } - - public void setConnectionId(String connectionId) { - this.connectionId = connectionId; - } - - public AbilityTable getTable() { - return table; + public int priority; + + public HandlerWithPriority(HandlerMapping handlerMapping, int priority) { + this.handlerMapping = handlerMapping; + this.priority = priority; } - - public void setTable(AbilityTable table) { - this.table = table; + + @Override + public int compareTo(HandlerWithPriority o) { + return o.priority - this.priority; } } - /** - * when a connection connected. + /**. + * notify when current node ability changing */ - public class AbilityComeEvent extends AbilityEvent { + public class AbilityUpdateEvent extends Event { - private static final long serialVersionUID = -123241121302761L; + private static final long serialVersionUID = -1232411212311111L; - private AbilityComeEvent(){} - } - - /** - * when a connection disconnected. - */ - public class AbilityExpiredEvent extends AbilityEvent { - - private static final long serialVersionUID = -123241121212127619L; - - private AbilityExpiredEvent(){} - + private AbilityKey abilityKey; + + private boolean isOn; + + private Map table; + + private AbilityUpdateEvent(){} + + public Map getAbilityTable() { + return table; + } + + public void setTable(Map abilityTable) { + this.table = abilityTable; + } + + public AbilityKey getAbilityKey() { + return abilityKey; + } + + public void setAbilityKey(AbilityKey abilityKey) { + this.abilityKey = abilityKey; + } + + public boolean isOn() { + return isOn; + } + + public void setOn(boolean on) { + isOn = on; + } } } diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java deleted file mode 100644 index 01fc7a60bb6..00000000000 --- a/common/src/main/java/com/alibaba/nacos/common/ability/DefaultAbilityControlManager.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright 1999-2022 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.ability; - -import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; -import com.alibaba.nacos.api.ability.entity.AbilityTable; -import com.alibaba.nacos.common.JustForTest; -import com.alibaba.nacos.common.ability.handler.HandlerMapping; -import com.alibaba.nacos.common.ability.inter.AbilityHandlerRegistry; -import com.alibaba.nacos.common.executor.ExecutorFactory; -import com.alibaba.nacos.common.notify.NotifyCenter; -import com.alibaba.nacos.common.utils.CollectionUtils; -import com.alibaba.nacos.common.utils.MapUtil; -import com.alibaba.nacos.common.utils.ThreadUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executor; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -/**. - * @author Daydreamer - * @description It is a relatively complete capability control center implementation. - * @date 2022/7/12 19:18 - **/ -@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule") -public abstract class DefaultAbilityControlManager extends AbstractAbilityControlManager - implements AbilityHandlerRegistry { - - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAbilityControlManager.class); - - /**. - * These handlers will be invoked when the flag of ability change key: - * ability key from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} value: - * components who want to be invoked if its interested ability turn on/off - */ - private final Map> handlerMappings = new ConcurrentHashMap<>(); - - /**. - * run for HandlerMapping - */ - private final Executor simpleThreadPool = ExecutorFactory.newSingleExecutorService(); - - private final ReentrantLock lockForHandlerMappings = new ReentrantLock(); - - protected DefaultAbilityControlManager() { - ThreadUtils.addShutdownHook(this::destroy); - NotifyCenter.registerToPublisher(AbilityUpdateEvent.class, 16384); - } - - /** - * . Turn on the ability whose key is

abilityKey

- * - * @param abilityKey ability key - * @return if turn success - */ - @Override - public boolean enableCurrentNodeAbility(AbilityKey abilityKey) { - return doTurn(true, abilityKey); - } - - /** - * . Turn off the ability whose key is

abilityKey

- * - * @param abilityKey ability key - * @return if turn success - */ - @Override - public boolean disableCurrentNodeAbility(AbilityKey abilityKey) { - return doTurn(false, abilityKey); - } - - /** - * . Turn on/off the ability of current node - * - * @param isOn is on - * @param abilityKey ability key from {@link AbilityKey} - * @return if turn success - */ - private boolean doTurn(boolean isOn, AbilityKey abilityKey) { - Boolean isEnabled = currentRunningAbility.get(abilityKey); - // if not supporting this key - if (isEnabled == null) { - LOGGER.warn("[AbilityControlManager] Attempt to turn on/off a not existed ability!"); - return false; - } else if (isOn == isEnabled) { - // if already turn on/off - return true; - } - // turn on/off - currentRunningAbility.put(abilityKey, isOn); - // handler mappings - triggerHandlerMappingAsyn(abilityKey, isOn, this.handlerMappings); - // notify event - AbilityUpdateEvent abilityUpdateEvent = new AbilityUpdateEvent(); - abilityUpdateEvent.setTable(new AbilityTable().setAbility(Collections.unmodifiableMap(currentRunningAbility))); - abilityUpdateEvent.isOn = isOn; - abilityUpdateEvent.abilityKey = abilityKey; - NotifyCenter.publishEvent(abilityUpdateEvent); - return true; - } - - /** - * Register the component which is managed by {@link AbstractAbilityControlManager}. if you are hoping that a - * component will be invoked when turn on/off the ability whose key is

abilityKey

. - * - * @param abilityKey component key. - * @param priority the higher the priority is, the faster it will be called. - * @param handlerMapping component instance. - */ - @Override - public void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority) { - doRegisterComponent(abilityKey, handlerMapping, this.handlerMappings, lockForHandlerMappings, priority, currentRunningAbility); - } - - @Override - public int removeComponent(AbilityKey abilityKey, Class handlerMappingClazz) { - return doRemove(abilityKey, handlerMappingClazz, lockForHandlerMappings, handlerMappings); - } - - @Override - public final void destroy() { - LOGGER.warn("[DefaultAbilityControlManager] - Start destroying..."); - ((ThreadPoolExecutor) simpleThreadPool).shutdown(); - if (MapUtil.isNotEmpty(handlerMappings)) { - handlerMappings.keySet().forEach(key -> doTriggerSyn(key, false, handlerMappings)); - } - // hook - doDestroy(); - LOGGER.warn("[DefaultAbilityControlManager] - Destruction of the end"); - } - - /**. - * hook for subclass - */ - protected void doDestroy() { - // for server ability manager - } - - /** - * Remove the component instance of

handlerMappingClazz

. - * - * @param abilityKey ability key from {@link AbstractAbilityRegistry} - * @param handlerMappingClazz implement of {@link HandlerMapping} - * @param lock lock for operation - * @param handlerMappingsMap handler collection map - * @return the count of components have removed - */ - protected int doRemove(AbilityKey abilityKey, Class handlerMappingClazz, Lock lock, - Map> handlerMappingsMap) { - List handlerMappings = handlerMappingsMap.get(abilityKey); - if (CollectionUtils.isEmpty(handlerMappings)) { - return 0; - } - lock.lock(); - try { - AtomicInteger count = new AtomicInteger(); - handlerMappings.removeIf(item -> { - if (item.handlerMapping.getClass().equals(handlerMappingClazz)) { - count.getAndIncrement(); - return true; - } - return false; - }); - return count.get(); - } finally { - lock.unlock(); - } - } - - @Override - public int removeAll(AbilityKey abilityKey) { - List remove = this.handlerMappings.remove(abilityKey); - return Optional.ofNullable(remove).orElse(Collections.emptyList()).size(); - } - - /**. - * Register the component into handlerMappings locking by lockForHandlerMappings to ensure concurrency security. - * - * @param abilityKey ability key - * @param handlerMapping component instance. - * @param handlerMappings container - * @param lockForHandlerMappings lock to ensure concurrency - * @param abilityTable behavioral basis of handler - */ - protected void doRegisterComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, - Map> handlerMappings, Lock lockForHandlerMappings, - int priority, Map abilityTable) { - if (!currentRunningAbility.containsKey(abilityKey)) { - LOGGER.warn("[AbilityHandlePostProcessor] Failed to register processor: {}, because illegal key!", - handlerMapping.getClass().getSimpleName()); - } - - // legal key - lockForHandlerMappings.lock(); - try { - List handlers = handlerMappings.getOrDefault(abilityKey, new CopyOnWriteArrayList<>()); - HandlerWithPriority handlerWithPriority = new HandlerWithPriority(handlerMapping, priority); - handlers.add(handlerWithPriority); - handlerMappings.put(abilityKey, handlers); - // choose behavior - // enable default - if (abilityTable.getOrDefault(abilityKey, false)) { - handlerMapping.enable(); - } else { - handlerMapping.disable(); - } - } catch (Exception e) { - e.printStackTrace(); - LOGGER.error("[DefaultAbilityControlManager] Fail to register handler: {}", handlerMapping.getClass().getSimpleName()); - } finally { - lockForHandlerMappings.unlock(); - LOGGER.info("[DefaultAbilityControlManager] Successfully registered processor: {}", - handlerMapping.getClass().getSimpleName()); - } - } - - /** - * Invoke componments which linked to ability key asyn. - * - * @param key ability key from {@link AbstractAbilityRegistry} - * @param isEnabled turn on/off - * @param handlerMappingsMap handler collection - */ - protected void triggerHandlerMappingAsyn(AbilityKey key, boolean isEnabled, - Map> handlerMappingsMap) { - simpleThreadPool.execute(() -> doTriggerSyn(key, isEnabled, handlerMappingsMap)); - } - - /** - * Invoke componments which linked to ability key syn. - * - * @param key ability key from {@link AbstractAbilityRegistry} - * @param isEnabled turn on/off - * @param handlerMappingsMap handler collection - */ - protected void doTriggerSyn(AbilityKey key, boolean isEnabled, - Map> handlerMappingsMap) { - List handlerWithPriorities = handlerMappingsMap.get(key); - // return if empty - if (CollectionUtils.isEmpty(handlerWithPriorities)) { - return; - } - Collections.sort(handlerWithPriorities); - // invoked all - handlerWithPriorities.forEach(handlerMappingWithPriorities -> { - // any error from current handler does not affect other handler - HandlerMapping handlerMapping = handlerMappingWithPriorities.handlerMapping; - try { - if (isEnabled) { - handlerMapping.enable(); - } else { - handlerMapping.disable(); - } - } catch (Throwable t) { - LOGGER.warn("[HandlerMapping] Failed to invoke {} :{}", handlerMapping.getClass().getSimpleName(), - t.getLocalizedMessage()); - } - }); - } - - @JustForTest - protected Map> handlerMapping() { - return this.handlerMappings; - } - - /** - * Support priority handler. - */ - protected class HandlerWithPriority implements Comparable { - - /**. - * Decorated - */ - public HandlerMapping handlerMapping; - - /**. - * the higher the priority, the faster it will be called - */ - public int priority; - - public HandlerWithPriority(HandlerMapping handlerMapping, int priority) { - this.handlerMapping = handlerMapping; - this.priority = priority; - } - - @Override - public int compareTo(HandlerWithPriority o) { - return o.priority - this.priority; - } - } - - /**. - * notify when current node ability changing - */ - public class AbilityUpdateEvent extends AbilityEvent { - - private static final long serialVersionUID = -1232411212311111L; - - private AbilityKey abilityKey; - - private boolean isOn; - - private AbilityUpdateEvent(){} - - public AbilityKey getAbilityKey() { - return abilityKey; - } - - public void setAbilityKey(AbilityKey abilityKey) { - this.abilityKey = abilityKey; - } - - public boolean isOn() { - return isOn; - } - - public void setOn(boolean on) { - isOn = on; - } - } -} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java b/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java index 668e96b9d77..3ca141718f6 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/discover/NacosAbilityManagerHolder.java @@ -17,8 +17,6 @@ package com.alibaba.nacos.common.ability.discover; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; -import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; -import com.alibaba.nacos.common.ability.inter.AbilityControlManager; import com.alibaba.nacos.common.spi.NacosServiceLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,19 +47,19 @@ private NacosAbilityManagerHolder() { /**. * singleton */ - private static DefaultAbilityControlManager abstractAbilityControlManager; + private static AbstractAbilityControlManager abstractAbilityControlManager; static { // spi discover implement - Collection load = null; + Collection load = null; try { // if server - load = NacosServiceLoader.load(DefaultAbilityControlManager.class); + load = NacosServiceLoader.load(AbstractAbilityControlManager.class); } catch (ServiceConfigurationError e) { throw new RuntimeException("[AbilityControlManager] Cannot find AbilityControlManger"); } // the priority of the server is higher - List collect = load.stream() + List collect = load.stream() .sorted(Comparator.comparingInt(AbstractAbilityControlManager::getPriority)) .collect(Collectors.toList()); // get the highest priority one @@ -76,7 +74,7 @@ private NacosAbilityManagerHolder() { * * @return BaseAbilityControlManager */ - public static DefaultAbilityControlManager getInstance() { + public static AbstractAbilityControlManager getInstance() { return abstractAbilityControlManager; } @@ -87,7 +85,7 @@ public static DefaultAbilityControlManager getInstance() { * @param target type * @return AbilityControlManager */ - public static T getInstance(Class clazz) { + public static T getInstance(Class clazz) { return clazz.cast(abstractAbilityControlManager); } } diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java deleted file mode 100644 index 304d673d4d1..00000000000 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityControlManager.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 1999-2022 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.ability.inter; - -import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; -import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; -import com.alibaba.nacos.api.ability.entity.AbilityTable; - -import java.util.Map; - -/**. - * @author Daydreamer - * @description This is a base interface to manage ability table - * @date 2022/8/10 23:18 - **/ -public interface AbilityControlManager { - - /** - * Whether the ability is supported for Connection. If the ability of current node is closed, it will return false. - * - * @param connectionId the connection range of ability table. - * @param abilityKey key name which comes from {@link AbstractAbilityRegistry}. - * @return whether the ability is supported in certain connection. - */ - AbilityStatus isSupport(String connectionId, AbilityKey abilityKey); - - /** - * Whether the ability current node supporting is running. Return false if current node doesn't support. - * - * @param abilityKey ability key - * @return is running - */ - boolean isCurrentNodeAbilityRunning(AbilityKey abilityKey); - - /** - * Register a new ability table. - * - * @param table the ability table. - */ - void addNewTable(AbilityTable table); - - /**. - * Remove a ability table - * - * @param connectionId the ability table which is removing. - */ - void removeTable(String connectionId); - - /**. - * whether contains this ability table - * - * @param connectionId connection id - * @return whether contains - */ - boolean contains(String connectionId); - - /**. - * Return ability table of current node - * - * @return ability table - */ - Map getCurrentRunningAbility(); - - /**. - * Initialize the manager - */ - void init(); - - /**. - * It should be invoked before destroy - */ - void destroy(); -} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java b/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java deleted file mode 100644 index 5cbc2a8a506..00000000000 --- a/common/src/main/java/com/alibaba/nacos/common/ability/inter/AbilityHandlerRegistry.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 1999-2022 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.ability.inter; - -import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; -import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; -import com.alibaba.nacos.common.ability.handler.HandlerMapping; - -/**. - * @author Daydreamer - * @description It provides the capability to notify components which interested in one ability for the {@link AbilityControlManager} - * @date 2022/8/10 23:43 - **/ -public interface AbilityHandlerRegistry { - - /**. - * Turn on the ability whose key is

abilityKey

- * - * @param abilityKey ability key - * @return if turn success - */ - boolean enableCurrentNodeAbility(AbilityKey abilityKey); - - /**. - * Turn off the ability whose key is

abilityKey

- * - * @param abilityKey ability key - * @return if turn success - */ - boolean disableCurrentNodeAbility(AbilityKey abilityKey); - - /**. - * Register the component which is managed by {@link AbstractAbilityControlManager}. - * if you are hoping that a component will be invoked when turn on/off the ability whose key is

abilityKey

. - * - * @param abilityKey component key from {@link AbstractAbilityRegistry} - * @param priority a positive number, the higher the priority is, the faster it will be called. `1` is the lowest priority. - * @param handlerMapping component instance. - */ - void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, int priority); - - /**. - * Default method to register component with the lowest priority. - * - * @param abilityKey component key from {@link AbstractAbilityRegistry} - * @param handlerMapping component instance. - */ - default void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMapping) { - registerComponent(abilityKey, handlerMapping, 1); - } - - /** - * Remove the component instance of

handlerMappingClazz

. - * - * @param abilityKey ability key from {@link AbstractAbilityRegistry} - * @param handlerMappingClazz implement of {@link HandlerMapping} - * @return the count of components have removed - */ - int removeComponent(AbilityKey abilityKey, Class handlerMappingClazz); - - /** - * Remove all {@link HandlerMapping} interested in the special ability. - * @param abilityKey abnility key from {@link AbstractAbilityRegistry} - * @return the count of components have removed - */ - int removeAll(AbilityKey abilityKey); - -} diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java b/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java deleted file mode 100644 index 0093709c5b4..00000000000 --- a/common/src/main/java/com/alibaba/nacos/common/ability/listener/ClientAbilityEventListener.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 1999-2022 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.ability.listener; - -import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; -import com.alibaba.nacos.common.remote.client.Connection; -import com.alibaba.nacos.common.remote.client.ConnectionEventListener; - -/**. - * @author Daydreamer - * @description This listener is used for remove ability table if disconnected. - * @date 2022/8/30 22:00 - **/ -public class ClientAbilityEventListener implements ConnectionEventListener { - - @Override - public void onConnected(Connection connection) { - // nothing to do - } - - @Override - public void onDisConnect(Connection connection) { - NacosAbilityManagerHolder.getInstance().removeTable(connection.getConnectionId()); - } -} diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java index b56eaaa3b87..51e81f44809 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java @@ -16,8 +16,11 @@ package com.alibaba.nacos.common.remote.client; +import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.remote.Requester; +import java.util.Map; + /** * connection on client side. * @@ -33,6 +36,8 @@ public abstract class Connection implements Requester { protected RpcClient.ServerInfo serverInfo; + protected Map abilityTable; + public Connection(RpcClient.ServerInfo serverInfo) { this.serverInfo = serverInfo; } @@ -45,6 +50,14 @@ public void setConnectionId(String connectionId) { this.connectionId = connectionId; } + public Map getAbilityTable() { + return abilityTable; + } + + public void setAbilityTable(Map abilityTable) { + this.abilityTable = abilityTable; + } + /** * Getter method for property abandon. * diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java index 6a65ae14676..22e2e1e26d5 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java @@ -28,8 +28,6 @@ import com.alibaba.nacos.api.remote.response.ConnectResetResponse; import com.alibaba.nacos.api.remote.response.ErrorResponse; import com.alibaba.nacos.api.remote.response.Response; -import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; -import com.alibaba.nacos.common.ability.listener.ClientAbilityEventListener; import com.alibaba.nacos.common.lifecycle.Closeable; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.PayloadRegistry; @@ -272,9 +270,6 @@ public final void start() throws NacosException { return; } - // add listener to remove expired ability table - registerConnectionListener(new ClientAbilityEventListener()); - clientEventExecutor = new ScheduledThreadPoolExecutor(2, r -> { Thread t = new Thread(r); t.setName("com.alibaba.nacos.client.remote.worker"); @@ -459,9 +454,6 @@ public void shutdown() throws NacosException { LOGGER.info("Shutdown rpc client, set status to shutdown"); rpcClientStatus.set(RpcClientStatus.SHUTDOWN); LOGGER.info("Shutdown client event executor " + clientEventExecutor); - if (currentConnection != null) { - NacosAbilityManagerHolder.getInstance().removeTable(currentConnection.getConnectionId()); - } if (clientEventExecutor != null) { clientEventExecutor.shutdownNow(); } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 308ead43b1a..4b37cbedfeb 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.common.remote.client.grpc; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -347,23 +346,19 @@ public Connection connectToServer(ServerInfo serverInfo) { // ability table will be null if server doesn't support ability table ServerCheckResponse serverCheckResponse = (ServerCheckResponse) response; connectionId = serverCheckResponse.getConnectionId(); - AbilityTable table = new AbilityTable(); - table.setServer(true) - .setConnectionId(connectionId); + BiRequestStreamGrpc.BiRequestStreamStub biRequestStreamStub = BiRequestStreamGrpc + .newStub(newChannelStubTemp.getChannel()); + GrpcConnection grpcConn = new GrpcConnection(serverInfo, grpcExecutor); + grpcConn.setConnectionId(connectionId); // if not supported, it will be null if (serverCheckResponse.getAbilities() != null) { Map abilityTable = AbilityKey.mapEnum(serverCheckResponse.getAbilities()); - table.setAbility(abilityTable); // mark markForSetup.put(serverCheckResponse.getConnectionId(), new CountDownLatch(1)); + // set server abilities to connection + grpcConn.setAbilityTable(abilityTable); } - NacosAbilityManagerHolder.getInstance().addNewTable(table); - - BiRequestStreamGrpc.BiRequestStreamStub biRequestStreamStub = BiRequestStreamGrpc - .newStub(newChannelStubTemp.getChannel()); - GrpcConnection grpcConn = new GrpcConnection(serverInfo, grpcExecutor); - grpcConn.setConnectionId(connectionId); //create stream request and bind connection event to this connection. StreamObserver payloadStreamObserver = bindRequestStream(biRequestStreamStub, grpcConn); @@ -377,7 +372,7 @@ public Connection connectToServer(ServerInfo serverInfo) { conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion()); conSetupRequest.setLabels(super.getLabels()); // set ability table - conSetupRequest.setAbilityTable(AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility())); + conSetupRequest.setAbilityTable(AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities())); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); // wait for response diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java b/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java index 1b49e8e190c..45b680b4b64 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/config/AbilityConfigs.java @@ -19,8 +19,8 @@ import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.common.JustForTest; +import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; -import com.alibaba.nacos.common.ability.inter.AbilityHandlerRegistry; import com.alibaba.nacos.common.event.ServerConfigChangeEvent; import com.alibaba.nacos.common.notify.Event; import com.alibaba.nacos.common.notify.NotifyCenter; @@ -49,7 +49,7 @@ public class AbilityConfigs extends Subscriber { private final Set serverAbilityKeys = new ConcurrentHashSet<>(); - private AbilityHandlerRegistry abilityHandlerRegistry = NacosAbilityManagerHolder.getInstance(); + private AbstractAbilityControlManager abilityHandlerRegistry = NacosAbilityManagerHolder.getInstance(); public AbilityConfigs() { // load ability @@ -102,7 +102,7 @@ protected Set getServerAbilityKeys() { } @JustForTest - protected void setAbilityHandlerRegistry(AbilityHandlerRegistry abilityHandlerRegistry) { + protected void setAbilityHandlerRegistry(AbstractAbilityControlManager abilityHandlerRegistry) { this.abilityHandlerRegistry = abilityHandlerRegistry; } diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 61d32bc6451..67845d8211e 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -17,61 +17,28 @@ package com.alibaba.nacos.core.ability.control; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; -import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; -import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; -import com.alibaba.nacos.common.ability.DefaultAbilityControlManager; -import com.alibaba.nacos.common.notify.NotifyCenter; -import com.alibaba.nacos.common.utils.ConcurrentHashSet; -import com.alibaba.nacos.common.utils.MapUtil; import com.alibaba.nacos.core.ability.config.AbilityConfigs; -import com.alibaba.nacos.core.ability.inte.ClusterAbilityControlSupport; import com.alibaba.nacos.sys.env.EnvUtil; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Optional; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; /**. * @author Daydreamer * @description {@link AbstractAbilityControlManager} for nacos-server. * @date 2022/7/13 21:14 **/ -public class ServerAbilityControlManager extends DefaultAbilityControlManager implements ClusterAbilityControlSupport { - - /**. - * ability for cluster - */ - private final Map clusterAbilityTable = new ConcurrentHashMap<>(); - - /**. - * ability for server - */ - private final Map serversAbilityTable = new ConcurrentHashMap<>(); - - /**. - * Number of servers that do not support capability negotiation - */ - private final ConcurrentHashSet serverNoAbilityNegotiation = new ConcurrentHashSet<>(); +public class ServerAbilityControlManager extends AbstractAbilityControlManager { public ServerAbilityControlManager() { - // add current node into - AbilityTable currentNodeAbility = new AbilityTable(); - currentNodeAbility.setAbility(super.currentRunningAbility); - currentNodeAbility.setConnectionId("current-node"); - serversAbilityTable.put(currentNodeAbility.getConnectionId(), currentNodeAbility); - clusterAbilityTable.putAll(currentNodeAbility.getAbility()); - NotifyCenter.registerToPublisher(ClusterAbilityUpdateEvent.class, 16384); } @Override - protected Map getCurrentNodeSupportAbility() { + protected Map initCurrentNodeAbilities() { // static abilities Map staticAbilities = ServerAbilities.getStaticAbilities(); // all function server can support @@ -99,160 +66,9 @@ protected Map getCurrentNodeSupportAbility() { return abilityTable; } - @Override - public AbilityStatus isSupport(String connectionId, AbilityKey abilityKey) { - AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - if (abilityTable == null) { - return AbilityStatus.UNKNOWN; - } - Boolean isSupport = Optional.ofNullable(abilityTable.getAbility()).orElse(Collections.emptyMap()) - .getOrDefault(abilityKey, false); - return isSupport ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; - } - - /**. - * Whether all the servers currently connected support a certain capability - * - * @param abilityKey ability key - * @return whether it is turn on - */ - @Override - public AbilityStatus isClusterEnableAbilityNow(AbilityKey abilityKey) { - if (serverNoAbilityNegotiation.size() > 0) { - return AbilityStatus.UNKNOWN; - } - return clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; - } - - @Override - public Map getClusterAbility() { - return serverNoAbilityNegotiation.size() > 0 ? null : Collections.unmodifiableMap(clusterAbilityTable); - } - - @Override - protected void add(AbilityTable table) { - // from which env - boolean isServer = table.isServer(); - // if not null - if (table.getConnectionId() != null && table.getAbility() != null) { - if (isServer) { - serversAbilityTable.put(table.getConnectionId(), table); - // enter cluster - Map nodeAbility = table.getAbility(); - Set keySet = clusterAbilityTable.keySet(); - keySet.forEach(abilityKey -> { - Boolean isEnabled = clusterAbilityTable.get(abilityKey); - Boolean val = nodeAbility.getOrDefault(abilityKey, Boolean.FALSE); - // new res - Boolean newRes = val && isEnabled; - // if ability changes - if (!newRes.equals(isEnabled)) { - clusterAbilityTable.replace(abilityKey, false); - // notify - NotifyCenter.publishEvent(buildClusterEvent(abilityKey, false)); - } - }); - } - } else if (isServer && table.getAbility() == null) { - // add mark if server doesn't support ability table - serverNoAbilityNegotiation.add(table.getConnectionId()); - } - } - - private ClusterAbilityUpdateEvent buildClusterEvent(AbilityKey abilityKey, boolean isOn) { - // notify - ClusterAbilityUpdateEvent event = new ClusterAbilityUpdateEvent(); - event.setAbilityKey(abilityKey); - event.setOn(isOn); - event.setTable(new AbilityTable().setAbility(Collections.unmodifiableMap(clusterAbilityTable))); - return event; - } - - @Override - protected void remove(String connectionId) { - // from which - AbilityTable abilityTable = nodeAbilityTable.get(connectionId); - // if not support - serverNoAbilityNegotiation.remove(connectionId); - // return if null - if (abilityTable == null) { - return; - } - // from which env - if (abilityTable.isServer()) { - // remove from server ability collection if support - serversAbilityTable.remove(connectionId); - // remove from cluster - if (MapUtil.isNotEmpty(serversAbilityTable)) { - Set keySet = clusterAbilityTable.keySet(); - keySet.forEach(abilityKey -> { - Boolean isEnabled = clusterAbilityTable.getOrDefault(abilityKey, Boolean.FALSE); - // nothing to do if enabled - if (isEnabled) { - return; - } - // recalculate - Boolean newVal = serversAbilityTable.values() - .stream() - .map(AbilityTable::getAbility) - .map((map) -> map.getOrDefault(abilityKey, Boolean.FALSE)) - .reduce((a, b) -> a && b) - .orElse(Boolean.FALSE); - clusterAbilityTable.replace(abilityKey, newVal); - // if change - if (!isEnabled.equals(newVal)) { - // notify - NotifyCenter.publishEvent(buildClusterEvent(abilityKey, newVal)); - } - }); - } - } - } - @Override public int getPriority() { return 1; } - - /**. - * notify when current node ability changing - */ - public class ClusterAbilityUpdateEvent extends AbilityEvent { - - private static final long serialVersionUID = -122222411212200111L; - - private AbilityKey abilityKey; - - private boolean isOn; - - private ClusterAbilityUpdateEvent(){} - - public AbilityKey getAbilityKey() { - return abilityKey; - } - - public void setAbilityKey(AbilityKey abilityKey) { - this.abilityKey = abilityKey; - } - - public boolean isOn() { - return isOn; - } - - public void setOn(boolean on) { - isOn = on; - } - - } - - @JustForTest - protected void setClusterAbilityTable(Map map) { - clusterAbilityTable.putAll(map); - } - - @JustForTest - protected Set serverNotSupport() { - return serverNoAbilityNegotiation; - } } diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java b/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java deleted file mode 100644 index 71f32488f71..00000000000 --- a/core/src/main/java/com/alibaba/nacos/core/ability/inte/ClusterAbilityControlSupport.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 1999-2022 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.core.ability.inte; - -import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; -import com.alibaba.nacos.common.ability.inter.AbilityControlManager; - -import java.util.Map; - -/**. - * @author Daydreamer - * @description It provides the capability to manage the AbilityTable in cluster for the {@link AbilityControlManager} - * @date 2022/8/10 23:18 - **/ -public interface ClusterAbilityControlSupport { - - /**. - * Return the cluster abilities. - * - * @return the cluster abilities. - */ - Map getClusterAbility(); - - /**. - * Whether all the servers currently connected support a certain capability - * - * @param abilityKey ability key - * @return whether it is turn on - */ - AbilityStatus isClusterEnableAbilityNow(AbilityKey abilityKey); -} diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java index 2e159bce16b..c5465fdd2f0 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java @@ -66,8 +66,10 @@ public void setAbilityTable(Map abilityTable) { /** * get abilities. * + * @deprecated it is replaced by abilityTable field * @return */ + @Deprecated public ClientAbilities getAbilities() { return abilities; } @@ -75,8 +77,10 @@ public ClientAbilities getAbilities() { /** * set abilities. * + * @deprecated it is replaced by abilityTable field * @param abilities abilities. */ + @Deprecated public void setAbilities(ClientAbilities abilities) { this.abilities = abilities; } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index fc9aff20bd3..bbee2862950 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -92,7 +92,7 @@ public void request(Payload grpcRequest, StreamObserver responseObserve if (ServerCheckRequest.class.getSimpleName().equals(type)) { Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(), // to str map - AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentRunningAbility()))); + AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities()))); traceIfNecessary(serverCheckResponseP, false); responseObserver.onNext(serverCheckResponseP); responseObserver.onCompleted(); diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/listener/ServerAbilityConnectionListener.java b/core/src/main/java/com/alibaba/nacos/core/remote/listener/ServerAbilityConnectionListener.java deleted file mode 100644 index 7b581059258..00000000000 --- a/core/src/main/java/com/alibaba/nacos/core/remote/listener/ServerAbilityConnectionListener.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 1999-2022 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.core.remote.listener; - -import com.alibaba.nacos.api.ability.entity.AbilityTable; -import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; -import com.alibaba.nacos.core.remote.ClientConnectionEventListener; -import com.alibaba.nacos.core.remote.Connection; -import org.springframework.stereotype.Component; - -/**. - * @author Daydreamer - * @description This listener is used to register or remove ability table. - * @date 2022/7/17 19:18 - **/ -@Component -public class ServerAbilityConnectionListener extends ClientConnectionEventListener { - - @Override - public void clientConnected(Connection connect) { - // it will be thought from client all - AbilityTable abilityTable = new AbilityTable(connect.getMetaInfo().getConnectionId(), connect.getAbilityTable(), - false, connect.getMetaInfo().getVersion()); - NacosAbilityManagerHolder.getInstance().addNewTable(abilityTable); - } - - @Override - public void clientDisConnected(Connection connect) { - NacosAbilityManagerHolder.getInstance().removeTable(connect.getMetaInfo().getConnectionId()); - } -} diff --git a/core/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager b/core/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.AbstractAbilityControlManager similarity index 100% rename from core/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.DefaultAbilityControlManager rename to core/src/main/resources/META-INF/services/com.alibaba.nacos.common.ability.AbstractAbilityControlManager diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java index 8a01dbc2de7..dcaad35f513 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java @@ -17,8 +17,6 @@ package com.alibaba.nacos.core.ability; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; -import com.alibaba.nacos.api.ability.entity.AbilityTable; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import org.junit.Assert; import org.junit.Before; @@ -40,99 +38,9 @@ public class AbilityControlManagerTest { public void inject() { Map newTable = new HashMap<>(); newTable.put(AbilityKey.TEST_1, true); - - Map cluster = new HashMap<>(); - cluster.put(AbilityKey.TEST_1, true); - serverAbilityControlManager.setClusterAbility(cluster); serverAbilityControlManager.setCurrentSupportingAbility(newTable); } - @Test - public void testClientAdd() { - Map newTable = new HashMap<>(); - newTable.put(AbilityKey.TEST_2, true); - newTable.put(AbilityKey.TEST_1, true); - AbilityTable table = new AbilityTable(); - table.setConnectionId("test-00001"); - table.setAbility(newTable); - table.setServer(true); - serverAbilityControlManager.addNewTable(table); - Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); - Assert.assertEquals(AbilityStatus.SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); - } - - @Test - public void testServerAdd() { - Map newTable = new HashMap<>(); - newTable.put(AbilityKey.TEST_2, true); - newTable.put(AbilityKey.TEST_1, true); - AbilityTable table = new AbilityTable(); - table.setConnectionId("test-00001"); - table.setAbility(newTable); - table.setServer(true); - serverAbilityControlManager.addNewTable(table); - Assert.assertEquals(AbilityStatus.NOT_SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_2)); - Assert.assertEquals(AbilityStatus.SUPPORTED, serverAbilityControlManager.isSupport("test-00001", AbilityKey.TEST_1)); - - Map otherServer = new HashMap<>(); - otherServer.put(AbilityKey.TEST_2, true); - otherServer.put(AbilityKey.TEST_1, false); - AbilityTable otherServerTable = new AbilityTable(); - otherServerTable.setConnectionId("test-00000"); - otherServerTable.setAbility(otherServer); - otherServerTable.setServer(true); - serverAbilityControlManager.addNewTable(otherServerTable); - - Map clientTa = new HashMap<>(); - clientTa.put(AbilityKey.TEST_2, true); - clientTa.put(AbilityKey.TEST_1, false); - AbilityTable clientTable = new AbilityTable(); - clientTable.setConnectionId("test-00002"); - clientTable.setAbility(clientTa); - clientTable.setServer(false); - serverAbilityControlManager.addNewTable(clientTable); - - // if not support - AbilityTable serverTable = new AbilityTable(); - serverTable.setConnectionId("test-001231"); - serverTable.setServer(true); - serverAbilityControlManager.addNewTable(serverTable); - // unknown because not support - Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); - Assert.assertEquals(serverAbilityControlManager.getServerNotSupportAbility().size(), 1); - Assert.assertTrue(serverAbilityControlManager.getServerNotSupportAbility().contains("test-001231")); - - AbilityTable serverTable1 = new AbilityTable(); - serverTable1.setConnectionId("test-001231231"); - serverTable1.setServer(true); - serverAbilityControlManager.addNewTable(serverTable1); - // unknown because not support - Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); - Assert.assertEquals(serverAbilityControlManager.getServerNotSupportAbility().size(), 2); - Assert.assertTrue(serverAbilityControlManager.getServerNotSupportAbility().contains("test-001231231")); - - // remove then support - serverAbilityControlManager.removeTable("test-001231"); - Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); - serverAbilityControlManager.removeTable("test-001231231"); - Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.NOT_SUPPORTED); - } - - @Test - public void testClientRemove() { - Map clientTa = new HashMap<>(); - clientTa.put(AbilityKey.TEST_2, true); - clientTa.put(AbilityKey.TEST_1, false); - AbilityTable clientTable = new AbilityTable(); - clientTable.setConnectionId("test-01111"); - clientTable.setAbility(clientTa); - clientTable.setServer(true); - serverAbilityControlManager.addNewTable(clientTable); - Assert.assertTrue(serverAbilityControlManager.contains(clientTable.getConnectionId())); - serverAbilityControlManager.removeTable("test-01111"); - Assert.assertFalse(serverAbilityControlManager.contains(clientTable.getConnectionId())); - } - @Test public void testComponent() throws InterruptedException { enabled = 0; @@ -177,7 +85,7 @@ public void testComponent() throws InterruptedException { @Test public void testCurrentNodeAbility() { - Set keySet = serverAbilityControlManager.getCurrentRunningAbility().keySet(); + Set keySet = serverAbilityControlManager.getCurrentNodeAbilities().keySet(); // diable all keySet.forEach(key -> serverAbilityControlManager.disableCurrentNodeAbility(key)); // get all @@ -190,42 +98,6 @@ public void testCurrentNodeAbility() { keySet.forEach(key -> { Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(key)); }); - - // add node doesn't support ability table - AbilityTable abilityTable = new AbilityTable(); - abilityTable.setServer(true); - abilityTable.setConnectionId("adsadsa1"); - serverAbilityControlManager.addNewTable(abilityTable); - // cluster abilities close - Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); - - AbilityTable abilityTable1 = new AbilityTable(); - abilityTable1.setServer(true); - abilityTable1.setConnectionId("adsadsa2"); - serverAbilityControlManager.addNewTable(abilityTable1); - // cluster abilities still close - Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); - Assert.assertNull(serverAbilityControlManager.getClusterAbility()); - - AbilityTable abilityTable2 = new AbilityTable(); - abilityTable2.setServer(true); - abilityTable2.setConnectionId("adsadsa3"); - Map clientTa = new HashMap<>(); - clientTa.put(AbilityKey.TEST_2, true); - clientTa.put(AbilityKey.TEST_1, false); - abilityTable2.setAbility(clientTa); - serverAbilityControlManager.addNewTable(abilityTable2); - // cluster abilities still close - Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); - Assert.assertNull(serverAbilityControlManager.getClusterAbility()); - - // remove - serverAbilityControlManager.removeTable("adsadsa3"); - serverAbilityControlManager.removeTable("adsadsa2"); - serverAbilityControlManager.removeTable("adsadsa1"); - // cluster abilities open - Assert.assertEquals(serverAbilityControlManager.isClusterEnableAbilityNow(AbilityKey.TEST_1), AbilityStatus.SUPPORTED); - Assert.assertNotNull(serverAbilityControlManager.getClusterAbility()); } class TestHandlerMapping implements HandlerMapping { diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java index 3953cf54e7a..d19fa2db67c 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java @@ -31,19 +31,9 @@ public void setCurrentSupportingAbility(Map ability) { currentRunningAbility.putAll(ability); } - @JustForTest - public void setClusterAbility(Map ability) { - super.setClusterAbilityTable(ability); - } - @JustForTest public int handlerMappingCount() { return super.handlerMapping().size(); } - @JustForTest - public Set getServerNotSupportAbility() { - return super.serverNotSupport(); - } - } diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java b/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java index d24b1677cb7..c0cbcea025d 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/config/TestAbilityConfig.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.core.ability.config; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.common.ability.inter.AbilityHandlerRegistry; import java.util.Set; @@ -33,8 +32,4 @@ public TestAbilityConfig() { serverAbilityKeys.add(AbilityKey.TEST_1); serverAbilityKeys.add(AbilityKey.TEST_2); } - - public void setAbilityControlManager(AbilityHandlerRegistry abilityHandlerRegistry) { - super.setAbilityHandlerRegistry(abilityHandlerRegistry); - } } From 12e447e690ae300e1914079105aa4ebf917df7ad Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 10 Sep 2022 14:46:30 +0800 Subject: [PATCH 032/181] Add the connection arg to ServerRequestHandler in order to get ability easily. --- .../api/ability/constant/AbilityKey.java | 2 +- .../client/config/impl/ClientWorker.java | 4 +- .../remote/gprc/NamingPushRequestHandler.java | 3 +- .../gprc/NamingPushRequestHandlerTest.java | 4 +- .../AbstractAbilityControlManager.java | 15 ++++--- .../nacos/common/remote/client/RpcClient.java | 45 ++++++++++--------- .../remote/client/ServerRequestHandler.java | 2 +- .../common/remote/client/grpc/GrpcClient.java | 2 +- .../nacos/core/cluster/MemberUtil.java | 3 +- .../TestServerAbilityControlManager.java | 1 - 10 files changed, 45 insertions(+), 36 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java index 6857e73e434..d2e71e126df 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java @@ -117,7 +117,7 @@ public static Map mapStr(Map abilities) { .collect(Collectors.toMap((entry) -> entry.getKey().getName(), Map.Entry::getValue)); } - /** + /**. * getter to obtain enum * * @param key string key diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index a227d537e9c..4661c8d12a3 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -593,7 +593,7 @@ private void initRpcClientHandler(final RpcClient rpcClientInner) { /* * Register Config Change /Config ReSync Handler */ - rpcClientInner.registerServerRequestHandler((request) -> { + rpcClientInner.registerServerRequestHandler((request, connection) -> { if (request instanceof ConfigChangeNotifyRequest) { ConfigChangeNotifyRequest configChangeNotifyRequest = (ConfigChangeNotifyRequest) request; LOGGER.info("[{}] [server-push] config changed. dataId={}, group={},tenant={}", @@ -617,7 +617,7 @@ private void initRpcClientHandler(final RpcClient rpcClientInner) { return null; }); - rpcClientInner.registerServerRequestHandler((request) -> { + rpcClientInner.registerServerRequestHandler((request, connection) -> { if (request instanceof ClientConfigMetricRequest) { ClientConfigMetricResponse response = new ClientConfigMetricResponse(); response.setMetrics(getMetrics(((ClientConfigMetricRequest) request).getMetricsKeys())); diff --git a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandler.java b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandler.java index 5a5dbb6dfc9..b0b4472af4e 100644 --- a/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandler.java +++ b/client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandler.java @@ -21,6 +21,7 @@ import com.alibaba.nacos.api.remote.request.Request; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; +import com.alibaba.nacos.common.remote.client.Connection; import com.alibaba.nacos.common.remote.client.ServerRequestHandler; /** @@ -37,7 +38,7 @@ public NamingPushRequestHandler(ServiceInfoHolder serviceInfoHolder) { } @Override - public Response requestReply(Request request) { + public Response requestReply(Request request, Connection connection) { if (request instanceof NotifySubscriberRequest) { NotifySubscriberRequest notifyResponse = (NotifySubscriberRequest) request; serviceInfoHolder.processServiceInfo(notifyResponse.getServiceInfo()); diff --git a/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandlerTest.java b/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandlerTest.java index 2e70dd24c38..22dc7fd64ff 100644 --- a/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandlerTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/naming/remote/gprc/NamingPushRequestHandlerTest.java @@ -24,6 +24,8 @@ import com.alibaba.nacos.api.remote.request.Request; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.client.naming.cache.ServiceInfoHolder; +import com.alibaba.nacos.client.naming.remote.TestConnection; +import com.alibaba.nacos.common.remote.client.RpcClient; import org.junit.Assert; import org.junit.Test; @@ -41,7 +43,7 @@ public void testRequestReply() { ServiceInfo info = new ServiceInfo("name", "cluster1"); Request req = NotifySubscriberRequest.buildNotifySubscriberRequest(info); //when - Response response = handler.requestReply(req); + Response response = handler.requestReply(req, new TestConnection(new RpcClient.ServerInfo())); //then Assert.assertTrue(response instanceof NotifySubscriberResponse); verify(holder, times(1)).processServiceInfo(info); diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 4b1271fc8da..08569913692 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -99,14 +99,14 @@ public boolean isCurrentNodeAbilityRunning(AbilityKey abilityKey) { return currentRunningAbility.getOrDefault(abilityKey, false); } - /** + /**. * Init current node abilities * * @return current node abilities */ protected abstract Map initCurrentNodeAbilities(); - /** + /**. * Return the abilities current node * * @return current abilities @@ -115,8 +115,8 @@ public Map getCurrentNodeAbilities() { return Collections.unmodifiableMap(currentRunningAbility); } - /** - * . Turn on/off the ability of current node + /**. + * Turn on/off the ability of current node * * @param isOn is on * @param abilityKey ability key from {@link AbilityKey} @@ -157,7 +157,7 @@ public void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMappi doRegisterComponent(abilityKey, handlerMapping, this.handlerMappings, lockForHandlerMappings, priority, currentRunningAbility); } - /** + /**. * Register component with the lowest priority * * @param abilityKey ability key @@ -167,7 +167,7 @@ public void registerComponent(AbilityKey abilityKey, HandlerMapping handlerMappi registerComponent(abilityKey, handlerMapping, -1); } - /** + /**. * Remove the specific type handler for a certain ability * * @param abilityKey ability key @@ -178,6 +178,9 @@ public int removeComponent(AbilityKey abilityKey, Class { + registerServerRequestHandler((request, connection) -> { if (request instanceof ClientDetectionRequest) { return new ClientDetectionResponse(); } @@ -412,7 +414,7 @@ public final void start() throws NacosException { class ConnectResetRequestHandler implements ServerRequestHandler { @Override - public Response requestReply(Request request) { + public Response requestReply(Request request, Connection connection) { if (request instanceof ConnectResetRequest) { @@ -831,7 +833,7 @@ protected Response handleServerRequest(final Request request) { lastActiveTimeStamp = System.currentTimeMillis(); for (ServerRequestHandler serverRequestHandler : serverRequestHandlers) { try { - Response response = serverRequestHandler.requestReply(request); + Response response = serverRequestHandler.requestReply(request, currentConnection); if (response != null) { LoggerUtils.printIfInfoEnabled(LOGGER, "[{}] Ack server push request, request = {}, requestId = {}", name, @@ -1039,24 +1041,6 @@ public ReconnectContext(ServerInfo serverInfo, boolean onRequestFail) { ServerInfo serverInfo; } - protected class RecServerAbilityContext { - - public RecServerAbilityContext(String connectionId, Map abilityTable, String version, String oldConnectionId) { - this.connectionId = connectionId; - this.abilityTable = abilityTable; - this.version = version; - this.oldConnectionId = oldConnectionId; - } - - String connectionId; - - Map abilityTable; - - String version; - - String oldConnectionId; - } - public String getTenant() { return tenant; } @@ -1064,4 +1048,23 @@ public String getTenant() { public void setTenant(String tenant) { this.tenant = tenant; } + + /**. + * Return ability of current connection + * + * @param abilityKey ability key + * @return whether support, return null if connection is not ready + */ + public AbilityStatus getConnectionAbility(AbilityKey abilityKey) { + if (currentConnection != null) { + Map abilityTable = currentConnection.getAbilityTable(); + // if null, the server may not support ability table + if (abilityTable == null) { + return AbilityStatus.UNKNOWN; + } + return abilityTable.getOrDefault(abilityKey, false) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; + } + // return null if connection is not ready + return null; + } } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/ServerRequestHandler.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/ServerRequestHandler.java index 19f97fde0f2..f4163249e45 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/ServerRequestHandler.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/ServerRequestHandler.java @@ -33,6 +33,6 @@ public interface ServerRequestHandler { * @param request request * @return response. */ - Response requestReply(Request request); + Response requestReply(Request request, Connection connection); } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 4b37cbedfeb..1467b3ddcae 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -96,7 +96,7 @@ public GrpcClient(String name) { super(name); // register to handler setup request - registerServerRequestHandler((request) -> { + registerServerRequestHandler((request, connection) -> { // if finish setup if (request instanceof SetupAckRequest) { SetupAckRequest setupAckRequest = (SetupAckRequest) request; diff --git a/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java b/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java index 07cf27b8aea..6a664a30dfb 100644 --- a/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java +++ b/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java @@ -284,7 +284,8 @@ public static boolean isBasicInfoChanged(Member actual, Member expected) { return true; } - if (!(expected.isSupportRemoteConnection() && actual.isSupportRemoteConnection())) { + // if change + if (expected.isSupportRemoteConnection() ^ actual.isSupportRemoteConnection()) { return true; } diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java index d19fa2db67c..dea6bef4e2f 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java @@ -21,7 +21,6 @@ import com.alibaba.nacos.core.ability.control.ServerAbilityControlManager; import java.util.Map; -import java.util.Set; public class TestServerAbilityControlManager extends ServerAbilityControlManager { From 2571bb6ca7c9d35b23ac80ac6381331be21598ba Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 10 Sep 2022 15:03:02 +0800 Subject: [PATCH 033/181] Combine junit test --- .../ability/AbilityControlManagerTest.java | 157 ------------------ .../TestClientAbilityControlManager.java | 46 ----- .../ability/AbilityControlManagerTest.java | 58 +++++++ .../TestServerAbilityControlManager.java | 11 ++ 4 files changed, 69 insertions(+), 203 deletions(-) delete mode 100644 client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java delete mode 100644 client/src/test/java/com/alibaba/nacos/client/ability/TestClientAbilityControlManager.java diff --git a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java deleted file mode 100644 index b0994fa596e..00000000000 --- a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityControlManagerTest.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 1999-2022 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.ability; - -import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.common.ability.handler.HandlerMapping; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; - -public class AbilityControlManagerTest { - - private TestClientAbilityControlManager clientAbilityControlManager = new TestClientAbilityControlManager(); - - private volatile int enabled = 0; - - private volatile LinkedList testPriority = new LinkedList<>(); - - @Before - public void inject() { - Map newTable = new HashMap<>(); - newTable.put(AbilityKey.TEST_1, true); - clientAbilityControlManager.setCurrentSupportingAbility(newTable); - } - - @Test - public void testComponent() throws InterruptedException { - enabled = 0; - // invoke enable() or disable() when registering - clientAbilityControlManager.registerComponent(AbilityKey.TEST_1, new TestHandlerMapping(), -1); - Assert.assertEquals(1, clientAbilityControlManager.handlerMappingCount()); - - clientAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); - // wait for invoking handler asyn - Thread.sleep(200L); - // nothing happens if it has enabled - Assert.assertEquals(enabled, 1); - Assert.assertTrue(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - - // invoke disable() - clientAbilityControlManager.disableCurrentNodeAbility(AbilityKey.TEST_1); - // wait for invoking handler asyn - Thread.sleep(200L); - // disable will invoke handler - Assert.assertEquals(enabled, 0); - Assert.assertFalse(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - - clientAbilityControlManager.disableCurrentNodeAbility(AbilityKey.TEST_1); - // wait for invoking handler asyn - Thread.sleep(200L); - // nothing to do because it has disable - Assert.assertEquals(enabled, 0); - Assert.assertFalse(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - - clientAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); - // wait for invoking handler asyn - Thread.sleep(200L); - Assert.assertEquals(enabled, 1); - Assert.assertTrue(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - - clientAbilityControlManager.enableCurrentNodeAbility(AbilityKey.TEST_1); - // wait for invoking handler asyn - Thread.sleep(200L); - Assert.assertEquals(enabled, 1); - Assert.assertTrue(clientAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); - } - - @Test - public void testPriority() throws InterruptedException { - TestClientAbilityControlManager testClientAbilityControlManager = new TestClientAbilityControlManager(); - AbilityKey key = AbilityKey.TEST_1; - TestPriority handlerMapping1 = new TestPriority("1"); - TestPriority handlerMapping2 = new TestPriority("2"); - TestPriority handlerMapping3 = new TestPriority("3"); - // first one, invoke enable() - testClientAbilityControlManager.registerComponent(key, handlerMapping2, 128); - // last one, invoke enable() - testClientAbilityControlManager.registerComponent(key, handlerMapping3); - // second one, invoke enable() - testClientAbilityControlManager.registerComponent(key, handlerMapping1, 12); - // trigger - testClientAbilityControlManager.trigger(key); - Assert.assertEquals(3, testClientAbilityControlManager.getHandlerMapping(key).size()); - // wait for invoking - Thread.sleep(200L); - Assert.assertEquals("2", testPriority.poll()); - Assert.assertEquals("3", testPriority.poll()); - Assert.assertEquals("1", testPriority.poll()); - // here are priority - Assert.assertEquals("2", testPriority.poll()); - Assert.assertEquals("1", testPriority.poll()); - Assert.assertEquals("3", testPriority.poll()); - - // remove - testClientAbilityControlManager.registerComponent(key, new TestHandlerMapping(), -1); - Assert.assertEquals(4, testClientAbilityControlManager.getHandlerMapping(key).size()); - Assert.assertEquals(1, testClientAbilityControlManager.removeComponent(key, TestHandlerMapping.class)); - Assert.assertEquals(3, testClientAbilityControlManager.getHandlerMapping(key).size()); - testClientAbilityControlManager.removeAll(key); - Assert.assertNull(testClientAbilityControlManager.getHandlerMapping(key)); - } - - class TestPriority implements HandlerMapping { - - String mark; - - public TestPriority(String mark) { - // unique one - this.mark = mark.intern(); - } - - @Override - public void enable() { - testPriority.offer(mark); - } - - @Override - public void disable() { - testPriority.offer(mark); - } - } - - class TestHandlerMapping implements HandlerMapping { - - @Override - public void enable() { - enabled++; - } - - @Override - public void disable() { - enabled--; - } - - } - -} - - diff --git a/client/src/test/java/com/alibaba/nacos/client/ability/TestClientAbilityControlManager.java b/client/src/test/java/com/alibaba/nacos/client/ability/TestClientAbilityControlManager.java deleted file mode 100644 index df52b85f3ea..00000000000 --- a/client/src/test/java/com/alibaba/nacos/client/ability/TestClientAbilityControlManager.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 1999-2022 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.ability; - -import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.common.JustForTest; - -import java.util.List; -import java.util.Map; - -public class TestClientAbilityControlManager extends ClientAbilityControlManager { - - @JustForTest - public void setCurrentSupportingAbility(Map ability) { - currentRunningAbility.putAll(ability); - } - - @JustForTest - public int handlerMappingCount() { - return super.handlerMapping().size(); - } - - @JustForTest - public List getHandlerMapping(AbilityKey abilityKey) { - return super.handlerMapping().get(abilityKey); - } - - @JustForTest - public void trigger(AbilityKey abilityKey) { - triggerHandlerMappingAsyn(abilityKey, true, handlerMapping()); - } -} diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java index dcaad35f513..26483920bef 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java @@ -24,6 +24,7 @@ import org.springframework.boot.test.context.SpringBootTest; import java.util.HashMap; +import java.util.LinkedList; import java.util.Map; import java.util.Set; @@ -33,6 +34,8 @@ public class AbilityControlManagerTest { private TestServerAbilityControlManager serverAbilityControlManager = new TestServerAbilityControlManager(); private volatile int enabled = 0; + + private volatile LinkedList testPriority = new LinkedList<>(); @Before public void inject() { @@ -100,6 +103,61 @@ public void testCurrentNodeAbility() { }); } + @Test + public void testPriority() throws InterruptedException { + TestServerAbilityControlManager testClientAbilityControlManager = new TestServerAbilityControlManager(); + AbilityKey key = AbilityKey.TEST_1; + TestPriority handlerMapping1 = new TestPriority("1"); + TestPriority handlerMapping2 = new TestPriority("2"); + TestPriority handlerMapping3 = new TestPriority("3"); + // first one, invoke enable() + testClientAbilityControlManager.registerComponent(key, handlerMapping2, 128); + // last one, invoke enable() + testClientAbilityControlManager.registerComponent(key, handlerMapping3); + // second one, invoke enable() + testClientAbilityControlManager.registerComponent(key, handlerMapping1, 12); + // trigger + testClientAbilityControlManager.trigger(key); + Assert.assertEquals(3, testClientAbilityControlManager.getHandlerMapping(key).size()); + // wait for invoking + Thread.sleep(200L); + Assert.assertEquals("2", testPriority.poll()); + Assert.assertEquals("3", testPriority.poll()); + Assert.assertEquals("1", testPriority.poll()); + // here are priority + Assert.assertEquals("2", testPriority.poll()); + Assert.assertEquals("1", testPriority.poll()); + Assert.assertEquals("3", testPriority.poll()); + + // remove + testClientAbilityControlManager.registerComponent(key, new TestHandlerMapping(), -1); + Assert.assertEquals(4, testClientAbilityControlManager.getHandlerMapping(key).size()); + Assert.assertEquals(1, testClientAbilityControlManager.removeComponent(key, TestHandlerMapping.class)); + Assert.assertEquals(3, testClientAbilityControlManager.getHandlerMapping(key).size()); + testClientAbilityControlManager.removeAll(key); + Assert.assertNull(testClientAbilityControlManager.getHandlerMapping(key)); + } + + class TestPriority implements HandlerMapping { + + String mark; + + public TestPriority(String mark) { + // unique one + this.mark = mark.intern(); + } + + @Override + public void enable() { + testPriority.offer(mark); + } + + @Override + public void disable() { + testPriority.offer(mark); + } + } + class TestHandlerMapping implements HandlerMapping { @Override diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java index dea6bef4e2f..e9bb30ff8f2 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java @@ -20,6 +20,7 @@ import com.alibaba.nacos.common.JustForTest; import com.alibaba.nacos.core.ability.control.ServerAbilityControlManager; +import java.util.List; import java.util.Map; public class TestServerAbilityControlManager extends ServerAbilityControlManager { @@ -35,4 +36,14 @@ public int handlerMappingCount() { return super.handlerMapping().size(); } + @JustForTest + public List getHandlerMapping(AbilityKey abilityKey) { + return super.handlerMapping().get(abilityKey); + } + + @JustForTest + public void trigger(AbilityKey abilityKey) { + triggerHandlerMappingAsyn(abilityKey, true, handlerMapping()); + } + } From a8c3b847c064f67b827b2a03df274eba53df07e3 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 10 Sep 2022 20:08:15 +0800 Subject: [PATCH 034/181] Add the api to judge ability, add junit test. --- .../nacos/client/ability/AbilityTest.java | 137 ++++++++++++++++++ .../common/remote/client/Connection.java | 8 +- .../nacos/common/remote/client/RpcClient.java | 7 +- .../alibaba/nacos/core/remote/Connection.java | 8 +- 4 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java diff --git a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java new file mode 100644 index 00000000000..f5f966f6e90 --- /dev/null +++ b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java @@ -0,0 +1,137 @@ +/* + * Copyright 1999-2022 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.ability; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.remote.RequestCallBack; +import com.alibaba.nacos.api.remote.RequestFuture; +import com.alibaba.nacos.api.remote.request.Request; +import com.alibaba.nacos.api.remote.response.Response; +import com.alibaba.nacos.client.naming.remote.TestConnection; +import com.alibaba.nacos.common.remote.ConnectionType; +import com.alibaba.nacos.common.remote.client.Connection; +import com.alibaba.nacos.common.remote.client.RpcClient; +import com.alibaba.nacos.common.remote.client.ServerListFactory; +import com.alibaba.nacos.common.remote.client.ServerRequestHandler; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; +import java.util.HashMap; +import java.util.List; + +public class AbilityTest { + + private RpcClient rpcClient; + + private Connection connection; + + @Test + public void testReceive() throws Exception { + rpcClient = new RpcClient("name") { + + @Override + public ConnectionType getConnectionType() { + return null; + } + + @Override + public int rpcPortOffset() { + return 0; + } + + @Override + public Connection connectToServer(ServerInfo serverInfo) throws Exception { + connection = new Connection(new RpcClient.ServerInfo()) { + + { + super.abilityTable = new HashMap<>(); + super.abilityTable.put(AbilityKey.TEST_1, true); + super.abilityTable.put(AbilityKey.TEST_2, false); + } + + @Override + public Response request(Request request, long timeoutMills) throws NacosException { + return null; + } + + @Override + public RequestFuture requestFuture(Request request) throws NacosException { + return null; + } + + @Override + public void asyncRequest(Request request, RequestCallBack requestCallBack) throws NacosException { + + } + + @Override + public void close() { + + } + };; + return connection; + } + }; + rpcClient.start(); + // test not ready + Assert.assertNull(rpcClient.getConnectionAbility(AbilityKey.TEST_1)); + + // test ready + rpcClient.serverListFactory(new ServerListFactory() { + + @Override + public String genNextServer() { + return "localhost:8848"; + } + + @Override + public String getCurrentServer() { + return "localhost:8848"; + } + + @Override + public List getServerList() { + return null; + } + }); + rpcClient.start(); + // if connect successfully + Assert.assertEquals(rpcClient.getConnectionAbility(AbilityKey.TEST_1), AbilityStatus.SUPPORTED); + Assert.assertEquals(rpcClient.getConnectionAbility(AbilityKey.TEST_2), AbilityStatus.NOT_SUPPORTED); + } + + @After + public void testServerRequestAbility() { + //test support + ServerRequestHandler serverRequestHandler = (request, connection) -> { + Assert.assertEquals(connection.getConnectionAbility(AbilityKey.TEST_1), AbilityStatus.SUPPORTED); + Assert.assertEquals(connection.getConnectionAbility(AbilityKey.TEST_2), AbilityStatus.NOT_SUPPORTED); + return new Response() { }; + }; + serverRequestHandler.requestReply(null, connection); + + // test no ability table + serverRequestHandler = (request, connection) -> { + Assert.assertEquals(connection.getConnectionAbility(AbilityKey.TEST_1), AbilityStatus.UNKNOWN); + return new Response() { }; + }; + serverRequestHandler.requestReply(null, new TestConnection(new RpcClient.ServerInfo())); + } + +} diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java index 51e81f44809..a7e37199c3f 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java @@ -17,6 +17,7 @@ package com.alibaba.nacos.common.remote.client; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.remote.Requester; import java.util.Map; @@ -50,8 +51,11 @@ public void setConnectionId(String connectionId) { this.connectionId = connectionId; } - public Map getAbilityTable() { - return abilityTable; + public AbilityStatus getConnectionAbility(AbilityKey abilityKey) { + if (abilityTable == null) { + return AbilityStatus.UNKNOWN; + } + return abilityTable.getOrDefault(abilityKey, false) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; } public void setAbilityTable(Map abilityTable) { diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java index 80cef72c630..f9f2143f47c 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/RpcClient.java @@ -1057,12 +1057,7 @@ public void setTenant(String tenant) { */ public AbilityStatus getConnectionAbility(AbilityKey abilityKey) { if (currentConnection != null) { - Map abilityTable = currentConnection.getAbilityTable(); - // if null, the server may not support ability table - if (abilityTable == null) { - return AbilityStatus.UNKNOWN; - } - return abilityTable.getOrDefault(abilityKey, false) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; + return currentConnection.getConnectionAbility(abilityKey); } // return null if connection is not ready return null; diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java index c5465fdd2f0..317fdf0ace5 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java @@ -18,6 +18,7 @@ import com.alibaba.nacos.api.ability.ClientAbilities; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.remote.Requester; import java.util.Map; @@ -55,8 +56,11 @@ public void setTraced(boolean traced) { this.traced = traced; } - public Map getAbilityTable() { - return abilityTable; + public AbilityStatus getConnectionAbility(AbilityKey abilityKey) { + if (abilityTable == null) { + return AbilityStatus.UNKNOWN; + } + return abilityTable.getOrDefault(abilityKey, false) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; } public void setAbilityTable(Map abilityTable) { From 8f14e63f0cb5ff3ff29d6ba22630bea168cd9de7 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 10 Sep 2022 20:20:09 +0800 Subject: [PATCH 035/181] Combine with current node abilities. --- .../ability/AbstractAbilityControlManager.java | 14 ++++++++++++++ .../common/remote/client/grpc/GrpcClient.java | 3 +++ .../remote/grpc/GrpcBiStreamRequestAcceptor.java | 8 +++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 08569913692..1529460265f 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -192,6 +192,20 @@ public final void destroy() { LOGGER.warn("[DefaultAbilityControlManager] - Destruction of the end"); } + /** + * Combine with current node abilities, in order to get abilities current node provides + * + * @param abilities combined ability table + */ + public void combine(Map abilities) { + currentRunningAbility.forEach((k, v) -> { + Boolean isCurrentSupport = currentRunningAbility.get(k); + if (isCurrentSupport != null) { + abilities.put(k, abilities.getOrDefault(k, false) && isCurrentSupport); + } + }); + } + /**. * hook for subclass */ diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 1467b3ddcae..5221f392235 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -356,6 +356,9 @@ public Connection connectToServer(ServerInfo serverInfo) { Map abilityTable = AbilityKey.mapEnum(serverCheckResponse.getAbilities()); // mark markForSetup.put(serverCheckResponse.getConnectionId(), new CountDownLatch(1)); + // combine with current node abilities + // in order to get abilities current node provides + NacosAbilityManagerHolder.getInstance().combine(abilityTable); // set server abilities to connection grpcConn.setAbilityTable(abilityTable); } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 61f82ba644c..32cef2075b5 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -24,6 +24,7 @@ import com.alibaba.nacos.api.remote.request.ConnectionSetupRequest; import com.alibaba.nacos.api.remote.request.SetupAckRequest; import com.alibaba.nacos.api.remote.response.Response; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.grpc.GrpcUtils; import com.alibaba.nacos.core.remote.Connection; @@ -125,7 +126,12 @@ public void onNext(Payload payload) { // null if supported if (setUpRequest.getAbilityTable() != null) { // map to table - connection.setAbilityTable(AbilityKey.mapEnum(setUpRequest.getAbilityTable())); + Map clientAbilities = AbilityKey + .mapEnum(setUpRequest.getAbilityTable()); + // combine with current node abilities + // in order to get abilities current node provides + NacosAbilityManagerHolder.getInstance().combine(clientAbilities); + connection.setAbilityTable(clientAbilities); } boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); From c97aca392339aae80b0657033f06a443b41c7847 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 10 Sep 2022 20:31:14 +0800 Subject: [PATCH 036/181] Remove unused code --- .../api/ability/entity/AbilityTable.java | 103 ------------------ .../register/impl/ServerAbilities.java | 2 - .../AbstractAbilityControlManager.java | 2 +- 3 files changed, 1 insertion(+), 106 deletions(-) delete mode 100644 api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java b/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java deleted file mode 100644 index 63fda78da96..00000000000 --- a/api/src/main/java/com/alibaba/nacos/api/ability/entity/AbilityTable.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 1999-2022 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.ability.entity; - -import com.alibaba.nacos.api.ability.constant.AbilityKey; - -import java.util.Map; - -/**. - * @author Daydreamer - * @description This table is linked to a server node or client node. - * @date 2022/7/12 19:25 - **/ -public class AbilityTable implements Cloneable { - - /**. - * id in connection instance - */ - private String connectionId; - - /**. - * ability table - * key: name from {@link com.alibaba.nacos.api.ability.constant.AbilityKey} - * value: whether to turn on - */ - private Map ability; - - /**. - * whether it from a server node - */ - private boolean isServer; - - /**. - * version of the client corresponding to the connection - */ - private String version; - - public AbilityTable() { - } - - public boolean isServer() { - return isServer; - } - - public AbilityTable setServer(boolean server) { - isServer = server; - return this; - } - - public String getVersion() { - return version; - } - - public AbilityTable setVersion(String version) { - this.version = version; - return this; - } - - public AbilityTable(String connectionId, Map ability, boolean isServer, String version) { - this.connectionId = connectionId; - this.ability = ability; - this.isServer = isServer; - this.version = version; - } - - public String getConnectionId() { - return connectionId; - } - - public AbilityTable setConnectionId(String connectionId) { - this.connectionId = connectionId; - return this; - } - - public Map getAbility() { - return ability; - } - - public AbilityTable setAbility(Map ability) { - this.ability = ability; - return this; - } - - @Override - public String toString() { - return "AbilityTable{" + "connectionId='" + connectionId + '\'' + ", ability=" + ability + ", isServer=" - + isServer + ", version='" + version + '\'' + '}'; - } -} diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java index 480861c0e00..ca4597a4f32 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/register/impl/ServerAbilities.java @@ -45,8 +45,6 @@ public class ServerAbilities extends AbstractAbilityRegistry { * */ // put ability here, which you want current server supports - supportedAbilities.put(AbilityKey.TEST_1, true); - supportedAbilities.put(AbilityKey.TEST_2, true); } /**. diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index 1529460265f..ca8c028d2f7 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -192,7 +192,7 @@ public final void destroy() { LOGGER.warn("[DefaultAbilityControlManager] - Destruction of the end"); } - /** + /**. * Combine with current node abilities, in order to get abilities current node provides * * @param abilities combined ability table From 4cff58da13a5e962b0360d13071bdaeafaa961ee Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Sat, 10 Sep 2022 21:32:42 +0800 Subject: [PATCH 037/181] Add capability table to RequestMeta. --- .../nacos/api/remote/request/RequestMeta.java | 23 ++++++++++++++++++- .../alibaba/nacos/core/remote/Connection.java | 12 ++++------ .../core/remote/grpc/GrpcRequestAcceptor.java | 1 + 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/RequestMeta.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/RequestMeta.java index 82eba58db1b..c212ebe3346 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/RequestMeta.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/RequestMeta.java @@ -16,6 +16,9 @@ package com.alibaba.nacos.api.remote.request; +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; + import java.util.HashMap; import java.util.Map; @@ -34,7 +37,25 @@ public class RequestMeta { private String clientVersion = ""; private Map labels = new HashMap<>(); - + + private Map abilityTable; + + public AbilityStatus getConnectionAbility(AbilityKey abilityKey) { + if (abilityTable == null) { + return AbilityStatus.UNKNOWN; + } + return abilityTable.getOrDefault(abilityKey, false) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; + } + + /** + * Setter method for property abilityTable. + * + * @param abilityTable property value of clientVersion + */ + public void setAbilityTable(Map abilityTable) { + this.abilityTable = abilityTable; + } + /** * Getter method for property clientVersion. * diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java index 317fdf0ace5..6f49a3ca77f 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java @@ -18,7 +18,6 @@ import com.alibaba.nacos.api.ability.ClientAbilities; import com.alibaba.nacos.api.ability.constant.AbilityKey; -import com.alibaba.nacos.api.ability.constant.AbilityStatus; import com.alibaba.nacos.api.remote.Requester; import java.util.Map; @@ -56,17 +55,14 @@ public void setTraced(boolean traced) { this.traced = traced; } - public AbilityStatus getConnectionAbility(AbilityKey abilityKey) { - if (abilityTable == null) { - return AbilityStatus.UNKNOWN; - } - return abilityTable.getOrDefault(abilityKey, false) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; - } - public void setAbilityTable(Map abilityTable) { this.abilityTable = abilityTable; } + public Map getAbilityTable() { + return this.abilityTable; + } + /** * get abilities. * diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index bbee2862950..eb69ab86f6d 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -168,6 +168,7 @@ public void request(Payload grpcRequest, StreamObserver responseObserve requestMeta.setConnectionId(CONTEXT_KEY_CONN_ID.get()); requestMeta.setClientVersion(connection.getMetaInfo().getVersion()); requestMeta.setLabels(connection.getMetaInfo().getLabels()); + requestMeta.setAbilityTable(connection.getAbilityTable()); connectionManager.refreshActiveTime(requestMeta.getConnectionId()); Response response = requestHandler.handleRequest(request, requestMeta); Payload payloadResponse = GrpcUtils.convert(response); From 5cbfc524a99edde94a90f6481d7662e57140017f Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Mon, 19 Sep 2022 21:44:22 +0800 Subject: [PATCH 038/181] Client combine ability then return to server. --- .../common/remote/client/grpc/GrpcClient.java | 33 +++++++++++++++++-- .../grpc/GrpcBiStreamRequestAcceptor.java | 3 -- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 5221f392235..5026d858d87 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -30,6 +30,7 @@ import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.remote.response.ServerCheckResponse; import com.alibaba.nacos.api.remote.response.SetupAckResponse; +import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.Connection; @@ -48,6 +49,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -353,7 +356,7 @@ public Connection connectToServer(ServerInfo serverInfo) { grpcConn.setConnectionId(connectionId); // if not supported, it will be null if (serverCheckResponse.getAbilities() != null) { - Map abilityTable = AbilityKey.mapEnum(serverCheckResponse.getAbilities()); + Map abilityTable = mapAndFilter(serverCheckResponse.getAbilities()); // mark markForSetup.put(serverCheckResponse.getConnectionId(), new CountDownLatch(1)); // combine with current node abilities @@ -375,7 +378,7 @@ public Connection connectToServer(ServerInfo serverInfo) { conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion()); conSetupRequest.setLabels(super.getLabels()); // set ability table - conSetupRequest.setAbilityTable(AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities())); + conSetupRequest.setAbilityTable(serverCheckResponse.getAbilities()); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); // wait for response @@ -401,6 +404,32 @@ public Connection connectToServer(ServerInfo serverInfo) { return null; } + /**. + * filter the ability current node not support, map to enum + * + * @param originClientAbilities origin client abilities + * @return enum map + */ + private Map mapAndFilter(Map originClientAbilities) { + Map res = new HashMap<>(originClientAbilities.size()); + Iterator> iterator = originClientAbilities.entrySet().iterator(); + + // filter ability current node not support + AbstractAbilityControlManager instance = NacosAbilityManagerHolder.getInstance(); + while (iterator.hasNext()) { + Map.Entry next = iterator.next(); + AbilityKey anEnum = AbilityKey.getEnum(next.getKey()); + if (anEnum != null) { + // whether support + boolean isRunning = instance.isCurrentNodeAbilityRunning(anEnum) && next.getValue(); + res.put(anEnum, isRunning); + // if not support + originClientAbilities.replace(next.getKey(), isRunning); + } + } + return res; + } + @Override protected void afterReset(ConnectResetRequest request) { String connectionId = request.getConnectionId(); diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 32cef2075b5..dcb01113ddb 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -128,9 +128,6 @@ public void onNext(Payload payload) { // map to table Map clientAbilities = AbilityKey .mapEnum(setUpRequest.getAbilityTable()); - // combine with current node abilities - // in order to get abilities current node provides - NacosAbilityManagerHolder.getInstance().combine(clientAbilities); connection.setAbilityTable(clientAbilities); } boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); From 5ec1d1f8b59727f350e0fa069220a190cd07d43e Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Tue, 20 Sep 2022 15:24:46 +0800 Subject: [PATCH 039/181] Change the format of ability table key to string, less time for format conversion when saving. --- .../api/ability/constant/AbilityKey.java | 2 +- .../nacos/api/remote/request/RequestMeta.java | 8 +-- .../ability/ClientAbilityControlManager.java | 4 +- .../nacos/client/ability/AbilityTest.java | 4 +- .../AbstractAbilityControlManager.java | 54 ++++++++----------- .../common/remote/client/Connection.java | 8 +-- .../common/remote/client/grpc/GrpcClient.java | 34 +----------- .../control/ServerAbilityControlManager.java | 12 ++--- .../alibaba/nacos/core/remote/Connection.java | 7 ++- .../grpc/GrpcBiStreamRequestAcceptor.java | 4 +- .../core/remote/grpc/GrpcRequestAcceptor.java | 5 +- .../ability/AbilityControlManagerTest.java | 14 ++--- .../TestServerAbilityControlManager.java | 2 +- .../ability/config/AbilityConfigsTest.java | 6 +-- 14 files changed, 61 insertions(+), 103 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java index d2e71e126df..d78de35d37e 100644 --- a/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java +++ b/api/src/main/java/com/alibaba/nacos/api/ability/constant/AbilityKey.java @@ -25,7 +25,7 @@ /**. * @author Daydreamer - * @description Ability key constant. + * @description Ability key constant. It is used to constrain the ability key. * @date 2022/8/31 12:27 **/ public enum AbilityKey { diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/RequestMeta.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/RequestMeta.java index c212ebe3346..c633f893484 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/RequestMeta.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/RequestMeta.java @@ -38,13 +38,13 @@ public class RequestMeta { private Map labels = new HashMap<>(); - private Map abilityTable; + private Map abilityTable; public AbilityStatus getConnectionAbility(AbilityKey abilityKey) { - if (abilityTable == null) { + if (abilityTable == null || !abilityTable.containsKey(abilityKey.getName())) { return AbilityStatus.UNKNOWN; } - return abilityTable.getOrDefault(abilityKey, false) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; + return abilityTable.get(abilityKey.getName()) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; } /** @@ -52,7 +52,7 @@ public AbilityStatus getConnectionAbility(AbilityKey abilityKey) { * * @param abilityTable property value of clientVersion */ - public void setAbilityTable(Map abilityTable) { + public void setAbilityTable(Map abilityTable) { this.abilityTable = abilityTable; } diff --git a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java index f1cb6cf7d8a..af537a60bb8 100644 --- a/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/ability/ClientAbilityControlManager.java @@ -33,8 +33,8 @@ public ClientAbilityControlManager() { } @Override - protected Map initCurrentNodeAbilities() { - return ClientAbilities.getStaticAbilities(); + protected Map initCurrentNodeAbilities() { + return AbilityKey.mapStr(ClientAbilities.getStaticAbilities()); } @Override diff --git a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java index f5f966f6e90..a11850a2792 100644 --- a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java @@ -61,8 +61,8 @@ public Connection connectToServer(ServerInfo serverInfo) throws Exception { { super.abilityTable = new HashMap<>(); - super.abilityTable.put(AbilityKey.TEST_1, true); - super.abilityTable.put(AbilityKey.TEST_2, false); + super.abilityTable.put(AbilityKey.TEST_1.getName(), true); + super.abilityTable.put(AbilityKey.TEST_2.getName(), false); } @Override diff --git a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java index ca8c028d2f7..a501145cba8 100644 --- a/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java +++ b/common/src/main/java/com/alibaba/nacos/common/ability/AbstractAbilityControlManager.java @@ -65,7 +65,7 @@ public abstract class AbstractAbilityControlManager { /**. * ability current node running */ - protected final Map currentRunningAbility = new ConcurrentHashMap<>(); + protected final Map currentRunningAbility = new ConcurrentHashMap<>(); private final ReentrantLock lockForHandlerMappings = new ReentrantLock(); @@ -75,18 +75,18 @@ protected AbstractAbilityControlManager() { currentRunningAbility.putAll(initCurrentNodeAbilities()); } - /** - * . Turn on the ability whose key is

abilityKey

+ /**. + * Turn on the ability whose key is

abilityKey

* - * @param abilityKey ability key + * @param abilityKey ability key{@link AbilityKey} * @return if turn success */ public boolean enableCurrentNodeAbility(AbilityKey abilityKey) { return doTurn(true, abilityKey); } - /** - * . Turn off the ability whose key is

abilityKey

+ /**. + * Turn off the ability whose key is

abilityKey

{@link AbilityKey} * * @param abilityKey ability key * @return if turn success @@ -95,8 +95,14 @@ public boolean disableCurrentNodeAbility(AbilityKey abilityKey) { return doTurn(false, abilityKey); } + /**. + * Whether current node support + * + * @param abilityKey ability key from {@link AbilityKey} + * @return whether support + */ public boolean isCurrentNodeAbilityRunning(AbilityKey abilityKey) { - return currentRunningAbility.getOrDefault(abilityKey, false); + return currentRunningAbility.getOrDefault(abilityKey.getName(), false); } /**. @@ -104,14 +110,14 @@ public boolean isCurrentNodeAbilityRunning(AbilityKey abilityKey) { * * @return current node abilities */ - protected abstract Map initCurrentNodeAbilities(); + protected abstract Map initCurrentNodeAbilities(); /**. * Return the abilities current node * * @return current abilities */ - public Map getCurrentNodeAbilities() { + public Map getCurrentNodeAbilities() { return Collections.unmodifiableMap(currentRunningAbility); } @@ -123,7 +129,7 @@ public Map getCurrentNodeAbilities() { * @return if turn success */ private boolean doTurn(boolean isOn, AbilityKey abilityKey) { - Boolean isEnabled = currentRunningAbility.get(abilityKey); + Boolean isEnabled = currentRunningAbility.get(abilityKey.getName()); // if not supporting this key if (isEnabled == null) { LOGGER.warn("[AbilityControlManager] Attempt to turn on/off a not existed ability!"); @@ -133,7 +139,7 @@ private boolean doTurn(boolean isOn, AbilityKey abilityKey) { return true; } // turn on/off - currentRunningAbility.put(abilityKey, isOn); + currentRunningAbility.put(abilityKey.getName(), isOn); // handler mappings triggerHandlerMappingAsyn(abilityKey, isOn, this.handlerMappings); // notify event @@ -192,20 +198,6 @@ public final void destroy() { LOGGER.warn("[DefaultAbilityControlManager] - Destruction of the end"); } - /**. - * Combine with current node abilities, in order to get abilities current node provides - * - * @param abilities combined ability table - */ - public void combine(Map abilities) { - currentRunningAbility.forEach((k, v) -> { - Boolean isCurrentSupport = currentRunningAbility.get(k); - if (isCurrentSupport != null) { - abilities.put(k, abilities.getOrDefault(k, false) && isCurrentSupport); - } - }); - } - /**. * hook for subclass */ @@ -260,8 +252,8 @@ public int removeAll(AbilityKey abilityKey) { */ protected void doRegisterComponent(AbilityKey abilityKey, HandlerMapping handlerMapping, Map> handlerMappings, Lock lockForHandlerMappings, - int priority, Map abilityTable) { - if (!currentRunningAbility.containsKey(abilityKey)) { + int priority, Map abilityTable) { + if (!currentRunningAbility.containsKey(abilityKey.getName())) { LOGGER.warn("[AbilityHandlePostProcessor] Failed to register processor: {}, because illegal key!", handlerMapping.getClass().getSimpleName()); } @@ -275,7 +267,7 @@ protected void doRegisterComponent(AbilityKey abilityKey, HandlerMapping handler handlerMappings.put(abilityKey, handlers); // choose behavior // enable default - if (abilityTable.getOrDefault(abilityKey, false)) { + if (abilityTable.getOrDefault(abilityKey.getName(), false)) { handlerMapping.enable(); } else { handlerMapping.disable(); @@ -384,15 +376,15 @@ public class AbilityUpdateEvent extends Event { private boolean isOn; - private Map table; + private Map table; private AbilityUpdateEvent(){} - public Map getAbilityTable() { + public Map getAbilityTable() { return table; } - public void setTable(Map abilityTable) { + public void setTable(Map abilityTable) { this.table = abilityTable; } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java index a7e37199c3f..b8ea5a83626 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/Connection.java @@ -37,7 +37,7 @@ public abstract class Connection implements Requester { protected RpcClient.ServerInfo serverInfo; - protected Map abilityTable; + protected Map abilityTable; public Connection(RpcClient.ServerInfo serverInfo) { this.serverInfo = serverInfo; @@ -52,13 +52,13 @@ public void setConnectionId(String connectionId) { } public AbilityStatus getConnectionAbility(AbilityKey abilityKey) { - if (abilityTable == null) { + if (abilityTable == null || !abilityTable.containsKey(abilityKey.getName())) { return AbilityStatus.UNKNOWN; } - return abilityTable.getOrDefault(abilityKey, false) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; + return abilityTable.get(abilityKey.getName()) ? AbilityStatus.SUPPORTED : AbilityStatus.NOT_SUPPORTED; } - public void setAbilityTable(Map abilityTable) { + public void setAbilityTable(Map abilityTable) { this.abilityTable = abilityTable; } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 5026d858d87..4c8f94e3ef4 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -356,14 +356,10 @@ public Connection connectToServer(ServerInfo serverInfo) { grpcConn.setConnectionId(connectionId); // if not supported, it will be null if (serverCheckResponse.getAbilities() != null) { - Map abilityTable = mapAndFilter(serverCheckResponse.getAbilities()); // mark markForSetup.put(serverCheckResponse.getConnectionId(), new CountDownLatch(1)); - // combine with current node abilities - // in order to get abilities current node provides - NacosAbilityManagerHolder.getInstance().combine(abilityTable); // set server abilities to connection - grpcConn.setAbilityTable(abilityTable); + grpcConn.setAbilityTable(serverCheckResponse.getAbilities()); } //create stream request and bind connection event to this connection. @@ -378,7 +374,7 @@ public Connection connectToServer(ServerInfo serverInfo) { conSetupRequest.setClientVersion(VersionUtils.getFullClientVersion()); conSetupRequest.setLabels(super.getLabels()); // set ability table - conSetupRequest.setAbilityTable(serverCheckResponse.getAbilities()); + conSetupRequest.setAbilityTable(NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities()); conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); // wait for response @@ -404,32 +400,6 @@ public Connection connectToServer(ServerInfo serverInfo) { return null; } - /**. - * filter the ability current node not support, map to enum - * - * @param originClientAbilities origin client abilities - * @return enum map - */ - private Map mapAndFilter(Map originClientAbilities) { - Map res = new HashMap<>(originClientAbilities.size()); - Iterator> iterator = originClientAbilities.entrySet().iterator(); - - // filter ability current node not support - AbstractAbilityControlManager instance = NacosAbilityManagerHolder.getInstance(); - while (iterator.hasNext()) { - Map.Entry next = iterator.next(); - AbilityKey anEnum = AbilityKey.getEnum(next.getKey()); - if (anEnum != null) { - // whether support - boolean isRunning = instance.isCurrentNodeAbilityRunning(anEnum) && next.getValue(); - res.put(anEnum, isRunning); - // if not support - originClientAbilities.replace(next.getKey(), isRunning); - } - } - return res; - } - @Override protected void afterReset(ConnectResetRequest request) { String connectionId = request.getConnectionId(); diff --git a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java index 67845d8211e..b42eaf9c818 100644 --- a/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/ability/control/ServerAbilityControlManager.java @@ -38,16 +38,16 @@ public ServerAbilityControlManager() { } @Override - protected Map initCurrentNodeAbilities() { + protected Map initCurrentNodeAbilities() { // static abilities - Map staticAbilities = ServerAbilities.getStaticAbilities(); + Map staticAbilities = AbilityKey.mapStr(ServerAbilities.getStaticAbilities()); // all function server can support - Set abilityKeys = staticAbilities.keySet(); - Map abilityTable = new HashMap<>(abilityKeys.size()); + Set abilityKeys = staticAbilities.keySet(); + Map abilityTable = new HashMap<>(abilityKeys.size()); // if not define in config, then load from ServerAbilities - Set unIncludedInConfig = new HashSet<>(); + Set unIncludedInConfig = new HashSet<>(); abilityKeys.forEach(abilityKey -> { - String key = AbilityConfigs.PREFIX + abilityKey.getName(); + String key = AbilityConfigs.PREFIX + abilityKey; try { Boolean property = EnvUtil.getProperty(key, Boolean.class); // if not null diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java index 6f49a3ca77f..ad1e4254eeb 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java @@ -17,7 +17,6 @@ package com.alibaba.nacos.core.remote; import com.alibaba.nacos.api.ability.ClientAbilities; -import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.remote.Requester; import java.util.Map; @@ -33,7 +32,7 @@ public abstract class Connection implements Requester { private boolean traced = false; - private Map abilityTable; + private Map abilityTable; private ClientAbilities abilities; @@ -55,11 +54,11 @@ public void setTraced(boolean traced) { this.traced = traced; } - public void setAbilityTable(Map abilityTable) { + public void setAbilityTable(Map abilityTable) { this.abilityTable = abilityTable; } - public Map getAbilityTable() { + public Map getAbilityTable() { return this.abilityTable; } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index dcb01113ddb..12440975d6a 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -126,9 +126,7 @@ public void onNext(Payload payload) { // null if supported if (setUpRequest.getAbilityTable() != null) { // map to table - Map clientAbilities = AbilityKey - .mapEnum(setUpRequest.getAbilityTable()); - connection.setAbilityTable(clientAbilities); + connection.setAbilityTable(setUpRequest.getAbilityTable()); } boolean rejectSdkOnStarting = metaInfo.isSdkSource() && !ApplicationUtils.isStarted(); diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index eb69ab86f6d..8fd7e1b58ca 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.core.remote.grpc; -import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.Payload; import com.alibaba.nacos.api.grpc.auto.RequestGrpc; @@ -91,8 +90,8 @@ public void request(Payload grpcRequest, StreamObserver responseObserve // server check. if (ServerCheckRequest.class.getSimpleName().equals(type)) { Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(), - // to str map - AbilityKey.mapStr(NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities()))); + // abilities current node supporting + NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities())); traceIfNecessary(serverCheckResponseP, false); responseObserver.onNext(serverCheckResponseP); responseObserver.onCompleted(); diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java index 26483920bef..44180a7aa51 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/AbilityControlManagerTest.java @@ -39,8 +39,8 @@ public class AbilityControlManagerTest { @Before public void inject() { - Map newTable = new HashMap<>(); - newTable.put(AbilityKey.TEST_1, true); + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_1.getName(), true); serverAbilityControlManager.setCurrentSupportingAbility(newTable); } @@ -88,18 +88,18 @@ public void testComponent() throws InterruptedException { @Test public void testCurrentNodeAbility() { - Set keySet = serverAbilityControlManager.getCurrentNodeAbilities().keySet(); + Set keySet = serverAbilityControlManager.getCurrentNodeAbilities().keySet(); // diable all - keySet.forEach(key -> serverAbilityControlManager.disableCurrentNodeAbility(key)); + keySet.forEach(key -> serverAbilityControlManager.disableCurrentNodeAbility(AbilityKey.getEnum(key))); // get all keySet.forEach(key -> { - Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(key)); + Assert.assertFalse(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.getEnum(key))); }); // enable all - keySet.forEach(key -> serverAbilityControlManager.enableCurrentNodeAbility(key)); + keySet.forEach(key -> serverAbilityControlManager.enableCurrentNodeAbility(AbilityKey.getEnum(key))); // get all keySet.forEach(key -> { - Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(key)); + Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.getEnum(key))); }); } diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java index e9bb30ff8f2..a3685bd79ec 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/TestServerAbilityControlManager.java @@ -26,7 +26,7 @@ public class TestServerAbilityControlManager extends ServerAbilityControlManager { @JustForTest - public void setCurrentSupportingAbility(Map ability) { + public void setCurrentSupportingAbility(Map ability) { currentRunningAbility.clear(); currentRunningAbility.putAll(ability); } diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java index 3a5ba7d6cfa..86e081f4435 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java @@ -60,9 +60,9 @@ public void setUp() throws Exception { void inject(AbilityConfigs abilityConfigs) { TestServerAbilityControlManager serverAbilityControlManager = new TestServerAbilityControlManager(); - Map newTable = new HashMap<>(); - newTable.put(AbilityKey.TEST_1, true); - newTable.put(AbilityKey.TEST_2, true); + Map newTable = new HashMap<>(); + newTable.put(AbilityKey.TEST_1.getName(), true); + newTable.put(AbilityKey.TEST_2.getName(), true); serverAbilityControlManager.setCurrentSupportingAbility(newTable); abilityConfigs.setAbilityHandlerRegistry(serverAbilityControlManager); this.serverAbilityControlManager = serverAbilityControlManager; From 677c50e2f69197fdbaf8672876a5398b2cb9d7cb Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Tue, 20 Sep 2022 16:22:15 +0800 Subject: [PATCH 040/181] Notify server ability by ServerRequest. --- .../api/remote/request/SetupAckRequest.java | 15 ++- .../remote/response/ServerCheckResponse.java | 16 ++-- .../common/remote/client/grpc/GrpcClient.java | 92 ++++++++++++++----- .../grpc/GrpcBiStreamRequestAcceptor.java | 2 +- .../core/remote/grpc/GrpcRequestAcceptor.java | 4 +- 5 files changed, 90 insertions(+), 39 deletions(-) diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/request/SetupAckRequest.java b/api/src/main/java/com/alibaba/nacos/api/remote/request/SetupAckRequest.java index 66f6eb2385b..8c37bf84241 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/request/SetupAckRequest.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/request/SetupAckRequest.java @@ -16,6 +16,8 @@ package com.alibaba.nacos.api.remote.request; +import java.util.Map; + import static com.alibaba.nacos.api.common.Constants.Remote.INTERNAL_MODULE; /**. @@ -27,11 +29,22 @@ public class SetupAckRequest extends ServerRequest { private String connectionId; + private Map abilityTable; + public SetupAckRequest() { } - public SetupAckRequest(String connectionId) { + public SetupAckRequest(String connectionId, Map abilityTable) { this.connectionId = connectionId; + this.abilityTable = abilityTable; + } + + public Map getAbilityTable() { + return abilityTable; + } + + public void setAbilityTable(Map abilityTable) { + this.abilityTable = abilityTable; } public String getConnectionId() { diff --git a/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java b/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java index d3c2ee44914..2b8e9fea84c 100644 --- a/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java +++ b/api/src/main/java/com/alibaba/nacos/api/remote/response/ServerCheckResponse.java @@ -16,8 +16,6 @@ package com.alibaba.nacos.api.remote.response; -import java.util.Map; - /** * response of server check. * @@ -28,15 +26,15 @@ public class ServerCheckResponse extends Response { private String connectionId; - private Map abilities; + private boolean supportAbilityNegotiation; public ServerCheckResponse() { } - public ServerCheckResponse(String connectionId, Map abilities) { + public ServerCheckResponse(String connectionId, boolean supportAbilityNegotiation) { this.connectionId = connectionId; - this.abilities = abilities; + this.supportAbilityNegotiation = supportAbilityNegotiation; } public String getConnectionId() { @@ -47,11 +45,11 @@ public void setConnectionId(String connectionId) { this.connectionId = connectionId; } - public Map getAbilities() { - return abilities; + public boolean isSupportAbilityNegotiation() { + return supportAbilityNegotiation; } - public void setAbilities(Map abilities) { - this.abilities = abilities; + public void setSupportAbilityNegotiation(boolean supportAbilityNegotiation) { + this.supportAbilityNegotiation = supportAbilityNegotiation; } } diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 4c8f94e3ef4..60da9be2e43 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.common.remote.client.grpc; -import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -30,7 +29,6 @@ import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.remote.response.ServerCheckResponse; import com.alibaba.nacos.api.remote.response.SetupAckResponse; -import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.ConnectionType; import com.alibaba.nacos.common.remote.client.Connection; @@ -49,8 +47,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -85,7 +81,7 @@ public abstract class GrpcClient extends RpcClient { /**. * Block to wait setup success response */ - private final Map markForSetup = new ConcurrentHashMap<>(); + private final Map markForSetup = new ConcurrentHashMap<>(); @Override public ConnectionType getConnectionType() { @@ -104,9 +100,15 @@ public GrpcClient(String name) { if (request instanceof SetupAckRequest) { SetupAckRequest setupAckRequest = (SetupAckRequest) request; // remove and count down - Optional.ofNullable(markForSetup.remove((setupAckRequest.getConnectionId()))) + RecAbilityContext context = markForSetup.remove(setupAckRequest.getConnectionId()); + if (context != null) { + // set server abilities + context.connection.setAbilityTable(setupAckRequest.getAbilityTable()); + // notify + Optional.ofNullable(context.blocker) .orElse(new CountDownLatch(1)) - .countDown(); + .countDown(); + } } return new SetupAckResponse(); }); @@ -273,9 +275,12 @@ public void onNext(Payload payload) { LoggerUtils.printIfErrorEnabled(LOGGER, "[{}]Error to process server push response: {}", grpcConn.getConnectionId(), payload.getBody().getValue().toStringUtf8()); // remove and notify - Optional.ofNullable(markForSetup.remove(grpcConn.getConnectionId())) - .orElse(new CountDownLatch(1)) - .countDown(); + RecAbilityContext context = markForSetup.remove(grpcConn.getConnectionId()); + if (context != null) { + Optional.ofNullable(context.blocker) + .orElse(new CountDownLatch(1)) + .countDown(); + } } } @@ -354,12 +359,10 @@ public Connection connectToServer(ServerInfo serverInfo) { .newStub(newChannelStubTemp.getChannel()); GrpcConnection grpcConn = new GrpcConnection(serverInfo, grpcExecutor); grpcConn.setConnectionId(connectionId); - // if not supported, it will be null - if (serverCheckResponse.getAbilities() != null) { + // if not supported, it will be false + if (serverCheckResponse.isSupportAbilityNegotiation()) { // mark - markForSetup.put(serverCheckResponse.getConnectionId(), new CountDownLatch(1)); - // set server abilities to connection - grpcConn.setAbilityTable(serverCheckResponse.getAbilities()); + markForSetup.put(serverCheckResponse.getConnectionId(), new RecAbilityContext(grpcConn, new CountDownLatch(1))); } //create stream request and bind connection event to this connection. @@ -378,11 +381,10 @@ public Connection connectToServer(ServerInfo serverInfo) { conSetupRequest.setTenant(super.getTenant()); grpcConn.sendRequest(conSetupRequest); // wait for response - CountDownLatch synResponse = markForSetup.get(connectionId); + RecAbilityContext synResponse = markForSetup.get(connectionId); if (synResponse != null) { - synResponse.await(2000L, TimeUnit.MICROSECONDS); - // ensure remove, it may being reset - markForSetup.remove(connectionId); + // try to wait for notify response + synResponse.blocker.await(5000L, TimeUnit.MICROSECONDS); } // leave for adapting old version server //wait to register connection setup @@ -393,24 +395,64 @@ public Connection connectToServer(ServerInfo serverInfo) { } catch (Exception e) { LOGGER.error("[{}]Fail to connect to server!,error={}", GrpcClient.this.getName(), e); // remove and notify - Optional.ofNullable(markForSetup.remove(connectionId)) - .orElse(new CountDownLatch(1)) - .countDown(); + RecAbilityContext context = markForSetup.remove(connectionId); + if (context != null) { + Optional.ofNullable(context.blocker) + .orElse(new CountDownLatch(1)) + .countDown(); + } } return null; } @Override protected void afterReset(ConnectResetRequest request) { - String connectionId = request.getConnectionId(); - if (connectionId != null) { + RecAbilityContext context = markForSetup.remove(request.getConnectionId()); + if (context != null) { // remove and notify - Optional.ofNullable(markForSetup.remove(connectionId)) + Optional.ofNullable(context.blocker) .orElse(new CountDownLatch(1)) .countDown(); } } + /**. + * This is for receiving server abilities + */ + class RecAbilityContext { + + /**. + * connection waiting for server abilities + */ + private Connection connection; + + /**. + * way to block client + */ + private CountDownLatch blocker; + + public RecAbilityContext(Connection connection, CountDownLatch blocker) { + this.connection = connection; + this.blocker = blocker; + } + + public Connection getConnection() { + return connection; + } + + public void setConnection(Connection connection) { + this.connection = connection; + } + + public CountDownLatch getBlocker() { + return blocker; + } + + public void setBlocker(CountDownLatch blocker) { + this.blocker = blocker; + } + } + } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 12440975d6a..08c033dfe8d 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -149,7 +149,7 @@ public void onNext(Payload payload) { } else { try { // finish register, tell client has set up successfully - connection.request(new SetupAckRequest(connectionId), 3000L); + connection.request(new SetupAckRequest(connectionId, NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities()), 3000L); } catch (Exception e) { // nothing to do diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index 8fd7e1b58ca..27c731ae22c 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -89,9 +89,7 @@ public void request(Payload grpcRequest, StreamObserver responseObserve // server check. if (ServerCheckRequest.class.getSimpleName().equals(type)) { - Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(), - // abilities current node supporting - NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities())); + Payload serverCheckResponseP = GrpcUtils.convert(new ServerCheckResponse(CONTEXT_KEY_CONN_ID.get(), true)); traceIfNecessary(serverCheckResponseP, false); responseObserver.onNext(serverCheckResponseP); responseObserver.onCompleted(); From a159e1261cce448aba2348523ef7657270fb5483 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Tue, 20 Sep 2022 20:36:34 +0800 Subject: [PATCH 041/181] Add integration test. --- .../remote/client/ServerRequestHandler.java | 1 + .../grpc/GrpcBiStreamRequestAcceptor.java | 4 +- .../core/remote/grpc/GrpcRequestAcceptor.java | 1 - .../nacos/test/ability/AbilityDiscovery.java | 209 ++++++++++++++++++ .../TestServerAbilityControlManager.java | 18 ++ 5 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityDiscovery.java create mode 100644 test/core-test/src/test/java/com/alibaba/nacos/test/ability/component/TestServerAbilityControlManager.java diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/ServerRequestHandler.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/ServerRequestHandler.java index f4163249e45..09ad1002e28 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/ServerRequestHandler.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/ServerRequestHandler.java @@ -31,6 +31,7 @@ public interface ServerRequestHandler { * Handle request from server. * * @param request request + * @param connection current connection, it can be used to know server ability * @return response. */ Response requestReply(Request request, Connection connection); diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java index 08c033dfe8d..71cf8ffa809 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcBiStreamRequestAcceptor.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.core.remote.grpc; -import com.alibaba.nacos.api.ability.constant.AbilityKey; import com.alibaba.nacos.api.common.Constants; import com.alibaba.nacos.api.grpc.auto.BiRequestStreamGrpc; import com.alibaba.nacos.api.grpc.auto.Payload; @@ -149,7 +148,8 @@ public void onNext(Payload payload) { } else { try { // finish register, tell client has set up successfully - connection.request(new SetupAckRequest(connectionId, NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities()), 3000L); + connection.request(new SetupAckRequest(connectionId, + NacosAbilityManagerHolder.getInstance().getCurrentNodeAbilities()), 3000L); } catch (Exception e) { // nothing to do diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java index 27c731ae22c..824b159a479 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/grpc/GrpcRequestAcceptor.java @@ -25,7 +25,6 @@ import com.alibaba.nacos.api.remote.response.ErrorResponse; import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.api.remote.response.ServerCheckResponse; -import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; import com.alibaba.nacos.common.remote.client.grpc.GrpcUtils; import com.alibaba.nacos.core.remote.Connection; import com.alibaba.nacos.core.remote.ConnectionManager; diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityDiscovery.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityDiscovery.java new file mode 100644 index 00000000000..7dd60999e1f --- /dev/null +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/AbilityDiscovery.java @@ -0,0 +1,209 @@ +package com.alibaba.nacos.test.ability; + +import com.alibaba.nacos.Nacos; +import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.PropertyKeyConst; +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.constant.AbilityStatus; +import com.alibaba.nacos.api.config.ConfigService; +import com.alibaba.nacos.api.config.remote.request.ConfigQueryRequest; +import com.alibaba.nacos.api.config.remote.response.ConfigQueryResponse; +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.remote.request.Request; +import com.alibaba.nacos.api.remote.request.RequestMeta; +import com.alibaba.nacos.api.remote.request.SetupAckRequest; +import com.alibaba.nacos.api.remote.response.Response; +import com.alibaba.nacos.common.ability.AbstractAbilityControlManager; +import com.alibaba.nacos.common.ability.discover.NacosAbilityManagerHolder; +import com.alibaba.nacos.common.remote.ConnectionType; +import com.alibaba.nacos.common.remote.client.Connection; +import com.alibaba.nacos.common.remote.client.RpcClient; +import com.alibaba.nacos.common.remote.client.RpcClientFactory; +import com.alibaba.nacos.common.remote.client.ServerListFactory; +import com.alibaba.nacos.common.remote.client.ServerRequestHandler; +import com.alibaba.nacos.core.remote.ConnectionManager; +import com.alibaba.nacos.core.remote.RequestFilters; +import com.alibaba.nacos.core.remote.RequestHandler; +import com.alibaba.nacos.core.remote.RequestHandlerRegistry; +import com.alibaba.nacos.test.ability.component.TestServerAbilityControlManager; +import org.junit.After; +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 javax.annotation.Resource; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = Nacos.class, properties = { + "server.servlet.context-path=/nacos"}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@SuppressWarnings("all") +public class AbilityDiscovery { + + @LocalServerPort + private int port; + + @Resource + private RequestHandlerRegistry requestHandlerRegistry; + + @Resource + private RequestFilters filters; + + @Resource + private ConnectionManager connectionManager; + + private RpcClient client; + + private ConfigService configService; + + private AbstractAbilityControlManager oldInstance; + + /** + * test server judge client abilities + */ + private volatile boolean serverSuccess = false; + + private volatile boolean clientSuccess = false; + + private Field abstractAbilityControlManager; + + private Field registryHandlerFields; + + private Field currentConnField; + + @Before + public void setup() throws NoSuchFieldException, IllegalAccessException, NacosException { + // load class + oldInstance = NacosAbilityManagerHolder.getInstance(); + + // replace + abstractAbilityControlManager = NacosAbilityManagerHolder.class + .getDeclaredField("abstractAbilityControlManager"); + abstractAbilityControlManager.setAccessible(true); + abstractAbilityControlManager.set(NacosAbilityManagerHolder.class, new TestServerAbilityControlManager()); + + // get registry field + registryHandlerFields = RequestHandlerRegistry.class.getDeclaredField("registryHandlers"); + registryHandlerFields.setAccessible(true); + + // currentConn + currentConnField = RpcClient.class.getDeclaredField("currentConnection"); + currentConnField.setAccessible(true); + + // init config service + Properties properties = new Properties(); + properties.put(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:" + port); + configService = NacosFactory.createConfigService(properties); + + // init client + client = RpcClientFactory.createClient(UUID.randomUUID().toString(), ConnectionType.GRPC, new HashMap<>()); + client.serverListFactory(new ServerListFactory() { + @Override + public String genNextServer() { + return "127.0.0.1:" + port; + } + + @Override + public String getCurrentServer() { + return "127.0.0.1:" + port; + } + + @Override + public List getServerList() { + return Collections.singletonList("127.0.0.1:" + port); + } + }); + // connect to server + client.start(); + } + + @Test + public void testClientDiscovery() throws NacosException { + // client judge ability + Assert.assertEquals(client.getConnectionAbility(AbilityKey.TEST_1), AbilityStatus.SUPPORTED); + Assert.assertEquals(client.getConnectionAbility(AbilityKey.TEST_2), AbilityStatus.NOT_SUPPORTED); + } + + @Test + public void testServerDiscoveryAndJudge() throws Exception { + Map handlers = (Map) registryHandlerFields + .get(requestHandlerRegistry); + + // set handler + RequestHandler oldRequestHandler = handlers.remove(ConfigQueryRequest.class.getSimpleName()); + handlers.put(ConfigQueryRequest.class.getSimpleName(), new ClientRequestHandler(filters)); + configService.getConfig("test", "DEFAULT_GROUP", 2000); + // wait server invoke + Thread.sleep(3000); + Assert.assertTrue(serverSuccess); + // recover + handlers.remove(ConfigQueryRequest.class.getSimpleName()); + handlers.put(ConfigQueryRequest.class.getSimpleName(), oldRequestHandler); + } + + @Test + public void testClientJudge() throws Exception { + // register + client.registerServerRequestHandler(new ServerRequestHandler() { + @Override + public Response requestReply(Request request, Connection connection) { + if (connection.getConnectionAbility(AbilityKey.TEST_1).equals(AbilityStatus.SUPPORTED) && connection + .getConnectionAbility(AbilityKey.TEST_2).equals(AbilityStatus.NOT_SUPPORTED)) { + clientSuccess = true; + } + return new Response(){}; + } + }); + + // get id + Connection conn = (Connection) currentConnField.get(client); + + com.alibaba.nacos.core.remote.Connection connection = connectionManager.getConnection(conn.getConnectionId()); + try { + connection.request(new SetupAckRequest(), 2000L); + } catch (NacosException e) { + // nothing to do + } + + // wait client react + Thread.sleep(4000); + Assert.assertTrue(clientSuccess); + } + + @After + public void recover() throws IllegalAccessException, NacosException { + abstractAbilityControlManager.set(NacosAbilityManagerHolder.class, oldInstance); + client.shutdown(); + } + + /** + * just to test ability + */ + class ClientRequestHandler extends RequestHandler { + + public ClientRequestHandler(RequestFilters requestFilters) throws NoSuchFieldException, IllegalAccessException { + Field declaredField = RequestHandler.class.getDeclaredField("requestFilters"); + declaredField.setAccessible(true); + declaredField.set(this, requestFilters); + } + + @Override + public ConfigQueryResponse handle(ConfigQueryRequest request, RequestMeta meta) throws NacosException { + if (meta.getConnectionAbility(AbilityKey.TEST_1).equals(AbilityStatus.SUPPORTED) && meta + .getConnectionAbility(AbilityKey.TEST_2).equals(AbilityStatus.NOT_SUPPORTED)) { + serverSuccess = true; + } + return new ConfigQueryResponse(); + } + } +} diff --git a/test/core-test/src/test/java/com/alibaba/nacos/test/ability/component/TestServerAbilityControlManager.java b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/component/TestServerAbilityControlManager.java new file mode 100644 index 00000000000..4620977fa55 --- /dev/null +++ b/test/core-test/src/test/java/com/alibaba/nacos/test/ability/component/TestServerAbilityControlManager.java @@ -0,0 +1,18 @@ +package com.alibaba.nacos.test.ability.component; + +import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.core.ability.control.ServerAbilityControlManager; + +import java.util.HashMap; +import java.util.Map; + +public class TestServerAbilityControlManager extends ServerAbilityControlManager { + + @Override + protected Map initCurrentNodeAbilities() { + Map map = new HashMap<>(); + map.put(AbilityKey.TEST_1.getName(), true); + map.put(AbilityKey.TEST_2.getName(), false); + return map; + } +} From d42ce9bc8f8747555f3fc0dd3613e04ebc69e7bd Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Wed, 28 Sep 2022 15:38:20 +0800 Subject: [PATCH 042/181] Add test for sever abilities initializing in manager. --- .../ability/config/AbilityConfigsTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java index 86e081f4435..8ae52fd6de3 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java @@ -17,6 +17,8 @@ package com.alibaba.nacos.core.ability.config; import com.alibaba.nacos.api.ability.constant.AbilityKey; +import com.alibaba.nacos.api.ability.register.AbstractAbilityRegistry; +import com.alibaba.nacos.api.ability.register.impl.ServerAbilities; import com.alibaba.nacos.common.ability.handler.HandlerMapping; import com.alibaba.nacos.common.event.ServerConfigChangeEvent; import com.alibaba.nacos.core.ability.TestServerAbilityControlManager; @@ -27,6 +29,7 @@ import org.junit.Test; import org.springframework.mock.env.MockEnvironment; +import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; @@ -45,6 +48,8 @@ public class AbilityConfigsTest { private ServerAbilityControlManager serverAbilityControlManager; + private Map currentAbilities; + @Before public void setUp() throws Exception { environment = new MockEnvironment(); @@ -68,6 +73,32 @@ void inject(AbilityConfigs abilityConfigs) { this.serverAbilityControlManager = serverAbilityControlManager; } + + public void fill() throws NoSuchFieldException, IllegalAccessException { + Field instanceField = ServerAbilities.class.getDeclaredField("INSTANCE"); + Field abilitiesField = AbstractAbilityRegistry.class.getDeclaredField("supportedAbilities"); + abilitiesField.setAccessible(true); + instanceField.setAccessible(true); + ServerAbilities serverAbilities = (ServerAbilities) instanceField.get(ServerAbilities.class); + currentAbilities = (Map) abilitiesField.get(serverAbilities); + currentAbilities.put(AbilityKey.TEST_1, true); + currentAbilities.put(AbilityKey.TEST_2, true); + } + + @Test + public void testLoadAbilities() throws NoSuchFieldException, IllegalAccessException, InterruptedException { + environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_1.getName(), Boolean.TRUE.toString()); + environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_2.getName(), Boolean.FALSE.toString()); + // test load + fill(); + ServerAbilityControlManager manager = new ServerAbilityControlManager(); + // config has higher priority + Assert.assertTrue(manager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); + Assert.assertFalse(manager.isCurrentNodeAbilityRunning(AbilityKey.TEST_2)); + // clear + currentAbilities.clear(); + } + @Test public void testInit() { Assert.assertTrue(serverAbilityControlManager.isCurrentNodeAbilityRunning(AbilityKey.TEST_1)); From bb92da0661156d6012009a3522c63623c4991051 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Tue, 25 Oct 2022 14:18:17 +0800 Subject: [PATCH 043/181] Remove unused wait in GrpcClient and field in ClientAbilities, change ^ to != in MemeberUtil. --- .../common/remote/client/grpc/GrpcClient.java | 6 +++-- .../nacos/core/cluster/MemberUtil.java | 2 +- .../alibaba/nacos/core/remote/Connection.java | 24 ------------------- 3 files changed, 5 insertions(+), 27 deletions(-) diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index 60da9be2e43..3f1f7ee2c56 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -387,8 +387,10 @@ public Connection connectToServer(ServerInfo serverInfo) { synResponse.blocker.await(5000L, TimeUnit.MICROSECONDS); } // leave for adapting old version server - //wait to register connection setup - Thread.sleep(100L); + else { + //wait to register connection setup + Thread.sleep(100L); + } return grpcConn; } return null; diff --git a/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java b/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java index 6a664a30dfb..d0f6dac5a15 100644 --- a/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java +++ b/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java @@ -285,7 +285,7 @@ public static boolean isBasicInfoChanged(Member actual, Member expected) { } // if change - if (expected.isSupportRemoteConnection() ^ actual.isSupportRemoteConnection()) { + if (expected.isSupportRemoteConnection() != actual.isSupportRemoteConnection()) { return true; } diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java index ad1e4254eeb..b010e2a8413 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java @@ -34,8 +34,6 @@ public abstract class Connection implements Requester { private Map abilityTable; - private ClientAbilities abilities; - private final ConnectionMeta metaInfo; public Connection(ConnectionMeta metaInfo) { @@ -62,28 +60,6 @@ public Map getAbilityTable() { return this.abilityTable; } - /** - * get abilities. - * - * @deprecated it is replaced by abilityTable field - * @return - */ - @Deprecated - public ClientAbilities getAbilities() { - return abilities; - } - - /** - * set abilities. - * - * @deprecated it is replaced by abilityTable field - * @param abilities abilities. - */ - @Deprecated - public void setAbilities(ClientAbilities abilities) { - this.abilities = abilities; - } - /** * check is connected. * From d4e9b836d2cf16014cc1907d027b335e26ad0f90 Mon Sep 17 00:00:00 2001 From: Daydreamer-ia <2296032269@qq.com> Date: Thu, 22 Jun 2023 17:08:04 +0800 Subject: [PATCH 044/181] fix checkstyle and fix bug --- .../request/ConnectionSetupRequestTest.java | 6 +-- .../response/ServerCheckResponseTest.java | 2 +- .../client/config/impl/ClientWorker.java | 1 - .../config/impl/ConfigTransportClient.java | 2 +- .../client/config/impl/ServerListManager.java | 2 +- .../nacos/client/ability/AbilityTest.java | 41 ++++++++++++++++++- .../common/remote/client/grpc/GrpcClient.java | 9 ++-- .../src/main/resources/application.properties | 20 ++++----- .../alibaba/nacos/core/cluster/Member.java | 10 ++--- .../nacos/core/cluster/MemberUtil.java | 8 ++-- .../core/cluster/ServerMemberManager.java | 17 ++++++-- .../alibaba/nacos/core/remote/Connection.java | 1 - .../ability/config/AbilityConfigsTest.java | 17 +++++--- .../nacos/core/cluster/MemberUtilTest.java | 2 +- 14 files changed, 94 insertions(+), 44 deletions(-) diff --git a/api/src/test/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequestTest.java b/api/src/test/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequestTest.java index e05860af9c7..03424d50a64 100644 --- a/api/src/test/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequestTest.java +++ b/api/src/test/java/com/alibaba/nacos/api/remote/request/ConnectionSetupRequestTest.java @@ -16,11 +16,11 @@ package com.alibaba.nacos.api.remote.request; -import com.alibaba.nacos.api.ability.ClientAbilities; import org.junit.Assert; import org.junit.Test; import java.util.Collections; +import java.util.HashMap; public class ConnectionSetupRequestTest extends BasicRequestTest { @@ -28,7 +28,7 @@ public class ConnectionSetupRequestTest extends BasicRequestTest { public void testSerialize() throws Exception { ConnectionSetupRequest request = new ConnectionSetupRequest(); request.setClientVersion("2.2.2"); - request.setAbilities(new ClientAbilities()); + request.setAbilityTable(new HashMap<>()); request.setTenant("testNamespaceId"); request.setLabels(Collections.singletonMap("labelKey", "labelValue")); request.setRequestId("1"); @@ -37,7 +37,7 @@ public void testSerialize() throws Exception { Assert.assertTrue(json.contains("\"clientVersion\":\"2.2.2\"")); Assert.assertTrue(json.contains("\"tenant\":\"testNamespaceId\"")); Assert.assertTrue(json.contains("\"labels\":{\"labelKey\":\"labelValue\"}")); - Assert.assertTrue(json.contains("\"abilities\":{")); + Assert.assertTrue(json.contains("\"abilityTable\":{")); Assert.assertTrue(json.contains("\"module\":\"internal\"")); Assert.assertTrue(json.contains("\"requestId\":\"1\"")); } diff --git a/api/src/test/java/com/alibaba/nacos/api/remote/response/ServerCheckResponseTest.java b/api/src/test/java/com/alibaba/nacos/api/remote/response/ServerCheckResponseTest.java index 80c2ac9ea6e..c010f0d9916 100644 --- a/api/src/test/java/com/alibaba/nacos/api/remote/response/ServerCheckResponseTest.java +++ b/api/src/test/java/com/alibaba/nacos/api/remote/response/ServerCheckResponseTest.java @@ -38,7 +38,7 @@ public void setUp() throws Exception { @Test public void testSerialization() throws JsonProcessingException { - ServerCheckResponse response = new ServerCheckResponse("35643245_1.1.1.1_3306"); + ServerCheckResponse response = new ServerCheckResponse("35643245_1.1.1.1_3306", false); String actual = mapper.writeValueAsString(response); assertTrue(actual.contains("\"connectionId\":\"35643245_1.1.1.1_3306\"")); } diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java index 77c7fc2fabd..1d11dac7614 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ClientWorker.java @@ -66,7 +66,6 @@ import com.alibaba.nacos.common.utils.StringUtils; import com.alibaba.nacos.common.utils.ThreadUtils; import com.alibaba.nacos.common.utils.VersionUtils; -import com.alibaba.nacos.plugin.auth.api.RequestResource; import com.google.gson.Gson; import com.google.gson.JsonObject; import org.slf4j.Logger; diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ConfigTransportClient.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ConfigTransportClient.java index 596c997846b..12e7f990369 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ConfigTransportClient.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ConfigTransportClient.java @@ -23,10 +23,10 @@ import com.alibaba.nacos.plugin.auth.api.RequestResource; import com.alibaba.nacos.client.config.filter.impl.ConfigResponse; import com.alibaba.nacos.client.security.SecurityProxy; -import com.alibaba.nacos.client.utils.ParamUtil; import com.alibaba.nacos.common.utils.ConvertUtils; import com.alibaba.nacos.common.utils.MD5Utils; import com.alibaba.nacos.common.utils.StringUtils; +import com.alibaba.nacos.client.utils.ParamUtil; import java.util.HashMap; import java.util.Map; diff --git a/client/src/main/java/com/alibaba/nacos/client/config/impl/ServerListManager.java b/client/src/main/java/com/alibaba/nacos/client/config/impl/ServerListManager.java index 4977a9e3f16..3210a5003e5 100644 --- a/client/src/main/java/com/alibaba/nacos/client/config/impl/ServerListManager.java +++ b/client/src/main/java/com/alibaba/nacos/client/config/impl/ServerListManager.java @@ -23,7 +23,6 @@ import com.alibaba.nacos.client.utils.ContextPathUtil; import com.alibaba.nacos.client.utils.EnvUtil; import com.alibaba.nacos.client.utils.LogUtils; -import com.alibaba.nacos.client.utils.ParamUtil; import com.alibaba.nacos.client.utils.TemplateUtils; import com.alibaba.nacos.common.http.HttpRestResult; import com.alibaba.nacos.common.http.client.NacosRestTemplate; @@ -48,6 +47,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import com.alibaba.nacos.client.utils.ParamUtil; import static com.alibaba.nacos.common.constant.RequestUrlConstants.HTTPS_PREFIX; import static com.alibaba.nacos.common.constant.RequestUrlConstants.HTTP_PREFIX; diff --git a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java index a11850a2792..75ca686d4ea 100644 --- a/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java +++ b/client/src/test/java/com/alibaba/nacos/client/ability/AbilityTest.java @@ -25,8 +25,9 @@ import com.alibaba.nacos.api.remote.response.Response; import com.alibaba.nacos.client.naming.remote.TestConnection; import com.alibaba.nacos.common.remote.ConnectionType; -import com.alibaba.nacos.common.remote.client.Connection; import com.alibaba.nacos.common.remote.client.RpcClient; +import com.alibaba.nacos.common.remote.client.Connection; +import com.alibaba.nacos.common.remote.client.RpcClientConfig; import com.alibaba.nacos.common.remote.client.ServerListFactory; import com.alibaba.nacos.common.remote.client.ServerRequestHandler; import org.junit.After; @@ -34,6 +35,7 @@ import org.junit.Test; import java.util.HashMap; import java.util.List; +import java.util.Map; public class AbilityTest { @@ -43,7 +45,42 @@ public class AbilityTest { @Test public void testReceive() throws Exception { - rpcClient = new RpcClient("name") { + rpcClient = new RpcClient(new RpcClientConfig() { + @Override + public String name() { + return "test"; + } + + @Override + public int retryTimes() { + return 1; + } + + @Override + public long timeOutMills() { + return 3000L; + } + + @Override + public long connectionKeepAlive() { + return 5000L; + } + + @Override + public int healthCheckRetryTimes() { + return 1; + } + + @Override + public long healthCheckTimeOut() { + return 3000L; + } + + @Override + public Map labels() { + return new HashMap<>(); + } + }) { @Override public ConnectionType getConnectionType() { diff --git a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java index f83e349ff09..121fd96d25d 100644 --- a/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java +++ b/common/src/main/java/com/alibaba/nacos/common/remote/client/grpc/GrpcClient.java @@ -43,7 +43,6 @@ import com.alibaba.nacos.common.utils.VersionUtils; import com.alibaba.nacos.common.utils.TlsTypeResolve; import com.alibaba.nacos.common.utils.ThreadFactoryBuilder; -import com.google.common.base.Optional; import com.google.common.util.concurrent.ListenableFuture; import io.grpc.CompressorRegistry; import io.grpc.DecompressorRegistry; @@ -65,7 +64,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.Arrays; -import java.util.Map; import java.util.Properties; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -421,9 +419,8 @@ public Connection connectToServer(ServerInfo serverInfo) { if (synResponse != null) { // try to wait for notify response synResponse.blocker.await(5000L, TimeUnit.MICROSECONDS); - } - // leave for adapting old version server - else { + } else { + // leave for adapting old version server //wait to register connection setup Thread.sleep(100L); } @@ -505,7 +502,7 @@ private Optional buildSslContext() { RpcClientTlsConfig tlsConfig = clientConfig.tlsConfig(); if (!tlsConfig.getEnableTls()) { - return Optional.absent(); + return Optional.empty(); } try { SslContextBuilder builder = GrpcSslContexts.forClient(); diff --git a/console/src/main/resources/application.properties b/console/src/main/resources/application.properties index 66081292d7f..e9796c45755 100644 --- a/console/src/main/resources/application.properties +++ b/console/src/main/resources/application.properties @@ -31,16 +31,16 @@ server.port=8848 #*************** Config Module Related Configurations ***************# ### Deprecated configuration property, it is recommended to use `spring.sql.init.platform` replaced. -# spring.datasource.platform=mysql -# nacos.plugin.datasource.log.enabled=true -#spring.sql.init.platform=mysql -### Count of DB: -# db.num=1 - -### Connect URL of DB: -# db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC -# db.user=nacos -# db.password=nacos +spring.datasource.platform=mysql +nacos.plugin.datasource.log.enabled=true +spring.sql.init.platform=mysql +## Count of DB: +db.num=1 + +## Connect URL of DB: +db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC +db.user=root +db.password=123456 #*************** Naming Module Related Configurations ***************# ### Data dispatch task execution period in milliseconds: diff --git a/core/src/main/java/com/alibaba/nacos/core/cluster/Member.java b/core/src/main/java/com/alibaba/nacos/core/cluster/Member.java index 69b0cafd6f2..7f5377629e8 100644 --- a/core/src/main/java/com/alibaba/nacos/core/cluster/Member.java +++ b/core/src/main/java/com/alibaba/nacos/core/cluster/Member.java @@ -56,7 +56,7 @@ public class Member implements Comparable, Cloneable, Serializable { @Deprecated private ServerAbilities abilities = new ServerAbilities(); - private boolean supportRemoteConnection; + private boolean grpcReportEnabled; public Member() { String prefix = "nacos.core.member.meta."; @@ -68,12 +68,12 @@ public Member() { .put(MemberMetaDataConstants.WEIGHT, EnvUtil.getProperty(prefix + MemberMetaDataConstants.WEIGHT, "1")); } - public boolean isSupportRemoteConnection() { - return supportRemoteConnection; + public boolean isGrpcReportEnabled() { + return grpcReportEnabled; } - public void setSupportRemoteConnection(boolean supportRemoteConnection) { - this.supportRemoteConnection = supportRemoteConnection; + public void setGrpcReportEnabled(boolean grpcReportEnabled) { + this.grpcReportEnabled = grpcReportEnabled; } @Deprecated diff --git a/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java b/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java index 7271555058d..97f8afcd0db 100644 --- a/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java +++ b/core/src/main/java/com/alibaba/nacos/core/cluster/MemberUtil.java @@ -66,7 +66,7 @@ public static void copy(Member newMember, Member oldMember) { oldMember.setExtendInfo(newMember.getExtendInfo()); oldMember.setAddress(newMember.getAddress()); oldMember.setAbilities(newMember.getAbilities()); - oldMember.setSupportRemoteConnection(newMember.isSupportRemoteConnection()); + oldMember.setGrpcReportEnabled(newMember.isGrpcReportEnabled()); } /** @@ -95,6 +95,8 @@ public static Member singleParse(String member) { extendInfo.put(MemberMetaDataConstants.RAFT_PORT, String.valueOf(calculateRaftPort(target))); extendInfo.put(MemberMetaDataConstants.READY_TO_UPGRADE, true); target.setExtendInfo(extendInfo); + // use grpc to report default + target.setGrpcReportEnabled(true); return target; } @@ -111,7 +113,7 @@ public static boolean isSupportedLongCon(Member member) { boolean oldVerJudge = member.getAbilities().getRemoteAbility().isSupportRemoteConnection(); - return member.isSupportRemoteConnection() || oldVerJudge; + return member.isGrpcReportEnabled() || oldVerJudge; } public static int calculateRaftPort(Member member) { @@ -281,7 +283,7 @@ public static boolean isBasicInfoChanged(Member actual, Member expected) { } // if change - if (expected.isSupportRemoteConnection() != actual.isSupportRemoteConnection()) { + if (expected.isGrpcReportEnabled() != actual.isGrpcReportEnabled()) { return true; } diff --git a/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java b/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java index a8436bfc154..eeee8855ccf 100644 --- a/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java +++ b/core/src/main/java/com/alibaba/nacos/core/cluster/ServerMemberManager.java @@ -164,7 +164,7 @@ protected void init() throws NacosException { this.localAddress = InetUtils.getSelfIP() + ":" + port; this.self = MemberUtil.singleParse(this.localAddress); this.self.setExtendVal(MemberMetaDataConstants.VERSION, VersionUtils.version); - this.self.setSupportRemoteConnection(true); + this.self.setGrpcReportEnabled(true); // init abilities. this.self.setAbilities(initMemberAbilities()); @@ -573,8 +573,9 @@ protected void executeBody() { Member target = members.get(cursor); Loggers.CLUSTER.debug("report the metadata to the node : {}", target.getAddress()); - - if (target.getAbilities().getRemoteAbility().isGrpcReportEnabled()) { + + // adapt old version + if (target.getAbilities().getRemoteAbility().isGrpcReportEnabled() || target.isGrpcReportEnabled()) { reportByGrpc(target); } else { reportByHttp(target); @@ -598,6 +599,9 @@ public void onReceive(RestResult result) { Loggers.CLUSTER.warn("failed to report new info to target node : {}, result : {}", target.getAddress(), result); MemberUtil.onFail(ServerMemberManager.this, target); + // try to connect by grpc next time, adapt old version + target.setGrpcReportEnabled(true); + target.getAbilities().getRemoteAbility().setGrpcReportEnabled(true); } } @@ -606,6 +610,9 @@ public void onError(Throwable throwable) { Loggers.CLUSTER.error("failed to report new info to target node : {}, error : {}", target.getAddress(), ExceptionUtil.getAllExceptionMsg(throwable)); MemberUtil.onFail(ServerMemberManager.this, target, throwable); + // try to connect by grpc next time, adapt old version + target.setGrpcReportEnabled(true); + target.getAbilities().getRemoteAbility().setGrpcReportEnabled(true); } @Override @@ -616,6 +623,9 @@ public void onCancel() { } catch (Throwable ex) { Loggers.CLUSTER.error("failed to report new info to target node by http : {}, error : {}", target.getAddress(), ExceptionUtil.getAllExceptionMsg(ex)); + // try to connect by grpc next time, adapt old version + target.setGrpcReportEnabled(true); + target.getAbilities().getRemoteAbility().setGrpcReportEnabled(true); } } @@ -643,6 +653,7 @@ protected void reportByGrpc(Member target) { } catch (NacosException e) { if (e.getErrCode() == NacosException.NO_HANDLER) { target.getAbilities().getRemoteAbility().setGrpcReportEnabled(false); + target.setGrpcReportEnabled(false); } Loggers.CLUSTER.error("failed to report new info to target node by grpc : {}, error : {}", target.getAddress(), ExceptionUtil.getAllExceptionMsg(e)); diff --git a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java index b010e2a8413..190787c5e4c 100644 --- a/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java +++ b/core/src/main/java/com/alibaba/nacos/core/remote/Connection.java @@ -16,7 +16,6 @@ package com.alibaba.nacos.core.remote; -import com.alibaba.nacos.api.ability.ClientAbilities; import com.alibaba.nacos.api.remote.Requester; import java.util.Map; diff --git a/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java index 8ae52fd6de3..d0da8108428 100644 --- a/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/ability/config/AbilityConfigsTest.java @@ -33,9 +33,10 @@ import java.util.HashMap; import java.util.Map; -/**. +/** + * test for ability in config. + * * @author Daydreamer - * @description * @date 2022/9/3 12:27 **/ public class AbilityConfigsTest { @@ -72,9 +73,13 @@ void inject(AbilityConfigs abilityConfigs) { abilityConfigs.setAbilityHandlerRegistry(serverAbilityControlManager); this.serverAbilityControlManager = serverAbilityControlManager; } - - - public void fill() throws NoSuchFieldException, IllegalAccessException { + + /** + * fill field. + * + * @throws Exception ignore + */ + public void fill() throws Exception { Field instanceField = ServerAbilities.class.getDeclaredField("INSTANCE"); Field abilitiesField = AbstractAbilityRegistry.class.getDeclaredField("supportedAbilities"); abilitiesField.setAccessible(true); @@ -86,7 +91,7 @@ public void fill() throws NoSuchFieldException, IllegalAccessException { } @Test - public void testLoadAbilities() throws NoSuchFieldException, IllegalAccessException, InterruptedException { + public void testLoadAbilities() throws Exception { environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_1.getName(), Boolean.TRUE.toString()); environment.setProperty(AbilityConfigs.PREFIX + AbilityKey.TEST_2.getName(), Boolean.FALSE.toString()); // test load diff --git a/core/src/test/java/com/alibaba/nacos/core/cluster/MemberUtilTest.java b/core/src/test/java/com/alibaba/nacos/core/cluster/MemberUtilTest.java index c1750dbeefa..679e5ada894 100644 --- a/core/src/test/java/com/alibaba/nacos/core/cluster/MemberUtilTest.java +++ b/core/src/test/java/com/alibaba/nacos/core/cluster/MemberUtilTest.java @@ -243,7 +243,7 @@ public void testIsBasicInfoChangedForChangedBasicExtendInfo() { @Test public void testIsBasicInfoChangedForChangedAbilities() { Member newMember = buildMember(); - newMember.getAbilities().getRemoteAbility().setSupportRemoteConnection(true); + newMember.setGrpcReportEnabled(true); assertTrue(MemberUtil.isBasicInfoChanged(newMember, originalMember)); } From a70483563c36ec161214a4aafc1c0a40fa94e644 Mon Sep 17 00:00:00 2001 From: Darren Luo Date: Wed, 5 Jul 2023 18:57:35 +0800 Subject: [PATCH 045/181] =?UTF-8?q?=E6=8D=A2=E4=B8=BAjs-yaml=E5=90=8E?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E4=BA=86=E9=94=99=E8=AF=AF=E7=9A=84=E6=96=B9?= =?UTF-8?q?=E6=B3=95=EF=BC=8C=E4=BF=AE=E5=A4=8D=E8=AF=A5=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E6=89=80=E6=9C=89yaml=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=9A=84=E6=A0=A1=E9=AA=8C=E9=83=BD=E6=8A=A5=E9=94=99=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(#10724)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- console-ui/src/utils/validateContent.js | 2 +- console/src/main/resources/static/index.html | 4 ++-- console/src/main/resources/static/js/main.js | 24 ++++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/console-ui/src/utils/validateContent.js b/console-ui/src/utils/validateContent.js index 76df188b279..aab7548d259 100644 --- a/console-ui/src/utils/validateContent.js +++ b/console-ui/src/utils/validateContent.js @@ -141,7 +141,7 @@ export default { */ validateYaml(str) { try { - return yaml.parse(str); + return yaml.load(str); } catch (e) { return false; } diff --git a/console/src/main/resources/static/index.html b/console/src/main/resources/static/index.html index 11dc085f901..17e54aae4dd 100644 --- a/console/src/main/resources/static/index.html +++ b/console/src/main/resources/static/index.html @@ -35,7 +35,7 @@ - +
@@ -56,6 +56,6 @@ - + diff --git a/console/src/main/resources/static/js/main.js b/console/src/main/resources/static/js/main.js index d5427c584f7..9f2f50a2190 100644 --- a/console/src/main/resources/static/js/main.js +++ b/console/src/main/resources/static/js/main.js @@ -1,23 +1,23 @@ -!function(n){var a={};function r(e){if(a[e])return a[e].exports;var t=a[e]={i:e,l:!1,exports:{}};return n[e].call(t.exports,t,t.exports,r),t.l=!0,t.exports}r.m=n,r.c=a,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)r.d(n,a,function(e){return t[e]}.bind(null,a));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=437)}([function(e,t,n){"use strict";e.exports=n(444)},function(e,t,n){"use strict";n.d(t,"a",function(){return x}),n.d(t,"d",function(){return C}),n.d(t,"b",function(){return m}),n.d(t,"c",function(){return L});n(50);var t=n(26),u=n.n(t),s=n(72),r=n(90),d=n(61),c=n(31),t=n(106),f=n.n(t),t=n(65),p=n.n(t),h=n(24);function m(){var e=window.location.href,e=(localStorage.removeItem("token"),e.split("#")[0]);console.log("base_url",e),window.location="".concat(e,"#/login")}var l,g,a,o,i,y,v,_,b,w,M,k,t=window,S=(l={},{once:function(e,t){this.listen.call(this,e,t,!0)},listen:function(e,t){var n=2>>0,a;for(a=0;a0)for(n=0;n=0;return(o?n?"+":"":"-")+Math.pow(10,Math.max(0,r)).toString().substr(1)+a}var ie=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,le=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,se={},ue={};function a(e,t,n,a){var r=a;if(typeof a==="string")r=function(){return this[a]()};if(e)ue[e]=r;if(t)ue[t[0]]=function(){return o(r.apply(this,arguments),t[1],t[2])};if(n)ue[n]=function(){return this.localeData().ordinal(r.apply(this,arguments),e)}}function de(e){if(e.match(/\[[\s\S]/))return e.replace(/^\[|\]$/g,"");return e.replace(/\\/g,"")}function ce(a){var r=a.match(ie),e,o;for(e=0,o=r.length;e=0&&le.test(e)){e=e.replace(le,a);le.lastIndex=0;n-=1}return e}var he={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"};function me(e){var t=this._longDateFormat[e],n=this._longDateFormat[e.toUpperCase()];if(t||!n)return t;this._longDateFormat[e]=n.match(ie).map(function(e){if(e==="MMMM"||e==="MM"||e==="DD"||e==="dddd")return e.slice(1);return e}).join("");return this._longDateFormat[e]}var ge="Invalid date";function ye(){return this._invalidDate}var ve="%d",_e=/\d{1,2}/;function be(e){return this._ordinal.replace("%d",e)}var we={future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function Me(e,t,n,a){var r=this._relativeTime[n];return h(r)?r(e,t,n,a):r.replace(/%d/i,e)}function ke(e,t){var n=this._relativeTime[e>0?"future":"past"];return h(n)?n(t):n.replace(/%s/i,t)}var Se={};function t(e,t){var n=e.toLowerCase();Se[n]=Se[n+"s"]=Se[t]=e}function m(e){return typeof e==="string"?Se[e]||Se[e.toLowerCase()]:undefined}function Ee(e){var t={},n,a;for(a in e)if(s(e,a)){n=m(a);if(n)t[n]=e[a]}return t}var xe={};function n(e,t){xe[e]=t}function Ce(e){var t=[],n;for(n in e)if(s(e,n))t.push({unit:n,priority:xe[n]});t.sort(function(e,t){return e.priority-t.priority});return t}function Le(e){return e%4===0&&e%100!==0||e%400===0}function g(e){if(e<0)return Math.ceil(e)||0;else return Math.floor(e)}function y(e){var t=+e,n=0;if(t!==0&&isFinite(t))n=g(t);return n}function Te(t,n){return function(e){if(e!=null){Oe(this,t,e);c.updateOffset(this,n);return this}else return De(this,t)}}function De(e,t){return e.isValid()?e._d["get"+(e._isUTC?"UTC":"")+t]():NaN}function Oe(e,t,n){if(e.isValid()&&!isNaN(n))if(t==="FullYear"&&Le(e.year())&&e.month()===1&&e.date()===29){n=y(n);e._d["set"+(e._isUTC?"UTC":"")+t](n,e.month(),ot(n,e.month()))}else e._d["set"+(e._isUTC?"UTC":"")+t](n)}function Ne(e){e=m(e);if(h(this[e]))return this[e]();return this}function Pe(e,t){if(typeof e==="object"){e=Ee(e);var n=Ce(e),a,r=n.length;for(a=0;a68?1900:2e3)};var Mt=Te("FullYear",true);function kt(){return Le(this.year())}function St(e,t,n,a,r,o,i){var l;if(e<100&&e>=0){l=new Date(e+400,t,n,a,r,o,i);if(isFinite(l.getFullYear()))l.setFullYear(e)}else l=new Date(e,t,n,a,r,o,i);return l}function Et(e){var t,n;if(e<100&&e>=0){n=Array.prototype.slice.call(arguments);n[0]=e+400;t=new Date(Date.UTC.apply(null,n));if(isFinite(t.getUTCFullYear()))t.setUTCFullYear(e)}else t=new Date(Date.UTC.apply(null,arguments));return t}function xt(e,t,n){var a=7+t-n,r=(7+Et(e,0,a).getUTCDay()-t)%7;return-r+a-1}function Ct(e,t,n,a,r){var o=(7+n-a)%7,i=xt(e,a,r),l=1+7*(t-1)+o+i,s,u;if(l<=0){s=e-1;u=wt(s)+l}else if(l>wt(e)){s=e+1;u=l-wt(e)}else{s=e;u=l}return{year:s,dayOfYear:u}}function Lt(e,t,n){var a=xt(e.year(),t,n),r=Math.floor((e.dayOfYear()-a-1)/7)+1,o,i;if(r<1){i=e.year()-1;o=r+T(i,t,n)}else if(r>T(e.year(),t,n)){o=r-T(e.year(),t,n);i=e.year()+1}else{i=e.year();o=r}return{week:o,year:i}}function T(e,t,n){var a=xt(e,t,n),r=xt(e+1,t,n);return(wt(e)-a+r)/7}function Tt(e){return Lt(e,this._week.dow,this._week.doy).week}a("w",["ww",2],"wo","week"),a("W",["WW",2],"Wo","isoWeek"),t("week","w"),t("isoWeek","W"),n("week",5),n("isoWeek",5),_("w",v),_("ww",v,r),_("W",v),_("WW",v,r),Ze(["w","ww","W","WW"],function(e,t,n,a){t[a.substr(0,1)]=y(e)});var Dt={dow:0,doy:6};function Ot(){return this._week.dow}function Nt(){return this._week.doy}function Pt(e){var t=this.localeData().week(this);return e==null?t:this.add((e-t)*7,"d")}function jt(e){var t=Lt(this,1,4).week;return e==null?t:this.add((e-t)*7,"d")}function Yt(e,t){if(typeof e!=="string")return e;if(!isNaN(e))return parseInt(e,10);e=t.weekdaysParse(e);if(typeof e==="number")return e;return null}function It(e,t){if(typeof e==="string")return t.weekdaysParse(e)%7||7;return isNaN(e)?null:e}function Rt(e,t){return e.slice(t,7).concat(e.slice(0,t))}a("d",0,"do","day"),a("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),a("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),a("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),a("e",0,0,"weekday"),a("E",0,0,"isoWeekday"),t("day","d"),t("weekday","e"),t("isoWeekday","E"),n("day",11),n("weekday",11),n("isoWeekday",11),_("d",v),_("e",v),_("E",v),_("dd",function(e,t){return t.weekdaysMinRegex(e)}),_("ddd",function(e,t){return t.weekdaysShortRegex(e)}),_("dddd",function(e,t){return t.weekdaysRegex(e)}),Ze(["dd","ddd","dddd"],function(e,t,n,a){var r=n._locale.weekdaysParse(e,a,n._strict);if(r!=null)t.d=r;else f(n).invalidWeekday=e}),Ze(["d","e","E"],function(e,t,n,a){t[a]=y(e)});var At="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Ht="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Ft="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),zt=Ge,Wt=Ge,Vt=Ge;function Bt(e,t){var n=i(this._weekdays)?this._weekdays:this._weekdays[e&&e!==true&&this._weekdays.isFormat.test(t)?"format":"standalone"];return e===true?Rt(n,this._week.dow):e?n[e.day()]:n}function Ut(e){return e===true?Rt(this._weekdaysShort,this._week.dow):e?this._weekdaysShort[e.day()]:this._weekdaysShort}function Kt(e){return e===true?Rt(this._weekdaysMin,this._week.dow):e?this._weekdaysMin[e.day()]:this._weekdaysMin}function qt(e,t,n){var a,r,o,i=e.toLocaleLowerCase();if(!this._weekdaysParse){this._weekdaysParse=[];this._shortWeekdaysParse=[];this._minWeekdaysParse=[];for(a=0;a<7;++a){o=d([2e3,1]).day(a);this._minWeekdaysParse[a]=this.weekdaysMin(o,"").toLocaleLowerCase();this._shortWeekdaysParse[a]=this.weekdaysShort(o,"").toLocaleLowerCase();this._weekdaysParse[a]=this.weekdays(o,"").toLocaleLowerCase()}}if(n)if(t==="dddd"){r=L.call(this._weekdaysParse,i);return r!==-1?r:null}else if(t==="ddd"){r=L.call(this._shortWeekdaysParse,i);return r!==-1?r:null}else{r=L.call(this._minWeekdaysParse,i);return r!==-1?r:null}else if(t==="dddd"){r=L.call(this._weekdaysParse,i);if(r!==-1)return r;r=L.call(this._shortWeekdaysParse,i);if(r!==-1)return r;r=L.call(this._minWeekdaysParse,i);return r!==-1?r:null}else if(t==="ddd"){r=L.call(this._shortWeekdaysParse,i);if(r!==-1)return r;r=L.call(this._weekdaysParse,i);if(r!==-1)return r;r=L.call(this._minWeekdaysParse,i);return r!==-1?r:null}else{r=L.call(this._minWeekdaysParse,i);if(r!==-1)return r;r=L.call(this._weekdaysParse,i);if(r!==-1)return r;r=L.call(this._shortWeekdaysParse,i);return r!==-1?r:null}}function Gt(e,t,n){var a,r,o;if(this._weekdaysParseExact)return qt.call(this,e,t,n);if(!this._weekdaysParse){this._weekdaysParse=[];this._minWeekdaysParse=[];this._shortWeekdaysParse=[];this._fullWeekdaysParse=[]}for(a=0;a<7;a++){r=d([2e3,1]).day(a);if(n&&!this._fullWeekdaysParse[a]){this._fullWeekdaysParse[a]=new RegExp("^"+this.weekdays(r,"").replace(".","\\.?")+"$","i");this._shortWeekdaysParse[a]=new RegExp("^"+this.weekdaysShort(r,"").replace(".","\\.?")+"$","i");this._minWeekdaysParse[a]=new RegExp("^"+this.weekdaysMin(r,"").replace(".","\\.?")+"$","i")}if(!this._weekdaysParse[a]){o="^"+this.weekdays(r,"")+"|^"+this.weekdaysShort(r,"")+"|^"+this.weekdaysMin(r,"");this._weekdaysParse[a]=new RegExp(o.replace(".",""),"i")}if(n&&t==="dddd"&&this._fullWeekdaysParse[a].test(e))return a;else if(n&&t==="ddd"&&this._shortWeekdaysParse[a].test(e))return a;else if(n&&t==="dd"&&this._minWeekdaysParse[a].test(e))return a;else if(!n&&this._weekdaysParse[a].test(e))return a}}function $t(e){if(!this.isValid())return e!=null?this:NaN;var t=this._isUTC?this._d.getUTCDay():this._d.getDay();if(e!=null){e=Yt(e,this.localeData());return this.add(e-t,"d")}else return t}function Jt(e){if(!this.isValid())return e!=null?this:NaN;var t=(this.day()+7-this.localeData()._week.dow)%7;return e==null?t:this.add(e-t,"d")}function Qt(e){if(!this.isValid())return e!=null?this:NaN;if(e!=null){var t=It(e,this.localeData());return this.day(this.day()%7?t:t-7)}else return this.day()||7}function Xt(e){if(this._weekdaysParseExact){if(!s(this,"_weekdaysRegex"))tn.call(this);if(e)return this._weekdaysStrictRegex;else return this._weekdaysRegex}else{if(!s(this,"_weekdaysRegex"))this._weekdaysRegex=zt;return this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex}}function Zt(e){if(this._weekdaysParseExact){if(!s(this,"_weekdaysRegex"))tn.call(this);if(e)return this._weekdaysShortStrictRegex;else return this._weekdaysShortRegex}else{if(!s(this,"_weekdaysShortRegex"))this._weekdaysShortRegex=Wt;return this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex}}function en(e){if(this._weekdaysParseExact){if(!s(this,"_weekdaysRegex"))tn.call(this);if(e)return this._weekdaysMinStrictRegex;else return this._weekdaysMinRegex}else{if(!s(this,"_weekdaysMinRegex"))this._weekdaysMinRegex=Vt;return this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex}}function tn(){function e(e,t){return t.length-e.length}var t=[],n=[],a=[],r=[],o,i,l,s,u;for(o=0;o<7;o++){i=d([2e3,1]).day(o);l=b(this.weekdaysMin(i,""));s=b(this.weekdaysShort(i,""));u=b(this.weekdays(i,""));t.push(l);n.push(s);a.push(u);r.push(l);r.push(s);r.push(u)}t.sort(e);n.sort(e);a.sort(e);r.sort(e);this._weekdaysRegex=new RegExp("^("+r.join("|")+")","i");this._weekdaysShortRegex=this._weekdaysRegex;this._weekdaysMinRegex=this._weekdaysRegex;this._weekdaysStrictRegex=new RegExp("^("+a.join("|")+")","i");this._weekdaysShortStrictRegex=new RegExp("^("+n.join("|")+")","i");this._weekdaysMinStrictRegex=new RegExp("^("+t.join("|")+")","i")}function nn(){return this.hours()%12||12}function an(){return this.hours()||24}function rn(e,t){a(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function on(e,t){return t._meridiemParse}function ln(e){return(e+"").toLowerCase().charAt(0)==="p"}a("H",["HH",2],0,"hour"),a("h",["hh",2],0,nn),a("k",["kk",2],0,an),a("hmm",0,0,function(){return""+nn.apply(this)+o(this.minutes(),2)}),a("hmmss",0,0,function(){return""+nn.apply(this)+o(this.minutes(),2)+o(this.seconds(),2)}),a("Hmm",0,0,function(){return""+this.hours()+o(this.minutes(),2)}),a("Hmmss",0,0,function(){return""+this.hours()+o(this.minutes(),2)+o(this.seconds(),2)}),rn("a",true),rn("A",false),t("hour","h"),n("hour",13),_("a",on),_("A",on),_("H",v),_("h",v),_("k",v),_("HH",v,r),_("hh",v,r),_("kk",v,r),_("hmm",Ae),_("hmmss",He),_("Hmm",Ae),_("Hmmss",He),w(["H","HH"],E),w(["k","kk"],function(e,t,n){var a=y(e);t[E]=a===24?0:a}),w(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e);n._meridiem=e}),w(["h","hh"],function(e,t,n){t[E]=y(e);f(n).bigHour=true}),w("hmm",function(e,t,n){var a=e.length-2;t[E]=y(e.substr(0,a));t[x]=y(e.substr(a));f(n).bigHour=true}),w("hmmss",function(e,t,n){var a=e.length-4,r=e.length-2;t[E]=y(e.substr(0,a));t[x]=y(e.substr(a,2));t[C]=y(e.substr(r));f(n).bigHour=true}),w("Hmm",function(e,t,n){var a=e.length-2;t[E]=y(e.substr(0,a));t[x]=y(e.substr(a))}),w("Hmmss",function(e,t,n){var a=e.length-4,r=e.length-2;t[E]=y(e.substr(0,a));t[x]=y(e.substr(a,2));t[C]=y(e.substr(r))});var sn,un=Te("Hours",true);function dn(e,t,n){if(e>11)return n?"pm":"PM";else return n?"am":"AM"}var cn={calendar:re,longDateFormat:he,invalidDate:ge,ordinal:ve,dayOfMonthOrdinalParse:_e,relativeTime:we,months:it,monthsShort:lt,week:Dt,weekdays:At,weekdaysMin:Ft,weekdaysShort:Ht,meridiemParse:/[ap]\.?m?\.?/i},D={},fn={},pn;function hn(e,t){var n,a=Math.min(e.length,t.length);for(n=0;n0){r=vn(o.slice(0,n).join("-"));if(r)return r;if(a&&a.length>=n&&hn(o,a)>=n-1)break;n--}t++}return pn}function yn(e){return e.match("^[^/\\\\]*$")!=null}function vn(t){var e=null,n;if(D[t]===undefined&&typeof di!=="undefined"&&di&&di.exports&&yn(t))try{e=pn._abbr;n=ci;fi(511)("./"+t);_n(e)}catch(e){D[t]=null}return D[t]}function _n(e,t){var n;if(e){if(l(t))n=Mn(e);else n=bn(e,t);if(n)pn=n;else if(typeof console!=="undefined"&&console.warn)console.warn("Locale "+e+" not found. Did you forget to load it?")}return pn._abbr}function bn(e,t){if(t!==null){var n,a=cn;t.abbr=e;if(D[e]!=null){ee("defineLocaleOverride","use moment.updateLocale(localeName, config) to change "+"an existing locale. moment.defineLocale(localeName, "+"config) should only be used for creating a new locale "+"See http://momentjs.com/guides/#/warnings/define-locale/ for more info.");a=D[e]._config}else if(t.parentLocale!=null)if(D[t.parentLocale]!=null)a=D[t.parentLocale]._config;else{n=vn(t.parentLocale);if(n!=null)a=n._config;else{if(!fn[t.parentLocale])fn[t.parentLocale]=[];fn[t.parentLocale].push({name:e,config:t});return null}}D[e]=new ae(ne(a,t));if(fn[e])fn[e].forEach(function(e){bn(e.name,e.config)});_n(e);return D[e]}else{delete D[e];return null}}function wn(e,t){if(t!=null){var n,a,r=cn;if(D[e]!=null&&D[e].parentLocale!=null)D[e].set(ne(D[e]._config,t));else{a=vn(e);if(a!=null)r=a._config;t=ne(r,t);if(a==null)t.abbr=e;n=new ae(t);n.parentLocale=D[e];D[e]=n}_n(e)}else if(D[e]!=null)if(D[e].parentLocale!=null){D[e]=D[e].parentLocale;if(e===_n())_n(e)}else if(D[e]!=null)delete D[e];return D[e]}function Mn(e){var t;if(e&&e._locale&&e._locale._abbr)e=e._locale._abbr;if(!e)return pn;if(!i(e)){t=vn(e);if(t)return t;e=[e]}return gn(e)}function kn(){return Z(D)}function Sn(e){var t,n=e._a;if(n&&f(e).overflow===-2){t=n[k]<0||n[k]>11?k:n[S]<1||n[S]>ot(n[M],n[k])?S:n[E]<0||n[E]>24||n[E]===24&&(n[x]!==0||n[C]!==0||n[tt]!==0)?E:n[x]<0||n[x]>59?x:n[C]<0||n[C]>59?C:n[tt]<0||n[tt]>999?tt:-1;if(f(e)._overflowDayOfYear&&(tS))t=S;if(f(e)._overflowWeeks&&t===-1)t=nt;if(f(e)._overflowWeekday&&t===-1)t=at;f(e).overflow=t}return e}var En=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,xn=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Cn=/Z|[+-]\d\d(?::?\d\d)?/,Ln=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,false],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,false],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,false],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,false],["YYYY",/\d{4}/,false]],Tn=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Dn=/^\/?Date\((-?\d+)/i,On=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,Nn={UT:0,GMT:0,EDT:-4*60,EST:-5*60,CDT:-5*60,CST:-6*60,MDT:-6*60,MST:-7*60,PDT:-7*60,PST:-8*60};function Pn(e){var t,n,a=e._i,r=En.exec(a)||xn.exec(a),o,i,l,s,u=Ln.length,d=Tn.length;if(r){f(e).iso=true;for(t=0,n=u;twt(i)||e._dayOfYear===0)f(e)._overflowDayOfYear=true;n=Et(i,0,e._dayOfYear);e._a[k]=n.getUTCMonth();e._a[S]=n.getUTCDate()}for(t=0;t<3&&e._a[t]==null;++t)e._a[t]=a[t]=r[t];for(;t<7;t++)e._a[t]=a[t]=e._a[t]==null?t===2?1:0:e._a[t];if(e._a[E]===24&&e._a[x]===0&&e._a[C]===0&&e._a[tt]===0){e._nextDay=true;e._a[E]=0}e._d=(e._useUTC?Et:St).apply(null,a);o=e._useUTC?e._d.getUTCDay():e._d.getDay();if(e._tzm!=null)e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm);if(e._nextDay)e._a[E]=24;if(e._w&&typeof e._w.d!=="undefined"&&e._w.d!==o)f(e).weekdayMismatch=true}function Bn(e){var t,n,a,r,o,i,l,s,u;t=e._w;if(t.GG!=null||t.W!=null||t.E!=null){o=1;i=4;n=zn(t.GG,e._a[M],Lt(O(),1,4).year);a=zn(t.W,1);r=zn(t.E,1);if(r<1||r>7)s=true}else{o=e._locale._week.dow;i=e._locale._week.doy;u=Lt(O(),o,i);n=zn(t.gg,e._a[M],u.year);a=zn(t.w,u.week);if(t.d!=null){r=t.d;if(r<0||r>6)s=true}else if(t.e!=null){r=t.e+o;if(t.e<0||t.e>6)s=true}else r=o}if(a<1||a>T(n,o,i))f(e)._overflowWeeks=true;else if(s!=null)f(e)._overflowWeekday=true;else{l=Ct(n,a,r,o,i);e._a[M]=l.year;e._dayOfYear=l.dayOfYear}}function Un(e){if(e._f===c.ISO_8601){Pn(e);return}if(e._f===c.RFC_2822){Hn(e);return}e._a=[];f(e).empty=true;var t=""+e._i,n,a,r,o,i,l=t.length,s=0,u,d;r=pe(e._f,e._locale).match(ie)||[];d=r.length;for(n=0;n0)f(e).unusedInput.push(i);t=t.slice(t.indexOf(a)+a.length);s+=a.length}if(ue[o]){if(a)f(e).empty=false;else f(e).unusedTokens.push(o);et(o,a,e)}else if(e._strict&&!a)f(e).unusedTokens.push(o)}f(e).charsLeftOver=l-s;if(t.length>0)f(e).unusedInput.push(t);if(e._a[E]<=12&&f(e).bigHour===true&&e._a[E]>0)f(e).bigHour=undefined;f(e).parsedDateParts=e._a.slice(0);f(e).meridiem=e._meridiem;e._a[E]=Kn(e._locale,e._a[E],e._meridiem);u=f(e).era;if(u!==null)e._a[M]=e._locale.erasConvertYear(u,e._a[M]);Vn(e);Sn(e)}function Kn(e,t,n){var a;if(n==null)return t;if(e.meridiemHour!=null)return e.meridiemHour(t,n);else if(e.isPM!=null){a=e.isPM(n);if(a&&t<12)t+=12;if(!a&&t===12)t=0;return t}else return t}function qn(e){var t,n,a,r,o,i,l=false,s=e._f.length;if(s===0){f(e).invalidFormat=true;e._d=new Date(NaN);return}for(r=0;rthis?this:e;else return K()});function ta(e,t){var n,a;if(t.length===1&&i(t[0]))t=t[0];if(!t.length)return O();n=t[0];for(a=1;athis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ea(){if(!l(this._isDSTShifted))return this._isDSTShifted;var e={},t;$(e,this);e=Jn(e);if(e._a){t=e._isUTC?d(e._a):O(e._a);this._isDSTShifted=this.isValid()&&fa(e._a,t.toArray())>0}else this._isDSTShifted=false;return this._isDSTShifted}function xa(){return this.isValid()?!this._isUTC:false}function Ca(){return this.isValid()?this._isUTC:false}function La(){return this.isValid()?this._isUTC&&this._offset===0:false}c.updateOffset=function(){};var Ta=/^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/,Da=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;function N(e,t){var n=e,a=null,r,o,i;if(da(e))n={ms:e._milliseconds,d:e._days,M:e._months};else if(u(e)||!isNaN(+e)){n={};if(t)n[t]=+e;else n.milliseconds=+e}else if(a=Ta.exec(e)){r=a[1]==="-"?-1:1;n={y:0,d:y(a[S])*r,h:y(a[E])*r,m:y(a[x])*r,s:y(a[C])*r,ms:y(ca(a[tt]*1e3))*r}}else if(a=Da.exec(e)){r=a[1]==="-"?-1:1;n={y:Oa(a[2],r),M:Oa(a[3],r),w:Oa(a[4],r),d:Oa(a[5],r),h:Oa(a[6],r),m:Oa(a[7],r),s:Oa(a[8],r)}}else if(n==null)n={};else if(typeof n==="object"&&("from"in n||"to"in n)){i=Pa(O(n.from),O(n.to));n={};n.ms=i.milliseconds;n.M=i.months}o=new ua(n);if(da(e)&&s(e,"_locale"))o._locale=e._locale;if(da(e)&&s(e,"_isValid"))o._isValid=e._isValid;return o}function Oa(e,t){var n=e&&parseFloat(e.replace(",","."));return(isNaN(n)?0:n)*t}function Na(e,t){var n={};n.months=t.month()-e.month()+(t.year()-e.year())*12;if(e.clone().add(n.months,"M").isAfter(t))--n.months;n.milliseconds=+t-+e.clone().add(n.months,"M");return n}function Pa(e,t){var n;if(!(e.isValid()&&t.isValid()))return{milliseconds:0,months:0};t=ga(t,e);if(e.isBefore(t))n=Na(e,t);else{n=Na(t,e);n.milliseconds=-n.milliseconds;n.months=-n.months}return n}function ja(r,o){return function(e,t){var n,a;if(t!==null&&!isNaN(+t)){ee(o,"moment()."+o+"(period, number) is deprecated. Please use moment()."+o+"(number, period). "+"See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.");a=e;e=t;t=a}n=N(e,t);Ya(this,n,r);return this}}function Ya(e,t,n,a){var r=t._milliseconds,o=ca(t._days),i=ca(t._months);if(!e.isValid())return;a=a==null?true:a;if(i)mt(e,De(e,"Month")+i*n);if(o)Oe(e,"Date",De(e,"Date")+o*n);if(r)e._d.setTime(e._d.valueOf()+r*n);if(a)c.updateOffset(e,o||i)}N.fn=ua.prototype,N.invalid=sa;var Ia=ja(1,"add"),Ra=ja(-1,"subtract");function Aa(e){return typeof e==="string"||e instanceof String}function Ha(e){return p(e)||z(e)||Aa(e)||u(e)||za(e)||Fa(e)||e===null||e===undefined}function Fa(e){var t=H(e)&&!F(e),n=false,a=["years","year","y","months","month","M","days","day","d","dates","date","D","hours","hour","h","minutes","minute","m","seconds","second","s","milliseconds","millisecond","ms"],r,o,i=a.length;for(r=0;rn.valueOf();else return n.valueOf()9999)return fe(n,t?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ");if(h(Date.prototype.toISOString))if(t)return this.toDate().toISOString();else return new Date(this.valueOf()+this.utcOffset()*60*1e3).toISOString().replace("Z",fe(n,"Z"));return fe(n,t?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")}function nr(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e="moment",t="",n,a,r,o;if(!this.isLocal()){e=this.utcOffset()===0?"moment.utc":"moment.parseZone";t="Z"}n="["+e+'("]';a=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY";r="-MM-DD[T]HH:mm:ss.SSS";o=t+'[")]';return this.format(n+a+r+o)}function ar(e){if(!e)e=this.isUtc()?c.defaultFormatUtc:c.defaultFormat;var t=fe(this,e);return this.localeData().postformat(t)}function rr(e,t){if(this.isValid()&&(p(e)&&e.isValid()||O(e).isValid()))return N({to:this,from:e}).locale(this.locale()).humanize(!t);else return this.localeData().invalidDate()}function or(e){return this.from(O(),e)}function ir(e,t){if(this.isValid()&&(p(e)&&e.isValid()||O(e).isValid()))return N({from:this,to:e}).locale(this.locale()).humanize(!t);else return this.localeData().invalidDate()}function lr(e){return this.to(O(),e)}function sr(e){var t;if(e===undefined)return this._locale._abbr;else{t=Mn(e);if(t!=null)this._locale=t;return this}}c.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",c.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var ur=e("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(e){if(e===undefined)return this.localeData();else return this.locale(e)});function dr(){return this._locale}var cr=1e3,fr=60*cr,pr=60*fr,hr=(365*400+97)*24*pr;function mr(e,t){return(e%t+t)%t}function gr(e,t,n){if(e<100&&e>=0)return new Date(e+400,t,n)-hr;else return new Date(e,t,n).valueOf()}function yr(e,t,n){if(e<100&&e>=0)return Date.UTC(e+400,t,n)-hr;else return Date.UTC(e,t,n)}function vr(e){var t,n;e=m(e);if(e===undefined||e==="millisecond"||!this.isValid())return this;n=this._isUTC?yr:gr;switch(e){case"year":t=n(this.year(),0,1);break;case"quarter":t=n(this.year(),this.month()-this.month()%3,1);break;case"month":t=n(this.year(),this.month(),1);break;case"week":t=n(this.year(),this.month(),this.date()-this.weekday());break;case"isoWeek":t=n(this.year(),this.month(),this.date()-(this.isoWeekday()-1));break;case"day":case"date":t=n(this.year(),this.month(),this.date());break;case"hour":t=this._d.valueOf();t-=mr(t+(this._isUTC?0:this.utcOffset()*fr),pr);break;case"minute":t=this._d.valueOf();t-=mr(t,fr);break;case"second":t=this._d.valueOf();t-=mr(t,cr);break}this._d.setTime(t);c.updateOffset(this,true);return this}function _r(e){var t,n;e=m(e);if(e===undefined||e==="millisecond"||!this.isValid())return this;n=this._isUTC?yr:gr;switch(e){case"year":t=n(this.year()+1,0,1)-1;break;case"quarter":t=n(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":t=n(this.year(),this.month()+1,1)-1;break;case"week":t=n(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":t=n(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":t=n(this.year(),this.month(),this.date()+1)-1;break;case"hour":t=this._d.valueOf();t+=pr-mr(t+(this._isUTC?0:this.utcOffset()*fr),pr)-1;break;case"minute":t=this._d.valueOf();t+=fr-mr(t,fr)-1;break;case"second":t=this._d.valueOf();t+=cr-mr(t,cr)-1;break}this._d.setTime(t);c.updateOffset(this,true);return this}function br(){return this._d.valueOf()-(this._offset||0)*6e4}function wr(){return Math.floor(this.valueOf()/1e3)}function Mr(){return new Date(this.valueOf())}function kr(){var e=this;return[e.year(),e.month(),e.date(),e.hour(),e.minute(),e.second(),e.millisecond()]}function Sr(){var e=this;return{years:e.year(),months:e.month(),date:e.date(),hours:e.hours(),minutes:e.minutes(),seconds:e.seconds(),milliseconds:e.milliseconds()}}function Er(){return this.isValid()?this.toISOString():null}function xr(){return U(this)}function Cr(){return V({},f(this))}function Lr(){return f(this).overflow}function Tr(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Dr(e,t){var n,a,r,o=this._eras||Mn("en")._eras;for(n=0,a=o.length;n=0)return o[a]}}function Nr(e,t){var n=e.since<=e.until?+1:-1;if(t===undefined)return c(e.since).year();else return c(e.since).year()+(t-e.offset)*n}function Pr(){var e,t,n,a=this.localeData().eras();for(e=0,t=a.length;eo)t=o;return Zr.call(this,e,t,n,a,r)}}function Zr(e,t,n,a,r){var o=Ct(e,t,n,a,r),i=Et(o.year,0,o.dayOfYear);this.year(i.getUTCFullYear());this.month(i.getUTCMonth());this.date(i.getUTCDate());return this}function eo(e){return e==null?Math.ceil((this.month()+1)/3):this.month((e-1)*3+this.month()%3)}a("N",0,0,"eraAbbr"),a("NN",0,0,"eraAbbr"),a("NNN",0,0,"eraAbbr"),a("NNNN",0,0,"eraName"),a("NNNNN",0,0,"eraNarrow"),a("y",["y",1],"yo","eraYear"),a("y",["yy",2],0,"eraYear"),a("y",["yyy",3],0,"eraYear"),a("y",["yyyy",4],0,"eraYear"),_("N",Fr),_("NN",Fr),_("NNN",Fr),_("NNNN",zr),_("NNNNN",Wr),w(["N","NN","NNN","NNNN","NNNNN"],function(e,t,n,a){var r=n._locale.erasParse(e,a,n._strict);if(r)f(n).era=r;else f(n).invalidEra=e}),_("y",Ve),_("yy",Ve),_("yyy",Ve),_("yyyy",Ve),_("yo",Vr),w(["y","yy","yyy","yyyy"],M),w(["yo"],function(e,t,n,a){var r;if(n._locale._eraYearOrdinalRegex)r=e.match(n._locale._eraYearOrdinalRegex);if(n._locale.eraYearOrdinalParse)t[M]=n._locale.eraYearOrdinalParse(e,r);else t[M]=parseInt(e,10)}),a(0,["gg",2],0,function(){return this.weekYear()%100}),a(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Ur("gggg","weekYear"),Ur("ggggg","weekYear"),Ur("GGGG","isoWeekYear"),Ur("GGGGG","isoWeekYear"),t("weekYear","gg"),t("isoWeekYear","GG"),n("weekYear",1),n("isoWeekYear",1),_("G",Be),_("g",Be),_("GG",v,r),_("gg",v,r),_("GGGG",ze,Ie),_("gggg",ze,Ie),_("GGGGG",We,Re),_("ggggg",We,Re),Ze(["gggg","ggggg","GGGG","GGGGG"],function(e,t,n,a){t[a.substr(0,2)]=y(e)}),Ze(["gg","GG"],function(e,t,n,a){t[a]=c.parseTwoDigitYear(e)}),a("Q",0,"Qo","quarter"),t("quarter","Q"),n("quarter",7),_("Q",je),w("Q",function(e,t){t[k]=(y(e)-1)*3}),a("D",["DD",2],"Do","date"),t("date","D"),n("date",9),_("D",v),_("DD",v,r),_("Do",function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient}),w(["D","DD"],S),w("Do",function(e,t){t[S]=y(e.match(v)[0])});var to=Te("Date",true);function no(e){var t=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return e==null?t:this.add(e-t,"d")}a("DDD",["DDDD",3],"DDDo","dayOfYear"),t("dayOfYear","DDD"),n("dayOfYear",4),_("DDD",Fe),_("DDDD",Ye),w(["DDD","DDDD"],function(e,t,n){n._dayOfYear=y(e)}),a("m",["mm",2],0,"minute"),t("minute","m"),n("minute",14),_("m",v),_("mm",v,r),w(["m","mm"],x);var ao=Te("Minutes",false),ro=(a("s",["ss",2],0,"second"),t("second","s"),n("second",15),_("s",v),_("ss",v,r),w(["s","ss"],C),Te("Seconds",false)),oo,io;for(a("S",0,0,function(){return~~(this.millisecond()/100)}),a(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),a(0,["SSS",3],0,"millisecond"),a(0,["SSSS",4],0,function(){return this.millisecond()*10}),a(0,["SSSSS",5],0,function(){return this.millisecond()*100}),a(0,["SSSSSS",6],0,function(){return this.millisecond()*1e3}),a(0,["SSSSSSS",7],0,function(){return this.millisecond()*1e4}),a(0,["SSSSSSSS",8],0,function(){return this.millisecond()*1e5}),a(0,["SSSSSSSSS",9],0,function(){return this.millisecond()*1e6}),t("millisecond","ms"),n("millisecond",16),_("S",Fe,je),_("SS",Fe,r),_("SSS",Fe,Ye),oo="SSSS";oo.length<=9;oo+="S")_(oo,Ve);function lo(e,t){t[tt]=y(("0."+e)*1e3)}for(oo="S";oo.length<=9;oo+="S")w(oo,lo);function so(){return this._isUTC?"UTC":""}function uo(){return this._isUTC?"Coordinated Universal Time":""}io=Te("Milliseconds",false),a("z",0,0,"zoneAbbr"),a("zz",0,0,"zoneName");var P=J.prototype;if(P.add=Ia,P.calendar=Ba,P.clone=Ua,P.diff=Xa,P.endOf=_r,P.format=ar,P.from=rr,P.fromNow=or,P.to=ir,P.toNow=lr,P.get=Ne,P.invalidAt=Lr,P.isAfter=Ka,P.isBefore=qa,P.isBetween=Ga,P.isSame=$a,P.isSameOrAfter=Ja,P.isSameOrBefore=Qa,P.isValid=xr,P.lang=ur,P.locale=sr,P.localeData=dr,P.max=ea,P.min=Zn,P.parsingFlags=Cr,P.set=Pe,P.startOf=vr,P.subtract=Ra,P.toArray=kr,P.toObject=Sr,P.toDate=Mr,P.toISOString=tr,P.inspect=nr,typeof Symbol!=="undefined"&&Symbol.for!=null)P[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"};function co(e){return O(e*1e3)}function fo(){return O.apply(null,arguments).parseZone()}function po(e){return e}P.toJSON=Er,P.toString=er,P.unix=wr,P.valueOf=br,P.creationData=Tr,P.eraName=Pr,P.eraNarrow=jr,P.eraAbbr=Yr,P.eraYear=Ir,P.year=Mt,P.isLeapYear=kt,P.weekYear=Kr,P.isoWeekYear=qr,P.quarter=P.quarters=eo,P.month=gt,P.daysInMonth=yt,P.week=P.weeks=Pt,P.isoWeek=P.isoWeeks=jt,P.weeksInYear=Jr,P.weeksInWeekYear=Qr,P.isoWeeksInYear=Gr,P.isoWeeksInISOWeekYear=$r,P.date=to,P.day=P.days=$t,P.weekday=Jt,P.isoWeekday=Qt,P.dayOfYear=no,P.hour=P.hours=un,P.minute=P.minutes=ao,P.second=P.seconds=ro,P.millisecond=P.milliseconds=io,P.utcOffset=va,P.utc=ba,P.local=wa,P.parseZone=Ma,P.hasAlignedHourOffset=ka,P.isDST=Sa,P.isLocal=xa,P.isUtcOffset=Ca,P.isUtc=La,P.isUTC=La,P.zoneAbbr=so,P.zoneName=uo,P.dates=e("dates accessor is deprecated. Use date instead.",to),P.months=e("months accessor is deprecated. Use month instead",gt),P.years=e("years accessor is deprecated. Use year instead",Mt),P.zone=e("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",_a),P.isDSTShifted=e("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Ea);var j=ae.prototype;function ho(e,t,n,a){var r=Mn(),o=d().set(a,t);return r[n](o,e)}function mo(e,t,n){if(u(e)){t=e;e=undefined}e=e||"";if(t!=null)return ho(e,t,n,"month");var a,r=[];for(a=0;a<12;a++)r[a]=ho(e,a,n,"month");return r}function go(e,t,n,a){if(typeof e==="boolean"){if(u(t)){n=t;t=undefined}t=t||""}else{t=e;n=t;e=false;if(u(t)){n=t;t=undefined}t=t||""}var r=Mn(),o=e?r._week.dow:0,i,l=[];if(n!=null)return ho(t,(n+o)%7,a,"day");for(i=0;i<7;i++)l[i]=ho(t,(i+o)%7,a,"day");return l}function yo(e,t){return mo(e,t,"months")}function vo(e,t){return mo(e,t,"monthsShort")}function _o(e,t,n){return go(e,t,n,"weekdays")}function bo(e,t,n){return go(e,t,n,"weekdaysShort")}function wo(e,t,n){return go(e,t,n,"weekdaysMin")}j.calendar=oe,j.longDateFormat=me,j.invalidDate=ye,j.ordinal=be,j.preparse=po,j.postformat=po,j.relativeTime=Me,j.pastFuture=ke,j.set=te,j.eras=Dr,j.erasParse=Or,j.erasConvertYear=Nr,j.erasAbbrRegex=Ar,j.erasNameRegex=Rr,j.erasNarrowRegex=Hr,j.months=ct,j.monthsShort=ft,j.monthsParse=ht,j.monthsRegex=_t,j.monthsShortRegex=vt,j.week=Tt,j.firstDayOfYear=Nt,j.firstDayOfWeek=Ot,j.weekdays=Bt,j.weekdaysMin=Kt,j.weekdaysShort=Ut,j.weekdaysParse=Gt,j.weekdaysRegex=Xt,j.weekdaysShortRegex=Zt,j.weekdaysMinRegex=en,j.isPM=ln,j.meridiem=dn,_n("en",{eras:[{since:"0001-01-01",until:+Infinity,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-Infinity,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10,n=y(e%100/10)===1?"th":t===1?"st":t===2?"nd":t===3?"rd":"th";return e+n}}),c.lang=e("moment.lang is deprecated. Use moment.locale instead.",_n),c.langData=e("moment.langData is deprecated. Use moment.localeData instead.",Mn);var Mo=Math.abs;function ko(){var e=this._data;this._milliseconds=Mo(this._milliseconds);this._days=Mo(this._days);this._months=Mo(this._months);e.milliseconds=Mo(e.milliseconds);e.seconds=Mo(e.seconds);e.minutes=Mo(e.minutes);e.hours=Mo(e.hours);e.months=Mo(e.months);e.years=Mo(e.years);return this}function So(e,t,n,a){var r=N(t,n);e._milliseconds+=a*r._milliseconds;e._days+=a*r._days;e._months+=a*r._months;return e._bubble()}function Eo(e,t){return So(this,e,t,1)}function xo(e,t){return So(this,e,t,-1)}function Co(e){if(e<0)return Math.floor(e);else return Math.ceil(e)}function Lo(){var e=this._milliseconds,t=this._days,n=this._months,a=this._data,r,o,i,l,s;if(!(e>=0&&t>=0&&n>=0||e<=0&&t<=0&&n<=0)){e+=Co(Do(n)+t)*864e5;t=0;n=0}a.milliseconds=e%1e3;r=g(e/1e3);a.seconds=r%60;o=g(r/60);a.minutes=o%60;i=g(o/60);a.hours=i%24;t+=g(i/24);s=g(To(t));n+=s;t-=Co(Do(s));l=g(n/12);n%=12;a.days=t;a.months=n;a.years=l;return this}function To(e){return e*4800/146097}function Do(e){return e*146097/4800}function Oo(e){if(!this.isValid())return NaN;var t,n,a=this._milliseconds;e=m(e);if(e==="month"||e==="quarter"||e==="year"){t=this._days+a/864e5;n=this._months+To(t);switch(e){case"month":return n;case"quarter":return n/3;case"year":return n/12}}else{t=this._days+Math.round(Do(this._months));switch(e){case"week":return t/7+a/6048e5;case"day":return t+a/864e5;case"hour":return t*24+a/36e5;case"minute":return t*1440+a/6e4;case"second":return t*86400+a/1e3;case"millisecond":return Math.floor(t*864e5)+a;default:throw new Error("Unknown unit "+e)}}}function No(){if(!this.isValid())return NaN;return this._milliseconds+this._days*864e5+this._months%12*2592e6+y(this._months/12)*31536e6}function Po(e){return function(){return this.as(e)}}var jo=Po("ms"),Yo=Po("s"),Io=Po("m"),Ro=Po("h"),Ao=Po("d"),Ho=Po("w"),Fo=Po("M"),zo=Po("Q"),Wo=Po("y");function Vo(){return N(this)}function Bo(e){e=m(e);return this.isValid()?this[e+"s"]():NaN}function Uo(e){return function(){return this.isValid()?this._data[e]:NaN}}var Ko=Uo("milliseconds"),qo=Uo("seconds"),Go=Uo("minutes"),$o=Uo("hours"),Jo=Uo("days"),Qo=Uo("months"),Xo=Uo("years");function Zo(){return g(this.days()/7)}var ei=Math.round,ti={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function ni(e,t,n,a,r){return r.relativeTime(t||1,!!n,e,a)}function ai(e,t,n,a){var r=N(e).abs(),o=ei(r.as("s")),i=ei(r.as("m")),l=ei(r.as("h")),s=ei(r.as("d")),u=ei(r.as("M")),d=ei(r.as("w")),c=ei(r.as("y")),f=o<=n.ss&&["s",o]||o0;f[4]=a;return ni.apply(null,f)}function ri(e){if(e===undefined)return ei;if(typeof e==="function"){ei=e;return true}return false}function oi(e,t){if(ti[e]===undefined)return false;if(t===undefined)return ti[e];ti[e]=t;if(e==="s")ti.ss=t-1;return true}function ii(e,t){if(!this.isValid())return this.localeData().invalidDate();var n=false,a=ti,r,o;if(typeof e==="object"){t=e;e=false}if(typeof e==="boolean")n=e;if(typeof t==="object"){a=Object.assign({},ti,t);if(t.s!=null&&t.ss==null)a.ss=t.s-1}r=this.localeData();o=ai(this,!n,a,r);if(n)o=r.pastFuture(+this,o);return r.postformat(o)}var li=Math.abs;function si(e){return(e>0)-(e<0)||+e}function ui(){if(!this.isValid())return this.localeData().invalidDate();var e=li(this._milliseconds)/1e3,t=li(this._days),n=li(this._months),a,r,o,i,l=this.asSeconds(),s,u,d,c;if(!l)return"P0D";a=g(e/60);r=g(a/60);e%=60;a%=60;o=g(n/12);n%=12;i=e?e.toFixed(3).replace(/\.?0+$/,""):"";s=l<0?"-":"";u=si(this._months)!==si(l)?"-":"";d=si(this._days)!==si(l)?"-":"";c=si(this._milliseconds)!==si(l)?"-":"";return s+"P"+(o?u+o+"Y":"")+(n?u+n+"M":"")+(t?d+t+"D":"")+(r||a||e?"T":"")+(r?c+r+"H":"")+(a?c+a+"M":"")+(e?c+i+"S":"")}var Y=ua.prototype;return Y.isValid=la,Y.abs=ko,Y.add=Eo,Y.subtract=xo,Y.as=Oo,Y.asMilliseconds=jo,Y.asSeconds=Yo,Y.asMinutes=Io,Y.asHours=Ro,Y.asDays=Ao,Y.asWeeks=Ho,Y.asMonths=Fo,Y.asQuarters=zo,Y.asYears=Wo,Y.valueOf=No,Y._bubble=Lo,Y.clone=Vo,Y.get=Bo,Y.milliseconds=Ko,Y.seconds=qo,Y.minutes=Go,Y.hours=$o,Y.days=Jo,Y.weeks=Zo,Y.months=Qo,Y.years=Xo,Y.humanize=ii,Y.toISOString=ui,Y.toString=ui,Y.toJSON=ui,Y.locale=sr,Y.localeData=dr,Y.toIsoString=e("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ui),Y.lang=ur,a("X",0,0,"unix"),a("x",0,0,"valueOf"),_("x",Be),_("X",qe),w("X",function(e,t,n){n._d=new Date(parseFloat(e)*1e3)}),w("x",function(e,t,n){n._d=new Date(y(e))}), +di.exports=function(){"use strict";var I,A;function c(){return I.apply(null,arguments)}function R(e){I=e}function i(e){return e instanceof Array||Object.prototype.toString.call(e)==="[object Array]"}function H(e){return e!=null&&Object.prototype.toString.call(e)==="[object Object]"}function s(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function F(e){if(Object.getOwnPropertyNames)return Object.getOwnPropertyNames(e).length===0;else{var t;for(t in e)if(s(e,t))return false;return true}}function l(e){return e===void 0}function u(e){return typeof e==="number"||Object.prototype.toString.call(e)==="[object Number]"}function z(e){return e instanceof Date||Object.prototype.toString.call(e)==="[object Date]"}function W(e,t){var n=[],a,r=e.length;for(a=0;a>>0,a;for(a=0;a0)for(n=0;n=0;return(o?n?"+":"":"-")+Math.pow(10,Math.max(0,r)).toString().substr(1)+a}var ie=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,le=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,se={},ue={};function a(e,t,n,a){var r=a;if(typeof a==="string")r=function(){return this[a]()};if(e)ue[e]=r;if(t)ue[t[0]]=function(){return o(r.apply(this,arguments),t[1],t[2])};if(n)ue[n]=function(){return this.localeData().ordinal(r.apply(this,arguments),e)}}function de(e){if(e.match(/\[[\s\S]/))return e.replace(/^\[|\]$/g,"");return e.replace(/\\/g,"")}function ce(a){var r=a.match(ie),e,o;for(e=0,o=r.length;e=0&&le.test(e)){e=e.replace(le,a);le.lastIndex=0;n-=1}return e}var he={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"};function me(e){var t=this._longDateFormat[e],n=this._longDateFormat[e.toUpperCase()];if(t||!n)return t;this._longDateFormat[e]=n.match(ie).map(function(e){if(e==="MMMM"||e==="MM"||e==="DD"||e==="dddd")return e.slice(1);return e}).join("");return this._longDateFormat[e]}var ge="Invalid date";function ye(){return this._invalidDate}var ve="%d",_e=/\d{1,2}/;function be(e){return this._ordinal.replace("%d",e)}var we={future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function Me(e,t,n,a){var r=this._relativeTime[n];return h(r)?r(e,t,n,a):r.replace(/%d/i,e)}function ke(e,t){var n=this._relativeTime[e>0?"future":"past"];return h(n)?n(t):n.replace(/%s/i,t)}var Se={};function t(e,t){var n=e.toLowerCase();Se[n]=Se[n+"s"]=Se[t]=e}function m(e){return typeof e==="string"?Se[e]||Se[e.toLowerCase()]:undefined}function xe(e){var t={},n,a;for(a in e)if(s(e,a)){n=m(a);if(n)t[n]=e[a]}return t}var Ee={};function n(e,t){Ee[e]=t}function Ce(e){var t=[],n;for(n in e)if(s(e,n))t.push({unit:n,priority:Ee[n]});t.sort(function(e,t){return e.priority-t.priority});return t}function Le(e){return e%4===0&&e%100!==0||e%400===0}function g(e){if(e<0)return Math.ceil(e)||0;else return Math.floor(e)}function y(e){var t=+e,n=0;if(t!==0&&isFinite(t))n=g(t);return n}function Te(t,n){return function(e){if(e!=null){Oe(this,t,e);c.updateOffset(this,n);return this}else return De(this,t)}}function De(e,t){return e.isValid()?e._d["get"+(e._isUTC?"UTC":"")+t]():NaN}function Oe(e,t,n){if(e.isValid()&&!isNaN(n))if(t==="FullYear"&&Le(e.year())&&e.month()===1&&e.date()===29){n=y(n);e._d["set"+(e._isUTC?"UTC":"")+t](n,e.month(),ot(n,e.month()))}else e._d["set"+(e._isUTC?"UTC":"")+t](n)}function Ne(e){e=m(e);if(h(this[e]))return this[e]();return this}function Pe(e,t){if(typeof e==="object"){e=xe(e);var n=Ce(e),a,r=n.length;for(a=0;a68?1900:2e3)};var Mt=Te("FullYear",true);function kt(){return Le(this.year())}function St(e,t,n,a,r,o,i){var l;if(e<100&&e>=0){l=new Date(e+400,t,n,a,r,o,i);if(isFinite(l.getFullYear()))l.setFullYear(e)}else l=new Date(e,t,n,a,r,o,i);return l}function xt(e){var t,n;if(e<100&&e>=0){n=Array.prototype.slice.call(arguments);n[0]=e+400;t=new Date(Date.UTC.apply(null,n));if(isFinite(t.getUTCFullYear()))t.setUTCFullYear(e)}else t=new Date(Date.UTC.apply(null,arguments));return t}function Et(e,t,n){var a=7+t-n,r=(7+xt(e,0,a).getUTCDay()-t)%7;return-r+a-1}function Ct(e,t,n,a,r){var o=(7+n-a)%7,i=Et(e,a,r),l=1+7*(t-1)+o+i,s,u;if(l<=0){s=e-1;u=wt(s)+l}else if(l>wt(e)){s=e+1;u=l-wt(e)}else{s=e;u=l}return{year:s,dayOfYear:u}}function Lt(e,t,n){var a=Et(e.year(),t,n),r=Math.floor((e.dayOfYear()-a-1)/7)+1,o,i;if(r<1){i=e.year()-1;o=r+T(i,t,n)}else if(r>T(e.year(),t,n)){o=r-T(e.year(),t,n);i=e.year()+1}else{i=e.year();o=r}return{week:o,year:i}}function T(e,t,n){var a=Et(e,t,n),r=Et(e+1,t,n);return(wt(e)-a+r)/7}function Tt(e){return Lt(e,this._week.dow,this._week.doy).week}a("w",["ww",2],"wo","week"),a("W",["WW",2],"Wo","isoWeek"),t("week","w"),t("isoWeek","W"),n("week",5),n("isoWeek",5),_("w",v),_("ww",v,r),_("W",v),_("WW",v,r),Ze(["w","ww","W","WW"],function(e,t,n,a){t[a.substr(0,1)]=y(e)});var Dt={dow:0,doy:6};function Ot(){return this._week.dow}function Nt(){return this._week.doy}function Pt(e){var t=this.localeData().week(this);return e==null?t:this.add((e-t)*7,"d")}function jt(e){var t=Lt(this,1,4).week;return e==null?t:this.add((e-t)*7,"d")}function Yt(e,t){if(typeof e!=="string")return e;if(!isNaN(e))return parseInt(e,10);e=t.weekdaysParse(e);if(typeof e==="number")return e;return null}function It(e,t){if(typeof e==="string")return t.weekdaysParse(e)%7||7;return isNaN(e)?null:e}function At(e,t){return e.slice(t,7).concat(e.slice(0,t))}a("d",0,"do","day"),a("dd",0,0,function(e){return this.localeData().weekdaysMin(this,e)}),a("ddd",0,0,function(e){return this.localeData().weekdaysShort(this,e)}),a("dddd",0,0,function(e){return this.localeData().weekdays(this,e)}),a("e",0,0,"weekday"),a("E",0,0,"isoWeekday"),t("day","d"),t("weekday","e"),t("isoWeekday","E"),n("day",11),n("weekday",11),n("isoWeekday",11),_("d",v),_("e",v),_("E",v),_("dd",function(e,t){return t.weekdaysMinRegex(e)}),_("ddd",function(e,t){return t.weekdaysShortRegex(e)}),_("dddd",function(e,t){return t.weekdaysRegex(e)}),Ze(["dd","ddd","dddd"],function(e,t,n,a){var r=n._locale.weekdaysParse(e,a,n._strict);if(r!=null)t.d=r;else f(n).invalidWeekday=e}),Ze(["d","e","E"],function(e,t,n,a){t[a]=y(e)});var Rt="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Ht="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Ft="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),zt=Ge,Wt=Ge,Vt=Ge;function Bt(e,t){var n=i(this._weekdays)?this._weekdays:this._weekdays[e&&e!==true&&this._weekdays.isFormat.test(t)?"format":"standalone"];return e===true?At(n,this._week.dow):e?n[e.day()]:n}function Ut(e){return e===true?At(this._weekdaysShort,this._week.dow):e?this._weekdaysShort[e.day()]:this._weekdaysShort}function Kt(e){return e===true?At(this._weekdaysMin,this._week.dow):e?this._weekdaysMin[e.day()]:this._weekdaysMin}function qt(e,t,n){var a,r,o,i=e.toLocaleLowerCase();if(!this._weekdaysParse){this._weekdaysParse=[];this._shortWeekdaysParse=[];this._minWeekdaysParse=[];for(a=0;a<7;++a){o=d([2e3,1]).day(a);this._minWeekdaysParse[a]=this.weekdaysMin(o,"").toLocaleLowerCase();this._shortWeekdaysParse[a]=this.weekdaysShort(o,"").toLocaleLowerCase();this._weekdaysParse[a]=this.weekdays(o,"").toLocaleLowerCase()}}if(n)if(t==="dddd"){r=L.call(this._weekdaysParse,i);return r!==-1?r:null}else if(t==="ddd"){r=L.call(this._shortWeekdaysParse,i);return r!==-1?r:null}else{r=L.call(this._minWeekdaysParse,i);return r!==-1?r:null}else if(t==="dddd"){r=L.call(this._weekdaysParse,i);if(r!==-1)return r;r=L.call(this._shortWeekdaysParse,i);if(r!==-1)return r;r=L.call(this._minWeekdaysParse,i);return r!==-1?r:null}else if(t==="ddd"){r=L.call(this._shortWeekdaysParse,i);if(r!==-1)return r;r=L.call(this._weekdaysParse,i);if(r!==-1)return r;r=L.call(this._minWeekdaysParse,i);return r!==-1?r:null}else{r=L.call(this._minWeekdaysParse,i);if(r!==-1)return r;r=L.call(this._weekdaysParse,i);if(r!==-1)return r;r=L.call(this._shortWeekdaysParse,i);return r!==-1?r:null}}function Gt(e,t,n){var a,r,o;if(this._weekdaysParseExact)return qt.call(this,e,t,n);if(!this._weekdaysParse){this._weekdaysParse=[];this._minWeekdaysParse=[];this._shortWeekdaysParse=[];this._fullWeekdaysParse=[]}for(a=0;a<7;a++){r=d([2e3,1]).day(a);if(n&&!this._fullWeekdaysParse[a]){this._fullWeekdaysParse[a]=new RegExp("^"+this.weekdays(r,"").replace(".","\\.?")+"$","i");this._shortWeekdaysParse[a]=new RegExp("^"+this.weekdaysShort(r,"").replace(".","\\.?")+"$","i");this._minWeekdaysParse[a]=new RegExp("^"+this.weekdaysMin(r,"").replace(".","\\.?")+"$","i")}if(!this._weekdaysParse[a]){o="^"+this.weekdays(r,"")+"|^"+this.weekdaysShort(r,"")+"|^"+this.weekdaysMin(r,"");this._weekdaysParse[a]=new RegExp(o.replace(".",""),"i")}if(n&&t==="dddd"&&this._fullWeekdaysParse[a].test(e))return a;else if(n&&t==="ddd"&&this._shortWeekdaysParse[a].test(e))return a;else if(n&&t==="dd"&&this._minWeekdaysParse[a].test(e))return a;else if(!n&&this._weekdaysParse[a].test(e))return a}}function $t(e){if(!this.isValid())return e!=null?this:NaN;var t=this._isUTC?this._d.getUTCDay():this._d.getDay();if(e!=null){e=Yt(e,this.localeData());return this.add(e-t,"d")}else return t}function Jt(e){if(!this.isValid())return e!=null?this:NaN;var t=(this.day()+7-this.localeData()._week.dow)%7;return e==null?t:this.add(e-t,"d")}function Qt(e){if(!this.isValid())return e!=null?this:NaN;if(e!=null){var t=It(e,this.localeData());return this.day(this.day()%7?t:t-7)}else return this.day()||7}function Xt(e){if(this._weekdaysParseExact){if(!s(this,"_weekdaysRegex"))tn.call(this);if(e)return this._weekdaysStrictRegex;else return this._weekdaysRegex}else{if(!s(this,"_weekdaysRegex"))this._weekdaysRegex=zt;return this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex}}function Zt(e){if(this._weekdaysParseExact){if(!s(this,"_weekdaysRegex"))tn.call(this);if(e)return this._weekdaysShortStrictRegex;else return this._weekdaysShortRegex}else{if(!s(this,"_weekdaysShortRegex"))this._weekdaysShortRegex=Wt;return this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex}}function en(e){if(this._weekdaysParseExact){if(!s(this,"_weekdaysRegex"))tn.call(this);if(e)return this._weekdaysMinStrictRegex;else return this._weekdaysMinRegex}else{if(!s(this,"_weekdaysMinRegex"))this._weekdaysMinRegex=Vt;return this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex}}function tn(){function e(e,t){return t.length-e.length}var t=[],n=[],a=[],r=[],o,i,l,s,u;for(o=0;o<7;o++){i=d([2e3,1]).day(o);l=b(this.weekdaysMin(i,""));s=b(this.weekdaysShort(i,""));u=b(this.weekdays(i,""));t.push(l);n.push(s);a.push(u);r.push(l);r.push(s);r.push(u)}t.sort(e);n.sort(e);a.sort(e);r.sort(e);this._weekdaysRegex=new RegExp("^("+r.join("|")+")","i");this._weekdaysShortRegex=this._weekdaysRegex;this._weekdaysMinRegex=this._weekdaysRegex;this._weekdaysStrictRegex=new RegExp("^("+a.join("|")+")","i");this._weekdaysShortStrictRegex=new RegExp("^("+n.join("|")+")","i");this._weekdaysMinStrictRegex=new RegExp("^("+t.join("|")+")","i")}function nn(){return this.hours()%12||12}function an(){return this.hours()||24}function rn(e,t){a(e,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)})}function on(e,t){return t._meridiemParse}function ln(e){return(e+"").toLowerCase().charAt(0)==="p"}a("H",["HH",2],0,"hour"),a("h",["hh",2],0,nn),a("k",["kk",2],0,an),a("hmm",0,0,function(){return""+nn.apply(this)+o(this.minutes(),2)}),a("hmmss",0,0,function(){return""+nn.apply(this)+o(this.minutes(),2)+o(this.seconds(),2)}),a("Hmm",0,0,function(){return""+this.hours()+o(this.minutes(),2)}),a("Hmmss",0,0,function(){return""+this.hours()+o(this.minutes(),2)+o(this.seconds(),2)}),rn("a",true),rn("A",false),t("hour","h"),n("hour",13),_("a",on),_("A",on),_("H",v),_("h",v),_("k",v),_("HH",v,r),_("hh",v,r),_("kk",v,r),_("hmm",Re),_("hmmss",He),_("Hmm",Re),_("Hmmss",He),w(["H","HH"],x),w(["k","kk"],function(e,t,n){var a=y(e);t[x]=a===24?0:a}),w(["a","A"],function(e,t,n){n._isPm=n._locale.isPM(e);n._meridiem=e}),w(["h","hh"],function(e,t,n){t[x]=y(e);f(n).bigHour=true}),w("hmm",function(e,t,n){var a=e.length-2;t[x]=y(e.substr(0,a));t[E]=y(e.substr(a));f(n).bigHour=true}),w("hmmss",function(e,t,n){var a=e.length-4,r=e.length-2;t[x]=y(e.substr(0,a));t[E]=y(e.substr(a,2));t[C]=y(e.substr(r));f(n).bigHour=true}),w("Hmm",function(e,t,n){var a=e.length-2;t[x]=y(e.substr(0,a));t[E]=y(e.substr(a))}),w("Hmmss",function(e,t,n){var a=e.length-4,r=e.length-2;t[x]=y(e.substr(0,a));t[E]=y(e.substr(a,2));t[C]=y(e.substr(r))});var sn,un=Te("Hours",true);function dn(e,t,n){if(e>11)return n?"pm":"PM";else return n?"am":"AM"}var cn={calendar:re,longDateFormat:he,invalidDate:ge,ordinal:ve,dayOfMonthOrdinalParse:_e,relativeTime:we,months:it,monthsShort:lt,week:Dt,weekdays:Rt,weekdaysMin:Ft,weekdaysShort:Ht,meridiemParse:/[ap]\.?m?\.?/i},D={},fn={},pn;function hn(e,t){var n,a=Math.min(e.length,t.length);for(n=0;n0){r=vn(o.slice(0,n).join("-"));if(r)return r;if(a&&a.length>=n&&hn(o,a)>=n-1)break;n--}t++}return pn}function yn(e){return e.match("^[^/\\\\]*$")!=null}function vn(t){var e=null,n;if(D[t]===undefined&&typeof di!=="undefined"&&di&&di.exports&&yn(t))try{e=pn._abbr;n=ci;fi(511)("./"+t);_n(e)}catch(e){D[t]=null}return D[t]}function _n(e,t){var n;if(e){if(l(t))n=Mn(e);else n=bn(e,t);if(n)pn=n;else if(typeof console!=="undefined"&&console.warn)console.warn("Locale "+e+" not found. Did you forget to load it?")}return pn._abbr}function bn(e,t){if(t!==null){var n,a=cn;t.abbr=e;if(D[e]!=null){ee("defineLocaleOverride","use moment.updateLocale(localeName, config) to change "+"an existing locale. moment.defineLocale(localeName, "+"config) should only be used for creating a new locale "+"See http://momentjs.com/guides/#/warnings/define-locale/ for more info.");a=D[e]._config}else if(t.parentLocale!=null)if(D[t.parentLocale]!=null)a=D[t.parentLocale]._config;else{n=vn(t.parentLocale);if(n!=null)a=n._config;else{if(!fn[t.parentLocale])fn[t.parentLocale]=[];fn[t.parentLocale].push({name:e,config:t});return null}}D[e]=new ae(ne(a,t));if(fn[e])fn[e].forEach(function(e){bn(e.name,e.config)});_n(e);return D[e]}else{delete D[e];return null}}function wn(e,t){if(t!=null){var n,a,r=cn;if(D[e]!=null&&D[e].parentLocale!=null)D[e].set(ne(D[e]._config,t));else{a=vn(e);if(a!=null)r=a._config;t=ne(r,t);if(a==null)t.abbr=e;n=new ae(t);n.parentLocale=D[e];D[e]=n}_n(e)}else if(D[e]!=null)if(D[e].parentLocale!=null){D[e]=D[e].parentLocale;if(e===_n())_n(e)}else if(D[e]!=null)delete D[e];return D[e]}function Mn(e){var t;if(e&&e._locale&&e._locale._abbr)e=e._locale._abbr;if(!e)return pn;if(!i(e)){t=vn(e);if(t)return t;e=[e]}return gn(e)}function kn(){return Z(D)}function Sn(e){var t,n=e._a;if(n&&f(e).overflow===-2){t=n[k]<0||n[k]>11?k:n[S]<1||n[S]>ot(n[M],n[k])?S:n[x]<0||n[x]>24||n[x]===24&&(n[E]!==0||n[C]!==0||n[tt]!==0)?x:n[E]<0||n[E]>59?E:n[C]<0||n[C]>59?C:n[tt]<0||n[tt]>999?tt:-1;if(f(e)._overflowDayOfYear&&(tS))t=S;if(f(e)._overflowWeeks&&t===-1)t=nt;if(f(e)._overflowWeekday&&t===-1)t=at;f(e).overflow=t}return e}var xn=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,En=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Cn=/Z|[+-]\d\d(?::?\d\d)?/,Ln=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,false],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,false],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,false],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,false],["YYYY",/\d{4}/,false]],Tn=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Dn=/^\/?Date\((-?\d+)/i,On=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,Nn={UT:0,GMT:0,EDT:-4*60,EST:-5*60,CDT:-5*60,CST:-6*60,MDT:-6*60,MST:-7*60,PDT:-7*60,PST:-8*60};function Pn(e){var t,n,a=e._i,r=xn.exec(a)||En.exec(a),o,i,l,s,u=Ln.length,d=Tn.length;if(r){f(e).iso=true;for(t=0,n=u;twt(i)||e._dayOfYear===0)f(e)._overflowDayOfYear=true;n=xt(i,0,e._dayOfYear);e._a[k]=n.getUTCMonth();e._a[S]=n.getUTCDate()}for(t=0;t<3&&e._a[t]==null;++t)e._a[t]=a[t]=r[t];for(;t<7;t++)e._a[t]=a[t]=e._a[t]==null?t===2?1:0:e._a[t];if(e._a[x]===24&&e._a[E]===0&&e._a[C]===0&&e._a[tt]===0){e._nextDay=true;e._a[x]=0}e._d=(e._useUTC?xt:St).apply(null,a);o=e._useUTC?e._d.getUTCDay():e._d.getDay();if(e._tzm!=null)e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm);if(e._nextDay)e._a[x]=24;if(e._w&&typeof e._w.d!=="undefined"&&e._w.d!==o)f(e).weekdayMismatch=true}function Bn(e){var t,n,a,r,o,i,l,s,u;t=e._w;if(t.GG!=null||t.W!=null||t.E!=null){o=1;i=4;n=zn(t.GG,e._a[M],Lt(O(),1,4).year);a=zn(t.W,1);r=zn(t.E,1);if(r<1||r>7)s=true}else{o=e._locale._week.dow;i=e._locale._week.doy;u=Lt(O(),o,i);n=zn(t.gg,e._a[M],u.year);a=zn(t.w,u.week);if(t.d!=null){r=t.d;if(r<0||r>6)s=true}else if(t.e!=null){r=t.e+o;if(t.e<0||t.e>6)s=true}else r=o}if(a<1||a>T(n,o,i))f(e)._overflowWeeks=true;else if(s!=null)f(e)._overflowWeekday=true;else{l=Ct(n,a,r,o,i);e._a[M]=l.year;e._dayOfYear=l.dayOfYear}}function Un(e){if(e._f===c.ISO_8601){Pn(e);return}if(e._f===c.RFC_2822){Hn(e);return}e._a=[];f(e).empty=true;var t=""+e._i,n,a,r,o,i,l=t.length,s=0,u,d;r=pe(e._f,e._locale).match(ie)||[];d=r.length;for(n=0;n0)f(e).unusedInput.push(i);t=t.slice(t.indexOf(a)+a.length);s+=a.length}if(ue[o]){if(a)f(e).empty=false;else f(e).unusedTokens.push(o);et(o,a,e)}else if(e._strict&&!a)f(e).unusedTokens.push(o)}f(e).charsLeftOver=l-s;if(t.length>0)f(e).unusedInput.push(t);if(e._a[x]<=12&&f(e).bigHour===true&&e._a[x]>0)f(e).bigHour=undefined;f(e).parsedDateParts=e._a.slice(0);f(e).meridiem=e._meridiem;e._a[x]=Kn(e._locale,e._a[x],e._meridiem);u=f(e).era;if(u!==null)e._a[M]=e._locale.erasConvertYear(u,e._a[M]);Vn(e);Sn(e)}function Kn(e,t,n){var a;if(n==null)return t;if(e.meridiemHour!=null)return e.meridiemHour(t,n);else if(e.isPM!=null){a=e.isPM(n);if(a&&t<12)t+=12;if(!a&&t===12)t=0;return t}else return t}function qn(e){var t,n,a,r,o,i,l=false,s=e._f.length;if(s===0){f(e).invalidFormat=true;e._d=new Date(NaN);return}for(r=0;rthis?this:e;else return K()});function ta(e,t){var n,a;if(t.length===1&&i(t[0]))t=t[0];if(!t.length)return O();n=t[0];for(a=1;athis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function xa(){if(!l(this._isDSTShifted))return this._isDSTShifted;var e={},t;$(e,this);e=Jn(e);if(e._a){t=e._isUTC?d(e._a):O(e._a);this._isDSTShifted=this.isValid()&&fa(e._a,t.toArray())>0}else this._isDSTShifted=false;return this._isDSTShifted}function Ea(){return this.isValid()?!this._isUTC:false}function Ca(){return this.isValid()?this._isUTC:false}function La(){return this.isValid()?this._isUTC&&this._offset===0:false}c.updateOffset=function(){};var Ta=/^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/,Da=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;function N(e,t){var n=e,a=null,r,o,i;if(da(e))n={ms:e._milliseconds,d:e._days,M:e._months};else if(u(e)||!isNaN(+e)){n={};if(t)n[t]=+e;else n.milliseconds=+e}else if(a=Ta.exec(e)){r=a[1]==="-"?-1:1;n={y:0,d:y(a[S])*r,h:y(a[x])*r,m:y(a[E])*r,s:y(a[C])*r,ms:y(ca(a[tt]*1e3))*r}}else if(a=Da.exec(e)){r=a[1]==="-"?-1:1;n={y:Oa(a[2],r),M:Oa(a[3],r),w:Oa(a[4],r),d:Oa(a[5],r),h:Oa(a[6],r),m:Oa(a[7],r),s:Oa(a[8],r)}}else if(n==null)n={};else if(typeof n==="object"&&("from"in n||"to"in n)){i=Pa(O(n.from),O(n.to));n={};n.ms=i.milliseconds;n.M=i.months}o=new ua(n);if(da(e)&&s(e,"_locale"))o._locale=e._locale;if(da(e)&&s(e,"_isValid"))o._isValid=e._isValid;return o}function Oa(e,t){var n=e&&parseFloat(e.replace(",","."));return(isNaN(n)?0:n)*t}function Na(e,t){var n={};n.months=t.month()-e.month()+(t.year()-e.year())*12;if(e.clone().add(n.months,"M").isAfter(t))--n.months;n.milliseconds=+t-+e.clone().add(n.months,"M");return n}function Pa(e,t){var n;if(!(e.isValid()&&t.isValid()))return{milliseconds:0,months:0};t=ga(t,e);if(e.isBefore(t))n=Na(e,t);else{n=Na(t,e);n.milliseconds=-n.milliseconds;n.months=-n.months}return n}function ja(r,o){return function(e,t){var n,a;if(t!==null&&!isNaN(+t)){ee(o,"moment()."+o+"(period, number) is deprecated. Please use moment()."+o+"(number, period). "+"See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.");a=e;e=t;t=a}n=N(e,t);Ya(this,n,r);return this}}function Ya(e,t,n,a){var r=t._milliseconds,o=ca(t._days),i=ca(t._months);if(!e.isValid())return;a=a==null?true:a;if(i)mt(e,De(e,"Month")+i*n);if(o)Oe(e,"Date",De(e,"Date")+o*n);if(r)e._d.setTime(e._d.valueOf()+r*n);if(a)c.updateOffset(e,o||i)}N.fn=ua.prototype,N.invalid=sa;var Ia=ja(1,"add"),Aa=ja(-1,"subtract");function Ra(e){return typeof e==="string"||e instanceof String}function Ha(e){return p(e)||z(e)||Ra(e)||u(e)||za(e)||Fa(e)||e===null||e===undefined}function Fa(e){var t=H(e)&&!F(e),n=false,a=["years","year","y","months","month","M","days","day","d","dates","date","D","hours","hour","h","minutes","minute","m","seconds","second","s","milliseconds","millisecond","ms"],r,o,i=a.length;for(r=0;rn.valueOf();else return n.valueOf()9999)return fe(n,t?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ");if(h(Date.prototype.toISOString))if(t)return this.toDate().toISOString();else return new Date(this.valueOf()+this.utcOffset()*60*1e3).toISOString().replace("Z",fe(n,"Z"));return fe(n,t?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")}function nr(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e="moment",t="",n,a,r,o;if(!this.isLocal()){e=this.utcOffset()===0?"moment.utc":"moment.parseZone";t="Z"}n="["+e+'("]';a=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY";r="-MM-DD[T]HH:mm:ss.SSS";o=t+'[")]';return this.format(n+a+r+o)}function ar(e){if(!e)e=this.isUtc()?c.defaultFormatUtc:c.defaultFormat;var t=fe(this,e);return this.localeData().postformat(t)}function rr(e,t){if(this.isValid()&&(p(e)&&e.isValid()||O(e).isValid()))return N({to:this,from:e}).locale(this.locale()).humanize(!t);else return this.localeData().invalidDate()}function or(e){return this.from(O(),e)}function ir(e,t){if(this.isValid()&&(p(e)&&e.isValid()||O(e).isValid()))return N({from:this,to:e}).locale(this.locale()).humanize(!t);else return this.localeData().invalidDate()}function lr(e){return this.to(O(),e)}function sr(e){var t;if(e===undefined)return this._locale._abbr;else{t=Mn(e);if(t!=null)this._locale=t;return this}}c.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",c.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var ur=e("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(e){if(e===undefined)return this.localeData();else return this.locale(e)});function dr(){return this._locale}var cr=1e3,fr=60*cr,pr=60*fr,hr=(365*400+97)*24*pr;function mr(e,t){return(e%t+t)%t}function gr(e,t,n){if(e<100&&e>=0)return new Date(e+400,t,n)-hr;else return new Date(e,t,n).valueOf()}function yr(e,t,n){if(e<100&&e>=0)return Date.UTC(e+400,t,n)-hr;else return Date.UTC(e,t,n)}function vr(e){var t,n;e=m(e);if(e===undefined||e==="millisecond"||!this.isValid())return this;n=this._isUTC?yr:gr;switch(e){case"year":t=n(this.year(),0,1);break;case"quarter":t=n(this.year(),this.month()-this.month()%3,1);break;case"month":t=n(this.year(),this.month(),1);break;case"week":t=n(this.year(),this.month(),this.date()-this.weekday());break;case"isoWeek":t=n(this.year(),this.month(),this.date()-(this.isoWeekday()-1));break;case"day":case"date":t=n(this.year(),this.month(),this.date());break;case"hour":t=this._d.valueOf();t-=mr(t+(this._isUTC?0:this.utcOffset()*fr),pr);break;case"minute":t=this._d.valueOf();t-=mr(t,fr);break;case"second":t=this._d.valueOf();t-=mr(t,cr);break}this._d.setTime(t);c.updateOffset(this,true);return this}function _r(e){var t,n;e=m(e);if(e===undefined||e==="millisecond"||!this.isValid())return this;n=this._isUTC?yr:gr;switch(e){case"year":t=n(this.year()+1,0,1)-1;break;case"quarter":t=n(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":t=n(this.year(),this.month()+1,1)-1;break;case"week":t=n(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":t=n(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":t=n(this.year(),this.month(),this.date()+1)-1;break;case"hour":t=this._d.valueOf();t+=pr-mr(t+(this._isUTC?0:this.utcOffset()*fr),pr)-1;break;case"minute":t=this._d.valueOf();t+=fr-mr(t,fr)-1;break;case"second":t=this._d.valueOf();t+=cr-mr(t,cr)-1;break}this._d.setTime(t);c.updateOffset(this,true);return this}function br(){return this._d.valueOf()-(this._offset||0)*6e4}function wr(){return Math.floor(this.valueOf()/1e3)}function Mr(){return new Date(this.valueOf())}function kr(){var e=this;return[e.year(),e.month(),e.date(),e.hour(),e.minute(),e.second(),e.millisecond()]}function Sr(){var e=this;return{years:e.year(),months:e.month(),date:e.date(),hours:e.hours(),minutes:e.minutes(),seconds:e.seconds(),milliseconds:e.milliseconds()}}function xr(){return this.isValid()?this.toISOString():null}function Er(){return U(this)}function Cr(){return V({},f(this))}function Lr(){return f(this).overflow}function Tr(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Dr(e,t){var n,a,r,o=this._eras||Mn("en")._eras;for(n=0,a=o.length;n=0)return o[a]}}function Nr(e,t){var n=e.since<=e.until?+1:-1;if(t===undefined)return c(e.since).year();else return c(e.since).year()+(t-e.offset)*n}function Pr(){var e,t,n,a=this.localeData().eras();for(e=0,t=a.length;eo)t=o;return Zr.call(this,e,t,n,a,r)}}function Zr(e,t,n,a,r){var o=Ct(e,t,n,a,r),i=xt(o.year,0,o.dayOfYear);this.year(i.getUTCFullYear());this.month(i.getUTCMonth());this.date(i.getUTCDate());return this}function eo(e){return e==null?Math.ceil((this.month()+1)/3):this.month((e-1)*3+this.month()%3)}a("N",0,0,"eraAbbr"),a("NN",0,0,"eraAbbr"),a("NNN",0,0,"eraAbbr"),a("NNNN",0,0,"eraName"),a("NNNNN",0,0,"eraNarrow"),a("y",["y",1],"yo","eraYear"),a("y",["yy",2],0,"eraYear"),a("y",["yyy",3],0,"eraYear"),a("y",["yyyy",4],0,"eraYear"),_("N",Fr),_("NN",Fr),_("NNN",Fr),_("NNNN",zr),_("NNNNN",Wr),w(["N","NN","NNN","NNNN","NNNNN"],function(e,t,n,a){var r=n._locale.erasParse(e,a,n._strict);if(r)f(n).era=r;else f(n).invalidEra=e}),_("y",Ve),_("yy",Ve),_("yyy",Ve),_("yyyy",Ve),_("yo",Vr),w(["y","yy","yyy","yyyy"],M),w(["yo"],function(e,t,n,a){var r;if(n._locale._eraYearOrdinalRegex)r=e.match(n._locale._eraYearOrdinalRegex);if(n._locale.eraYearOrdinalParse)t[M]=n._locale.eraYearOrdinalParse(e,r);else t[M]=parseInt(e,10)}),a(0,["gg",2],0,function(){return this.weekYear()%100}),a(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Ur("gggg","weekYear"),Ur("ggggg","weekYear"),Ur("GGGG","isoWeekYear"),Ur("GGGGG","isoWeekYear"),t("weekYear","gg"),t("isoWeekYear","GG"),n("weekYear",1),n("isoWeekYear",1),_("G",Be),_("g",Be),_("GG",v,r),_("gg",v,r),_("GGGG",ze,Ie),_("gggg",ze,Ie),_("GGGGG",We,Ae),_("ggggg",We,Ae),Ze(["gggg","ggggg","GGGG","GGGGG"],function(e,t,n,a){t[a.substr(0,2)]=y(e)}),Ze(["gg","GG"],function(e,t,n,a){t[a]=c.parseTwoDigitYear(e)}),a("Q",0,"Qo","quarter"),t("quarter","Q"),n("quarter",7),_("Q",je),w("Q",function(e,t){t[k]=(y(e)-1)*3}),a("D",["DD",2],"Do","date"),t("date","D"),n("date",9),_("D",v),_("DD",v,r),_("Do",function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient}),w(["D","DD"],S),w("Do",function(e,t){t[S]=y(e.match(v)[0])});var to=Te("Date",true);function no(e){var t=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return e==null?t:this.add(e-t,"d")}a("DDD",["DDDD",3],"DDDo","dayOfYear"),t("dayOfYear","DDD"),n("dayOfYear",4),_("DDD",Fe),_("DDDD",Ye),w(["DDD","DDDD"],function(e,t,n){n._dayOfYear=y(e)}),a("m",["mm",2],0,"minute"),t("minute","m"),n("minute",14),_("m",v),_("mm",v,r),w(["m","mm"],E);var ao=Te("Minutes",false),ro=(a("s",["ss",2],0,"second"),t("second","s"),n("second",15),_("s",v),_("ss",v,r),w(["s","ss"],C),Te("Seconds",false)),oo,io;for(a("S",0,0,function(){return~~(this.millisecond()/100)}),a(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),a(0,["SSS",3],0,"millisecond"),a(0,["SSSS",4],0,function(){return this.millisecond()*10}),a(0,["SSSSS",5],0,function(){return this.millisecond()*100}),a(0,["SSSSSS",6],0,function(){return this.millisecond()*1e3}),a(0,["SSSSSSS",7],0,function(){return this.millisecond()*1e4}),a(0,["SSSSSSSS",8],0,function(){return this.millisecond()*1e5}),a(0,["SSSSSSSSS",9],0,function(){return this.millisecond()*1e6}),t("millisecond","ms"),n("millisecond",16),_("S",Fe,je),_("SS",Fe,r),_("SSS",Fe,Ye),oo="SSSS";oo.length<=9;oo+="S")_(oo,Ve);function lo(e,t){t[tt]=y(("0."+e)*1e3)}for(oo="S";oo.length<=9;oo+="S")w(oo,lo);function so(){return this._isUTC?"UTC":""}function uo(){return this._isUTC?"Coordinated Universal Time":""}io=Te("Milliseconds",false),a("z",0,0,"zoneAbbr"),a("zz",0,0,"zoneName");var P=J.prototype;if(P.add=Ia,P.calendar=Ba,P.clone=Ua,P.diff=Xa,P.endOf=_r,P.format=ar,P.from=rr,P.fromNow=or,P.to=ir,P.toNow=lr,P.get=Ne,P.invalidAt=Lr,P.isAfter=Ka,P.isBefore=qa,P.isBetween=Ga,P.isSame=$a,P.isSameOrAfter=Ja,P.isSameOrBefore=Qa,P.isValid=Er,P.lang=ur,P.locale=sr,P.localeData=dr,P.max=ea,P.min=Zn,P.parsingFlags=Cr,P.set=Pe,P.startOf=vr,P.subtract=Aa,P.toArray=kr,P.toObject=Sr,P.toDate=Mr,P.toISOString=tr,P.inspect=nr,typeof Symbol!=="undefined"&&Symbol.for!=null)P[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"};function co(e){return O(e*1e3)}function fo(){return O.apply(null,arguments).parseZone()}function po(e){return e}P.toJSON=xr,P.toString=er,P.unix=wr,P.valueOf=br,P.creationData=Tr,P.eraName=Pr,P.eraNarrow=jr,P.eraAbbr=Yr,P.eraYear=Ir,P.year=Mt,P.isLeapYear=kt,P.weekYear=Kr,P.isoWeekYear=qr,P.quarter=P.quarters=eo,P.month=gt,P.daysInMonth=yt,P.week=P.weeks=Pt,P.isoWeek=P.isoWeeks=jt,P.weeksInYear=Jr,P.weeksInWeekYear=Qr,P.isoWeeksInYear=Gr,P.isoWeeksInISOWeekYear=$r,P.date=to,P.day=P.days=$t,P.weekday=Jt,P.isoWeekday=Qt,P.dayOfYear=no,P.hour=P.hours=un,P.minute=P.minutes=ao,P.second=P.seconds=ro,P.millisecond=P.milliseconds=io,P.utcOffset=va,P.utc=ba,P.local=wa,P.parseZone=Ma,P.hasAlignedHourOffset=ka,P.isDST=Sa,P.isLocal=Ea,P.isUtcOffset=Ca,P.isUtc=La,P.isUTC=La,P.zoneAbbr=so,P.zoneName=uo,P.dates=e("dates accessor is deprecated. Use date instead.",to),P.months=e("months accessor is deprecated. Use month instead",gt),P.years=e("years accessor is deprecated. Use year instead",Mt),P.zone=e("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",_a),P.isDSTShifted=e("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",xa);var j=ae.prototype;function ho(e,t,n,a){var r=Mn(),o=d().set(a,t);return r[n](o,e)}function mo(e,t,n){if(u(e)){t=e;e=undefined}e=e||"";if(t!=null)return ho(e,t,n,"month");var a,r=[];for(a=0;a<12;a++)r[a]=ho(e,a,n,"month");return r}function go(e,t,n,a){if(typeof e==="boolean"){if(u(t)){n=t;t=undefined}t=t||""}else{t=e;n=t;e=false;if(u(t)){n=t;t=undefined}t=t||""}var r=Mn(),o=e?r._week.dow:0,i,l=[];if(n!=null)return ho(t,(n+o)%7,a,"day");for(i=0;i<7;i++)l[i]=ho(t,(i+o)%7,a,"day");return l}function yo(e,t){return mo(e,t,"months")}function vo(e,t){return mo(e,t,"monthsShort")}function _o(e,t,n){return go(e,t,n,"weekdays")}function bo(e,t,n){return go(e,t,n,"weekdaysShort")}function wo(e,t,n){return go(e,t,n,"weekdaysMin")}j.calendar=oe,j.longDateFormat=me,j.invalidDate=ye,j.ordinal=be,j.preparse=po,j.postformat=po,j.relativeTime=Me,j.pastFuture=ke,j.set=te,j.eras=Dr,j.erasParse=Or,j.erasConvertYear=Nr,j.erasAbbrRegex=Rr,j.erasNameRegex=Ar,j.erasNarrowRegex=Hr,j.months=ct,j.monthsShort=ft,j.monthsParse=ht,j.monthsRegex=_t,j.monthsShortRegex=vt,j.week=Tt,j.firstDayOfYear=Nt,j.firstDayOfWeek=Ot,j.weekdays=Bt,j.weekdaysMin=Kt,j.weekdaysShort=Ut,j.weekdaysParse=Gt,j.weekdaysRegex=Xt,j.weekdaysShortRegex=Zt,j.weekdaysMinRegex=en,j.isPM=ln,j.meridiem=dn,_n("en",{eras:[{since:"0001-01-01",until:+Infinity,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-Infinity,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10,n=y(e%100/10)===1?"th":t===1?"st":t===2?"nd":t===3?"rd":"th";return e+n}}),c.lang=e("moment.lang is deprecated. Use moment.locale instead.",_n),c.langData=e("moment.langData is deprecated. Use moment.localeData instead.",Mn);var Mo=Math.abs;function ko(){var e=this._data;this._milliseconds=Mo(this._milliseconds);this._days=Mo(this._days);this._months=Mo(this._months);e.milliseconds=Mo(e.milliseconds);e.seconds=Mo(e.seconds);e.minutes=Mo(e.minutes);e.hours=Mo(e.hours);e.months=Mo(e.months);e.years=Mo(e.years);return this}function So(e,t,n,a){var r=N(t,n);e._milliseconds+=a*r._milliseconds;e._days+=a*r._days;e._months+=a*r._months;return e._bubble()}function xo(e,t){return So(this,e,t,1)}function Eo(e,t){return So(this,e,t,-1)}function Co(e){if(e<0)return Math.floor(e);else return Math.ceil(e)}function Lo(){var e=this._milliseconds,t=this._days,n=this._months,a=this._data,r,o,i,l,s;if(!(e>=0&&t>=0&&n>=0||e<=0&&t<=0&&n<=0)){e+=Co(Do(n)+t)*864e5;t=0;n=0}a.milliseconds=e%1e3;r=g(e/1e3);a.seconds=r%60;o=g(r/60);a.minutes=o%60;i=g(o/60);a.hours=i%24;t+=g(i/24);s=g(To(t));n+=s;t-=Co(Do(s));l=g(n/12);n%=12;a.days=t;a.months=n;a.years=l;return this}function To(e){return e*4800/146097}function Do(e){return e*146097/4800}function Oo(e){if(!this.isValid())return NaN;var t,n,a=this._milliseconds;e=m(e);if(e==="month"||e==="quarter"||e==="year"){t=this._days+a/864e5;n=this._months+To(t);switch(e){case"month":return n;case"quarter":return n/3;case"year":return n/12}}else{t=this._days+Math.round(Do(this._months));switch(e){case"week":return t/7+a/6048e5;case"day":return t+a/864e5;case"hour":return t*24+a/36e5;case"minute":return t*1440+a/6e4;case"second":return t*86400+a/1e3;case"millisecond":return Math.floor(t*864e5)+a;default:throw new Error("Unknown unit "+e)}}}function No(){if(!this.isValid())return NaN;return this._milliseconds+this._days*864e5+this._months%12*2592e6+y(this._months/12)*31536e6}function Po(e){return function(){return this.as(e)}}var jo=Po("ms"),Yo=Po("s"),Io=Po("m"),Ao=Po("h"),Ro=Po("d"),Ho=Po("w"),Fo=Po("M"),zo=Po("Q"),Wo=Po("y");function Vo(){return N(this)}function Bo(e){e=m(e);return this.isValid()?this[e+"s"]():NaN}function Uo(e){return function(){return this.isValid()?this._data[e]:NaN}}var Ko=Uo("milliseconds"),qo=Uo("seconds"),Go=Uo("minutes"),$o=Uo("hours"),Jo=Uo("days"),Qo=Uo("months"),Xo=Uo("years");function Zo(){return g(this.days()/7)}var ei=Math.round,ti={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function ni(e,t,n,a,r){return r.relativeTime(t||1,!!n,e,a)}function ai(e,t,n,a){var r=N(e).abs(),o=ei(r.as("s")),i=ei(r.as("m")),l=ei(r.as("h")),s=ei(r.as("d")),u=ei(r.as("M")),d=ei(r.as("w")),c=ei(r.as("y")),f=o<=n.ss&&["s",o]||o0;f[4]=a;return ni.apply(null,f)}function ri(e){if(e===undefined)return ei;if(typeof e==="function"){ei=e;return true}return false}function oi(e,t){if(ti[e]===undefined)return false;if(t===undefined)return ti[e];ti[e]=t;if(e==="s")ti.ss=t-1;return true}function ii(e,t){if(!this.isValid())return this.localeData().invalidDate();var n=false,a=ti,r,o;if(typeof e==="object"){t=e;e=false}if(typeof e==="boolean")n=e;if(typeof t==="object"){a=Object.assign({},ti,t);if(t.s!=null&&t.ss==null)a.ss=t.s-1}r=this.localeData();o=ai(this,!n,a,r);if(n)o=r.pastFuture(+this,o);return r.postformat(o)}var li=Math.abs;function si(e){return(e>0)-(e<0)||+e}function ui(){if(!this.isValid())return this.localeData().invalidDate();var e=li(this._milliseconds)/1e3,t=li(this._days),n=li(this._months),a,r,o,i,l=this.asSeconds(),s,u,d,c;if(!l)return"P0D";a=g(e/60);r=g(a/60);e%=60;a%=60;o=g(n/12);n%=12;i=e?e.toFixed(3).replace(/\.?0+$/,""):"";s=l<0?"-":"";u=si(this._months)!==si(l)?"-":"";d=si(this._days)!==si(l)?"-":"";c=si(this._milliseconds)!==si(l)?"-":"";return s+"P"+(o?u+o+"Y":"")+(n?u+n+"M":"")+(t?d+t+"D":"")+(r||a||e?"T":"")+(r?c+r+"H":"")+(a?c+a+"M":"")+(e?c+i+"S":"")}var Y=ua.prototype;return Y.isValid=la,Y.abs=ko,Y.add=xo,Y.subtract=Eo,Y.as=Oo,Y.asMilliseconds=jo,Y.asSeconds=Yo,Y.asMinutes=Io,Y.asHours=Ao,Y.asDays=Ro,Y.asWeeks=Ho,Y.asMonths=Fo,Y.asQuarters=zo,Y.asYears=Wo,Y.valueOf=No,Y._bubble=Lo,Y.clone=Vo,Y.get=Bo,Y.milliseconds=Ko,Y.seconds=qo,Y.minutes=Go,Y.hours=$o,Y.days=Jo,Y.weeks=Zo,Y.months=Qo,Y.years=Xo,Y.humanize=ii,Y.toISOString=ui,Y.toString=ui,Y.toJSON=ui,Y.locale=sr,Y.localeData=dr,Y.toIsoString=e("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ui),Y.lang=ur,a("X",0,0,"unix"),a("x",0,0,"valueOf"),_("x",Be),_("X",qe),w("X",function(e,t,n){n._d=new Date(parseFloat(e)*1e3)}),w("x",function(e,t,n){n._d=new Date(y(e))}), //! moment.js -c.version="2.29.4",A(O),c.fn=P,c.min=na,c.max=aa,c.now=ra,c.utc=d,c.unix=co,c.months=yo,c.isDate=z,c.locale=_n,c.invalid=K,c.duration=N,c.isMoment=p,c.weekdays=_o,c.parseZone=fo,c.localeData=Mn,c.isDuration=da,c.monthsShort=vo,c.weekdaysMin=wo,c.defineLocale=bn,c.updateLocale=wn,c.locales=kn,c.weekdaysShort=bo,c.normalizeUnits=m,c.relativeTimeRounding=ri,c.relativeTimeThreshold=oi,c.calendarFormat=Va,c.prototype=P,c.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},c}()}.call(this,fi(510)(e))},function(e,t,n){"use strict";t.__esModule=!0;var a=u(n(2)),r=u(n(12)),o=u(n(8)),i=u(n(358)),l=u(n(575)),s=u(n(576)),n=u(n(360));function u(e){return e&&e.__esModule?e:{default:e}}i.default.Password=o.default.config(l.default,{exportNames:["getInputNode","focus"],transform:function(e,t){var n;return"hasLimitHint"in e&&(t("hasLimitHint","showLimitHint","Input"),n=(t=e).hasLimitHint,t=(0,r.default)(t,["hasLimitHint"]),e=(0,a.default)({showLimitHint:n},t)),e}}),i.default.TextArea=o.default.config(s.default,{exportNames:["getInputNode","focus"],transform:function(e,t){var n;return"hasLimitHint"in e&&(t("hasLimitHint","showLimitHint","Input"),n=(t=e).hasLimitHint,t=(0,r.default)(t,["hasLimitHint"]),e=(0,a.default)({showLimitHint:n},t)),e}}),i.default.Group=n.default,t.default=o.default.config(i.default,{exportNames:["getInputNode","focus"],transform:function(e,t){var n;return"hasLimitHint"in e&&(t("hasLimitHint","showLimitHint","Input"),n=(t=e).hasLimitHint,t=(0,r.default)(t,["hasLimitHint"]),e=(0,a.default)({showLimitHint:n},t)),e}}),e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0,t.pickAttrs=t.datejs=t.htmlId=t.KEYCODE=t.guid=t.focus=t.support=t.str=t.obj=t.log=t.func=t.events=t.env=t.dom=void 0;var a=y(n(199)),r=y(n(202)),o=y(n(493)),i=y(n(494)),l=y(n(201)),s=y(n(97)),u=y(n(200)),d=y(n(502)),c=y(n(503)),f=y(n(504)),p=g(n(505)),h=g(n(204)),m=g(n(153)),n=g(n(506));function g(e){return e&&e.__esModule?e:{default:e}}function y(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}t.dom=a,t.env=r,t.events=o,t.func=i,t.log=l,t.obj=s,t.str=u,t.support=d,t.focus=c,t.guid=p.default,t.KEYCODE=h.default,t.htmlId=f,t.datejs=m.default,t.pickAttrs=n.default},function(e,t,n){"use strict";t.__esModule=!0,t.default=function(e,t){var n,a={};for(n in e)0<=t.indexOf(n)||Object.prototype.hasOwnProperty.call(e,n)&&(a[n]=e[n]);return a}},function(e,t,n){var a; +c.version="2.29.4",R(O),c.fn=P,c.min=na,c.max=aa,c.now=ra,c.utc=d,c.unix=co,c.months=yo,c.isDate=z,c.locale=_n,c.invalid=K,c.duration=N,c.isMoment=p,c.weekdays=_o,c.parseZone=fo,c.localeData=Mn,c.isDuration=da,c.monthsShort=vo,c.weekdaysMin=wo,c.defineLocale=bn,c.updateLocale=wn,c.locales=kn,c.weekdaysShort=bo,c.normalizeUnits=m,c.relativeTimeRounding=ri,c.relativeTimeThreshold=oi,c.calendarFormat=Va,c.prototype=P,c.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},c}()}.call(this,fi(510)(e))},function(e,t,n){"use strict";t.__esModule=!0;var a=u(n(2)),r=u(n(12)),o=u(n(8)),i=u(n(358)),l=u(n(575)),s=u(n(576)),n=u(n(360));function u(e){return e&&e.__esModule?e:{default:e}}i.default.Password=o.default.config(l.default,{exportNames:["getInputNode","focus"],transform:function(e,t){var n;return"hasLimitHint"in e&&(t("hasLimitHint","showLimitHint","Input"),n=(t=e).hasLimitHint,t=(0,r.default)(t,["hasLimitHint"]),e=(0,a.default)({showLimitHint:n},t)),e}}),i.default.TextArea=o.default.config(s.default,{exportNames:["getInputNode","focus"],transform:function(e,t){var n;return"hasLimitHint"in e&&(t("hasLimitHint","showLimitHint","Input"),n=(t=e).hasLimitHint,t=(0,r.default)(t,["hasLimitHint"]),e=(0,a.default)({showLimitHint:n},t)),e}}),i.default.Group=n.default,t.default=o.default.config(i.default,{exportNames:["getInputNode","focus"],transform:function(e,t){var n;return"hasLimitHint"in e&&(t("hasLimitHint","showLimitHint","Input"),n=(t=e).hasLimitHint,t=(0,r.default)(t,["hasLimitHint"]),e=(0,a.default)({showLimitHint:n},t)),e}}),e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0,t.pickAttrs=t.datejs=t.htmlId=t.KEYCODE=t.guid=t.focus=t.support=t.str=t.obj=t.log=t.func=t.events=t.env=t.dom=void 0;var a=y(n(199)),r=y(n(202)),o=y(n(493)),i=y(n(494)),l=y(n(201)),s=y(n(97)),u=y(n(200)),d=y(n(502)),c=y(n(503)),f=y(n(504)),p=g(n(505)),h=g(n(204)),m=g(n(153)),n=g(n(506));function g(e){return e&&e.__esModule?e:{default:e}}function y(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}t.dom=a,t.env=r,t.events=o,t.func=i,t.log=l,t.obj=s,t.str=u,t.support=d,t.focus=c,t.guid=p.default,t.KEYCODE=h.default,t.htmlId=f,t.datejs=m.default,t.pickAttrs=n.default},function(e,t,n){"use strict";t.__esModule=!0,t.default=function(e,t){var n,a={};for(n in e)0<=t.indexOf(n)||Object.prototype.hasOwnProperty.call(e,n)&&(a[n]=e[n]);return a}},function(e,t,n){var a; /*! Copyright (c) 2018 Jed Watson. Licensed under the MIT License (MIT), see http://jedwatson.github.io/classnames */ -!function(){"use strict";var i={}.hasOwnProperty;function l(){for(var e=[],t=0;t")),"shouldUpdatePosition"in r&&(delete t.shouldUpdatePosition,d.log.warning("Warning: [ shouldUpdatePosition ] is deprecated at [ ]")),"minMargin"in r&&o("minMargin","top/bottom",""),"isFullScreen"in r&&(r.overFlowScroll=!r.isFullScreen,delete t.isFullScreen,o("isFullScreen","overFlowScroll","")),t;return["target","offset","beforeOpen","onOpen","afterOpen","beforePosition","onPosition","cache","safeNode","wrapperClassName","container"].forEach(function(e){var t,n,a;e in r&&(o(e,"overlayProps."+e,"Dialog"),t=(n=r).overlayProps,n=(0,l.default)(n,["overlayProps"]),a=(0,i.default)(((a={})[e]=r[e],a),t||{}),delete n[e],r=(0,i.default)({overlayProps:a},n))}),r}n.displayName="Dialog",n.Inner=p.default,n.show=function(e){return!1!==u.default.getContextProps(e,"Dialog").warning&&(e=v(e,d.log.deprecated)),(0,h.show)(e)},n.alert=function(e){return!1!==u.default.getContextProps(e,"Dialog").warning&&(e=v(e,d.log.deprecated)),(0,h.alert)(e)},n.confirm=function(e){return!1!==u.default.getContextProps(e,"Dialog").warning&&(e=v(e,d.log.deprecated)),(0,h.confirm)(e)},n.success=function(e){return(0,h.success)(e)},n.error=function(e){return(0,h.error)(e)},n.notice=function(e){return(0,h.notice)(e)},n.warning=function(e){return(0,h.warning)(e)},n.help=function(e){return(0,h.help)(e)},n.withContext=h.withContext,t.default=u.default.config(n,{transform:v}),e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var o=r(n(2)),i=r(n(12)),a=r(n(8)),l=r(n(570)),n=r(n(571));function r(e){return e&&e.__esModule?e:{default:e}}l.default.Group=n.default,t.default=a.default.config(l.default,{transform:function(e,t){var n,a,r;return"shape"in e&&(t("shape","text | warning | ghost","Button"),n=(t=e).shape,a=t.type,t=(0,i.default)(t,["shape","type"]),r=void 0,"ghost"===n&&(r={primary:"dark",secondary:"dark",normal:"light",dark:"dark",light:"light"}[a||l.default.defaultProps.type]),e=(0,o.default)({type:"light"===a||"dark"===a||"secondary"===a&&"warning"===n?"normal":a,ghost:r,text:"text"===n,warning:"warning"===n},t)),e}}),e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var i=v(n(2)),l=v(n(12)),a=v(n(8)),r=v(n(632)),o=v(n(637)),s=v(n(640)),u=v(n(641)),d=v(n(642)),c=v(n(643)),f=v(n(645)),p=v(n(646)),h=v(n(647)),m=v(n(650)),g=v(n(391)),y=v(n(392));function v(e){return e&&e.__esModule?e:{default:e}}var _=n(11).env.ieVersion,n=[s.default,f.default,u.default,d.default,c.default,o.default,h.default,m.default],b=n.reduce(function(e,t){return e=t(e)},r.default),n=(f.default._typeMark="lock",d.default._typeMark="expanded",s.default._typeMark="fixed",n.reduce(function(e,t){var n=!_;return e="lock"===t._typeMark?(n?(0,p.default):(0,f.default))(e):"expanded"===t._typeMark?n?(0,d.default)(e,!0):(0,d.default)(e):"fixed"===t._typeMark?n?(0,s.default)(e,!0):(0,s.default)(e):t(e)},r.default));b.Base=r.default,b.fixed=s.default,b.lock=f.default,b.selection=u.default,b.expanded=d.default,b.tree=o.default,b.virtual=c.default,b.list=h.default,b.sticky=m.default,b.GroupHeader=g.default,b.GroupFooter=y.default,b.StickyLock=a.default.config(n,{componentName:"Table"}),t.default=a.default.config(b,{componentName:"Table",transform:function(e,t){var n,a,r,o;return"expandedRowKeys"in e&&(t("expandedRowKeys","openRowKeys","Table"),o=(r=e).expandedRowKeys,r=(0,l.default)(r,["expandedRowKeys"]),e=(0,i.default)({openRowKeys:o},r)),"onExpandedChange"in e&&(t("onExpandedChange","onRowOpen","Table"),r=(o=e).onExpandedChange,o=(0,l.default)(o,["onExpandedChange"]),e=(0,i.default)({onRowOpen:r},o)),"isLoading"in e&&(t("isLoading","loading","Table"),o=(r=e).isLoading,r=(0,l.default)(r,["isLoading"]),e=(0,i.default)({loading:o},r)),"indentSize"in e&&(t("indentSize","indent","Table"),r=(o=e).indentSize,o=(0,l.default)(o,["indentSize"]),e=(0,i.default)({indent:r},o)),"optimization"in e&&(t("optimization","pure","Table"),o=(r=e).optimization,r=(0,l.default)(r,["optimization"]),e=(0,i.default)({pure:o},r)),"getRowClassName"in e&&(t("getRowClassName","getRowProps","Table"),n=(o=e).getRowClassName,a=o.getRowProps,r=(0,l.default)(o,["getRowClassName","getRowProps"]),e=n?(0,i.default)({getRowProps:function(){return(0,i.default)({className:n.apply(void 0,arguments)},a?a.apply(void 0,arguments):{})}},r):(0,i.default)({getRowProps:a},r)),"getRowProps"in e&&(t("getRowProps","rowProps","Table in 1.15.0"),r=(o=e).getRowProps,o=(0,l.default)(o,["getRowProps"]),e=(0,i.default)({rowProps:r},o)),"getCellProps"in e&&(t("getCellProps","cellProps","Table in 1.15.0"),o=(r=e).getCellProps,t=(0,l.default)(r,["getCellProps"]),e=(0,i.default)({cellProps:o},t)),e}}),e.exports=t.default},function(e,t,n){"use strict";n.d(t,"a",function(){return o});var a=n(90);function r(t,e){var n,a=Object.keys(t);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(t),e&&(n=n.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),a.push.apply(a,n)),a}function o(t){for(var e=1;e 16.8.0")},p.prototype.validate=function(e,t){this.validateCallback(e,t)},p.prototype.reset=function(e){var t=1","Select");t=s(e,t);return e.onInputUpdate&&(t.onSearch=e.onInputUpdate,t.showSearch=!0),t}}),t.default=a.default.config(r.default,{transform:s,exportNames:["focusInput","handleSearchClear"]}),e.exports=t.default},function(e,t,n){"use strict";function s(){var e=this.constructor.getDerivedStateFromProps(this.props,this.state);null!=e&&this.setState(e)}function u(t){this.setState(function(e){return null!=(e=this.constructor.getDerivedStateFromProps(t,e))?e:null}.bind(this))}function d(e,t){try{var n=this.props,a=this.state;this.props=e,this.state=t,this.__reactInternalSnapshotFlag=!0,this.__reactInternalSnapshot=this.getSnapshotBeforeUpdate(n,a)}finally{this.props=n,this.state=a}}function a(e){var t=e.prototype;if(!t||!t.isReactComponent)throw new Error("Can only polyfill class components");if("function"==typeof e.getDerivedStateFromProps||"function"==typeof t.getSnapshotBeforeUpdate){var n,a,r=null,o=null,i=null;if("function"==typeof t.componentWillMount?r="componentWillMount":"function"==typeof t.UNSAFE_componentWillMount&&(r="UNSAFE_componentWillMount"),"function"==typeof t.componentWillReceiveProps?o="componentWillReceiveProps":"function"==typeof t.UNSAFE_componentWillReceiveProps&&(o="UNSAFE_componentWillReceiveProps"),"function"==typeof t.componentWillUpdate?i="componentWillUpdate":"function"==typeof t.UNSAFE_componentWillUpdate&&(i="UNSAFE_componentWillUpdate"),null!==r||null!==o||null!==i)throw n=e.displayName||e.name,a="function"==typeof e.getDerivedStateFromProps?"getDerivedStateFromProps()":"getSnapshotBeforeUpdate()",Error("Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n"+n+" uses "+a+" but also contains the following legacy lifecycles:"+(null!==r?"\n "+r:"")+(null!==o?"\n "+o:"")+(null!==i?"\n "+i:"")+"\n\nThe above lifecycles should be removed. Learn more about this warning here:\nhttps://fb.me/react-async-component-lifecycle-hooks");if("function"==typeof e.getDerivedStateFromProps&&(t.componentWillMount=s,t.componentWillReceiveProps=u),"function"==typeof t.getSnapshotBeforeUpdate){if("function"!=typeof t.componentDidUpdate)throw new Error("Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype");t.componentWillUpdate=d;var l=t.componentDidUpdate;t.componentDidUpdate=function(e,t,n){n=this.__reactInternalSnapshotFlag?this.__reactInternalSnapshot:n;l.call(this,e,t,n)}}}return e}n.r(t),n.d(t,"polyfill",function(){return a}),d.__suppressDeprecationWarning=u.__suppressDeprecationWarning=s.__suppressDeprecationWarning=!0},function(e,t,n){"use strict";n.d(t,"a",function(){return r});var a=n(132);function r(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e)){var n=[],a=!0,r=!1,o=void 0;try{for(var i,l=e[Symbol.iterator]();!(a=(i=l.next()).done)&&(n.push(i.value),!t||n.length!==t);a=!0);}catch(e){r=!0,o=e}finally{try{a||null==l.return||l.return()}finally{if(r)throw o}}return n}}(e,t)||Object(a.a)(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}},function(e,t,n){"use strict";n(43),n(534)},function(e,t,n){"use strict";t.__esModule=!0;var v=s(n(2)),a=s(n(4)),r=s(n(6)),o=s(n(7)),_=s(n(0)),i=s(n(3)),b=s(n(13)),w=s(n(62)),l=s(n(8)),M=n(11);function s(e){return e&&e.__esModule?e:{default:e}}u=_.default.Component,(0,o.default)(k,u),k.prototype.render=function(){var e=this.props,t=e.tip,n=e.visible,a=e.children,r=e.className,o=e.style,i=e.indicator,l=e.color,s=e.prefix,u=e.fullScreen,d=e.disableScroll,c=e.onVisibleChange,f=e.tipAlign,p=e.size,h=e.inline,m=e.rtl,e=e.safeNode,g=null,y=s+"loading-dot",p=(g=i||(i=l,p=(0,b.default)(((l={})[s+"loading-fusion-reactor"]=!0,l[s+"loading-medium-fusion-reactor"]="medium"===p,l)),_.default.createElement("div",{className:p,dir:m?"rtl":void 0},_.default.createElement("span",{className:y,style:{backgroundColor:i}}),_.default.createElement("span",{className:y,style:{backgroundColor:i}}),_.default.createElement("span",{className:y,style:{backgroundColor:i}}),_.default.createElement("span",{className:y,style:{backgroundColor:i}}))),(0,b.default)(((l={})[s+"loading"]=!0,l[s+"open"]=n,l[s+"loading-inline"]=h,l[r]=r,l))),y=(0,b.default)(((m={})[s+"loading-tip"]=!0,m[s+"loading-tip-fullscreen"]=u,m[s+"loading-right-tip"]="right"===f,m)),i=M.obj.pickOthers(k.propTypes,this.props),l=(0,b.default)(((h={})[s+"loading-component"]=n,h[s+"loading-wrap"]=!0,h));return u?[a,_.default.createElement(w.default,(0,v.default)({key:"overlay",hasMask:!0,align:"cc cc",safeNode:e,disableScroll:d},i,{className:r,style:o,visible:n,onRequestClose:c}),_.default.createElement("div",{className:y},_.default.createElement("div",{className:s+"loading-indicator"},g),_.default.createElement("div",{className:s+"loading-tip-content"},t),_.default.createElement("div",{className:s+"loading-tip-placeholder"},t)))]:_.default.createElement("div",(0,v.default)({className:p,style:o},i),n?_.default.createElement("div",{className:y},_.default.createElement("div",{className:s+"loading-indicator"},g),_.default.createElement("div",{className:s+"loading-tip-content"},t),_.default.createElement("div",{className:s+"loading-tip-placeholder"},t)):null,_.default.createElement("div",{className:l},n?_.default.createElement("div",{className:s+"loading-masker"}):null,a))},o=n=k,n.propTypes=(0,v.default)({},l.default.propTypes,{prefix:i.default.string,tip:i.default.any,tipAlign:i.default.oneOf(["right","bottom"]),visible:i.default.bool,onVisibleChange:i.default.func,className:i.default.string,style:i.default.object,size:i.default.oneOf(["large","medium"]),indicator:i.default.any,color:i.default.string,fullScreen:i.default.bool,disableScroll:i.default.bool,safeNode:i.default.any,children:i.default.any,inline:i.default.bool,rtl:i.default.bool}),n.defaultProps={prefix:"next-",visible:!0,onVisibleChange:M.func.noop,animate:null,tipAlign:"bottom",size:"large",inline:!0,disableScroll:!1};var u,i=o;function k(){return(0,a.default)(this,k),(0,r.default)(this,u.apply(this,arguments))}i.displayName="Loading",t.default=l.default.config(i),e.exports=t.default},function(e,t,n){"use strict";n(50);var a=n(26),r=n.n(a),o=n(72),a=n(135),a=n.n(a),i=n(410),l=n.n(i),s=n(47),u="Request error, please try again later!";function d(){var e=window.location.href,e=(localStorage.removeItem("token"),e.split("#")[0]);window.location.href="".concat(e,"#/login")}t.a=((i=a.a.create()).interceptors.request.use(function(e){var t=e.url,n=e.params,a=e.data,r=e.method,o=e.headers;if(n||(e.params={}),!t.includes("auth/users/login")&&localStorage.token){n={};try{n=JSON.parse(localStorage.token)}catch(e){console.log(e),d()}var i=n.accessToken,i=void 0===i?"":i,n=n.username,n=void 0===n?"":n;e.params.accessToken=i,t.includes("auth")||(e.params.username=n),e.headers=Object.assign({},o,{accessToken:i})}return a&&Object(s.d)(a)&&["post","put"].includes(r)&&(e.data=l.a.stringify(a),o||(e.headers={}),e.headers["Content-Type"]="application/x-www-form-urlencoded"),e},function(e){return Promise.reject(e)}),i.interceptors.response.use(function(e){var t=e.data;t.success,t.resultCode,t.resultMessage;return e.data},function(e){var t,n,a;return e.response?(t=void 0===(t=(n=e.response).data)?{}:t,n=n.status,a="HTTP ERROR: ".concat(n),"string"==typeof t?a=t:"object"===Object(o.a)(t)&&(a=t.message),r.a.error(a),[401,403].includes(n)&&["unknown user!","token invalid!","token expired!","session expired!"].includes(a)&&d(),Promise.reject(e.response)):(r.a.error(u),Promise.reject(e))}),i)},function(e,t,n){"use strict";n(76),n(50),n(32),n(43),n(535)},function(e,t,n){"use strict";n(43),n(536)},function(M,e,t){"use strict";t.d(e,"a",function(){return a}),t.d(e,"b",function(){return B});var x=t(0),C=t.n(x),d=C.a.createContext(null);function s(){return n}var n=function(e){e()};var r={notify:function(){},get:function(){return[]}};function L(t,n){var o,i=r;function l(){e.onStateChange&&e.onStateChange()}function a(){var e,a,r;o||(o=n?n.addNestedSub(l):t.subscribe(l),e=s(),r=a=null,i={clear:function(){r=a=null},notify:function(){e(function(){for(var e=a;e;)e.callback(),e=e.next})},get:function(){for(var e=[],t=a;t;)e.push(t),t=t.next;return e},subscribe:function(e){var t=!0,n=r={callback:e,next:null,prev:r};return n.prev?n.prev.next=n:a=n,function(){t&&null!==a&&(t=!1,n.next?n.next.prev=n.prev:r=n.prev,n.prev?n.prev.next=n.next:a=n.next)}}})}var e={addNestedSub:function(e){return a(),i.subscribe(e)},notifyNestedSubs:function(){i.notify()},handleChangeWrapper:l,isSubscribed:function(){return Boolean(o)},trySubscribe:a,tryUnsubscribe:function(){o&&(o(),o=void 0,i.clear(),i=r)},getListeners:function(){return i}};return e}var o="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?x.useLayoutEffect:x.useEffect;var a=function(e){var t=e.store,n=e.context,e=e.children,a=Object(x.useMemo)(function(){var e=L(t);return{store:t,subscription:e}},[t]),r=Object(x.useMemo)(function(){return t.getState()},[t]),n=(o(function(){var e=a.subscription;return e.onStateChange=e.notifyNestedSubs,e.trySubscribe(),r!==t.getState()&&e.notifyNestedSubs(),function(){e.tryUnsubscribe(),e.onStateChange=null}},[a,r]),n||d);return C.a.createElement(n.Provider,{value:a},e)},T=t(42),D=t(54),e=t(101),c=t.n(e),O=t(407),f=["getDisplayName","methodName","renderCountProp","shouldHandleStateChanges","storeKey","withRef","forwardRef","context"],N=["reactReduxForwardedRef"],P=[],j=[null,null];function Y(e,t){e=e[1];return[t.payload,e+1]}function I(e,t,n){o(function(){return e.apply(void 0,t)},n)}function R(e,t,n,a,r,o,i){e.current=a,t.current=r,n.current=!1,o.current&&(o.current=null,i())}function A(e,a,t,r,o,i,l,s,u,d){var c,f;if(e)return c=!1,f=null,e=function(){if(!c){var e,t,n=a.getState();try{e=r(n,o.current)}catch(e){f=t=e}t||(f=null),e===i.current?l.current||u():(i.current=e,s.current=e,l.current=!0,d({type:"STORE_UPDATED",payload:{error:t}}))}},t.onStateChange=e,t.trySubscribe(),e(),function(){if(c=!0,t.tryUnsubscribe(),t.onStateChange=null,f)throw f}}var H=function(){return[null,0]};function i(k,e){var e=e=void 0===e?{}:e,t=e.getDisplayName,r=void 0===t?function(e){return"ConnectAdvanced("+e+")"}:t,t=e.methodName,o=void 0===t?"connectAdvanced":t,t=e.renderCountProp,i=void 0===t?void 0:t,t=e.shouldHandleStateChanges,S=void 0===t||t,t=e.storeKey,l=void 0===t?"store":t,t=(e.withRef,e.forwardRef),s=void 0!==t&&t,t=e.context,t=void 0===t?d:t,u=Object(D.a)(e,f),E=t;return function(b){var e=b.displayName||b.name||"Component",t=r(e),w=Object(T.a)({},u,{getDisplayName:r,methodName:o,renderCountProp:i,shouldHandleStateChanges:S,storeKey:l,displayName:t,wrappedComponentName:e,WrappedComponent:b}),e=u.pure;var M=e?x.useMemo:function(e){return e()};function n(n){var e=Object(x.useMemo)(function(){var e=n.reactReduxForwardedRef,t=Object(D.a)(n,N);return[n.context,e,t]},[n]),t=e[0],a=e[1],r=e[2],o=Object(x.useMemo)(function(){return t&&t.Consumer&&Object(O.isContextConsumer)(C.a.createElement(t.Consumer,null))?t:E},[t,E]),i=Object(x.useContext)(o),l=Boolean(n.store)&&Boolean(n.store.getState)&&Boolean(n.store.dispatch),s=(Boolean(i)&&Boolean(i.store),(l?n:i).store),u=Object(x.useMemo)(function(){return k(s.dispatch,w)},[s]),e=Object(x.useMemo)(function(){if(!S)return j;var e=L(s,l?null:i.subscription),t=e.notifyNestedSubs.bind(e);return[e,t]},[s,l,i]),d=e[0],e=e[1],c=Object(x.useMemo)(function(){return l?i:Object(T.a)({},i,{subscription:d})},[l,i,d]),f=Object(x.useReducer)(Y,P,H),p=f[0][0],f=f[1];if(p&&p.error)throw p.error;var h=Object(x.useRef)(),m=Object(x.useRef)(r),g=Object(x.useRef)(),y=Object(x.useRef)(!1),v=M(function(){return g.current&&r===m.current?g.current:u(s.getState(),r)},[s,p,r]),_=(I(R,[m,h,y,r,v,g,e]),I(A,[S,s,d,u,m,h,y,g,e,f],[s,d,u]),Object(x.useMemo)(function(){return C.a.createElement(b,Object(T.a)({},v,{ref:a}))},[a,b,v]));return Object(x.useMemo)(function(){return S?C.a.createElement(o.Provider,{value:c},_):_},[o,_,c])}var a=e?C.a.memo(n):n;return a.WrappedComponent=b,a.displayName=n.displayName=t,s?((e=C.a.forwardRef(function(e,t){return C.a.createElement(a,Object(T.a)({},e,{reactReduxForwardedRef:t}))})).displayName=t,e.WrappedComponent=b,c()(e,b)):c()(a,b)}}function l(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!=e&&t!=t}function m(e,t){if(!l(e,t)){if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),a=Object.keys(t);if(n.length!==a.length)return!1;for(var r=0;re?t.splice(e,t.length-e,n):t.push(n),i({action:"PUSH",location:n,index:e,entries:t}))})},replace:function(e,t){var n=O(e,t,l(),u.location);o.confirmTransitionTo(n,"REPLACE",a,function(e){e&&i({action:"REPLACE",location:u.entries[u.index]=n})})},go:s,goBack:function(){s(-1)},goForward:function(){s(1)},canGo:function(e){return 0<=(e=u.index+e)&&ex',"Tag"),"readonly"!==n&&"interactive"!==n||r.log.warning("Warning: [ shape="+n+" ] is deprecated at [ Tag ]"),"secondary"===a&&r.log.warning("Warning: [ type=secondary ] is deprecated at [ Tag ]"),["count","marked","value","onChange"].forEach(function(e){e in t&&r.log.warning("Warning: [ "+e+" ] is deprecated at [ Tag ]")}),("selected"in t||"defaultSelected"in t)&&r.log.warning("Warning: [ selected|defaultSelected ] is deprecated at [ Tag ], use [ checked|defaultChecked ] at [ Tag.Selectable ] instead of it"),"closed"in t&&r.log.warning("Warning: [ closed ] is deprecated at [ Tag ], use [ onClose ] at [ Tag.Closeable ] instead of it"),"onSelect"in t&&e("onSelect","","Tag"),"afterClose"in t&&r.log.warning("Warning: [ afterClose ] is deprecated at [ Tag ], use [ afterClose ] at [ Tag.Closeable ] instead of it"),t}});o.Group=a.default.config(i.default),o.Selectable=a.default.config(l.default),o.Closable=a.default.config(n.default),o.Closeable=o.Closable,t.default=o,e.exports=t.default},function(e,t,n){"use strict";n(70),n(441)},function(e,t){e=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=e)},function(e,t){e=e.exports={version:"2.6.12"};"number"==typeof __e&&(__e=e)},function(e,t,n){e.exports=!n(108)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){"use strict";t.__esModule=!0;var a=o(n(342)),r=o(n(520)),n=o(n(521));function o(e){return e&&e.__esModule?e:{default:e}}a.default.Expand=r.default,a.default.OverlayAnimate=n.default,t.default=a.default,e.exports=t.default},function(e,t,n){"use strict";n(43),n(70),n(124),n(109),n(532)},function(e,t,n){"use strict";n.d(t,"a",function(){return r});function v(e,t){return"function"==typeof e?e(t):e}function _(e,t){return"string"==typeof e?Object(d.c)(e,null,null,t):e}function u(e){return e}var b=n(40),a=n(58),t=n(0),w=n.n(t),d=n(55),M=n(42),k=n(54),S=n(57),r=(w.a.Component,function(r){function e(){for(var e,t=arguments.length,n=new Array(t),a=0;athis.menuNode.clientHeight&&(this.menuNode.clientHeight+this.menuNode.scrollTop<(e=this.itemNode.offsetTop+this.itemNode.offsetHeight)?this.menuNode.scrollTop=e-this.menuNode.clientHeight:this.itemNode.offsetTope.length)&&(t=e.length);for(var n=0,a=new Array(t);n>16&255),o.push(r>>8&255),o.push(255&r)),r=r<<6|a.indexOf(t.charAt(i));return 0==(e=n%4*6)?(o.push(r>>16&255),o.push(r>>8&255),o.push(255&r)):18==e?(o.push(r>>10&255),o.push(r>>2&255)):12==e&&o.push(r>>4&255),new Uint8Array(o)},predicate:function(e){return"[object Uint8Array]"===Object.prototype.toString.call(e)},represent:function(e){for(var t,n="",a=0,r=e.length,o=w,i=0;i>18&63]+o[a>>12&63])+o[a>>6&63]+o[63&a]),a=(a<<8)+e[i];return 0==(t=r%3)?n=(n=n+o[a>>18&63]+o[a>>12&63])+o[a>>6&63]+o[63&a]:2==t?n=(n=n+o[a>>10&63]+o[a>>4&63])+o[a<<2&63]+o[64]:1==t&&(n=(n=n+o[a>>2&63]+o[a<<4&63])+o[64]+o[64]),n}}),M=Object.prototype.hasOwnProperty,k=Object.prototype.toString;var f=new u("tag:yaml.org,2002:omap",{kind:"sequence",resolve:function(e){if(null!==e)for(var t,n,a,r=[],o=e,i=0,l=o.length;idocument.F=Object<\/script>"),e.close(),u=e.F;t--;)delete u[s][i[t]];return u()};e.exports=Object.create||function(e,t){var n;return null!==e?(a[s]=r(e),n=new a,a[s]=null,n[l]=e):n=u(),void 0===t?n:o(n,t)}},function(e,t,n){var a=n(85).f,r=n(86),o=n(96)("toStringTag");e.exports=function(e,t,n){e&&!r(e=n?e:e.prototype,o)&&a(e,o,{configurable:!0,value:t})}},function(e,t,n){t.f=n(96)},function(e,t,n){var a=n(77),r=n(78),o=n(120),i=n(151),l=n(85).f;e.exports=function(e){var t=r.Symbol||(r.Symbol=!o&&a.Symbol||{});"_"==e.charAt(0)||e in t||l(t,e,{value:i.f(e)})}},function(e,t,n){"use strict";t.__esModule=!0;var a=d(n(203)),r=d(n(495)),o=d(n(496)),i=d(n(497)),l=d(n(498)),s=d(n(499)),u=d(n(500));function d(e){return e&&e.__esModule?e:{default:e}}n(501),a.default.extend(s.default),a.default.extend(l.default),a.default.extend(r.default),a.default.extend(o.default),a.default.extend(i.default),a.default.extend(u.default),a.default.locale("zh-cn");n=a.default;n.isSelf=a.default.isDayjs,a.default.localeData(),t.default=n,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var v=c(n(2)),o=c(n(4)),i=c(n(6)),a=c(n(7)),r=n(0),_=c(r),l=c(n(3)),s=n(30),b=c(n(13)),u=c(n(44)),w=c(n(25)),M=c(n(80)),d=c(n(8)),k=n(11);function c(e){return e&&e.__esModule?e:{default:e}}function f(){}p=r.Component,(0,a.default)(S,p),S.getDerivedStateFromProps=function(e){return"visible"in e?{visible:e.visible}:{}},S.prototype.render=function(){var e,t=this.props,n=t.prefix,a=(t.pure,t.className),r=t.style,o=t.type,i=t.shape,l=t.size,s=t.title,u=t.children,d=(t.defaultVisible,t.visible,t.iconType),c=t.closeable,f=(t.onClose,t.afterClose),p=t.animation,h=t.rtl,t=t.locale,m=(0,v.default)({},k.obj.pickOthers(Object.keys(S.propTypes),this.props)),g=this.state.visible,y=n+"message",o=(0,b.default)(((e={})[y]=!0,e[n+"message-"+o]=o,e[""+n+i]=i,e[""+n+l]=l,e[n+"title-content"]=!!s,e[n+"only-content"]=!s&&!!u,e[a]=a,e)),i=g?_.default.createElement("div",(0,v.default)({role:"alert",style:r},m,{className:o,dir:h?"rtl":void 0}),c?_.default.createElement("a",{role:"button","aria-label":t.closeAriaLabel,className:y+"-close",onClick:this.onClose},_.default.createElement(w.default,{type:"close"})):null,!1!==d?_.default.createElement(w.default,{className:y+"-symbol "+(!d&&y+"-symbol-icon"),type:d}):null,s?_.default.createElement("div",{className:y+"-title"},s):null,u?_.default.createElement("div",{className:y+"-content"},u):null):null;return p?_.default.createElement(M.default.Expand,{animationAppear:!1,afterLeave:f},i):i},r=n=S,n.propTypes={prefix:l.default.string,pure:l.default.bool,className:l.default.string,style:l.default.object,type:l.default.oneOf(["success","warning","error","notice","help","loading"]),shape:l.default.oneOf(["inline","addon","toast"]),size:l.default.oneOf(["medium","large"]),title:l.default.node,children:l.default.node,defaultVisible:l.default.bool,visible:l.default.bool,iconType:l.default.oneOfType([l.default.string,l.default.bool]),closeable:l.default.bool,onClose:l.default.func,afterClose:l.default.func,animation:l.default.bool,locale:l.default.object,rtl:l.default.bool},n.defaultProps={prefix:"next-",pure:!1,type:"success",shape:"inline",size:"medium",defaultVisible:!0,closeable:!1,onClose:f,afterClose:f,animation:!0,locale:u.default.Message};var p,a=r;function S(){var e,t;(0,o.default)(this,S);for(var n=arguments.length,a=Array(n),r=0;r=n.length?(s=!!(c=h(o,u)))&&"get"in c&&!("originalValue"in c.get)?c.get:o[u]:(s=_(o,u),o[u]),s&&!i&&(y[d]=o)}}return o}},function(e,t,n){"use strict";n=n(598);e.exports=Function.prototype.bind||n},function(e,t,n){"use strict";var a=String.prototype.replace,r=/%20/g,o="RFC1738",i="RFC3986";e.exports={default:i,formatters:{RFC1738:function(e){return a.call(e,r,"+")},RFC3986:function(e){return String(e)}},RFC1738:o,RFC3986:i}},function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var d=s(n(2)),a=s(n(4)),r=s(n(6)),o=s(n(7)),c=n(0),f=s(c),i=s(n(3)),p=s(n(13)),h=s(n(25)),l=n(11),m=s(n(99));function s(e){return e&&e.__esModule?e:{default:e}}var u,g=l.func.bindCtx,y=l.obj.pickOthers,i=(u=c.Component,(0,o.default)(v,u),v.prototype.getSelected=function(){var e=this.props,t=e._key,n=e.root,e=e.selected,a=n.props.selectMode,n=n.state.selectedKeys;return e||!!a&&-1e.length&&e.every(function(e,t){return e===n[t]})},t.isAvailablePos=function(e,t,n){var n=n[t],a=n.type,n=n.disabled;return r(e,t)&&("item"===a&&!n||"submenu"===a)});t.getFirstAvaliablelChildKey=function(t,n){var e=Object.keys(n).find(function(e){return a(t+"-0",e,n)});return e?n[e].key:null},t.getChildSelected=function(e){var t=e.selectMode,n=e.selectedKeys,a=e._k2n,e=e._key;if(!a)return!1;var r=(a[e]&&a[e].pos)+"-";return!!t&&n.some(function(e){return a[e]&&0===a[e].pos.indexOf(r)})}},function(e,t,n){"use strict";n(43),n(32),n(620)},function(e,t,n){var o=n(633),i=Object.prototype.hasOwnProperty;function l(e){return Array.isArray(e)?"array":typeof e}function s(e,t){var n,a=0,r=0;for(n in e)if(i.call(e,n)){if("style"===n){if(!o(e[n],t[n]))return!1}else if("children"!==n&&e[n]!==t[n])return!1;a++}for(n in t)i.call(t,n)&&r++;return a===r&&function e(t,n){var a=l(t);if(a!==l(n))return!1;switch(a){case"array":if(t.length!==n.length)return!1;for(var r=0;r=u,u=(0,O.default)(((u={})[n+"upload-inner"]=!0,u[n+"hidden"]=x,u)),C=this.props.children;if("card"===r&&(r=(0,O.default)(((r={})[n+"upload-card"]=!0,r[n+"disabled"]=s,r)),C=D.default.createElement("div",{className:r},D.default.createElement(P.default,{size:"large",type:"add",className:n+"upload-add-icon"}),D.default.createElement("div",{tabIndex:"0",role:"button",className:n+"upload-text"},C))),b)return"function"==typeof w?(b=(0,O.default)(((r={})[n+"form-preview"]=!0,r[o]=!!o,r)),D.default.createElement("div",{style:i,className:b},w(this.state.value,this.props))):t?D.default.createElement(Y.default,{isPreview:!0,listType:t,style:i,className:o,value:this.state.value}):null;n=s?N.func.prevent:p,r=N.obj.pickAttrsWith(this.props,"data-");return D.default.createElement("div",(0,L.default)({className:f,style:i},r),D.default.createElement(j.default,(0,L.default)({},e,{name:M,beforeUpload:c,dragable:a,disabled:s||x,className:u,onSelect:this.onSelect,onDrop:this.onDrop,onProgress:this.onProgress,onSuccess:this.onSuccess,onError:this.onError,ref:this.saveUploaderRef}),C),t||g?D.default.createElement(Y.default,{useDataURL:l,fileNameRender:k,actionRender:S,uploader:this,listType:t,value:this.state.value,closable:d,onRemove:n,progressProps:v,onCancel:h,onPreview:m,extraRender:y,rtl:_,previewOnFileName:E}):null)},i=u=h,u.displayName="Upload",u.propTypes=(0,L.default)({},d.default.propTypes,Y.default.propTypes,{prefix:l.default.string.isRequired,action:l.default.string,value:l.default.array,defaultValue:l.default.array,shape:l.default.oneOf(["card"]),listType:l.default.oneOf(["text","image","card"]),list:l.default.any,name:l.default.string,data:l.default.oneOfType([l.default.object,l.default.func]),formatter:l.default.func,limit:l.default.number,timeout:l.default.number,dragable:l.default.bool,closable:l.default.bool,useDataURL:l.default.bool,disabled:l.default.bool,onSelect:l.default.func,onProgress:l.default.func,onChange:l.default.func,onSuccess:l.default.func,afterSelect:l.default.func,onRemove:l.default.func,onError:l.default.func,beforeUpload:l.default.func,onDrop:l.default.func,className:l.default.string,style:l.default.object,children:l.default.node,autoUpload:l.default.bool,request:l.default.func,progressProps:l.default.object,rtl:l.default.bool,isPreview:l.default.bool,renderPreview:l.default.func,fileKeyName:l.default.string,fileNameRender:l.default.func,actionRender:l.default.func,previewOnFileName:l.default.bool}),u.defaultProps=(0,L.default)({},d.default.defaultProps,{prefix:"next-",limit:1/0,autoUpload:!0,closable:!0,onSelect:n,onProgress:n,onChange:n,onSuccess:n,onRemove:n,onError:n,onDrop:n,beforeUpload:n,afterSelect:n,previewOnFileName:!1}),a=function(){var u=this;this.onSelect=function(e){var t,n,a=u.props,r=a.autoUpload,o=a.afterSelect,i=a.onSelect,a=a.limit,l=u.state.value.length+e.length,s=a-u.state.value.length;s<=0||(t=e=e.map(function(e){e=(0,c.fileToObject)(e);return e.state="selected",e}),n=[],ai||l+a.width>o):t<0||e<0||t+a.height>u.height||e+a.width>u.width}function T(e,t,n,a){var r=a.overlayInfo,a=a.containerInfo,n=n.split("");return 1===n.length&&n.push(""),t<0&&(n=[n[0].replace("t","b"),n[1].replace("b","t")]),e<0&&(n=[n[0].replace("l","r"),n[1].replace("r","l")]),t+r.height>a.height&&(n=[n[0].replace("b","t"),n[1].replace("t","b")]),(n=e+r.width>a.width?[n[0].replace("r","l"),n[1].replace("l","r")]:n).join("")}function D(e,t,n){var a=n.overlayInfo,n=n.containerInfo;return(t=t<0?0:t)+a.height>n.height&&(t=n.height-a.height),{left:e=(e=e<0?0:e)+a.width>n.width?n.width-a.width:e,top:t}}function ve(e){var t=e.target,n=e.overlay,a=e.container,r=e.scrollNode,o=e.placement,i=e.placementOffset,i=void 0===i?0:i,l=e.points,l=void 0===l?["tl","bl"]:l,s=e.offset,s=void 0===s?[0,0]:s,u=e.position,u=void 0===u?"absolute":u,d=e.beforePosition,c=e.autoAdjust,c=void 0===c||c,f=e.autoHideScrollOverflow,f=void 0===f||f,e=e.rtl,p="offsetWidth"in(p=n)&&"offsetHeight"in p?{width:p.offsetWidth,height:p.offsetHeight}:{width:(p=p.getBoundingClientRect()).width,height:p.height},h=p.width,p=p.height;if("fixed"===u)return m={config:{placement:void 0,points:void 0},style:{position:u,left:s[0],top:s[1]}},d?d(m,{overlay:{node:n,width:h,height:p}}):m;var m=t.getBoundingClientRect(),g=m.width,y=m.height,v=m.left,_=m.top,m=x(a),b=m.left,m=m.top,w=a.scrollWidth,M=a.scrollHeight,k=a.scrollTop,S=a.scrollLeft,b={targetInfo:{width:g,height:y,left:v,top:_},containerInfo:{left:b,top:m,width:w,height:M,scrollTop:k,scrollLeft:S},overlayInfo:{width:h,height:p},points:l,placementOffset:i,offset:s,container:a,rtl:e},m=C(o,b),w=m.left,M=m.top,k=m.points,S=function(e){for(var t=e;t;){var n=fe(t,"overflow");if(null!=n&&n.match(/auto|scroll|hidden/))return t;t=t.parentNode}return document.documentElement}(a),E=(c&&o&&L(w,M,S,b)&&(o!==(l=T(w,M,o,b))&&(M=L(s=(i=C(l,b)).left,e=i.top,S,b)&&l!==(m=T(s,e,l,b))?(w=(c=D((a=C(o=m,b)).left,a.top,b)).left,c.top):(o=l,w=s,e)),w=(i=D(w,M,b)).left,M=i.top),{config:{placement:o,points:k},style:{position:u,left:Math.round(w),top:Math.round(M)}});return f&&o&&null!=r&&r.length&&r.forEach(function(e){var e=e.getBoundingClientRect(),t=e.top,n=e.left,a=e.width,e=e.height;E.style.display=_+y=e.length?{done:!0}:{done:!1,value:e[n++]}};throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);nt.clientHeight&&0")),"shouldUpdatePosition"in r&&(delete t.shouldUpdatePosition,d.log.warning("Warning: [ shouldUpdatePosition ] is deprecated at [ ]")),"minMargin"in r&&o("minMargin","top/bottom",""),"isFullScreen"in r&&(r.overFlowScroll=!r.isFullScreen,delete t.isFullScreen,o("isFullScreen","overFlowScroll","")),t;return["target","offset","beforeOpen","onOpen","afterOpen","beforePosition","onPosition","cache","safeNode","wrapperClassName","container"].forEach(function(e){var t,n,a;e in r&&(o(e,"overlayProps."+e,"Dialog"),t=(n=r).overlayProps,n=(0,l.default)(n,["overlayProps"]),a=(0,i.default)(((a={})[e]=r[e],a),t||{}),delete n[e],r=(0,i.default)({overlayProps:a},n))}),r}n.displayName="Dialog",n.Inner=p.default,n.show=function(e){return!1!==u.default.getContextProps(e,"Dialog").warning&&(e=v(e,d.log.deprecated)),(0,h.show)(e)},n.alert=function(e){return!1!==u.default.getContextProps(e,"Dialog").warning&&(e=v(e,d.log.deprecated)),(0,h.alert)(e)},n.confirm=function(e){return!1!==u.default.getContextProps(e,"Dialog").warning&&(e=v(e,d.log.deprecated)),(0,h.confirm)(e)},n.success=function(e){return(0,h.success)(e)},n.error=function(e){return(0,h.error)(e)},n.notice=function(e){return(0,h.notice)(e)},n.warning=function(e){return(0,h.warning)(e)},n.help=function(e){return(0,h.help)(e)},n.withContext=h.withContext,t.default=u.default.config(n,{transform:v}),e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var o=r(n(2)),i=r(n(12)),a=r(n(8)),l=r(n(570)),n=r(n(571));function r(e){return e&&e.__esModule?e:{default:e}}l.default.Group=n.default,t.default=a.default.config(l.default,{transform:function(e,t){var n,a,r;return"shape"in e&&(t("shape","text | warning | ghost","Button"),n=(t=e).shape,a=t.type,t=(0,i.default)(t,["shape","type"]),r=void 0,"ghost"===n&&(r={primary:"dark",secondary:"dark",normal:"light",dark:"dark",light:"light"}[a||l.default.defaultProps.type]),e=(0,o.default)({type:"light"===a||"dark"===a||"secondary"===a&&"warning"===n?"normal":a,ghost:r,text:"text"===n,warning:"warning"===n},t)),e}}),e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var i=v(n(2)),l=v(n(12)),a=v(n(8)),r=v(n(632)),o=v(n(637)),s=v(n(640)),u=v(n(641)),d=v(n(642)),c=v(n(643)),f=v(n(645)),p=v(n(646)),h=v(n(647)),m=v(n(650)),g=v(n(391)),y=v(n(392));function v(e){return e&&e.__esModule?e:{default:e}}var _=n(11).env.ieVersion,n=[s.default,f.default,u.default,d.default,c.default,o.default,h.default,m.default],b=n.reduce(function(e,t){return e=t(e)},r.default),n=(f.default._typeMark="lock",d.default._typeMark="expanded",s.default._typeMark="fixed",n.reduce(function(e,t){var n=!_;return e="lock"===t._typeMark?(n?(0,p.default):(0,f.default))(e):"expanded"===t._typeMark?n?(0,d.default)(e,!0):(0,d.default)(e):"fixed"===t._typeMark?n?(0,s.default)(e,!0):(0,s.default)(e):t(e)},r.default));b.Base=r.default,b.fixed=s.default,b.lock=f.default,b.selection=u.default,b.expanded=d.default,b.tree=o.default,b.virtual=c.default,b.list=h.default,b.sticky=m.default,b.GroupHeader=g.default,b.GroupFooter=y.default,b.StickyLock=a.default.config(n,{componentName:"Table"}),t.default=a.default.config(b,{componentName:"Table",transform:function(e,t){var n,a,r,o;return"expandedRowKeys"in e&&(t("expandedRowKeys","openRowKeys","Table"),o=(r=e).expandedRowKeys,r=(0,l.default)(r,["expandedRowKeys"]),e=(0,i.default)({openRowKeys:o},r)),"onExpandedChange"in e&&(t("onExpandedChange","onRowOpen","Table"),r=(o=e).onExpandedChange,o=(0,l.default)(o,["onExpandedChange"]),e=(0,i.default)({onRowOpen:r},o)),"isLoading"in e&&(t("isLoading","loading","Table"),o=(r=e).isLoading,r=(0,l.default)(r,["isLoading"]),e=(0,i.default)({loading:o},r)),"indentSize"in e&&(t("indentSize","indent","Table"),r=(o=e).indentSize,o=(0,l.default)(o,["indentSize"]),e=(0,i.default)({indent:r},o)),"optimization"in e&&(t("optimization","pure","Table"),o=(r=e).optimization,r=(0,l.default)(r,["optimization"]),e=(0,i.default)({pure:o},r)),"getRowClassName"in e&&(t("getRowClassName","getRowProps","Table"),n=(o=e).getRowClassName,a=o.getRowProps,r=(0,l.default)(o,["getRowClassName","getRowProps"]),e=n?(0,i.default)({getRowProps:function(){return(0,i.default)({className:n.apply(void 0,arguments)},a?a.apply(void 0,arguments):{})}},r):(0,i.default)({getRowProps:a},r)),"getRowProps"in e&&(t("getRowProps","rowProps","Table in 1.15.0"),r=(o=e).getRowProps,o=(0,l.default)(o,["getRowProps"]),e=(0,i.default)({rowProps:r},o)),"getCellProps"in e&&(t("getCellProps","cellProps","Table in 1.15.0"),o=(r=e).getCellProps,t=(0,l.default)(r,["getCellProps"]),e=(0,i.default)({cellProps:o},t)),e}}),e.exports=t.default},function(e,t,n){"use strict";n.d(t,"a",function(){return o});var a=n(90);function r(t,e){var n,a=Object.keys(t);return Object.getOwnPropertySymbols&&(n=Object.getOwnPropertySymbols(t),e&&(n=n.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),a.push.apply(a,n)),a}function o(t){for(var e=1;e 16.8.0")},p.prototype.validate=function(e,t){this.validateCallback(e,t)},p.prototype.reset=function(e){var t=1","Select");t=s(e,t);return e.onInputUpdate&&(t.onSearch=e.onInputUpdate,t.showSearch=!0),t}}),t.default=a.default.config(r.default,{transform:s,exportNames:["focusInput","handleSearchClear"]}),e.exports=t.default},function(e,t,n){"use strict";function s(){var e=this.constructor.getDerivedStateFromProps(this.props,this.state);null!=e&&this.setState(e)}function u(t){this.setState(function(e){return null!=(e=this.constructor.getDerivedStateFromProps(t,e))?e:null}.bind(this))}function d(e,t){try{var n=this.props,a=this.state;this.props=e,this.state=t,this.__reactInternalSnapshotFlag=!0,this.__reactInternalSnapshot=this.getSnapshotBeforeUpdate(n,a)}finally{this.props=n,this.state=a}}function a(e){var t=e.prototype;if(!t||!t.isReactComponent)throw new Error("Can only polyfill class components");if("function"==typeof e.getDerivedStateFromProps||"function"==typeof t.getSnapshotBeforeUpdate){var n,a,r=null,o=null,i=null;if("function"==typeof t.componentWillMount?r="componentWillMount":"function"==typeof t.UNSAFE_componentWillMount&&(r="UNSAFE_componentWillMount"),"function"==typeof t.componentWillReceiveProps?o="componentWillReceiveProps":"function"==typeof t.UNSAFE_componentWillReceiveProps&&(o="UNSAFE_componentWillReceiveProps"),"function"==typeof t.componentWillUpdate?i="componentWillUpdate":"function"==typeof t.UNSAFE_componentWillUpdate&&(i="UNSAFE_componentWillUpdate"),null!==r||null!==o||null!==i)throw n=e.displayName||e.name,a="function"==typeof e.getDerivedStateFromProps?"getDerivedStateFromProps()":"getSnapshotBeforeUpdate()",Error("Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n"+n+" uses "+a+" but also contains the following legacy lifecycles:"+(null!==r?"\n "+r:"")+(null!==o?"\n "+o:"")+(null!==i?"\n "+i:"")+"\n\nThe above lifecycles should be removed. Learn more about this warning here:\nhttps://fb.me/react-async-component-lifecycle-hooks");if("function"==typeof e.getDerivedStateFromProps&&(t.componentWillMount=s,t.componentWillReceiveProps=u),"function"==typeof t.getSnapshotBeforeUpdate){if("function"!=typeof t.componentDidUpdate)throw new Error("Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype");t.componentWillUpdate=d;var l=t.componentDidUpdate;t.componentDidUpdate=function(e,t,n){n=this.__reactInternalSnapshotFlag?this.__reactInternalSnapshot:n;l.call(this,e,t,n)}}}return e}n.r(t),n.d(t,"polyfill",function(){return a}),d.__suppressDeprecationWarning=u.__suppressDeprecationWarning=s.__suppressDeprecationWarning=!0},function(e,t,n){"use strict";n.d(t,"a",function(){return r});var a=n(132);function r(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e)){var n=[],a=!0,r=!1,o=void 0;try{for(var i,l=e[Symbol.iterator]();!(a=(i=l.next()).done)&&(n.push(i.value),!t||n.length!==t);a=!0);}catch(e){r=!0,o=e}finally{try{a||null==l.return||l.return()}finally{if(r)throw o}}return n}}(e,t)||Object(a.a)(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}},function(e,t,n){"use strict";n(43),n(534)},function(e,t,n){"use strict";t.__esModule=!0;var v=s(n(2)),a=s(n(4)),r=s(n(6)),o=s(n(7)),_=s(n(0)),i=s(n(3)),b=s(n(13)),w=s(n(62)),l=s(n(8)),M=n(11);function s(e){return e&&e.__esModule?e:{default:e}}u=_.default.Component,(0,o.default)(k,u),k.prototype.render=function(){var e=this.props,t=e.tip,n=e.visible,a=e.children,r=e.className,o=e.style,i=e.indicator,l=e.color,s=e.prefix,u=e.fullScreen,d=e.disableScroll,c=e.onVisibleChange,f=e.tipAlign,p=e.size,h=e.inline,m=e.rtl,e=e.safeNode,g=null,y=s+"loading-dot",p=(g=i||(i=l,p=(0,b.default)(((l={})[s+"loading-fusion-reactor"]=!0,l[s+"loading-medium-fusion-reactor"]="medium"===p,l)),_.default.createElement("div",{className:p,dir:m?"rtl":void 0},_.default.createElement("span",{className:y,style:{backgroundColor:i}}),_.default.createElement("span",{className:y,style:{backgroundColor:i}}),_.default.createElement("span",{className:y,style:{backgroundColor:i}}),_.default.createElement("span",{className:y,style:{backgroundColor:i}}))),(0,b.default)(((l={})[s+"loading"]=!0,l[s+"open"]=n,l[s+"loading-inline"]=h,l[r]=r,l))),y=(0,b.default)(((m={})[s+"loading-tip"]=!0,m[s+"loading-tip-fullscreen"]=u,m[s+"loading-right-tip"]="right"===f,m)),i=M.obj.pickOthers(k.propTypes,this.props),l=(0,b.default)(((h={})[s+"loading-component"]=n,h[s+"loading-wrap"]=!0,h));return u?[a,_.default.createElement(w.default,(0,v.default)({key:"overlay",hasMask:!0,align:"cc cc",safeNode:e,disableScroll:d},i,{className:r,style:o,visible:n,onRequestClose:c}),_.default.createElement("div",{className:y},_.default.createElement("div",{className:s+"loading-indicator"},g),_.default.createElement("div",{className:s+"loading-tip-content"},t),_.default.createElement("div",{className:s+"loading-tip-placeholder"},t)))]:_.default.createElement("div",(0,v.default)({className:p,style:o},i),n?_.default.createElement("div",{className:y},_.default.createElement("div",{className:s+"loading-indicator"},g),_.default.createElement("div",{className:s+"loading-tip-content"},t),_.default.createElement("div",{className:s+"loading-tip-placeholder"},t)):null,_.default.createElement("div",{className:l},n?_.default.createElement("div",{className:s+"loading-masker"}):null,a))},o=n=k,n.propTypes=(0,v.default)({},l.default.propTypes,{prefix:i.default.string,tip:i.default.any,tipAlign:i.default.oneOf(["right","bottom"]),visible:i.default.bool,onVisibleChange:i.default.func,className:i.default.string,style:i.default.object,size:i.default.oneOf(["large","medium"]),indicator:i.default.any,color:i.default.string,fullScreen:i.default.bool,disableScroll:i.default.bool,safeNode:i.default.any,children:i.default.any,inline:i.default.bool,rtl:i.default.bool}),n.defaultProps={prefix:"next-",visible:!0,onVisibleChange:M.func.noop,animate:null,tipAlign:"bottom",size:"large",inline:!0,disableScroll:!1};var u,i=o;function k(){return(0,a.default)(this,k),(0,r.default)(this,u.apply(this,arguments))}i.displayName="Loading",t.default=l.default.config(i),e.exports=t.default},function(e,t,n){"use strict";n(50);var a=n(26),r=n.n(a),o=n(72),a=n(135),a=n.n(a),i=n(410),l=n.n(i),s=n(47),u="Request error, please try again later!";function d(){var e=window.location.href,e=(localStorage.removeItem("token"),e.split("#")[0]);window.location.href="".concat(e,"#/login")}t.a=((i=a.a.create()).interceptors.request.use(function(e){var t=e.url,n=e.params,a=e.data,r=e.method,o=e.headers;if(n||(e.params={}),!t.includes("auth/users/login")&&localStorage.token){n={};try{n=JSON.parse(localStorage.token)}catch(e){console.log(e),d()}var i=n.accessToken,i=void 0===i?"":i,n=n.username,n=void 0===n?"":n;e.params.accessToken=i,t.includes("auth")||(e.params.username=n),e.headers=Object.assign({},o,{accessToken:i})}return a&&Object(s.d)(a)&&["post","put"].includes(r)&&(e.data=l.a.stringify(a),o||(e.headers={}),e.headers["Content-Type"]="application/x-www-form-urlencoded"),e},function(e){return Promise.reject(e)}),i.interceptors.response.use(function(e){var t=e.data;t.success,t.resultCode,t.resultMessage;return e.data},function(e){var t,n,a;return e.response?(t=void 0===(t=(n=e.response).data)?{}:t,n=n.status,a="HTTP ERROR: ".concat(n),"string"==typeof t?a=t:"object"===Object(o.a)(t)&&(a=t.message),r.a.error(a),[401,403].includes(n)&&["unknown user!","token invalid!","token expired!","session expired!"].includes(a)&&d(),Promise.reject(e.response)):(r.a.error(u),Promise.reject(e))}),i)},function(e,t,n){"use strict";n(76),n(50),n(32),n(43),n(535)},function(e,t,n){"use strict";n(43),n(536)},function(M,e,t){"use strict";t.d(e,"a",function(){return a}),t.d(e,"b",function(){return B});var E=t(0),C=t.n(E),d=C.a.createContext(null);function s(){return n}var n=function(e){e()};var r={notify:function(){},get:function(){return[]}};function L(t,n){var o,i=r;function l(){e.onStateChange&&e.onStateChange()}function a(){var e,a,r;o||(o=n?n.addNestedSub(l):t.subscribe(l),e=s(),r=a=null,i={clear:function(){r=a=null},notify:function(){e(function(){for(var e=a;e;)e.callback(),e=e.next})},get:function(){for(var e=[],t=a;t;)e.push(t),t=t.next;return e},subscribe:function(e){var t=!0,n=r={callback:e,next:null,prev:r};return n.prev?n.prev.next=n:a=n,function(){t&&null!==a&&(t=!1,n.next?n.next.prev=n.prev:r=n.prev,n.prev?n.prev.next=n.next:a=n.next)}}})}var e={addNestedSub:function(e){return a(),i.subscribe(e)},notifyNestedSubs:function(){i.notify()},handleChangeWrapper:l,isSubscribed:function(){return Boolean(o)},trySubscribe:a,tryUnsubscribe:function(){o&&(o(),o=void 0,i.clear(),i=r)},getListeners:function(){return i}};return e}var o="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?E.useLayoutEffect:E.useEffect;var a=function(e){var t=e.store,n=e.context,e=e.children,a=Object(E.useMemo)(function(){var e=L(t);return{store:t,subscription:e}},[t]),r=Object(E.useMemo)(function(){return t.getState()},[t]),n=(o(function(){var e=a.subscription;return e.onStateChange=e.notifyNestedSubs,e.trySubscribe(),r!==t.getState()&&e.notifyNestedSubs(),function(){e.tryUnsubscribe(),e.onStateChange=null}},[a,r]),n||d);return C.a.createElement(n.Provider,{value:a},e)},T=t(42),D=t(54),e=t(101),c=t.n(e),O=t(407),f=["getDisplayName","methodName","renderCountProp","shouldHandleStateChanges","storeKey","withRef","forwardRef","context"],N=["reactReduxForwardedRef"],P=[],j=[null,null];function Y(e,t){e=e[1];return[t.payload,e+1]}function I(e,t,n){o(function(){return e.apply(void 0,t)},n)}function A(e,t,n,a,r,o,i){e.current=a,t.current=r,n.current=!1,o.current&&(o.current=null,i())}function R(e,a,t,r,o,i,l,s,u,d){var c,f;if(e)return c=!1,f=null,e=function(){if(!c){var e,t,n=a.getState();try{e=r(n,o.current)}catch(e){f=t=e}t||(f=null),e===i.current?l.current||u():(i.current=e,s.current=e,l.current=!0,d({type:"STORE_UPDATED",payload:{error:t}}))}},t.onStateChange=e,t.trySubscribe(),e(),function(){if(c=!0,t.tryUnsubscribe(),t.onStateChange=null,f)throw f}}var H=function(){return[null,0]};function i(k,e){var e=e=void 0===e?{}:e,t=e.getDisplayName,r=void 0===t?function(e){return"ConnectAdvanced("+e+")"}:t,t=e.methodName,o=void 0===t?"connectAdvanced":t,t=e.renderCountProp,i=void 0===t?void 0:t,t=e.shouldHandleStateChanges,S=void 0===t||t,t=e.storeKey,l=void 0===t?"store":t,t=(e.withRef,e.forwardRef),s=void 0!==t&&t,t=e.context,t=void 0===t?d:t,u=Object(D.a)(e,f),x=t;return function(b){var e=b.displayName||b.name||"Component",t=r(e),w=Object(T.a)({},u,{getDisplayName:r,methodName:o,renderCountProp:i,shouldHandleStateChanges:S,storeKey:l,displayName:t,wrappedComponentName:e,WrappedComponent:b}),e=u.pure;var M=e?E.useMemo:function(e){return e()};function n(n){var e=Object(E.useMemo)(function(){var e=n.reactReduxForwardedRef,t=Object(D.a)(n,N);return[n.context,e,t]},[n]),t=e[0],a=e[1],r=e[2],o=Object(E.useMemo)(function(){return t&&t.Consumer&&Object(O.isContextConsumer)(C.a.createElement(t.Consumer,null))?t:x},[t,x]),i=Object(E.useContext)(o),l=Boolean(n.store)&&Boolean(n.store.getState)&&Boolean(n.store.dispatch),s=(Boolean(i)&&Boolean(i.store),(l?n:i).store),u=Object(E.useMemo)(function(){return k(s.dispatch,w)},[s]),e=Object(E.useMemo)(function(){if(!S)return j;var e=L(s,l?null:i.subscription),t=e.notifyNestedSubs.bind(e);return[e,t]},[s,l,i]),d=e[0],e=e[1],c=Object(E.useMemo)(function(){return l?i:Object(T.a)({},i,{subscription:d})},[l,i,d]),f=Object(E.useReducer)(Y,P,H),p=f[0][0],f=f[1];if(p&&p.error)throw p.error;var h=Object(E.useRef)(),m=Object(E.useRef)(r),g=Object(E.useRef)(),y=Object(E.useRef)(!1),v=M(function(){return g.current&&r===m.current?g.current:u(s.getState(),r)},[s,p,r]),_=(I(A,[m,h,y,r,v,g,e]),I(R,[S,s,d,u,m,h,y,g,e,f],[s,d,u]),Object(E.useMemo)(function(){return C.a.createElement(b,Object(T.a)({},v,{ref:a}))},[a,b,v]));return Object(E.useMemo)(function(){return S?C.a.createElement(o.Provider,{value:c},_):_},[o,_,c])}var a=e?C.a.memo(n):n;return a.WrappedComponent=b,a.displayName=n.displayName=t,s?((e=C.a.forwardRef(function(e,t){return C.a.createElement(a,Object(T.a)({},e,{reactReduxForwardedRef:t}))})).displayName=t,e.WrappedComponent=b,c()(e,b)):c()(a,b)}}function l(e,t){return e===t?0!==e||0!==t||1/e==1/t:e!=e&&t!=t}function m(e,t){if(!l(e,t)){if("object"!=typeof e||null===e||"object"!=typeof t||null===t)return!1;var n=Object.keys(e),a=Object.keys(t);if(n.length!==a.length)return!1;for(var r=0;re?t.splice(e,t.length-e,n):t.push(n),i({action:"PUSH",location:n,index:e,entries:t}))})},replace:function(e,t){var n=O(e,t,l(),u.location);o.confirmTransitionTo(n,"REPLACE",a,function(e){e&&i({action:"REPLACE",location:u.entries[u.index]=n})})},go:s,goBack:function(){s(-1)},goForward:function(){s(1)},canGo:function(e){return 0<=(e=u.index+e)&&ex',"Tag"),"readonly"!==n&&"interactive"!==n||r.log.warning("Warning: [ shape="+n+" ] is deprecated at [ Tag ]"),"secondary"===a&&r.log.warning("Warning: [ type=secondary ] is deprecated at [ Tag ]"),["count","marked","value","onChange"].forEach(function(e){e in t&&r.log.warning("Warning: [ "+e+" ] is deprecated at [ Tag ]")}),("selected"in t||"defaultSelected"in t)&&r.log.warning("Warning: [ selected|defaultSelected ] is deprecated at [ Tag ], use [ checked|defaultChecked ] at [ Tag.Selectable ] instead of it"),"closed"in t&&r.log.warning("Warning: [ closed ] is deprecated at [ Tag ], use [ onClose ] at [ Tag.Closeable ] instead of it"),"onSelect"in t&&e("onSelect","","Tag"),"afterClose"in t&&r.log.warning("Warning: [ afterClose ] is deprecated at [ Tag ], use [ afterClose ] at [ Tag.Closeable ] instead of it"),t}});o.Group=a.default.config(i.default),o.Selectable=a.default.config(l.default),o.Closable=a.default.config(n.default),o.Closeable=o.Closable,t.default=o,e.exports=t.default},function(e,t,n){"use strict";n(70),n(441)},function(e,t){e=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=e)},function(e,t){e=e.exports={version:"2.6.12"};"number"==typeof __e&&(__e=e)},function(e,t,n){e.exports=!n(108)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t,n){"use strict";t.__esModule=!0;var a=o(n(342)),r=o(n(520)),n=o(n(521));function o(e){return e&&e.__esModule?e:{default:e}}a.default.Expand=r.default,a.default.OverlayAnimate=n.default,t.default=a.default,e.exports=t.default},function(e,t,n){"use strict";n(43),n(70),n(124),n(109),n(532)},function(e,t,n){"use strict";n.d(t,"a",function(){return r});function v(e,t){return"function"==typeof e?e(t):e}function _(e,t){return"string"==typeof e?Object(d.c)(e,null,null,t):e}function u(e){return e}var b=n(40),a=n(58),t=n(0),w=n.n(t),d=n(55),M=n(42),k=n(54),S=n(57),r=(w.a.Component,function(r){function e(){for(var e,t=arguments.length,n=new Array(t),a=0;athis.menuNode.clientHeight&&(this.menuNode.clientHeight+this.menuNode.scrollTop<(e=this.itemNode.offsetTop+this.itemNode.offsetHeight)?this.menuNode.scrollTop=e-this.menuNode.clientHeight:this.itemNode.offsetTope.length)&&(t=e.length);for(var n=0,a=new Array(t);n=o.length);c++)l=f(e.buffer,r[i+c],o[i+c],e.position-(r[i]-r[i+c]),d),s+=m.repeat(" ",t.indent)+p((e.line+c+1).toString(),u)+" | "+l.str+"\n";return s.replace(/\n$/,"")},F=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],z=["scalar","sequence","mapping"];var a=function(t,e){var n,a;if(e=e||{},Object.keys(e).forEach(function(e){if(-1===F.indexOf(e))throw new r('Unknown option "'+e+'" is met in definition of "'+t+'" YAML type.')}),this.options=e,this.tag=t,this.kind=e.kind||null,this.resolve=e.resolve||function(){return!0},this.construct=e.construct||function(e){return e},this.instanceOf=e.instanceOf||null,this.predicate=e.predicate||null,this.represent=e.represent||null,this.representName=e.representName||null,this.defaultStyle=e.defaultStyle||null,this.multi=e.multi||!1,this.styleAliases=(n=e.styleAliases||null,a={},null!==n&&Object.keys(n).forEach(function(t){n[t].forEach(function(e){a[String(e)]=t})}),a),-1===z.indexOf(this.kind))throw new r('Unknown kind "'+this.kind+'" is specified for "'+t+'" YAML type.')};function o(e,t){var r=[];return e[t].forEach(function(n){var a=r.length;r.forEach(function(e,t){e.tag===n.tag&&e.kind===n.kind&&e.multi===n.multi&&(a=t)}),r[a]=n}),r}function i(e){return this.extend(e)}i.prototype.extend=function(e){var t=[],n=[];if(e instanceof a)n.push(e);else if(Array.isArray(e))n=n.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new r("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(n=n.concat(e.explicit))}t.forEach(function(e){if(!(e instanceof a))throw new r("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new r("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new r("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")}),n.forEach(function(e){if(!(e instanceof a))throw new r("Specified list of YAML types (or a single Type object) contains a non-Type object.")});e=Object.create(i.prototype);return e.implicit=(this.implicit||[]).concat(t),e.explicit=(this.explicit||[]).concat(n),e.compiledImplicit=o(e,"implicit"),e.compiledExplicit=o(e,"explicit"),e.compiledTypeMap=function(){var e,t,n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function a(e){e.multi?(n.multi[e.kind].push(e),n.multi.fallback.push(e)):n[e.kind][e.tag]=n.fallback[e.tag]=e}for(e=0,t=arguments.length;e>16&255),o.push(r>>8&255),o.push(255&r)),r=r<<6|a.indexOf(t.charAt(i));return 0==(e=n%4*6)?(o.push(r>>16&255),o.push(r>>8&255),o.push(255&r)):18==e?(o.push(r>>10&255),o.push(r>>2&255)):12==e&&o.push(r>>4&255),new Uint8Array(o)},predicate:function(e){return"[object Uint8Array]"===Object.prototype.toString.call(e)},represent:function(e){for(var t,n="",a=0,r=e.length,o=g,i=0;i>18&63]+o[a>>12&63])+o[a>>6&63]+o[63&a]),a=(a<<8)+e[i];return 0==(t=r%3)?n=(n=n+o[a>>18&63]+o[a>>12&63])+o[a>>6&63]+o[63&a]:2==t?n=(n=n+o[a>>10&63]+o[a>>4&63])+o[a<<2&63]+o[64]:1==t&&(n=(n=n+o[a>>2&63]+o[a<<4&63])+o[64]+o[64]),n}}),U=Object.prototype.hasOwnProperty,K=Object.prototype.toString;var l=new a("tag:yaml.org,2002:omap",{kind:"sequence",resolve:function(e){if(null!==e)for(var t,n,a,r=[],o=e,i=0,l=o.length;i>10),56320+(s-65536&1023)),e.position++}else E(e,"unknown escape sequence");n=a=e.position}else w(u)?(L(e,n,a,!0),P(e,O(e,!1,t)),n=a=e.position):e.position===e.lineStart&&N(e)?E(e,"unexpected end of the document within a double quoted scalar"):(e.position++,a=e.position)}E(e,"unexpected end of the stream within a double quoted scalar")}}function ge(e,t){var n,a,r=e.tag,o=e.anchor,i=[],l=!1;if(-1!==e.firstTabInLine)return!1;for(null!==e.anchor&&(e.anchorMap[e.anchor]=i),a=e.input.charCodeAt(e.position);0!==a&&(-1!==e.firstTabInLine&&(e.position=e.firstTabInLine,E(e,"tab characters must not be used in indentation")),45===a)&&k(e.input.charCodeAt(e.position+1));)if(l=!0,e.position++,O(e,!0,-1)&&e.lineIndent<=t)i.push(null),a=e.input.charCodeAt(e.position);else if(n=e.line,j(e,t,Z,!1,!0),i.push(e.result),O(e,!0,-1),a=e.input.charCodeAt(e.position),(e.line===n||e.lineIndent>t)&&0!==a)E(e,"bad indentation of a sequence entry");else if(e.lineIndentt?f=1:e.lineIndent===t?f=0:e.lineIndentt?f=1:e.lineIndent===t?f=0:e.lineIndentt)&&(y&&(i=e.line,l=e.lineStart,s=e.position),j(e,t,_,!0,r)&&(y?m=e.result:g=e.result),y||(T(e,f,p,h,m,g,i,l,s),h=m=g=null),O(e,!0,-1),u=e.input.charCodeAt(e.position)),(e.line===o||e.lineIndent>t)&&0!==u)E(e,"bad indentation of a mapping entry");else if(e.lineIndents&&(s=e.lineIndent),w(c))u++;else{if(e.lineIndent=t){i=!0,f=e.input.charCodeAt(e.position);continue}e.position=o,e.line=l,e.lineStart=s,e.lineIndent=u;break}}i&&(L(e,r,o,!1),P(e,e.line-l),r=o=e.position,i=!1),M(f)||(o=e.position+1),f=e.input.charCodeAt(++e.position)}if(L(e,r,o,!1),e.result)return 1;e.kind=d,e.result=c}}(e,a,v===n)&&(h=!0,null===e.tag&&(e.tag="?")):(h=!0,null===e.tag&&null===e.anchor||E(e,"alias node should not have any properties")),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):0===f&&(h=l&&ge(e,r))),null===e.tag)null!==e.anchor&&(e.anchorMap[e.anchor]=e.result);else if("?"===e.tag){for(null!==e.result&&"scalar"!==e.kind&&E(e,'unacceptable node kind for ! tag; it should be "scalar", not "'+e.kind+'"'),s=0,u=e.implicitTypes.length;s"),null!==e.result&&c.kind!==e.kind&&E(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+c.kind+'", not "'+e.kind+'"'),c.resolve(e.result,e.tag)?(e.result=c.construct(e.result,e.tag),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):E(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")}return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||h}function ye(e,t){t=t||{},0!==(e=String(e)).length&&(10!==e.charCodeAt(e.length-1)&&13!==e.charCodeAt(e.length-1)&&(e+="\n"),65279===e.charCodeAt(0)&&(e=e.slice(1)));var n=new ce(e,t),t=e.indexOf("\0");for(-1!==t&&(n.position=t,E(n,"null byte is not allowed in input")),n.input+="\0";32===n.input.charCodeAt(n.position);)n.lineIndent+=1,n.position+=1;for(;n.positiondocument.F=Object<\/script>"),e.close(),u=e.F;t--;)delete u[s][i[t]];return u()};e.exports=Object.create||function(e,t){var n;return null!==e?(a[s]=r(e),n=new a,a[s]=null,n[l]=e):n=u(),void 0===t?n:o(n,t)}},function(e,t,n){var a=n(85).f,r=n(86),o=n(96)("toStringTag");e.exports=function(e,t,n){e&&!r(e=n?e:e.prototype,o)&&a(e,o,{configurable:!0,value:t})}},function(e,t,n){t.f=n(96)},function(e,t,n){var a=n(77),r=n(78),o=n(120),i=n(151),l=n(85).f;e.exports=function(e){var t=r.Symbol||(r.Symbol=!o&&a.Symbol||{});"_"==e.charAt(0)||e in t||l(t,e,{value:i.f(e)})}},function(e,t,n){"use strict";t.__esModule=!0;var a=d(n(203)),r=d(n(495)),o=d(n(496)),i=d(n(497)),l=d(n(498)),s=d(n(499)),u=d(n(500));function d(e){return e&&e.__esModule?e:{default:e}}n(501),a.default.extend(s.default),a.default.extend(l.default),a.default.extend(r.default),a.default.extend(o.default),a.default.extend(i.default),a.default.extend(u.default),a.default.locale("zh-cn");n=a.default;n.isSelf=a.default.isDayjs,a.default.localeData(),t.default=n,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var v=c(n(2)),o=c(n(4)),i=c(n(6)),a=c(n(7)),r=n(0),_=c(r),l=c(n(3)),s=n(30),b=c(n(13)),u=c(n(44)),w=c(n(25)),M=c(n(80)),d=c(n(8)),k=n(11);function c(e){return e&&e.__esModule?e:{default:e}}function f(){}p=r.Component,(0,a.default)(S,p),S.getDerivedStateFromProps=function(e){return"visible"in e?{visible:e.visible}:{}},S.prototype.render=function(){var e,t=this.props,n=t.prefix,a=(t.pure,t.className),r=t.style,o=t.type,i=t.shape,l=t.size,s=t.title,u=t.children,d=(t.defaultVisible,t.visible,t.iconType),c=t.closeable,f=(t.onClose,t.afterClose),p=t.animation,h=t.rtl,t=t.locale,m=(0,v.default)({},k.obj.pickOthers(Object.keys(S.propTypes),this.props)),g=this.state.visible,y=n+"message",o=(0,b.default)(((e={})[y]=!0,e[n+"message-"+o]=o,e[""+n+i]=i,e[""+n+l]=l,e[n+"title-content"]=!!s,e[n+"only-content"]=!s&&!!u,e[a]=a,e)),i=g?_.default.createElement("div",(0,v.default)({role:"alert",style:r},m,{className:o,dir:h?"rtl":void 0}),c?_.default.createElement("a",{role:"button","aria-label":t.closeAriaLabel,className:y+"-close",onClick:this.onClose},_.default.createElement(w.default,{type:"close"})):null,!1!==d?_.default.createElement(w.default,{className:y+"-symbol "+(!d&&y+"-symbol-icon"),type:d}):null,s?_.default.createElement("div",{className:y+"-title"},s):null,u?_.default.createElement("div",{className:y+"-content"},u):null):null;return p?_.default.createElement(M.default.Expand,{animationAppear:!1,afterLeave:f},i):i},r=n=S,n.propTypes={prefix:l.default.string,pure:l.default.bool,className:l.default.string,style:l.default.object,type:l.default.oneOf(["success","warning","error","notice","help","loading"]),shape:l.default.oneOf(["inline","addon","toast"]),size:l.default.oneOf(["medium","large"]),title:l.default.node,children:l.default.node,defaultVisible:l.default.bool,visible:l.default.bool,iconType:l.default.oneOfType([l.default.string,l.default.bool]),closeable:l.default.bool,onClose:l.default.func,afterClose:l.default.func,animation:l.default.bool,locale:l.default.object,rtl:l.default.bool},n.defaultProps={prefix:"next-",pure:!1,type:"success",shape:"inline",size:"medium",defaultVisible:!0,closeable:!1,onClose:f,afterClose:f,animation:!0,locale:u.default.Message};var p,a=r;function S(){var e,t;(0,o.default)(this,S);for(var n=arguments.length,a=Array(n),r=0;r=n.length?(s=!!(c=h(o,u)))&&"get"in c&&!("originalValue"in c.get)?c.get:o[u]:(s=_(o,u),o[u]),s&&!i&&(y[d]=o)}}return o}},function(e,t,n){"use strict";n=n(598);e.exports=Function.prototype.bind||n},function(e,t,n){"use strict";var a=String.prototype.replace,r=/%20/g,o="RFC1738",i="RFC3986";e.exports={default:i,formatters:{RFC1738:function(e){return a.call(e,r,"+")},RFC3986:function(e){return String(e)}},RFC1738:o,RFC3986:i}},function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var d=s(n(2)),a=s(n(4)),r=s(n(6)),o=s(n(7)),c=n(0),f=s(c),i=s(n(3)),p=s(n(13)),h=s(n(25)),l=n(11),m=s(n(99));function s(e){return e&&e.__esModule?e:{default:e}}var u,g=l.func.bindCtx,y=l.obj.pickOthers,i=(u=c.Component,(0,o.default)(v,u),v.prototype.getSelected=function(){var e=this.props,t=e._key,n=e.root,e=e.selected,a=n.props.selectMode,n=n.state.selectedKeys;return e||!!a&&-1e.length&&e.every(function(e,t){return e===n[t]})},t.isAvailablePos=function(e,t,n){var n=n[t],a=n.type,n=n.disabled;return r(e,t)&&("item"===a&&!n||"submenu"===a)});t.getFirstAvaliablelChildKey=function(t,n){var e=Object.keys(n).find(function(e){return a(t+"-0",e,n)});return e?n[e].key:null},t.getChildSelected=function(e){var t=e.selectMode,n=e.selectedKeys,a=e._k2n,e=e._key;if(!a)return!1;var r=(a[e]&&a[e].pos)+"-";return!!t&&n.some(function(e){return a[e]&&0===a[e].pos.indexOf(r)})}},function(e,t,n){"use strict";n(43),n(32),n(620)},function(e,t,n){var o=n(633),i=Object.prototype.hasOwnProperty;function l(e){return Array.isArray(e)?"array":typeof e}function s(e,t){var n,a=0,r=0;for(n in e)if(i.call(e,n)){if("style"===n){if(!o(e[n],t[n]))return!1}else if("children"!==n&&e[n]!==t[n])return!1;a++}for(n in t)i.call(t,n)&&r++;return a===r&&function e(t,n){var a=l(t);if(a!==l(n))return!1;switch(a){case"array":if(t.length!==n.length)return!1;for(var r=0;r=u,u=(0,O.default)(((u={})[n+"upload-inner"]=!0,u[n+"hidden"]=E,u)),C=this.props.children;if("card"===r&&(r=(0,O.default)(((r={})[n+"upload-card"]=!0,r[n+"disabled"]=s,r)),C=D.default.createElement("div",{className:r},D.default.createElement(P.default,{size:"large",type:"add",className:n+"upload-add-icon"}),D.default.createElement("div",{tabIndex:"0",role:"button",className:n+"upload-text"},C))),b)return"function"==typeof w?(b=(0,O.default)(((r={})[n+"form-preview"]=!0,r[o]=!!o,r)),D.default.createElement("div",{style:i,className:b},w(this.state.value,this.props))):t?D.default.createElement(Y.default,{isPreview:!0,listType:t,style:i,className:o,value:this.state.value}):null;n=s?N.func.prevent:p,r=N.obj.pickAttrsWith(this.props,"data-");return D.default.createElement("div",(0,L.default)({className:f,style:i},r),D.default.createElement(j.default,(0,L.default)({},e,{name:M,beforeUpload:c,dragable:a,disabled:s||E,className:u,onSelect:this.onSelect,onDrop:this.onDrop,onProgress:this.onProgress,onSuccess:this.onSuccess,onError:this.onError,ref:this.saveUploaderRef}),C),t||g?D.default.createElement(Y.default,{useDataURL:l,fileNameRender:k,actionRender:S,uploader:this,listType:t,value:this.state.value,closable:d,onRemove:n,progressProps:v,onCancel:h,onPreview:m,extraRender:y,rtl:_,previewOnFileName:x}):null)},i=u=h,u.displayName="Upload",u.propTypes=(0,L.default)({},d.default.propTypes,Y.default.propTypes,{prefix:l.default.string.isRequired,action:l.default.string,value:l.default.array,defaultValue:l.default.array,shape:l.default.oneOf(["card"]),listType:l.default.oneOf(["text","image","card"]),list:l.default.any,name:l.default.string,data:l.default.oneOfType([l.default.object,l.default.func]),formatter:l.default.func,limit:l.default.number,timeout:l.default.number,dragable:l.default.bool,closable:l.default.bool,useDataURL:l.default.bool,disabled:l.default.bool,onSelect:l.default.func,onProgress:l.default.func,onChange:l.default.func,onSuccess:l.default.func,afterSelect:l.default.func,onRemove:l.default.func,onError:l.default.func,beforeUpload:l.default.func,onDrop:l.default.func,className:l.default.string,style:l.default.object,children:l.default.node,autoUpload:l.default.bool,request:l.default.func,progressProps:l.default.object,rtl:l.default.bool,isPreview:l.default.bool,renderPreview:l.default.func,fileKeyName:l.default.string,fileNameRender:l.default.func,actionRender:l.default.func,previewOnFileName:l.default.bool}),u.defaultProps=(0,L.default)({},d.default.defaultProps,{prefix:"next-",limit:1/0,autoUpload:!0,closable:!0,onSelect:n,onProgress:n,onChange:n,onSuccess:n,onRemove:n,onError:n,onDrop:n,beforeUpload:n,afterSelect:n,previewOnFileName:!1}),a=function(){var u=this;this.onSelect=function(e){var t,n,a=u.props,r=a.autoUpload,o=a.afterSelect,i=a.onSelect,a=a.limit,l=u.state.value.length+e.length,s=a-u.state.value.length;s<=0||(t=e=e.map(function(e){e=(0,c.fileToObject)(e);return e.state="selected",e}),n=[],ai||l+a.width>o):t<0||e<0||t+a.height>u.height||e+a.width>u.width}function T(e,t,n,a){var r=a.overlayInfo,a=a.containerInfo,n=n.split("");return 1===n.length&&n.push(""),t<0&&(n=[n[0].replace("t","b"),n[1].replace("b","t")]),e<0&&(n=[n[0].replace("l","r"),n[1].replace("r","l")]),t+r.height>a.height&&(n=[n[0].replace("b","t"),n[1].replace("t","b")]),(n=e+r.width>a.width?[n[0].replace("r","l"),n[1].replace("l","r")]:n).join("")}function D(e,t,n){var a=n.overlayInfo,n=n.containerInfo;return(t=t<0?0:t)+a.height>n.height&&(t=n.height-a.height),{left:e=(e=e<0?0:e)+a.width>n.width?n.width-a.width:e,top:t}}function ve(e){var t=e.target,n=e.overlay,a=e.container,r=e.scrollNode,o=e.placement,i=e.placementOffset,i=void 0===i?0:i,l=e.points,l=void 0===l?["tl","bl"]:l,s=e.offset,s=void 0===s?[0,0]:s,u=e.position,u=void 0===u?"absolute":u,d=e.beforePosition,c=e.autoAdjust,c=void 0===c||c,f=e.autoHideScrollOverflow,f=void 0===f||f,e=e.rtl,p="offsetWidth"in(p=n)&&"offsetHeight"in p?{width:p.offsetWidth,height:p.offsetHeight}:{width:(p=p.getBoundingClientRect()).width,height:p.height},h=p.width,p=p.height;if("fixed"===u)return m={config:{placement:void 0,points:void 0},style:{position:u,left:s[0],top:s[1]}},d?d(m,{overlay:{node:n,width:h,height:p}}):m;var m=t.getBoundingClientRect(),g=m.width,y=m.height,v=m.left,_=m.top,m=E(a),b=m.left,m=m.top,w=a.scrollWidth,M=a.scrollHeight,k=a.scrollTop,S=a.scrollLeft,b={targetInfo:{width:g,height:y,left:v,top:_},containerInfo:{left:b,top:m,width:w,height:M,scrollTop:k,scrollLeft:S},overlayInfo:{width:h,height:p},points:l,placementOffset:i,offset:s,container:a,rtl:e},m=C(o,b),w=m.left,M=m.top,k=m.points,S=function(e){for(var t=e;t;){var n=fe(t,"overflow");if(null!=n&&n.match(/auto|scroll|hidden/))return t;t=t.parentNode}return document.documentElement}(a),x=(c&&o&&L(w,M,S,b)&&(o!==(l=T(w,M,o,b))&&(M=L(s=(i=C(l,b)).left,e=i.top,S,b)&&l!==(m=T(s,e,l,b))?(w=(c=D((a=C(o=m,b)).left,a.top,b)).left,c.top):(o=l,w=s,e)),w=(i=D(w,M,b)).left,M=i.top),{config:{placement:o,points:k},style:{position:u,left:Math.round(w),top:Math.round(M)}});return f&&o&&null!=r&&r.length&&r.forEach(function(e){var e=e.getBoundingClientRect(),t=e.top,n=e.left,a=e.width,e=e.height;x.style.display=_+y=e.length?{done:!0}:{done:!1,value:e[n++]}};throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,a=new Array(t);nt.clientHeight&&0r;)!i(a,n=t[r++])||~s(o,n)||o.push(n);return o}},function(e,t,n){var a=n(193);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==a(e)?e.split(""):Object(e)}},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t,n){"use strict";function y(){return this}var v=n(120),_=n(92),b=n(195),w=n(93),M=n(148),k=n(466),S=n(150),E=n(469),x=n(96)("iterator"),C=!([].keys&&"next"in[].keys()),L="values";e.exports=function(e,t,n,a,r,o,i){k(n,t,a);function l(e){if(!C&&e in f)return f[e];switch(e){case"keys":case L:return function(){return new n(this,e)}}return function(){return new n(this,e)}}var s,u,a=t+" Iterator",d=r==L,c=!1,f=e.prototype,p=f[x]||f["@@iterator"]||r&&f[r],h=p||l(r),m=r?d?l("entries"):h:void 0,g="Array"==t&&f.entries||p;if(g&&(g=E(g.call(new e)))!==Object.prototype&&g.next&&(S(g,a,!0),v||"function"==typeof g[x]||w(g,x,y)),d&&p&&p.name!==L&&(c=!0,h=function(){return p.call(this)}),v&&!i||!C&&!c&&f[x]||w(f,x,h),M[t]=h,M[a]=y,r)if(s={values:d?h:l(L),keys:o?h:l("keys"),entries:m},i)for(u in s)u in f||b(f,u,s[u]);else _(_.P+_.F*(C||c),t,s);return s}},function(e,t,n){e.exports=n(93)},function(e,t,n){var a=n(191),r=n(145).concat("length","prototype");t.f=Object.getOwnPropertyNames||function(e){return a(e,r)}},function(e,t,n){var a=n(122),r=n(118),o=n(95),i=n(140),l=n(86),s=n(189),u=Object.getOwnPropertyDescriptor;t.f=n(79)?u:function(e,t){if(e=o(e),t=i(t,!0),s)try{return u(e,t)}catch(e){}if(l(e,t))return r(!a.f.call(e,t),e[t])}},function(e,t,n){"use strict";t.__esModule=!0;var v=a(n(2));t.default=function(e,t,n){var a=e.prefix,r=e.locale,o=(e.defaultPropsConfig,e.pure),i=e.rtl,l=e.device,s=e.popupContainer,e=e.errorBoundary,u=t.nextPrefix,d=t.nextLocale,c=t.nextDefaultPropsConfig,f=t.nextPure,p=t.nextWarning,h=t.nextRtl,m=t.nextDevice,g=t.nextPopupContainer,t=t.nextErrorBoundary,a=a||u,u=void 0,y=n;switch(n){case"DatePicker2":y="DatePicker";break;case"Calendar2":y="Calendar";break;case"TimePicker2":y="TimePicker"}d&&(u=d[y])&&(u.momentLocale=d.momentLocale);n=void 0;r?n=b.obj.deepMerge({},_.default[y],u,r):u&&(n=b.obj.deepMerge({},_.default[y],u));d="boolean"==typeof o?o:f,r="boolean"==typeof i?i:h,u=(0,v.default)({},w(t),w(e));"open"in u||(u.open=!1);return{prefix:a,locale:n,pure:d,rtl:r,warning:p,defaultPropsConfig:c||{},device:l||m||void 0,popupContainer:s||g,errorBoundary:u}};var _=a(n(44)),b=n(11);function a(e){return e&&e.__esModule?e:{default:e}}var w=function(e){return null==e?{}:"boolean"==typeof e?{open:e}:(0,v.default)({open:!0},e)};e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0,t.matches=t.hasDOM=void 0;var a=n(38),r=(a=a)&&a.__esModule?a:{default:a},o=(t.hasClass=s,t.addClass=u,t.removeClass=d,t.toggleClass=function(e,t){if(!l||!e)return!1;{var n;return e.classList?e.classList.toggle(t):(((n=s(e,t))?d:u)(e,t,!0),!n)}},t.getNodeHozWhitespace=function(e){var t=m(e,"paddingLeft"),n=m(e,"paddingRight"),a=m(e,"marginLeft"),e=m(e,"marginRight");return t+n+a+e},t.getStyle=m,t.setStyle=g,t.scrollbar=v,t.hasScroll=function(e){if("hidden"===m(e,"overflow"))return!1;var t=e.parentNode;return t&&t.scrollHeight>t.clientHeight&&0=t?e:""+Array(t+1-a.length).join(n)+e},t={s:o,z:function(e){var t=-e.utcOffset(),n=Math.abs(t),a=Math.floor(n/60),r=n%60;return(t<=0?"+":"-")+o(a,2,"0")+":"+o(r,2,"0")},m:function e(t,n){if(t.date()1)return e(i[0])}else{var l=t.name;S[l]=t,r=l}return!a&&r&&(k=r),r||!a&&k},E=function(e,t){if(a(e))return e.clone();var n="object"==typeof t?t:{};return n.date=e,n.args=arguments,new l(n)},x=t,l=(x.l=r,x.i=a,x.w=function(e,t){return E(e,{locale:t.$L,utc:t.$u,x:t.$x,$offset:t.$offset})},function(){function e(e){this.$L=r(e.locale,null,!0),this.parse(e)}var t=e.prototype;return t.parse=function(e){this.$d=function(e){var t=e.date,n=e.utc;if(null===t)return new Date(NaN);if(x.u(t))return new Date;if(t instanceof Date)return new Date(t);if("string"==typeof t&&!/Z$/i.test(t)){var a=t.match(i);if(a){var r=a[2]-1||0,o=(a[7]||"0").substring(0,3);return n?new Date(Date.UTC(a[1],r,a[3]||1,a[4]||0,a[5]||0,a[6]||0,o)):new Date(a[1],r,a[3]||1,a[4]||0,a[5]||0,a[6]||0,o)}}return new Date(t)}(e),this.$x=e.x||{},this.init()},t.init=function(){var e=this.$d;this.$y=e.getFullYear(),this.$M=e.getMonth(),this.$D=e.getDate(),this.$W=e.getDay(),this.$H=e.getHours(),this.$m=e.getMinutes(),this.$s=e.getSeconds(),this.$ms=e.getMilliseconds()},t.$utils=function(){return x},t.isValid=function(){return!(this.$d.toString()===w)},t.isSame=function(e,t){var n=E(e);return this.startOf(t)<=n&&n<=this.endOf(t)},t.isAfter=function(e,t){return E(e)r;)!i(a,n=t[r++])||~s(o,n)||o.push(n);return o}},function(e,t,n){var a=n(193);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==a(e)?e.split(""):Object(e)}},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t,n){"use strict";function y(){return this}var v=n(120),_=n(92),b=n(195),w=n(93),M=n(148),k=n(466),S=n(150),x=n(469),E=n(96)("iterator"),C=!([].keys&&"next"in[].keys()),L="values";e.exports=function(e,t,n,a,r,o,i){k(n,t,a);function l(e){if(!C&&e in f)return f[e];switch(e){case"keys":case L:return function(){return new n(this,e)}}return function(){return new n(this,e)}}var s,u,a=t+" Iterator",d=r==L,c=!1,f=e.prototype,p=f[E]||f["@@iterator"]||r&&f[r],h=p||l(r),m=r?d?l("entries"):h:void 0,g="Array"==t&&f.entries||p;if(g&&(g=x(g.call(new e)))!==Object.prototype&&g.next&&(S(g,a,!0),v||"function"==typeof g[E]||w(g,E,y)),d&&p&&p.name!==L&&(c=!0,h=function(){return p.call(this)}),v&&!i||!C&&!c&&f[E]||w(f,E,h),M[t]=h,M[a]=y,r)if(s={values:d?h:l(L),keys:o?h:l("keys"),entries:m},i)for(u in s)u in f||b(f,u,s[u]);else _(_.P+_.F*(C||c),t,s);return s}},function(e,t,n){e.exports=n(93)},function(e,t,n){var a=n(191),r=n(145).concat("length","prototype");t.f=Object.getOwnPropertyNames||function(e){return a(e,r)}},function(e,t,n){var a=n(122),r=n(118),o=n(95),i=n(140),l=n(86),s=n(189),u=Object.getOwnPropertyDescriptor;t.f=n(79)?u:function(e,t){if(e=o(e),t=i(t,!0),s)try{return u(e,t)}catch(e){}if(l(e,t))return r(!a.f.call(e,t),e[t])}},function(e,t,n){"use strict";t.__esModule=!0;var v=a(n(2));t.default=function(e,t,n){var a=e.prefix,r=e.locale,o=(e.defaultPropsConfig,e.pure),i=e.rtl,l=e.device,s=e.popupContainer,e=e.errorBoundary,u=t.nextPrefix,d=t.nextLocale,c=t.nextDefaultPropsConfig,f=t.nextPure,p=t.nextWarning,h=t.nextRtl,m=t.nextDevice,g=t.nextPopupContainer,t=t.nextErrorBoundary,a=a||u,u=void 0,y=n;switch(n){case"DatePicker2":y="DatePicker";break;case"Calendar2":y="Calendar";break;case"TimePicker2":y="TimePicker"}d&&(u=d[y])&&(u.momentLocale=d.momentLocale);n=void 0;r?n=b.obj.deepMerge({},_.default[y],u,r):u&&(n=b.obj.deepMerge({},_.default[y],u));d="boolean"==typeof o?o:f,r="boolean"==typeof i?i:h,u=(0,v.default)({},w(t),w(e));"open"in u||(u.open=!1);return{prefix:a,locale:n,pure:d,rtl:r,warning:p,defaultPropsConfig:c||{},device:l||m||void 0,popupContainer:s||g,errorBoundary:u}};var _=a(n(44)),b=n(11);function a(e){return e&&e.__esModule?e:{default:e}}var w=function(e){return null==e?{}:"boolean"==typeof e?{open:e}:(0,v.default)({open:!0},e)};e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0,t.matches=t.hasDOM=void 0;var a=n(38),r=(a=a)&&a.__esModule?a:{default:a},o=(t.hasClass=s,t.addClass=u,t.removeClass=d,t.toggleClass=function(e,t){if(!l||!e)return!1;{var n;return e.classList?e.classList.toggle(t):(((n=s(e,t))?d:u)(e,t,!0),!n)}},t.getNodeHozWhitespace=function(e){var t=m(e,"paddingLeft"),n=m(e,"paddingRight"),a=m(e,"marginLeft"),e=m(e,"marginRight");return t+n+a+e},t.getStyle=m,t.setStyle=g,t.scrollbar=v,t.hasScroll=function(e){if("hidden"===m(e,"overflow"))return!1;var t=e.parentNode;return t&&t.scrollHeight>t.clientHeight&&0=t?e:""+Array(t+1-a.length).join(n)+e},t={s:o,z:function(e){var t=-e.utcOffset(),n=Math.abs(t),a=Math.floor(n/60),r=n%60;return(t<=0?"+":"-")+o(a,2,"0")+":"+o(r,2,"0")},m:function e(t,n){if(t.date()1)return e(i[0])}else{var l=t.name;S[l]=t,r=l}return!a&&r&&(k=r),r||!a&&k},x=function(e,t){if(a(e))return e.clone();var n="object"==typeof t?t:{};return n.date=e,n.args=arguments,new l(n)},E=t,l=(E.l=r,E.i=a,E.w=function(e,t){return x(e,{locale:t.$L,utc:t.$u,x:t.$x,$offset:t.$offset})},function(){function e(e){this.$L=r(e.locale,null,!0),this.parse(e)}var t=e.prototype;return t.parse=function(e){this.$d=function(e){var t=e.date,n=e.utc;if(null===t)return new Date(NaN);if(E.u(t))return new Date;if(t instanceof Date)return new Date(t);if("string"==typeof t&&!/Z$/i.test(t)){var a=t.match(i);if(a){var r=a[2]-1||0,o=(a[7]||"0").substring(0,3);return n?new Date(Date.UTC(a[1],r,a[3]||1,a[4]||0,a[5]||0,a[6]||0,o)):new Date(a[1],r,a[3]||1,a[4]||0,a[5]||0,a[6]||0,o)}}return new Date(t)}(e),this.$x=e.x||{},this.init()},t.init=function(){var e=this.$d;this.$y=e.getFullYear(),this.$M=e.getMonth(),this.$D=e.getDate(),this.$W=e.getDay(),this.$H=e.getHours(),this.$m=e.getMinutes(),this.$s=e.getSeconds(),this.$ms=e.getMilliseconds()},t.$utils=function(){return E},t.isValid=function(){return!(this.$d.toString()===w)},t.isSame=function(e,t){var n=x(e);return this.startOf(t)<=n&&n<=this.endOf(t)},t.isAfter=function(e,t){return x(e)=20?"ste":"de")},week:{dow:1,doy:4}})}(n(9))},function(e,t,n){!function(e){"use strict"; //! moment.js locale configuration @@ -287,7 +287,7 @@ var t;e.defineLocale("zh-hk",{months:"一月_二月_三月_四月_五月_六月_ //! moment.js locale configuration var t;e.defineLocale("zh-mo",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"D/M/YYYY",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){if(e===12)e=0;if(t==="凌晨"||t==="早上"||t==="上午")return e;else if(t==="中午")return e>=11?e:e+12;else if(t==="下午"||t==="晚上")return e+12},meridiem:function(e,t,n){var a=e*100+t;if(a<600)return"凌晨";else if(a<900)return"早上";else if(a<1130)return"上午";else if(a<1230)return"中午";else if(a<1800)return"下午";else return"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(n(9))},function(e,t,n){!function(e){"use strict"; //! moment.js locale configuration -var t;e.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){if(e===12)e=0;if(t==="凌晨"||t==="早上"||t==="上午")return e;else if(t==="中午")return e>=11?e:e+12;else if(t==="下午"||t==="晚上")return e+12},meridiem:function(e,t,n){var a=e*100+t;if(a<600)return"凌晨";else if(a<900)return"早上";else if(a<1130)return"上午";else if(a<1230)return"中午";else if(a<1800)return"下午";else return"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(n(9))},function(e,t,n){"use strict";t.__esModule=!0;var u=p(n(2)),a=p(n(4)),r=p(n(6)),o=p(n(7)),i=n(0),d=p(i),l=p(n(3)),c=p(n(13)),s=p(n(8)),f=n(11);function p(e){return e&&e.__esModule?e:{default:e}}h=i.Component,(0,o.default)(m,h),m.prototype.render=function(){var e,t=this.props,n=t.prefix,a=t.type,r=t.size,o=t.className,i=t.rtl,l=t.style,t=t.children,s=f.obj.pickOthers((0,u.default)({},m.propTypes),this.props),n=(0,c.default)(((e={})[n+"icon"]=!0,e[n+"icon-"+a]=!!a,e[""+n+r]=!!r&&"string"==typeof r,e[o]=!!o,e)),o=(i&&-1!==["arrow-left","arrow-right","arrow-double-left","arrow-double-right","switch","sorting","descending","ascending"].indexOf(a)&&(s.dir="rtl"),"number"==typeof r?{width:r,height:r,lineHeight:r+"px",fontSize:r}:{});return d.default.createElement("i",(0,u.default)({},s,{style:(0,u.default)({},o,l),className:n}),t)},i=n=m,n.propTypes=(0,u.default)({},s.default.propTypes,{type:l.default.string,children:l.default.node,size:l.default.oneOfType([l.default.oneOf(["xxs","xs","small","medium","large","xl","xxl","xxxl","inherit"]),l.default.number]),className:l.default.string,style:l.default.object}),n.defaultProps={prefix:"next-",size:"medium"},n._typeMark="icon";var h,o=i;function m(){return(0,a.default)(this,m),(0,r.default)(this,h.apply(this,arguments))}o.displayName="Icon",t.default=o,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var g=s(n(2)),y=s(n(12)),a=s(n(38)),r=s(n(4)),o=s(n(6)),i=s(n(7)),v=n(0),_=s(v),l=s(n(3)),b=n(155),w=s(n(519));function s(e){return e&&e.__esModule?e:{default:e}}function u(){}function M(e){return _.default.Children.toArray(e.children)[0]||null}d=v.Component,(0,i.default)(c,d),c.prototype.normalizeNames=function(e){return"string"==typeof e?{appear:e+"-appear",appearActive:e+"-appear-active",enter:e+"-enter",enterActive:e+"-enter-active",leave:e+"-leave",leaveActive:e+"-leave-active"}:"object"===(void 0===e?"undefined":(0,a.default)(e))?{appear:e.appear,appearActive:e.appear+"-active",enter:""+e.enter,enterActive:e.enter+"-active",leave:""+e.leave,leaveActive:e.leave+"-active"}:void 0},c.prototype.render=function(){var t=this,e=this.props,n=e.animation,a=e.children,r=e.animationAppear,o=e.singleMode,i=e.component,l=e.beforeAppear,s=e.onAppear,u=e.afterAppear,d=e.beforeEnter,c=e.onEnter,f=e.afterEnter,p=e.beforeLeave,h=e.onLeave,m=e.afterLeave,e=(0,y.default)(e,["animation","children","animationAppear","singleMode","component","beforeAppear","onAppear","afterAppear","beforeEnter","onEnter","afterEnter","beforeLeave","onLeave","afterLeave"]),a=v.Children.map(a,function(e){return _.default.createElement(w.default,{key:e.key,names:t.normalizeNames(n),onAppear:l,onAppearing:s,onAppeared:u,onEnter:d,onEntering:c,onEntered:f,onExit:p,onExiting:h,onExited:m},e)});return _.default.createElement(b.TransitionGroup,(0,g.default)({appear:r,component:o?M:i},e),a)},i=n=c,n.propTypes={animation:l.default.oneOfType([l.default.string,l.default.object]),animationAppear:l.default.bool,component:l.default.any,singleMode:l.default.bool,children:l.default.oneOfType([l.default.element,l.default.arrayOf(l.default.element)]),beforeAppear:l.default.func,onAppear:l.default.func,afterAppear:l.default.func,beforeEnter:l.default.func,onEnter:l.default.func,afterEnter:l.default.func,beforeLeave:l.default.func,onLeave:l.default.func,afterLeave:l.default.func},n.defaultProps={animationAppear:!0,component:"div",singleMode:!0,beforeAppear:u,onAppear:u,afterAppear:u,beforeEnter:u,onEnter:u,afterEnter:u,beforeLeave:u,onLeave:u,afterLeave:u};var d,l=i;function c(){return(0,r.default)(this,c),(0,o.default)(this,d.apply(this,arguments))}l.displayName="Animate",t.default=l,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0,t.default=t.EXITING=t.ENTERED=t.ENTERING=t.EXITED=t.UNMOUNTED=void 0;var a=function(e){{if(e&&e.__esModule)return e;var t,n={};if(null!=e)for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&((t=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(e,a):{}).get||t.set?Object.defineProperty(n,a,t):n[a]=e[a]);return n.default=e,n}}(n(3)),o=l(n(0)),i=l(n(23)),r=n(30);n(344);function l(e){return e&&e.__esModule?e:{default:e}}var s="unmounted",u=(t.UNMOUNTED=s,"exited"),d=(t.EXITED=u,"entering"),c=(t.ENTERING=d,"entered"),f=(t.ENTERED=c,"exiting"),n=(t.EXITING=f,function(r){var e;function t(e,t){var n,a=r.call(this,e,t)||this,t=t.transitionGroup,t=t&&!t.isMounting?e.enter:e.appear;return a.appearStatus=null,e.in?t?(n=u,a.appearStatus=d):n=c:n=e.unmountOnExit||e.mountOnEnter?s:u,a.state={status:n},a.nextCallback=null,a}e=r,(n=t).prototype=Object.create(e.prototype),(n.prototype.constructor=n).__proto__=e;var n=t.prototype;return n.getChildContext=function(){return{transitionGroup:null}},t.getDerivedStateFromProps=function(e,t){return e.in&&t.status===s?{status:u}:null},n.componentDidMount=function(){this.updateStatus(!0,this.appearStatus)},n.componentDidUpdate=function(e){var t=null;e!==this.props&&(e=this.state.status,this.props.in?e!==d&&e!==c&&(t=d):e!==d&&e!==c||(t=f)),this.updateStatus(!1,t)},n.componentWillUnmount=function(){this.cancelNextCallback()},n.getTimeouts=function(){var e,t,n=this.props.timeout,a=e=t=n;return null!=n&&"number"!=typeof n&&(a=n.exit,e=n.enter,t=void 0!==n.appear?n.appear:e),{exit:a,enter:e,appear:t}},n.updateStatus=function(e,t){var n;void 0===e&&(e=!1),null!==t?(this.cancelNextCallback(),n=i.default.findDOMNode(this),t===d?this.performEnter(n,e):this.performExit(n)):this.props.unmountOnExit&&this.state.status===u&&this.setState({status:s})},n.performEnter=function(e,t){var n=this,a=this.props.enter,r=this.context.transitionGroup?this.context.transitionGroup.isMounting:t,o=this.getTimeouts(),i=r?o.appear:o.enter;t||a?(this.props.onEnter(e,r),this.safeSetState({status:d},function(){n.props.onEntering(e,r),n.onTransitionEnd(e,i,function(){n.safeSetState({status:c},function(){n.props.onEntered(e,r)})})})):this.safeSetState({status:c},function(){n.props.onEntered(e)})},n.performExit=function(e){var t=this,n=this.props.exit,a=this.getTimeouts();n?(this.props.onExit(e),this.safeSetState({status:f},function(){t.props.onExiting(e),t.onTransitionEnd(e,a.exit,function(){t.safeSetState({status:u},function(){t.props.onExited(e)})})})):this.safeSetState({status:u},function(){t.props.onExited(e)})},n.cancelNextCallback=function(){null!==this.nextCallback&&(this.nextCallback.cancel(),this.nextCallback=null)},n.safeSetState=function(e,t){t=this.setNextCallback(t),this.setState(e,t)},n.setNextCallback=function(t){var n=this,a=!0;return this.nextCallback=function(e){a&&(a=!1,n.nextCallback=null,t(e))},this.nextCallback.cancel=function(){a=!1},this.nextCallback},n.onTransitionEnd=function(e,t,n){this.setNextCallback(n);n=null==t&&!this.props.addEndListener;!e||n?setTimeout(this.nextCallback,0):(this.props.addEndListener&&this.props.addEndListener(e,this.nextCallback),null!=t&&setTimeout(this.nextCallback,t))},n.render=function(){var e=this.state.status;if(e===s)return null;var t=this.props,n=t.children,t=function(e,t){if(null==e)return{};for(var n,a={},r=Object.keys(e),o=0;o 16.8.0"),null;function t(e){j.current=e,ne({})}function a(e,t){N(te,null),"function"==typeof S&&S(e,t)}function n(e){27===e.keyCode&&Y&&!P.current.size&&a("esc",e)}function r(){j.current||(t(!0),he.dom.setStyle(D.current,"display","none"),me.default.unlock(document.body,ee.current),s&&O.current&&(O.current.focus(),O.current=null),I())}var o=e.prefix,o=void 0===o?"next-":o,i=e.afterClose,I=void 0===i?ye:i,i=e.hasMask,l=void 0===i||i,i=e.autoFocus,s=void 0!==i&&i,i=e.className,R=e.title,A=e.children,H=e.footer,F=e.footerAlign,z=e.footerActions,u=e.onOk,u=void 0===u?ye:u,d=e.onCancel,W=e.okProps,V=e.cancelProps,c=e.locale,c=void 0===c?pe.default.Dialog:c,B=e.rtl,f=e.visible,p=e.closeMode,p=void 0===p?["close","esc"]:p,U=e.closeIcon,h=e.animation,h=void 0===h?{in:"fadeInUp",out:"fadeOutUp"}:h,m=e.cache,K=e.wrapperStyle,g=e.popupContainer,y=void 0===g?document.body:g,g=e.dialogRender,v=e.centered,_=e.top,_=void 0===_?v?40:100:_,b=e.bottom,b=void 0===b?40:b,w=e.width,w=void 0===w?520:w,q=e.height,M=e.isFullScreen,k=e.overflowScroll,M=void 0===k?!M:k,k=e.minMargin,S=e.onClose,G=e.style,E=(0,ie.default)(e,["prefix","afterClose","hasMask","autoFocus","className","title","children","footer","footerAlign","footerActions","onOk","onCancel","okProps","cancelProps","locale","rtl","visible","closeMode","closeIcon","animation","cache","wrapperStyle","popupContainer","dialogRender","centered","top","bottom","width","height","isFullScreen","overflowScroll","minMargin","onClose","style"]),x=("isFullScreen"in e&&he.log.deprecated("isFullScreen","overflowScroll","Dialog v2"),"minMargin"in e&&he.log.deprecated("minMargin","top/bottom","Dialog v2"),(0,le.useState)(f||!1)),$=x[0],J=x[1],x=(0,le.useState)(f),C=x[0],Q=x[1],X="string"==typeof y?function(){return document.getElementById(y)}:"function"!=typeof y?function(){return y}:y,x=(0,le.useState)(X()),L=x[0],Z=x[1],T=(0,le.useRef)(null),D=(0,le.useRef)(null),O=(0,le.useRef)(null),ee=(0,le.useRef)(null),te=(0,le.useState)((0,he.guid)())[0],x=(0,le.useContext)(ge),N=x.setVisibleOverlayToParent,x=(0,ie.default)(x,["setVisibleOverlayToParent"]),P=(0,le.useRef)(new Map),j=(0,le.useRef)(!1),ne=(0,le.useState)()[1],Y=!1,ae=!1,re=!1;(Array.isArray(p)?p:[p]).forEach(function(e){switch(e){case"esc":Y=!0;break;case"mask":ae=!0;break;case"close":re=!0}}),(0,le.useEffect)(function(){"visible"in e&&Q(f)},[f]),(0,le.useEffect)(function(){var e;C&&l&&(e={overflow:"hidden"},he.dom.hasScroll(document.body)&&he.dom.scrollbar().width&&(e.paddingRight=he.dom.getStyle(document.body,"paddingRight")+he.dom.scrollbar().width+"px"),ee.current=me.default.lock(document.body,e))},[C&&l]),(0,le.useEffect)(function(){if(C&&Y)return document.body.addEventListener("keydown",n,!1),function(){document.body.removeEventListener("keydown",n,!1)}},[C&&Y]),(0,le.useEffect)(function(){!$&&C&&J(!0)},[C]),(0,le.useEffect)(function(){L||setTimeout(function(){Z(X())})},[L]);if((0,le.useEffect)(function(){return function(){r()}},[]),!1===$||!L)return null;if(!C&&!m&&j.current)return null;m=(0,de.default)(((p={})[o+"overlay-wrapper"]=!0,p.opened=C,p)),i=(0,de.default)(((p={})[o+"dialog-v2"]=!0,p[i]=!!i,p)),p={},k=void(v?_||b||!k?(_&&(p.marginTop=_),b&&(p.marginBottom=b)):(p.marginTop=k,p.marginBottom=k):(_&&(p.top=_),b&&(p.paddingBottom=b))),M&&(k="calc(100vh - "+(_+b)+"px)"),M={appear:300,enter:300,exit:250},_=se.default.createElement(fe.default.OverlayAnimate,{visible:C,animation:h,timeout:M,onEnter:function(){t(!1),he.dom.setStyle(D.current,"display","")},onEntered:function(){var e;s&&T.current&&T.current.bodyNode&&(0<(e=he.focus.getFocusNodeList(T.current.bodyNode)).length&&e[0]&&(O.current=document.activeElement,e[0].focus())),N(te,D.current)},onExited:r},se.default.createElement(ce.default,(0,oe.default)({},E,{style:v?(0,oe.default)({},p,G):G,v2:!0,ref:T,prefix:o,className:i,title:R,footer:H,footerAlign:F,footerActions:z,onOk:C?u:ye,onCancel:C?function(e){"function"==typeof d?d(e):a("cancelBtn",e)}:ye,okProps:W,cancelProps:V,locale:c,closeable:re,rtl:B,onClose:function(){for(var e=arguments.length,t=Array(e),n=0;n>6]+d[128|63&s]:s<55296||57344<=s?i+=d[224|s>>12]+d[128|s>>6&63]+d[128|63&s]:(l+=1,s=65536+((1023&s)<<10|1023&o.charCodeAt(l)),i+=d[240|s>>18]+d[128|s>>12&63]+d[128|s>>6&63]+d[128|63&s])}return i},isBuffer:function(e){return!(!e||"object"!=typeof e)&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},maybeMap:function(e,t){if(m(e)){for(var n=[],a=0;athis.popupNode.offsetWidth&&p(this.popupNode,"width",l.offsetWidth+"px"),"outside"!==a||"hoz"===r&&1===n||(p(this.popupNode,"height",u.offsetHeight+"px"),this.popupNode.firstElementChild&&p(this.popupNode.firstElementChild,"overflow-y","auto")),this.popupProps);d.onOpen&&d.onOpen()}catch(e){return null}},S.prototype.handlePopupClose=function(){var e=this.props.root.popupNodes,t=e.indexOf(this.popupNode),e=(-1t?r[t+1]:r[0])}),n[a]||(o=r[0]),i.onSort(a,o)},i.keydownHandler=function(e){e.preventDefault(),e.stopPropagation(),e.keyCode===l.KEYCODE.ENTER&&i.handleClick()},i.onSort=function(e,t){var n={};n[e]=t,i.props.onSort(e,t,n)},(0,o.default)(i,e)}i.displayName="Sort",t.default=i,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r=c(n(2)),a=c(n(4)),o=c(n(6)),i=c(n(7)),l=c(n(0)),s=c(n(3)),u=c(n(13)),d=c(n(387));function c(e){return e&&e.__esModule?e:{default:e}}f=l.default.Component,(0,i.default)(p,f),p.prototype.render=function(){var e=this.props,t=e.className,n=e.record,e=e.primaryKey,a=this.context.selectedRowKeys,n=(0,u.default)(((a={selected:-1e.slidesToShow&&(n=e.slideWidth*e.slidesToShow*-1,o=e.slideHeight*e.slidesToShow*-1),e.slideCount%e.slidesToScroll!=0&&(t=e.slideIndex+e.slidesToScroll>e.slideCount&&e.slideCount>e.slidesToShow,(t=e.rtl?(e.slideIndex>=e.slideCount?e.slideCount-e.slideIndex:e.slideIndex)+e.slidesToScroll>e.slideCount&&e.slideCount>e.slidesToShow:t)&&(o=e.slideIndex>e.slideCount?(n=(e.slidesToShow-(e.slideIndex-e.slideCount))*e.slideWidth*-1,(e.slidesToShow-(e.slideIndex-e.slideCount))*e.slideHeight*-1):(n=e.slideCount%e.slidesToScroll*e.slideWidth*-1,e.slideCount%e.slidesToScroll*e.slideHeight*-1)))):e.slideCount%e.slidesToScroll!=0&&e.slideIndex+e.slidesToScroll>e.slideCount&&e.slideCount>e.slidesToShow&&(n=(e.slidesToShow-e.slideCount%e.slidesToScroll)*e.slideWidth),e.centerMode&&(e.infinite?n+=e.slideWidth*Math.floor(e.slidesToShow/2):n=e.slideWidth*Math.floor(e.slidesToShow/2)),a=e.vertical?e.slideIndex*e.slideHeight*-1+o:e.slideIndex*e.slideWidth*-1+n,!0===e.variableWidth&&(t=void 0,a=(r=e.slideCount<=e.slidesToShow||!1===e.infinite?i.default.findDOMNode(e.trackRef).childNodes[e.slideIndex]:(t=e.slideIndex+e.slidesToShow,i.default.findDOMNode(e.trackRef).childNodes[t]))?-1*r.offsetLeft:0,!0===e.centerMode&&(r=!1===e.infinite?i.default.findDOMNode(e.trackRef).children[e.slideIndex]:i.default.findDOMNode(e.trackRef).children[e.slideIndex+e.slidesToShow+1])&&(a=-1*r.offsetLeft+(e.listWidth-r.offsetWidth)/2)),a)}},function(e,t,n){"use strict";t.__esModule=!0;var p=u(n(2)),h=u(n(12)),o=u(n(4)),i=u(n(6)),a=u(n(7)),m=u(n(0)),r=u(n(3)),g=u(n(13)),l=u(n(8)),y=u(n(25)),s=n(11);function u(e){return e&&e.__esModule?e:{default:e}}d=m.default.Component,(0,a.default)(c,d),c.prototype.render=function(){var e=this.props,t=e.title,n=e.children,a=e.className,r=e.isExpanded,o=e.disabled,i=e.style,l=e.prefix,s=e.onClick,u=e.id,e=(0,h.default)(e,["title","children","className","isExpanded","disabled","style","prefix","onClick","id"]),a=(0,g.default)(((d={})[l+"collapse-panel"]=!0,d[l+"collapse-panel-hidden"]=!r,d[l+"collapse-panel-expanded"]=r,d[l+"collapse-panel-disabled"]=o,d[a]=a,d)),d=(0,g.default)(((d={})[l+"collapse-panel-icon"]=!0,d[l+"collapse-panel-icon-expanded"]=r,d)),c=u?u+"-heading":void 0,f=u?u+"-region":void 0;return m.default.createElement("div",(0,p.default)({className:a,style:i,id:u},e),m.default.createElement("div",{id:c,className:l+"collapse-panel-title",onClick:s,onKeyDown:this.onKeyDown,tabIndex:"0","aria-disabled":o,"aria-expanded":r,"aria-controls":f,role:"button"},m.default.createElement(y.default,{type:"arrow-right",className:d,"aria-hidden":"true"}),t),m.default.createElement("div",{className:l+"collapse-panel-content",role:"region",id:f},n))},a=n=c,n.propTypes={prefix:r.default.string,style:r.default.object,children:r.default.any,isExpanded:r.default.bool,disabled:r.default.bool,title:r.default.node,className:r.default.string,onClick:r.default.func,id:r.default.string},n.defaultProps={prefix:"next-",isExpanded:!1,onClick:s.func.noop},n.isNextPanel=!0;var d,r=a;function c(){var e,n;(0,o.default)(this,c);for(var t=arguments.length,a=Array(t),r=0;r\n com.alibaba.nacos\n nacos-client\n ${version}\n \n*/\npackage com.alibaba.nacos.example;\n\nimport java.util.Properties;\nimport java.util.concurrent.Executor;\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.config.listener.Listener;\nimport com.alibaba.nacos.api.exception.NacosException;\n\n/**\n * Config service example\n *\n * @author Nacos\n *\n */\npublic class ConfigExample {\n\n\tpublic static void main(String[] args) throws NacosException, InterruptedException {\n\t\tString serverAddr = "localhost";\n\t\tString dataId = "'.concat(e.dataId,'";\n\t\tString group = "').concat(e.group,'";\n\t\tProperties properties = new Properties();\n\t\tproperties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);\n\t\tConfigService configService = NacosFactory.createConfigService(properties);\n\t\tString content = configService.getConfig(dataId, group, 5000);\n\t\tSystem.out.println(content);\n\t\tconfigService.addListener(dataId, group, new Listener() {\n\t\t\t@Override\n\t\t\tpublic void receiveConfigInfo(String configInfo) {\n\t\t\t\tSystem.out.println("recieve:" + configInfo);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Executor getExecutor() {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t});\n\n\t\tboolean isPublishOk = configService.publishConfig(dataId, group, "content");\n\t\tSystem.out.println(isPublishOk);\n\n\t\tThread.sleep(3000);\n\t\tcontent = configService.getConfig(dataId, group, 5000);\n\t\tSystem.out.println(content);\n\n\t\tboolean isRemoveOk = configService.removeConfig(dataId, group);\n\t\tSystem.out.println(isRemoveOk);\n\t\tThread.sleep(3000);\n\n\t\tcontent = configService.getConfig(dataId, group, 5000);\n\t\tSystem.out.println(content);\n\t\tThread.sleep(300000);\n\n\t}\n}\n')}},{key:"getNodejsCode",value:function(e){return"TODO"}},{key:"getCppCode",value:function(e){return"TODO"}},{key:"getShellCode",value:function(e){return"TODO"}},{key:"getPythonCode",value:function(e){return"TODO"}},{key:"getCSharpCode",value:function(e){return'/*\nDemo for Basic Nacos Opreation\nApp.csproj\n\n\n \n\n*/\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Nacos.V2;\nusing Nacos.V2.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nclass Program\n{\n static async Task Main(string[] args)\n {\n string serverAddr = "http://localhost:8848";\n string dataId = "'.concat(e.dataId,'";\n string group = "').concat(e.group,'";\n\n IServiceCollection services = new ServiceCollection();\n\n services.AddNacosV2Config(x =>\n {\n x.ServerAddresses = new List { serverAddr };\n x.Namespace = "cs-test";\n\n // swich to use http or rpc\n x.ConfigUseRpc = true;\n });\n\n IServiceProvider serviceProvider = services.BuildServiceProvider();\n var configSvc = serviceProvider.GetService();\n\n var content = await configSvc.GetConfig(dataId, group, 3000);\n Console.WriteLine(content);\n\n var listener = new ConfigListener();\n\n await configSvc.AddListener(dataId, group, listener);\n\n var isPublishOk = await configSvc.PublishConfig(dataId, group, "content");\n Console.WriteLine(isPublishOk);\n\n await Task.Delay(3000);\n content = await configSvc.GetConfig(dataId, group, 5000);\n Console.WriteLine(content);\n\n var isRemoveOk = await configSvc.RemoveConfig(dataId, group);\n Console.WriteLine(isRemoveOk);\n await Task.Delay(3000);\n\n content = await configSvc.GetConfig(dataId, group, 5000);\n Console.WriteLine(content);\n await Task.Delay(300000);\n }\n\n internal class ConfigListener : IListener\n {\n public void ReceiveConfigInfo(string configInfo)\n {\n Console.WriteLine("recieve:" + configInfo);\n }\n }\n}\n\n/*\nRefer to document: https://github.com/nacos-group/nacos-sdk-csharp/tree/dev/samples/MsConfigApp\nDemo for ASP.NET Core Integration\nMsConfigApp.csproj\n\n\n \n\n*/\n\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Serilog;\nusing Serilog.Events;\n\npublic class Program\n{\n public static void Main(string[] args)\n {\n Log.Logger = new LoggerConfiguration()\n .Enrich.FromLogContext()\n .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)\n .MinimumLevel.Override("System", LogEventLevel.Warning)\n .MinimumLevel.Debug()\n .WriteTo.Console()\n .CreateLogger();\n\n try\n {\n Log.ForContext().Information("Application starting...");\n CreateHostBuilder(args, Log.Logger).Build().Run();\n }\n catch (System.Exception ex)\n {\n Log.ForContext().Fatal(ex, "Application start-up failed!!");\n }\n finally\n {\n Log.CloseAndFlush();\n }\n }\n\n public static IHostBuilder CreateHostBuilder(string[] args, Serilog.ILogger logger) =>\n Host.CreateDefaultBuilder(args)\n .ConfigureAppConfiguration((context, builder) =>\n {\n var c = builder.Build();\n builder.AddNacosV2Configuration(c.GetSection("NacosConfig"), logAction: x => x.AddSerilog(logger));\n })\n .ConfigureWebHostDefaults(webBuilder =>\n {\n webBuilder.UseStartup().UseUrls("http://*:8787");\n })\n .UseSerilog();\n}\n ')}},{key:"openDialog",value:function(e){var t=this;this.setState({dialogvisible:!0}),this.record=e,setTimeout(function(){t.getData()})}},{key:"closeDialog",value:function(){this.setState({dialogvisible:!1})}},{key:"createCodeMirror",value:function(e,t){var n=this.refs.codepreview;n&&(n.innerHTML="",this.cm=window.CodeMirror(n,{value:t,mode:e,height:400,width:500,lineNumbers:!0,theme:"xq-light",lint:!0,tabMode:"indent",autoMatchParens:!0,textWrapping:!0,gutters:["CodeMirror-lint-markers"],extraKeys:{F1:function(e){e.setOption("fullScreen",!e.getOption("fullScreen"))},Esc:function(e){e.getOption("fullScreen")&&e.setOption("fullScreen",!1)}}}))}},{key:"changeTab",value:function(e,t){var n=this;setTimeout(function(){n[e]=!0,n.createCodeMirror("text/javascript",t)})}},{key:"render",value:function(){var e=this.props.locale,e=void 0===e?{}:e;return x.a.createElement("div",null,x.a.createElement(y.a,{title:e.sampleCode,style:{width:"80%"},visible:this.state.dialogvisible,footer:x.a.createElement("div",null),onClose:this.closeDialog.bind(this)},x.a.createElement("div",{style:{height:500}},x.a.createElement(A.a,{tip:e.loading,style:{width:"100%"},visible:this.state.loading},x.a.createElement(D.a,{shape:"text",style:{height:40,paddingBottom:10}},x.a.createElement(O,{title:"Java",key:1,onClick:this.changeTab.bind(this,"commoneditor1",this.defaultCode)}),x.a.createElement(O,{title:"Spring Boot",key:2,onClick:this.changeTab.bind(this,"commoneditor2",this.sprigboot_code)}),x.a.createElement(O,{title:"Spring Cloud",key:21,onClick:this.changeTab.bind(this,"commoneditor21",this.sprigcloud_code)}),x.a.createElement(O,{title:"Node.js",key:3,onClick:this.changeTab.bind(this,"commoneditor3",this.nodejsCode)}),x.a.createElement(O,{title:"C++",key:4,onClick:this.changeTab.bind(this,"commoneditor4",this.cppCode)}),x.a.createElement(O,{title:"Shell",key:5,onClick:this.changeTab.bind(this,"commoneditor5",this.shellCode)}),x.a.createElement(O,{title:"Python",key:6,onClick:this.changeTab.bind(this,"commoneditor6",this.pythonCode)}),x.a.createElement(O,{title:"C#",key:7,onClick:this.changeTab.bind(this,"commoneditor7",this.csharpCode)})),x.a.createElement("div",{ref:"codepreview"})))))}}]),n}(x.a.Component)).displayName="ShowCodeing",S=S))||S,S=(t(66),t(41)),S=t.n(S),F=(t(704),S.a.Row),N=S.a.Col,z=(0,n.a.config)(((S=function(e){Object(M.a)(n,e);var t=Object(k.a)(n);function n(e){return Object(_.a)(this,n),(e=t.call(this,e)).state={visible:!1,title:"",content:"",isok:!0,dataId:"",group:""},e}return Object(b.a)(n,[{key:"componentDidMount",value:function(){this.initData()}},{key:"initData",value:function(){var e=this.props.locale;this.setState({title:(void 0===e?{}:e).confManagement})}},{key:"openDialog",value:function(e){this.setState({visible:!0,title:e.title,content:e.content,isok:e.isok,dataId:e.dataId,group:e.group,message:e.message})}},{key:"closeDialog",value:function(){this.setState({visible:!1})}},{key:"render",value:function(){var e=this.props.locale,e=void 0===e?{}:e,t=x.a.createElement("div",{style:{textAlign:"right"}},x.a.createElement(d.a,{type:"primary",onClick:this.closeDialog.bind(this)},e.determine));return x.a.createElement("div",null,x.a.createElement(y.a,{visible:this.state.visible,footer:t,style:{width:555},onCancel:this.closeDialog.bind(this),onClose:this.closeDialog.bind(this),title:e.deletetitle},x.a.createElement("div",null,x.a.createElement(F,null,x.a.createElement(N,{span:"4",style:{paddingTop:16}},x.a.createElement(m.a,{type:"".concat(this.state.isok?"success":"delete","-filling"),style:{color:this.state.isok?"green":"red"},size:"xl"})),x.a.createElement(N,{span:"20"},x.a.createElement("div",null,x.a.createElement("h3",null,this.state.isok?e.deletedSuccessfully:e.deleteFailed),x.a.createElement("p",null,x.a.createElement("span",{style:{color:"#999",marginRight:5}},"Data ID"),x.a.createElement("span",{style:{color:"#c7254e"}},this.state.dataId)),x.a.createElement("p",null,x.a.createElement("span",{style:{color:"#999",marginRight:5}},"Group"),x.a.createElement("span",{style:{color:"#c7254e"}},this.state.group)),this.state.isok?"":x.a.createElement("p",{style:{color:"red"}},this.state.message)))))))}}]),n}(x.a.Component)).displayName="DeleteDialog",S=S))||S,S=(t(705),t(413)),W=t.n(S),V=(0,n.a.config)(((S=function(e){Object(M.a)(n,e);var t=Object(k.a)(n);function n(){return Object(_.a)(this,n),t.apply(this,arguments)}return Object(b.a)(n,[{key:"render",value:function(){var e=this.props,t=e.data,t=void 0===t?{}:t,n=e.height,e=e.locale,a=void 0===e?{}:e;return x.a.createElement("div",null,"notice"===t.modeType?x.a.createElement("div",{"data-spm-click":"gostr=/aliyun;locaid=notice"},x.a.createElement(W.a,{style:{marginBottom:1\n com.alibaba.nacos\n nacos-client\n ${latest.version}\n \n*/\npackage com.alibaba.nacos.example;\n\nimport java.util.Properties;\n\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingFactory;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.listener.Event;\nimport com.alibaba.nacos.api.naming.listener.EventListener;\nimport com.alibaba.nacos.api.naming.listener.NamingEvent;\n\n/**\n * @author nkorange\n */\npublic class NamingExample {\n\n public static void main(String[] args) throws NacosException {\n\n Properties properties = new Properties();\n properties.setProperty("serverAddr", System.getProperty("serverAddr"));\n properties.setProperty("namespace", System.getProperty("namespace"));\n\n NamingService naming = NamingFactory.createNamingService(properties);\n\n naming.registerInstance("'.concat(this.record.name,'", "11.11.11.11", 8888, "TEST1");\n\n naming.registerInstance("').concat(this.record.name,'", "2.2.2.2", 9999, "DEFAULT");\n\n System.out.println(naming.getAllInstances("').concat(this.record.name,'"));\n\n naming.deregisterInstance("').concat(this.record.name,'", "2.2.2.2", 9999, "DEFAULT");\n\n System.out.println(naming.getAllInstances("').concat(this.record.name,'"));\n\n naming.subscribe("').concat(this.record.name,'", new EventListener() {\n @Override\n public void onEvent(Event event) {\n System.out.println(((NamingEvent)event).getServiceName());\n System.out.println(((NamingEvent)event).getInstances());\n }\n });\n }\n}')}},{key:"getSpringCode",value:function(e){return'/* Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-example/nacos-spring-discovery-example\n* pom.xml\n \n com.alibaba.nacos\n nacos-spring-context\n ${latest.version}\n \n*/\n\n// Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-example/nacos-spring-discovery-example/src/main/java/com/alibaba/nacos/example/spring\npackage com.alibaba.nacos.example.spring;\n\nimport com.alibaba.nacos.api.annotation.NacosProperties;\nimport com.alibaba.nacos.spring.context.annotation.discovery.EnableNacosDiscovery;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\n@EnableNacosDiscovery(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))\npublic class NacosConfiguration {\n\n}\n\n// Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-example/nacos-spring-discovery-example/src/main/java/com/alibaba/nacos/example/spring/controller\npackage com.alibaba.nacos.example.spring.controller;\n\nimport com.alibaba.nacos.api.annotation.NacosInjected;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\nimport static org.springframework.web.bind.annotation.RequestMethod.GET;\n\n@Controller\n@RequestMapping("discovery")\npublic class DiscoveryController {\n\n @NacosInjected\n private NamingService namingService;\n\n @RequestMapping(value = "/get", method = GET)\n @ResponseBody\n public List get(@RequestParam String serviceName) throws NacosException {\n return namingService.getAllInstances(serviceName);\n }\n}'}},{key:"getSpringBootCode",value:function(e){return'/* Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-boot-example/nacos-spring-boot-discovery-example\n* pom.xml\n \n com.alibaba.boot\n nacos-discovery-spring-boot-starter\n ${latest.version}\n \n*/\n/* Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-boot-example/nacos-spring-boot-discovery-example/src/main/resources\n* application.properties\n nacos.discovery.server-addr=127.0.0.1:8848\n*/\n// Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-boot-example/nacos-spring-boot-discovery-example/src/main/java/com/alibaba/nacos/example/spring/boot/controller\n\npackage com.alibaba.nacos.example.spring.boot.controller;\n\nimport com.alibaba.nacos.api.annotation.NacosInjected;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\nimport static org.springframework.web.bind.annotation.RequestMethod.GET;\n\n@Controller\n@RequestMapping("discovery")\npublic class DiscoveryController {\n\n @NacosInjected\n private NamingService namingService;\n\n @RequestMapping(value = "/get", method = GET)\n @ResponseBody\n public List get(@RequestParam String serviceName) throws NacosException {\n return namingService.getAllInstances(serviceName);\n }\n}'}},{key:"getSpringCloudCode",value:function(e){return"/* Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/\n* pom.xml\n \n org.springframework.cloud\n spring-cloud-starter-alibaba-nacos-discovery\n ${latest.version}\n \n*/\n\n// nacos-spring-cloud-provider-example\n\n/* Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/nacos-spring-cloud-provider-example/src/main/resources\n* application.properties\nserver.port=18080\nspring.application.name=".concat(this.record.name,'\nspring.cloud.nacos.discovery.server-addr=127.0.0.1:8848\n*/\n\n// Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/nacos-spring-cloud-provider-example/src/main/java/com/alibaba/nacos/example/spring/cloud\npackage com.alibaba.nacos.example.spring.cloud;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.discovery.EnableDiscoveryClient;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * @author xiaojing\n */\n@SpringBootApplication\n@EnableDiscoveryClient\npublic class NacosProviderApplication {\n\n public static void main(String[] args) {\n SpringApplication.run(NacosProviderApplication.class, args);\n}\n\n @RestController\n class EchoController {\n @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)\n public String echo(@PathVariable String string) {\n return "Hello Nacos Discovery " + string;\n }\n }\n}\n\n// nacos-spring-cloud-consumer-example\n\n/* Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/nacos-spring-cloud-consumer-example/src/main/resources\n* application.properties\nspring.application.name=micro-service-oauth2\nspring.cloud.nacos.discovery.server-addr=127.0.0.1:8848\n*/\n\n// Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/nacos-spring-cloud-consumer-example/src/main/java/com/alibaba/nacos/example/spring/cloud\npackage com.alibaba.nacos.example.spring.cloud;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.discovery.EnableDiscoveryClient;\nimport org.springframework.cloud.client.loadbalancer.LoadBalanced;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * @author xiaojing\n */\n@SpringBootApplication\n@EnableDiscoveryClient\npublic class NacosConsumerApplication {\n\n @LoadBalanced\n @Bean\n public RestTemplate restTemplate() {\n return new RestTemplate();\n }\n\n public static void main(String[] args) {\n SpringApplication.run(NacosConsumerApplication.class, args);\n }\n\n @RestController\n public class TestController {\n\n private final RestTemplate restTemplate;\n\n @Autowired\n public TestController(RestTemplate restTemplate) {this.restTemplate = restTemplate;}\n\n @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)\n public String echo(@PathVariable String str) {\n return restTemplate.getForObject("http://service-provider/echo/" + str, String.class);\n }\n }\n}')}},{key:"getNodejsCode",value:function(e){return"TODO"}},{key:"getCppCode",value:function(e){return"TODO"}},{key:"getShellCode",value:function(e){return"TODO"}},{key:"getPythonCode",value:function(e){return"TODO"}},{key:"getCSharpCode",value:function(e){return'/* Refer to document: https://github.com/nacos-group/nacos-sdk-csharp/\nDemo for Basic Nacos Opreation\nApp.csproj\n\n\n \n\n*/\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Nacos.V2;\nusing Nacos.V2.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nclass Program\n{\n static async Task Main(string[] args)\n {\n IServiceCollection services = new ServiceCollection();\n\n services.AddNacosV2Naming(x =>\n {\n x.ServerAddresses = new List { "http://localhost:8848/" };\n x.Namespace = "cs-test";\n\n // swich to use http or rpc\n x.NamingUseRpc = true;\n });\n\n IServiceProvider serviceProvider = services.BuildServiceProvider();\n var namingSvc = serviceProvider.GetService();\n\n await namingSvc.RegisterInstance("'.concat(this.record.name,'", "11.11.11.11", 8888, "TEST1");\n\n await namingSvc.RegisterInstance("').concat(this.record.name,'", "2.2.2.2", 9999, "DEFAULT");\n\n Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(await namingSvc.GetAllInstances("').concat(this.record.name,'")));\n\n await namingSvc.DeregisterInstance("').concat(this.record.name,'", "2.2.2.2", 9999, "DEFAULT");\n\n var listener = new EventListener();\n\n await namingSvc.Subscribe("').concat(this.record.name,'", listener);\n }\n\n internal class EventListener : IEventListener\n {\n public Task OnEvent(IEvent @event)\n {\n Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(@event));\n return Task.CompletedTask;\n }\n }\n}\n\n/* Refer to document: https://github.com/nacos-group/nacos-sdk-csharp/\nDemo for ASP.NET Core Integration\nApp.csproj\n\n\n \n\n*/\n\n/* Refer to document: https://github.com/nacos-group/nacos-sdk-csharp/blob/dev/samples/App1/appsettings.json\n* appsettings.json\n{\n "nacos": {\n "ServerAddresses": [ "http://localhost:8848" ],\n "DefaultTimeOut": 15000,\n "Namespace": "cs",\n "ServiceName": "App1",\n "GroupName": "DEFAULT_GROUP",\n "ClusterName": "DEFAULT",\n "Port": 0,\n "Weight": 100,\n "RegisterEnabled": true,\n "InstanceEnabled": true,\n "Ephemeral": true,\n "NamingUseRpc": true,\n "NamingLoadCacheAtStart": ""\n }\n}\n*/\n\n// Refer to document: https://github.com/nacos-group/nacos-sdk-csharp/blob/dev/samples/App1/Startup.cs\nusing Nacos.AspNetCore.V2;\n\npublic class Startup\n{\n public Startup(IConfiguration configuration)\n {\n Configuration = configuration;\n }\n\n public IConfiguration Configuration { get; }\n\n public void ConfigureServices(IServiceCollection services)\n {\n // ....\n services.AddNacosAspNet(Configuration);\n }\n\n public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n {\n // ....\n }\n}\n ')}},{key:"openDialog",value:function(e){var t=this;this.setState({dialogvisible:!0}),this.record=e,setTimeout(function(){t.getData()})}},{key:"closeDialog",value:function(){this.setState({dialogvisible:!1})}},{key:"createCodeMirror",value:function(e,t){var n=this.refs.codepreview;n&&(n.innerHTML="",this.cm=window.CodeMirror(n,{value:t,mode:e,height:400,width:500,lineNumbers:!0,theme:"xq-light",lint:!0,tabMode:"indent",autoMatchParens:!0,textWrapping:!0,gutters:["CodeMirror-lint-markers"],extraKeys:{F1:function(e){e.setOption("fullScreen",!e.getOption("fullScreen"))},Esc:function(e){e.getOption("fullScreen")&&e.setOption("fullScreen",!1)}}}),this.cm.setSize("auto","490px"))}},{key:"changeTab",value:function(e,t){var n=this;setTimeout(function(){n[e]=!0,n.createCodeMirror("text/javascript",t)})}},{key:"render",value:function(){var e=this.props.locale,e=void 0===e?{}:e;return L.a.createElement("div",null,L.a.createElement(o.a,{title:e.sampleCode,style:{width:"80%"},visible:this.state.dialogvisible,footer:L.a.createElement("div",null),onClose:this.closeDialog.bind(this)},L.a.createElement("div",{style:{height:500}},L.a.createElement(h.a,{tip:e.loading,style:{width:"100%"},visible:this.state.loading},L.a.createElement(m.a,{shape:"text",style:{height:40,paddingBottom:10}},L.a.createElement(g,{title:"Java",key:0,onClick:this.changeTab.bind(this,"commoneditor1",this.defaultCode)}),L.a.createElement(g,{title:"Spring",key:1,onClick:this.changeTab.bind(this,"commoneditor1",this.springCode)}),L.a.createElement(g,{title:"Spring Boot",key:2,onClick:this.changeTab.bind(this,"commoneditor2",this.sprigbootCode)}),L.a.createElement(g,{title:"Spring Cloud",key:21,onClick:this.changeTab.bind(this,"commoneditor21",this.sprigcloudCode)}),L.a.createElement(g,{title:"Node.js",key:3,onClick:this.changeTab.bind(this,"commoneditor3",this.nodejsCode)}),L.a.createElement(g,{title:"C++",key:4,onClick:this.changeTab.bind(this,"commoneditor4",this.cppCode)}),L.a.createElement(g,{title:"Shell",key:5,onClick:this.changeTab.bind(this,"commoneditor5",this.shellCode)}),L.a.createElement(g,{title:"Python",key:6,onClick:this.changeTab.bind(this,"commoneditor6",this.pythonCode)}),L.a.createElement(g,{title:"C#",key:7,onClick:this.changeTab.bind(this,"commoneditor7",this.csharpCode)})),L.a.createElement("div",{ref:"codepreview"})))))}}]),n}(L.a.Component)).displayName="ShowServiceCodeing",f=f))||f,P=t(69),j=(t(726),t(24)),Y=C.a.Item,I=a.a.Row,R=a.a.Col,A=x.a.Column,a=(0,n.a.config)(((f=function(e){Object(d.a)(a,e);var t=Object(c.a)(a);function a(e){var n;return Object(l.a)(this,a),(n=t.call(this,e)).getQueryLater=function(){setTimeout(function(){return n.queryServiceList()})},n.showcode=function(){setTimeout(function(){return n.queryServiceList()})},n.setNowNameSpace=function(e,t){return n.setState({nowNamespaceName:e,nowNamespaceId:t})},n.rowColor=function(e){return{className:e.healthyInstanceCount?"":"row-bg-red"}},n.editServiceDialog=L.a.createRef(),n.showcode=L.a.createRef(),n.state={loading:!1,total:0,pageSize:10,currentPage:1,dataSource:[],search:{serviceName:Object(p.a)("serviceNameParam")||"",groupName:Object(p.a)("groupNameParam")||""},hasIpCount:!("false"===localStorage.getItem("hasIpCount"))},n.field=new i.a(Object(u.a)(n)),n}return Object(s.a)(a,[{key:"openLoading",value:function(){this.setState({loading:!0})}},{key:"closeLoading",value:function(){this.setState({loading:!1})}},{key:"openEditServiceDialog",value:function(){try{this.editServiceDialog.current.getInstance().show(this.state.service)}catch(e){}}},{key:"queryServiceList",value:function(){var n=this,e=this.state,t=e.currentPage,a=e.pageSize,r=e.search,o=e.withInstances,o=void 0!==o&&o,e=e.hasIpCount,e=["hasIpCount=".concat(e),"withInstances=".concat(o),"pageNo=".concat(t),"pageSize=".concat(a),"serviceNameParam=".concat(r.serviceName),"groupNameParam=".concat(r.groupName)];Object(p.d)({serviceNameParam:r.serviceName,groupNameParam:r.groupName}),this.openLoading(),Object(p.c)({url:"v1/ns/catalog/services?".concat(e.join("&")),success:function(){var e=0o&&v.a.createElement(u.a,{className:"users-pagination",current:i,total:n.totalCount,pageSize:o,onChange:function(e){return t.setState({pageNo:e},function(){return t.getUsers()})}}),v.a.createElement(E,{visible:l,onOk:function(e){return Object(_.c)(e).then(function(e){return t.setState({pageNo:1},function(){return t.getUsers()}),e})},onCancel:function(){return t.colseCreateUser()}}),v.a.createElement(x.a,{visible:s,username:e,onOk:function(e){return Object(_.k)(e).then(function(e){return t.getUsers(),e})},onCancel:function(){return t.setState({passwordResetUser:void 0,passwordResetUserVisible:!1})}}))}}]),n}(v.a.Component)).displayName="UserManagement",n=o))||n)||n;t.a=r},function(e,t,n){"use strict";n(64);var a=n(46),s=n.n(a),a=(n(35),n(18)),u=n.n(a),d=n(31),a=(n(63),n(20)),c=n.n(a),a=(n(32),n(19)),f=n.n(a),a=(n(88),n(53)),p=n.n(a),a=(n(39),n(5)),h=n.n(a),a=(n(36),n(10)),m=n.n(a),i=n(14),l=n(15),g=n(22),y=n(17),v=n(16),a=(n(27),n(8)),a=n.n(a),r=n(0),_=n.n(r),r=n(37),b=n(45),o=n(83),w=n(48),M=(n(49),n(28)),k=n.n(M),M=(n(59),n(29)),S=n.n(M),E=h.a.Item,x=S.a.Option,C={labelCol:{fixedSpan:4},wrapperCol:{span:19}},L=Object(r.b)(function(e){return{namespaces:e.namespace.namespaces}},{getNamespaces:o.b,searchRoles:b.l})(M=(0,a.a.config)(((M=function(e){Object(y.a)(o,e);var r=Object(v.a)(o);function o(){var t;Object(i.a)(this,o);for(var e=arguments.length,n=new Array(e),a=0;ai&&_.a.createElement(s.a,{className:"users-pagination",current:l,total:t.totalCount,pageSize:i,onChange:function(e){return a.setState({pageNo:e},function(){return a.getPermissions()})}}),_.a.createElement(L,{visible:n,onOk:function(e){return Object(b.a)(e).then(function(e){return a.setState({pageNo:1},function(){return a.getPermissions()}),e})},onCancel:function(){return a.colseCreatePermission()}}))}}]),n}(_.a.Component)).displayName="PermissionsManagement",n=M))||n)||n);t.a=r},function(e,t,n){"use strict";n(64);var a=n(46),s=n.n(a),a=(n(35),n(18)),u=n.n(a),a=(n(63),n(20)),d=n.n(a),a=(n(32),n(19)),c=n.n(a),a=(n(88),n(53)),f=n.n(a),a=(n(39),n(5)),p=n.n(a),a=(n(36),n(10)),h=n.n(a),i=n(14),l=n(15),m=n(22),g=n(17),y=n(16),a=(n(27),n(8)),a=n.n(a),r=n(0),v=n.n(r),r=n(37),_=n(45),b=n(48),o=(n(59),n(29)),w=n.n(o),o=(n(49),n(28)),M=n.n(o),k=p.a.Item,S={labelCol:{fixedSpan:4},wrapperCol:{span:19}},E=Object(r.b)(function(e){return{users:e.authority.users}},{searchUsers:_.m})(o=(0,a.a.config)(((o=function(e){Object(g.a)(o,e);var r=Object(y.a)(o);function o(){var t;Object(i.a)(this,o);for(var e=arguments.length,n=new Array(e),a=0;ao&&v.a.createElement(s.a,{className:"users-pagination",current:i,total:t.totalCount,pageSize:o,onChange:function(e){return a.setState({pageNo:e},function(){return a.getRoles()})}}),v.a.createElement(E,{visible:l,onOk:function(e){return Object(_.b)(e).then(function(e){return a.getRoles(),e})},onCancel:function(){return a.colseCreateRole()}}))}}]),n}(v.a.Component)).displayName="RolesManagement",n=o))||n)||n);t.a=r},function(e,t,n){"use strict";n(50);function o(e){var t=void 0===(t=localStorage.token)?"{}":t,t=(Object(v.c)(t)&&JSON.parse(t)||{}).globalAdmin,n=[];return"naming"===e?n.push(_):"config"===e?n.push(b):n.push(b,_),t&&n.push(w),n.push(M),n.push(k),n.filter(function(e){return e})}var a=n(26),i=n.n(a),a=(n(43),n(25)),l=n.n(a),r=n(14),s=n(15),u=n(17),d=n(16),a=(n(27),n(8)),a=n.n(a),c=n(21),f=(n(81),n(51)),p=n.n(f),f=n(0),h=n.n(f),f=n(40),m=n(37),g=n(133),y=n(74),v=n(47),_={key:"serviceManagementVirtual",children:[{key:"serviceManagement",url:"/serviceManagement"},{key:"subscriberList",url:"/subscriberList"}]},b={key:"configurationManagementVirtual",children:[{key:"configurationManagement",url:"/configurationManagement"},{key:"historyRollback",url:"/historyRollback"},{key:"listeningToQuery",url:"/listeningToQuery"}]},w={key:"authorityControl",children:[{key:"userList",url:"/userManagement"},{key:"roleManagement",url:"/rolesManagement"},{key:"privilegeManagement",url:"/permissionsManagement"}]},M={key:"namespace",url:"/namespace"},k={key:"clusterManagementVirtual",children:[{key:"clusterManagement",url:"/clusterManagement"}]},S=p.a.SubMenu,E=p.a.Item,f=(n=Object(m.b)(function(e){return Object(c.a)(Object(c.a)({},e.locale),e.base)},{getState:y.c,getNotice:y.b}),m=a.a.config,Object(f.g)(a=n(a=m(((y=function(e){Object(u.a)(n,e);var t=Object(d.a)(n);function n(){return Object(r.a)(this,n),t.apply(this,arguments)}return Object(s.a)(n,[{key:"componentDidMount",value:function(){this.props.getState(),this.props.getNotice()}},{key:"goBack",value:function(){this.props.history.goBack()}},{key:"navTo",value:function(e){var t=this.props.location.search,t=new URLSearchParams(t);t.set("namespace",window.nownamespace),t.set("namespaceShowName",window.namespaceShowName),this.props.history.push([e,"?",t.toString()].join(""))}},{key:"isCurrentPath",value:function(e){return e===this.props.location.pathname?"current-path next-selected":void 0}},{key:"defaultOpenKeys",value:function(){for(var t=this,e=o(this.props.functionMode),n=0,a=e.length;nthis.state.pageSize&&M.a.createElement("div",{style:{marginTop:10,textAlign:"right"}},M.a.createElement(g.a,{current:this.state.pageNo,total:a,pageSize:this.state.pageSize,onChange:function(e){return t.setState({pageNo:e},function(){return t.querySubscriberList()})}}))))}}]),a}(M.a.Component)).displayName="SubscriberList",c=n))||c)||c;t.a=f},function(e,t,n){"use strict";n(52);var a=n(33),c=n.n(a),a=(n(64),n(46)),f=n.n(a),a=(n(173),n(75)),p=n.n(a),a=(n(36),n(10)),h=n.n(a),a=(n(32),n(19)),m=n.n(a),a=(n(35),n(18)),r=n.n(a),a=(n(49),n(28)),o=n.n(a),i=n(14),l=n(15),s=n(22),u=n(17),d=n(16),a=(n(27),n(8)),a=n.n(a),g=(n(398),n(115)),y=n.n(g),g=(n(63),n(20)),v=n.n(g),g=(n(66),n(41)),g=n.n(g),_=(n(39),n(5)),b=n.n(_),_=n(0),w=n.n(_),M=n(1),k=n(48),_=n(135),S=n.n(_),E=n(69),x=(n(729),b.a.Item),C=g.a.Row,L=g.a.Col,T=v.a.Column,D=y.a.Panel,g=(0,a.a.config)(((_=function(e){Object(u.a)(a,e);var t=Object(d.a)(a);function a(e){var n;return Object(i.a)(this,a),(n=t.call(this,e)).getQueryLater=function(){setTimeout(function(){return n.queryClusterStateList()})},n.setNowNameSpace=function(e,t){return n.setState({nowNamespaceName:e,nowNamespaceId:t})},n.rowColor=function(e){return{className:(e.voteFor,"")}},n.state={loading:!1,total:0,pageSize:10,currentPage:1,keyword:"",dataSource:[]},n.field=new o.a(Object(s.a)(n)),n}return Object(l.a)(a,[{key:"openLoading",value:function(){this.setState({loading:!0})}},{key:"closeLoading",value:function(){this.setState({loading:!1})}},{key:"openEditServiceDialog",value:function(){try{this.editServiceDialog.current.getInstance().show(this.state.service)}catch(e){}}},{key:"queryClusterStateList",value:function(){var n=this,e=this.state,t=e.currentPage,a=e.pageSize,r=e.keyword,e=e.withInstances,e=["withInstances=".concat(void 0!==e&&e),"pageNo=".concat(t),"pageSize=".concat(a),"keyword=".concat(r)];Object(M.c)({url:"v1/core/cluster/nodes?".concat(e.join("&")),beforeSend:function(){return n.openLoading()},success:function(){var e=0this.state.pageSize&&w.a.createElement("div",{style:{marginTop:10,textAlign:"right"}},w.a.createElement(f.a,{current:this.state.currentPage,total:this.state.total,pageSize:this.state.pageSize,onChange:function(e){return t.setState({currentPage:e},function(){return t.queryClusterStateList()})}}))))}}]),a}(w.a.Component)).displayName="ClusterNodeList",n=_))||n;t.a=g},function(e,t,z){"use strict";z.r(t),function(e){z(52);var t=z(33),a=z.n(t),t=(z(27),z(8)),r=z.n(t),o=z(14),i=z(15),l=z(17),s=z(16),n=z(21),t=z(0),u=z.n(t),t=z(23),t=z.n(t),d=z(117),c=z(406),f=z(417),p=z(37),h=z(40),m=z(82),g=(z(452),z(426)),y=z(24),v=z(427),_=z(420),b=z(428),w=z(429),M=z(421),k=z(430),S=z(431),E=z(432),x=z(433),C=z(434),L=z(418),T=z(422),D=z(419),O=z(435),N=z(436),P=z(423),j=z(424),I=z(425),R=z(415),Y=z(416),A=z(104),H=z(74),e=(z(732),e.hot,localStorage.getItem(y.g)||localStorage.setItem(y.g,"zh-CN"===navigator.language?"zh-CN":"en-US"),Object(d.b)(Object(n.a)(Object(n.a)({},Y.a),{},{routing:c.routerReducer}))),Y=Object(d.d)(e,Object(d.c)(Object(d.a)(f.a),window[y.k]?window[y.k]():function(e){return e})),F=[{path:"/",exact:!0,render:function(){return u.a.createElement(h.a,{to:"/welcome"})}},{path:"/welcome",component:R.a},{path:"/namespace",component:_.a},{path:"/newconfig",component:b.a},{path:"/configsync",component:w.a},{path:"/configdetail",component:M.a},{path:"/configeditor",component:k.a},{path:"/historyDetail",component:S.a},{path:"/configRollback",component:E.a},{path:"/historyRollback",component:x.a},{path:"/listeningToQuery",component:C.a},{path:"/configurationManagement",component:L.a},{path:"/serviceManagement",component:T.a},{path:"/serviceDetail",component:D.a},{path:"/subscriberList",component:O.a},{path:"/clusterManagement",component:N.a},{path:"/userManagement",component:P.a},{path:"/rolesManagement",component:I.a},{path:"/permissionsManagement",component:j.a}],e=Object(p.b)(function(e){return Object(n.a)(Object(n.a)({},e.locale),e.base)},{changeLanguage:A.a,getState:H.c})(c=function(e){Object(l.a)(n,e);var t=Object(s.a)(n);function n(e){return Object(o.a)(this,n),(e=t.call(this,e)).state={shownotice:"none",noticecontent:"",nacosLoading:{}},e}return Object(i.a)(n,[{key:"componentDidMount",value:function(){this.props.getState();var e=localStorage.getItem(y.g);this.props.changeLanguage(e)}},{key:"router",get:function(){var e=this.props.loginPageEnabled;return u.a.createElement(m.a,null,u.a.createElement(h.d,null,e&&"false"===e?null:u.a.createElement(h.b,{path:"/login",component:v.a}),u.a.createElement(g.a,null,F.map(function(e){return u.a.createElement(h.b,Object.assign({key:e.path},e))}))))}},{key:"render",value:function(){var e=this.props,t=e.locale,e=e.loginPageEnabled;return u.a.createElement(a.a,Object.assign({className:"nacos-loading",shape:"flower",tip:"loading...",visible:!e,fullScreen:!0},this.state.nacosLoading),u.a.createElement(r.a,{locale:t},this.router))}}]),n}(u.a.Component))||c;t.a.render(u.a.createElement(p.a,{store:Y},u.a.createElement(e,null)),document.getElementById("root"))}.call(this,z(438)(e))},function(e,t){e.exports=function(e){var t;return e.webpackPolyfill||((t=Object.create(e)).children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),Object.defineProperty(t,"exports",{enumerable:!0}),t.webpackPolyfill=1),t}},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(I,e,t){"use strict"; +var t;e.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){if(e===12)e=0;if(t==="凌晨"||t==="早上"||t==="上午")return e;else if(t==="中午")return e>=11?e:e+12;else if(t==="下午"||t==="晚上")return e+12},meridiem:function(e,t,n){var a=e*100+t;if(a<600)return"凌晨";else if(a<900)return"早上";else if(a<1130)return"上午";else if(a<1230)return"中午";else if(a<1800)return"下午";else return"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(n(9))},function(e,t,n){"use strict";t.__esModule=!0;var u=p(n(2)),a=p(n(4)),r=p(n(6)),o=p(n(7)),i=n(0),d=p(i),l=p(n(3)),c=p(n(13)),s=p(n(8)),f=n(11);function p(e){return e&&e.__esModule?e:{default:e}}h=i.Component,(0,o.default)(m,h),m.prototype.render=function(){var e,t=this.props,n=t.prefix,a=t.type,r=t.size,o=t.className,i=t.rtl,l=t.style,t=t.children,s=f.obj.pickOthers((0,u.default)({},m.propTypes),this.props),n=(0,c.default)(((e={})[n+"icon"]=!0,e[n+"icon-"+a]=!!a,e[""+n+r]=!!r&&"string"==typeof r,e[o]=!!o,e)),o=(i&&-1!==["arrow-left","arrow-right","arrow-double-left","arrow-double-right","switch","sorting","descending","ascending"].indexOf(a)&&(s.dir="rtl"),"number"==typeof r?{width:r,height:r,lineHeight:r+"px",fontSize:r}:{});return d.default.createElement("i",(0,u.default)({},s,{style:(0,u.default)({},o,l),className:n}),t)},i=n=m,n.propTypes=(0,u.default)({},s.default.propTypes,{type:l.default.string,children:l.default.node,size:l.default.oneOfType([l.default.oneOf(["xxs","xs","small","medium","large","xl","xxl","xxxl","inherit"]),l.default.number]),className:l.default.string,style:l.default.object}),n.defaultProps={prefix:"next-",size:"medium"},n._typeMark="icon";var h,o=i;function m(){return(0,a.default)(this,m),(0,r.default)(this,h.apply(this,arguments))}o.displayName="Icon",t.default=o,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0;var g=s(n(2)),y=s(n(12)),a=s(n(38)),r=s(n(4)),o=s(n(6)),i=s(n(7)),v=n(0),_=s(v),l=s(n(3)),b=n(155),w=s(n(519));function s(e){return e&&e.__esModule?e:{default:e}}function u(){}function M(e){return _.default.Children.toArray(e.children)[0]||null}d=v.Component,(0,i.default)(c,d),c.prototype.normalizeNames=function(e){return"string"==typeof e?{appear:e+"-appear",appearActive:e+"-appear-active",enter:e+"-enter",enterActive:e+"-enter-active",leave:e+"-leave",leaveActive:e+"-leave-active"}:"object"===(void 0===e?"undefined":(0,a.default)(e))?{appear:e.appear,appearActive:e.appear+"-active",enter:""+e.enter,enterActive:e.enter+"-active",leave:""+e.leave,leaveActive:e.leave+"-active"}:void 0},c.prototype.render=function(){var t=this,e=this.props,n=e.animation,a=e.children,r=e.animationAppear,o=e.singleMode,i=e.component,l=e.beforeAppear,s=e.onAppear,u=e.afterAppear,d=e.beforeEnter,c=e.onEnter,f=e.afterEnter,p=e.beforeLeave,h=e.onLeave,m=e.afterLeave,e=(0,y.default)(e,["animation","children","animationAppear","singleMode","component","beforeAppear","onAppear","afterAppear","beforeEnter","onEnter","afterEnter","beforeLeave","onLeave","afterLeave"]),a=v.Children.map(a,function(e){return _.default.createElement(w.default,{key:e.key,names:t.normalizeNames(n),onAppear:l,onAppearing:s,onAppeared:u,onEnter:d,onEntering:c,onEntered:f,onExit:p,onExiting:h,onExited:m},e)});return _.default.createElement(b.TransitionGroup,(0,g.default)({appear:r,component:o?M:i},e),a)},i=n=c,n.propTypes={animation:l.default.oneOfType([l.default.string,l.default.object]),animationAppear:l.default.bool,component:l.default.any,singleMode:l.default.bool,children:l.default.oneOfType([l.default.element,l.default.arrayOf(l.default.element)]),beforeAppear:l.default.func,onAppear:l.default.func,afterAppear:l.default.func,beforeEnter:l.default.func,onEnter:l.default.func,afterEnter:l.default.func,beforeLeave:l.default.func,onLeave:l.default.func,afterLeave:l.default.func},n.defaultProps={animationAppear:!0,component:"div",singleMode:!0,beforeAppear:u,onAppear:u,afterAppear:u,beforeEnter:u,onEnter:u,afterEnter:u,beforeLeave:u,onLeave:u,afterLeave:u};var d,l=i;function c(){return(0,r.default)(this,c),(0,o.default)(this,d.apply(this,arguments))}l.displayName="Animate",t.default=l,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0,t.default=t.EXITING=t.ENTERED=t.ENTERING=t.EXITED=t.UNMOUNTED=void 0;var a=function(e){{if(e&&e.__esModule)return e;var t,n={};if(null!=e)for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&((t=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(e,a):{}).get||t.set?Object.defineProperty(n,a,t):n[a]=e[a]);return n.default=e,n}}(n(3)),o=l(n(0)),i=l(n(23)),r=n(30);n(344);function l(e){return e&&e.__esModule?e:{default:e}}var s="unmounted",u=(t.UNMOUNTED=s,"exited"),d=(t.EXITED=u,"entering"),c=(t.ENTERING=d,"entered"),f=(t.ENTERED=c,"exiting"),n=(t.EXITING=f,function(r){var e;function t(e,t){var n,a=r.call(this,e,t)||this,t=t.transitionGroup,t=t&&!t.isMounting?e.enter:e.appear;return a.appearStatus=null,e.in?t?(n=u,a.appearStatus=d):n=c:n=e.unmountOnExit||e.mountOnEnter?s:u,a.state={status:n},a.nextCallback=null,a}e=r,(n=t).prototype=Object.create(e.prototype),(n.prototype.constructor=n).__proto__=e;var n=t.prototype;return n.getChildContext=function(){return{transitionGroup:null}},t.getDerivedStateFromProps=function(e,t){return e.in&&t.status===s?{status:u}:null},n.componentDidMount=function(){this.updateStatus(!0,this.appearStatus)},n.componentDidUpdate=function(e){var t=null;e!==this.props&&(e=this.state.status,this.props.in?e!==d&&e!==c&&(t=d):e!==d&&e!==c||(t=f)),this.updateStatus(!1,t)},n.componentWillUnmount=function(){this.cancelNextCallback()},n.getTimeouts=function(){var e,t,n=this.props.timeout,a=e=t=n;return null!=n&&"number"!=typeof n&&(a=n.exit,e=n.enter,t=void 0!==n.appear?n.appear:e),{exit:a,enter:e,appear:t}},n.updateStatus=function(e,t){var n;void 0===e&&(e=!1),null!==t?(this.cancelNextCallback(),n=i.default.findDOMNode(this),t===d?this.performEnter(n,e):this.performExit(n)):this.props.unmountOnExit&&this.state.status===u&&this.setState({status:s})},n.performEnter=function(e,t){var n=this,a=this.props.enter,r=this.context.transitionGroup?this.context.transitionGroup.isMounting:t,o=this.getTimeouts(),i=r?o.appear:o.enter;t||a?(this.props.onEnter(e,r),this.safeSetState({status:d},function(){n.props.onEntering(e,r),n.onTransitionEnd(e,i,function(){n.safeSetState({status:c},function(){n.props.onEntered(e,r)})})})):this.safeSetState({status:c},function(){n.props.onEntered(e)})},n.performExit=function(e){var t=this,n=this.props.exit,a=this.getTimeouts();n?(this.props.onExit(e),this.safeSetState({status:f},function(){t.props.onExiting(e),t.onTransitionEnd(e,a.exit,function(){t.safeSetState({status:u},function(){t.props.onExited(e)})})})):this.safeSetState({status:u},function(){t.props.onExited(e)})},n.cancelNextCallback=function(){null!==this.nextCallback&&(this.nextCallback.cancel(),this.nextCallback=null)},n.safeSetState=function(e,t){t=this.setNextCallback(t),this.setState(e,t)},n.setNextCallback=function(t){var n=this,a=!0;return this.nextCallback=function(e){a&&(a=!1,n.nextCallback=null,t(e))},this.nextCallback.cancel=function(){a=!1},this.nextCallback},n.onTransitionEnd=function(e,t,n){this.setNextCallback(n);n=null==t&&!this.props.addEndListener;!e||n?setTimeout(this.nextCallback,0):(this.props.addEndListener&&this.props.addEndListener(e,this.nextCallback),null!=t&&setTimeout(this.nextCallback,t))},n.render=function(){var e=this.state.status;if(e===s)return null;var t=this.props,n=t.children,t=function(e,t){if(null==e)return{};for(var n,a={},r=Object.keys(e),o=0;o 16.8.0"),null;function t(e){j.current=e,ne({})}function a(e,t){N(te,null),"function"==typeof S&&S(e,t)}function n(e){27===e.keyCode&&Y&&!P.current.size&&a("esc",e)}function r(){j.current||(t(!0),he.dom.setStyle(D.current,"display","none"),me.default.unlock(document.body,ee.current),s&&O.current&&(O.current.focus(),O.current=null),I())}var o=e.prefix,o=void 0===o?"next-":o,i=e.afterClose,I=void 0===i?ye:i,i=e.hasMask,l=void 0===i||i,i=e.autoFocus,s=void 0!==i&&i,i=e.className,A=e.title,R=e.children,H=e.footer,F=e.footerAlign,z=e.footerActions,u=e.onOk,u=void 0===u?ye:u,d=e.onCancel,W=e.okProps,V=e.cancelProps,c=e.locale,c=void 0===c?pe.default.Dialog:c,B=e.rtl,f=e.visible,p=e.closeMode,p=void 0===p?["close","esc"]:p,U=e.closeIcon,h=e.animation,h=void 0===h?{in:"fadeInUp",out:"fadeOutUp"}:h,m=e.cache,K=e.wrapperStyle,g=e.popupContainer,y=void 0===g?document.body:g,g=e.dialogRender,v=e.centered,_=e.top,_=void 0===_?v?40:100:_,b=e.bottom,b=void 0===b?40:b,w=e.width,w=void 0===w?520:w,q=e.height,M=e.isFullScreen,k=e.overflowScroll,M=void 0===k?!M:k,k=e.minMargin,S=e.onClose,G=e.style,x=(0,ie.default)(e,["prefix","afterClose","hasMask","autoFocus","className","title","children","footer","footerAlign","footerActions","onOk","onCancel","okProps","cancelProps","locale","rtl","visible","closeMode","closeIcon","animation","cache","wrapperStyle","popupContainer","dialogRender","centered","top","bottom","width","height","isFullScreen","overflowScroll","minMargin","onClose","style"]),E=("isFullScreen"in e&&he.log.deprecated("isFullScreen","overflowScroll","Dialog v2"),"minMargin"in e&&he.log.deprecated("minMargin","top/bottom","Dialog v2"),(0,le.useState)(f||!1)),$=E[0],J=E[1],E=(0,le.useState)(f),C=E[0],Q=E[1],X="string"==typeof y?function(){return document.getElementById(y)}:"function"!=typeof y?function(){return y}:y,E=(0,le.useState)(X()),L=E[0],Z=E[1],T=(0,le.useRef)(null),D=(0,le.useRef)(null),O=(0,le.useRef)(null),ee=(0,le.useRef)(null),te=(0,le.useState)((0,he.guid)())[0],E=(0,le.useContext)(ge),N=E.setVisibleOverlayToParent,E=(0,ie.default)(E,["setVisibleOverlayToParent"]),P=(0,le.useRef)(new Map),j=(0,le.useRef)(!1),ne=(0,le.useState)()[1],Y=!1,ae=!1,re=!1;(Array.isArray(p)?p:[p]).forEach(function(e){switch(e){case"esc":Y=!0;break;case"mask":ae=!0;break;case"close":re=!0}}),(0,le.useEffect)(function(){"visible"in e&&Q(f)},[f]),(0,le.useEffect)(function(){var e;C&&l&&(e={overflow:"hidden"},he.dom.hasScroll(document.body)&&he.dom.scrollbar().width&&(e.paddingRight=he.dom.getStyle(document.body,"paddingRight")+he.dom.scrollbar().width+"px"),ee.current=me.default.lock(document.body,e))},[C&&l]),(0,le.useEffect)(function(){if(C&&Y)return document.body.addEventListener("keydown",n,!1),function(){document.body.removeEventListener("keydown",n,!1)}},[C&&Y]),(0,le.useEffect)(function(){!$&&C&&J(!0)},[C]),(0,le.useEffect)(function(){L||setTimeout(function(){Z(X())})},[L]);if((0,le.useEffect)(function(){return function(){r()}},[]),!1===$||!L)return null;if(!C&&!m&&j.current)return null;m=(0,de.default)(((p={})[o+"overlay-wrapper"]=!0,p.opened=C,p)),i=(0,de.default)(((p={})[o+"dialog-v2"]=!0,p[i]=!!i,p)),p={},k=void(v?_||b||!k?(_&&(p.marginTop=_),b&&(p.marginBottom=b)):(p.marginTop=k,p.marginBottom=k):(_&&(p.top=_),b&&(p.paddingBottom=b))),M&&(k="calc(100vh - "+(_+b)+"px)"),M={appear:300,enter:300,exit:250},_=se.default.createElement(fe.default.OverlayAnimate,{visible:C,animation:h,timeout:M,onEnter:function(){t(!1),he.dom.setStyle(D.current,"display","")},onEntered:function(){var e;s&&T.current&&T.current.bodyNode&&(0<(e=he.focus.getFocusNodeList(T.current.bodyNode)).length&&e[0]&&(O.current=document.activeElement,e[0].focus())),N(te,D.current)},onExited:r},se.default.createElement(ce.default,(0,oe.default)({},x,{style:v?(0,oe.default)({},p,G):G,v2:!0,ref:T,prefix:o,className:i,title:A,footer:H,footerAlign:F,footerActions:z,onOk:C?u:ye,onCancel:C?function(e){"function"==typeof d?d(e):a("cancelBtn",e)}:ye,okProps:W,cancelProps:V,locale:c,closeable:re,rtl:B,onClose:function(){for(var e=arguments.length,t=Array(e),n=0;n>6]+d[128|63&s]:s<55296||57344<=s?i+=d[224|s>>12]+d[128|s>>6&63]+d[128|63&s]:(l+=1,s=65536+((1023&s)<<10|1023&o.charCodeAt(l)),i+=d[240|s>>18]+d[128|s>>12&63]+d[128|s>>6&63]+d[128|63&s])}return i},isBuffer:function(e){return!(!e||"object"!=typeof e)&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},maybeMap:function(e,t){if(m(e)){for(var n=[],a=0;athis.popupNode.offsetWidth&&p(this.popupNode,"width",l.offsetWidth+"px"),"outside"!==a||"hoz"===r&&1===n||(p(this.popupNode,"height",u.offsetHeight+"px"),this.popupNode.firstElementChild&&p(this.popupNode.firstElementChild,"overflow-y","auto")),this.popupProps);d.onOpen&&d.onOpen()}catch(e){return null}},S.prototype.handlePopupClose=function(){var e=this.props.root.popupNodes,t=e.indexOf(this.popupNode),e=(-1t?r[t+1]:r[0])}),n[a]||(o=r[0]),i.onSort(a,o)},i.keydownHandler=function(e){e.preventDefault(),e.stopPropagation(),e.keyCode===l.KEYCODE.ENTER&&i.handleClick()},i.onSort=function(e,t){var n={};n[e]=t,i.props.onSort(e,t,n)},(0,o.default)(i,e)}i.displayName="Sort",t.default=i,e.exports=t.default},function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r=c(n(2)),a=c(n(4)),o=c(n(6)),i=c(n(7)),l=c(n(0)),s=c(n(3)),u=c(n(13)),d=c(n(387));function c(e){return e&&e.__esModule?e:{default:e}}f=l.default.Component,(0,i.default)(p,f),p.prototype.render=function(){var e=this.props,t=e.className,n=e.record,e=e.primaryKey,a=this.context.selectedRowKeys,n=(0,u.default)(((a={selected:-1e.slidesToShow&&(n=e.slideWidth*e.slidesToShow*-1,o=e.slideHeight*e.slidesToShow*-1),e.slideCount%e.slidesToScroll!=0&&(t=e.slideIndex+e.slidesToScroll>e.slideCount&&e.slideCount>e.slidesToShow,(t=e.rtl?(e.slideIndex>=e.slideCount?e.slideCount-e.slideIndex:e.slideIndex)+e.slidesToScroll>e.slideCount&&e.slideCount>e.slidesToShow:t)&&(o=e.slideIndex>e.slideCount?(n=(e.slidesToShow-(e.slideIndex-e.slideCount))*e.slideWidth*-1,(e.slidesToShow-(e.slideIndex-e.slideCount))*e.slideHeight*-1):(n=e.slideCount%e.slidesToScroll*e.slideWidth*-1,e.slideCount%e.slidesToScroll*e.slideHeight*-1)))):e.slideCount%e.slidesToScroll!=0&&e.slideIndex+e.slidesToScroll>e.slideCount&&e.slideCount>e.slidesToShow&&(n=(e.slidesToShow-e.slideCount%e.slidesToScroll)*e.slideWidth),e.centerMode&&(e.infinite?n+=e.slideWidth*Math.floor(e.slidesToShow/2):n=e.slideWidth*Math.floor(e.slidesToShow/2)),a=e.vertical?e.slideIndex*e.slideHeight*-1+o:e.slideIndex*e.slideWidth*-1+n,!0===e.variableWidth&&(t=void 0,a=(r=e.slideCount<=e.slidesToShow||!1===e.infinite?i.default.findDOMNode(e.trackRef).childNodes[e.slideIndex]:(t=e.slideIndex+e.slidesToShow,i.default.findDOMNode(e.trackRef).childNodes[t]))?-1*r.offsetLeft:0,!0===e.centerMode&&(r=!1===e.infinite?i.default.findDOMNode(e.trackRef).children[e.slideIndex]:i.default.findDOMNode(e.trackRef).children[e.slideIndex+e.slidesToShow+1])&&(a=-1*r.offsetLeft+(e.listWidth-r.offsetWidth)/2)),a)}},function(e,t,n){"use strict";t.__esModule=!0;var p=u(n(2)),h=u(n(12)),o=u(n(4)),i=u(n(6)),a=u(n(7)),m=u(n(0)),r=u(n(3)),g=u(n(13)),l=u(n(8)),y=u(n(25)),s=n(11);function u(e){return e&&e.__esModule?e:{default:e}}d=m.default.Component,(0,a.default)(c,d),c.prototype.render=function(){var e=this.props,t=e.title,n=e.children,a=e.className,r=e.isExpanded,o=e.disabled,i=e.style,l=e.prefix,s=e.onClick,u=e.id,e=(0,h.default)(e,["title","children","className","isExpanded","disabled","style","prefix","onClick","id"]),a=(0,g.default)(((d={})[l+"collapse-panel"]=!0,d[l+"collapse-panel-hidden"]=!r,d[l+"collapse-panel-expanded"]=r,d[l+"collapse-panel-disabled"]=o,d[a]=a,d)),d=(0,g.default)(((d={})[l+"collapse-panel-icon"]=!0,d[l+"collapse-panel-icon-expanded"]=r,d)),c=u?u+"-heading":void 0,f=u?u+"-region":void 0;return m.default.createElement("div",(0,p.default)({className:a,style:i,id:u},e),m.default.createElement("div",{id:c,className:l+"collapse-panel-title",onClick:s,onKeyDown:this.onKeyDown,tabIndex:"0","aria-disabled":o,"aria-expanded":r,"aria-controls":f,role:"button"},m.default.createElement(y.default,{type:"arrow-right",className:d,"aria-hidden":"true"}),t),m.default.createElement("div",{className:l+"collapse-panel-content",role:"region",id:f},n))},a=n=c,n.propTypes={prefix:r.default.string,style:r.default.object,children:r.default.any,isExpanded:r.default.bool,disabled:r.default.bool,title:r.default.node,className:r.default.string,onClick:r.default.func,id:r.default.string},n.defaultProps={prefix:"next-",isExpanded:!1,onClick:s.func.noop},n.isNextPanel=!0;var d,r=a;function c(){var e,n;(0,o.default)(this,c);for(var t=arguments.length,a=Array(t),r=0;r\n com.alibaba.nacos\n nacos-client\n ${version}\n \n*/\npackage com.alibaba.nacos.example;\n\nimport java.util.Properties;\nimport java.util.concurrent.Executor;\nimport com.alibaba.nacos.api.NacosFactory;\nimport com.alibaba.nacos.api.config.ConfigService;\nimport com.alibaba.nacos.api.config.listener.Listener;\nimport com.alibaba.nacos.api.exception.NacosException;\n\n/**\n * Config service example\n *\n * @author Nacos\n *\n */\npublic class ConfigExample {\n\n\tpublic static void main(String[] args) throws NacosException, InterruptedException {\n\t\tString serverAddr = "localhost";\n\t\tString dataId = "'.concat(e.dataId,'";\n\t\tString group = "').concat(e.group,'";\n\t\tProperties properties = new Properties();\n\t\tproperties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);\n\t\tConfigService configService = NacosFactory.createConfigService(properties);\n\t\tString content = configService.getConfig(dataId, group, 5000);\n\t\tSystem.out.println(content);\n\t\tconfigService.addListener(dataId, group, new Listener() {\n\t\t\t@Override\n\t\t\tpublic void receiveConfigInfo(String configInfo) {\n\t\t\t\tSystem.out.println("recieve:" + configInfo);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Executor getExecutor() {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t});\n\n\t\tboolean isPublishOk = configService.publishConfig(dataId, group, "content");\n\t\tSystem.out.println(isPublishOk);\n\n\t\tThread.sleep(3000);\n\t\tcontent = configService.getConfig(dataId, group, 5000);\n\t\tSystem.out.println(content);\n\n\t\tboolean isRemoveOk = configService.removeConfig(dataId, group);\n\t\tSystem.out.println(isRemoveOk);\n\t\tThread.sleep(3000);\n\n\t\tcontent = configService.getConfig(dataId, group, 5000);\n\t\tSystem.out.println(content);\n\t\tThread.sleep(300000);\n\n\t}\n}\n')}},{key:"getNodejsCode",value:function(e){return"TODO"}},{key:"getCppCode",value:function(e){return"TODO"}},{key:"getShellCode",value:function(e){return"TODO"}},{key:"getPythonCode",value:function(e){return"TODO"}},{key:"getCSharpCode",value:function(e){return'/*\nDemo for Basic Nacos Opreation\nApp.csproj\n\n\n \n\n*/\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Nacos.V2;\nusing Nacos.V2.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nclass Program\n{\n static async Task Main(string[] args)\n {\n string serverAddr = "http://localhost:8848";\n string dataId = "'.concat(e.dataId,'";\n string group = "').concat(e.group,'";\n\n IServiceCollection services = new ServiceCollection();\n\n services.AddNacosV2Config(x =>\n {\n x.ServerAddresses = new List { serverAddr };\n x.Namespace = "cs-test";\n\n // swich to use http or rpc\n x.ConfigUseRpc = true;\n });\n\n IServiceProvider serviceProvider = services.BuildServiceProvider();\n var configSvc = serviceProvider.GetService();\n\n var content = await configSvc.GetConfig(dataId, group, 3000);\n Console.WriteLine(content);\n\n var listener = new ConfigListener();\n\n await configSvc.AddListener(dataId, group, listener);\n\n var isPublishOk = await configSvc.PublishConfig(dataId, group, "content");\n Console.WriteLine(isPublishOk);\n\n await Task.Delay(3000);\n content = await configSvc.GetConfig(dataId, group, 5000);\n Console.WriteLine(content);\n\n var isRemoveOk = await configSvc.RemoveConfig(dataId, group);\n Console.WriteLine(isRemoveOk);\n await Task.Delay(3000);\n\n content = await configSvc.GetConfig(dataId, group, 5000);\n Console.WriteLine(content);\n await Task.Delay(300000);\n }\n\n internal class ConfigListener : IListener\n {\n public void ReceiveConfigInfo(string configInfo)\n {\n Console.WriteLine("recieve:" + configInfo);\n }\n }\n}\n\n/*\nRefer to document: https://github.com/nacos-group/nacos-sdk-csharp/tree/dev/samples/MsConfigApp\nDemo for ASP.NET Core Integration\nMsConfigApp.csproj\n\n\n \n\n*/\n\nusing Microsoft.AspNetCore.Hosting;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.Hosting;\nusing Serilog;\nusing Serilog.Events;\n\npublic class Program\n{\n public static void Main(string[] args)\n {\n Log.Logger = new LoggerConfiguration()\n .Enrich.FromLogContext()\n .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)\n .MinimumLevel.Override("System", LogEventLevel.Warning)\n .MinimumLevel.Debug()\n .WriteTo.Console()\n .CreateLogger();\n\n try\n {\n Log.ForContext().Information("Application starting...");\n CreateHostBuilder(args, Log.Logger).Build().Run();\n }\n catch (System.Exception ex)\n {\n Log.ForContext().Fatal(ex, "Application start-up failed!!");\n }\n finally\n {\n Log.CloseAndFlush();\n }\n }\n\n public static IHostBuilder CreateHostBuilder(string[] args, Serilog.ILogger logger) =>\n Host.CreateDefaultBuilder(args)\n .ConfigureAppConfiguration((context, builder) =>\n {\n var c = builder.Build();\n builder.AddNacosV2Configuration(c.GetSection("NacosConfig"), logAction: x => x.AddSerilog(logger));\n })\n .ConfigureWebHostDefaults(webBuilder =>\n {\n webBuilder.UseStartup().UseUrls("http://*:8787");\n })\n .UseSerilog();\n}\n ')}},{key:"openDialog",value:function(e){var t=this;this.setState({dialogvisible:!0}),this.record=e,setTimeout(function(){t.getData()})}},{key:"closeDialog",value:function(){this.setState({dialogvisible:!1})}},{key:"createCodeMirror",value:function(e,t){var n=this.refs.codepreview;n&&(n.innerHTML="",this.cm=window.CodeMirror(n,{value:t,mode:e,height:400,width:500,lineNumbers:!0,theme:"xq-light",lint:!0,tabMode:"indent",autoMatchParens:!0,textWrapping:!0,gutters:["CodeMirror-lint-markers"],extraKeys:{F1:function(e){e.setOption("fullScreen",!e.getOption("fullScreen"))},Esc:function(e){e.getOption("fullScreen")&&e.setOption("fullScreen",!1)}}}))}},{key:"changeTab",value:function(e,t){var n=this;setTimeout(function(){n[e]=!0,n.createCodeMirror("text/javascript",t)})}},{key:"render",value:function(){var e=this.props.locale,e=void 0===e?{}:e;return E.a.createElement("div",null,E.a.createElement(y.a,{title:e.sampleCode,style:{width:"80%"},visible:this.state.dialogvisible,footer:E.a.createElement("div",null),onClose:this.closeDialog.bind(this)},E.a.createElement("div",{style:{height:500}},E.a.createElement(R.a,{tip:e.loading,style:{width:"100%"},visible:this.state.loading},E.a.createElement(D.a,{shape:"text",style:{height:40,paddingBottom:10}},E.a.createElement(O,{title:"Java",key:1,onClick:this.changeTab.bind(this,"commoneditor1",this.defaultCode)}),E.a.createElement(O,{title:"Spring Boot",key:2,onClick:this.changeTab.bind(this,"commoneditor2",this.sprigboot_code)}),E.a.createElement(O,{title:"Spring Cloud",key:21,onClick:this.changeTab.bind(this,"commoneditor21",this.sprigcloud_code)}),E.a.createElement(O,{title:"Node.js",key:3,onClick:this.changeTab.bind(this,"commoneditor3",this.nodejsCode)}),E.a.createElement(O,{title:"C++",key:4,onClick:this.changeTab.bind(this,"commoneditor4",this.cppCode)}),E.a.createElement(O,{title:"Shell",key:5,onClick:this.changeTab.bind(this,"commoneditor5",this.shellCode)}),E.a.createElement(O,{title:"Python",key:6,onClick:this.changeTab.bind(this,"commoneditor6",this.pythonCode)}),E.a.createElement(O,{title:"C#",key:7,onClick:this.changeTab.bind(this,"commoneditor7",this.csharpCode)})),E.a.createElement("div",{ref:"codepreview"})))))}}]),n}(E.a.Component)).displayName="ShowCodeing",S=S))||S,S=(t(66),t(41)),S=t.n(S),F=(t(704),S.a.Row),N=S.a.Col,z=(0,n.a.config)(((S=function(e){Object(M.a)(n,e);var t=Object(k.a)(n);function n(e){return Object(_.a)(this,n),(e=t.call(this,e)).state={visible:!1,title:"",content:"",isok:!0,dataId:"",group:""},e}return Object(b.a)(n,[{key:"componentDidMount",value:function(){this.initData()}},{key:"initData",value:function(){var e=this.props.locale;this.setState({title:(void 0===e?{}:e).confManagement})}},{key:"openDialog",value:function(e){this.setState({visible:!0,title:e.title,content:e.content,isok:e.isok,dataId:e.dataId,group:e.group,message:e.message})}},{key:"closeDialog",value:function(){this.setState({visible:!1})}},{key:"render",value:function(){var e=this.props.locale,e=void 0===e?{}:e,t=E.a.createElement("div",{style:{textAlign:"right"}},E.a.createElement(d.a,{type:"primary",onClick:this.closeDialog.bind(this)},e.determine));return E.a.createElement("div",null,E.a.createElement(y.a,{visible:this.state.visible,footer:t,style:{width:555},onCancel:this.closeDialog.bind(this),onClose:this.closeDialog.bind(this),title:e.deletetitle},E.a.createElement("div",null,E.a.createElement(F,null,E.a.createElement(N,{span:"4",style:{paddingTop:16}},E.a.createElement(m.a,{type:"".concat(this.state.isok?"success":"delete","-filling"),style:{color:this.state.isok?"green":"red"},size:"xl"})),E.a.createElement(N,{span:"20"},E.a.createElement("div",null,E.a.createElement("h3",null,this.state.isok?e.deletedSuccessfully:e.deleteFailed),E.a.createElement("p",null,E.a.createElement("span",{style:{color:"#999",marginRight:5}},"Data ID"),E.a.createElement("span",{style:{color:"#c7254e"}},this.state.dataId)),E.a.createElement("p",null,E.a.createElement("span",{style:{color:"#999",marginRight:5}},"Group"),E.a.createElement("span",{style:{color:"#c7254e"}},this.state.group)),this.state.isok?"":E.a.createElement("p",{style:{color:"red"}},this.state.message)))))))}}]),n}(E.a.Component)).displayName="DeleteDialog",S=S))||S,S=(t(705),t(413)),W=t.n(S),V=(0,n.a.config)(((S=function(e){Object(M.a)(n,e);var t=Object(k.a)(n);function n(){return Object(_.a)(this,n),t.apply(this,arguments)}return Object(b.a)(n,[{key:"render",value:function(){var e=this.props,t=e.data,t=void 0===t?{}:t,n=e.height,e=e.locale,a=void 0===e?{}:e;return E.a.createElement("div",null,"notice"===t.modeType?E.a.createElement("div",{"data-spm-click":"gostr=/aliyun;locaid=notice"},E.a.createElement(W.a,{style:{marginBottom:1\n com.alibaba.nacos\n nacos-client\n ${latest.version}\n \n*/\npackage com.alibaba.nacos.example;\n\nimport java.util.Properties;\n\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingFactory;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.listener.Event;\nimport com.alibaba.nacos.api.naming.listener.EventListener;\nimport com.alibaba.nacos.api.naming.listener.NamingEvent;\n\n/**\n * @author nkorange\n */\npublic class NamingExample {\n\n public static void main(String[] args) throws NacosException {\n\n Properties properties = new Properties();\n properties.setProperty("serverAddr", System.getProperty("serverAddr"));\n properties.setProperty("namespace", System.getProperty("namespace"));\n\n NamingService naming = NamingFactory.createNamingService(properties);\n\n naming.registerInstance("'.concat(this.record.name,'", "11.11.11.11", 8888, "TEST1");\n\n naming.registerInstance("').concat(this.record.name,'", "2.2.2.2", 9999, "DEFAULT");\n\n System.out.println(naming.getAllInstances("').concat(this.record.name,'"));\n\n naming.deregisterInstance("').concat(this.record.name,'", "2.2.2.2", 9999, "DEFAULT");\n\n System.out.println(naming.getAllInstances("').concat(this.record.name,'"));\n\n naming.subscribe("').concat(this.record.name,'", new EventListener() {\n @Override\n public void onEvent(Event event) {\n System.out.println(((NamingEvent)event).getServiceName());\n System.out.println(((NamingEvent)event).getInstances());\n }\n });\n }\n}')}},{key:"getSpringCode",value:function(e){return'/* Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-example/nacos-spring-discovery-example\n* pom.xml\n \n com.alibaba.nacos\n nacos-spring-context\n ${latest.version}\n \n*/\n\n// Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-example/nacos-spring-discovery-example/src/main/java/com/alibaba/nacos/example/spring\npackage com.alibaba.nacos.example.spring;\n\nimport com.alibaba.nacos.api.annotation.NacosProperties;\nimport com.alibaba.nacos.spring.context.annotation.discovery.EnableNacosDiscovery;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\n@EnableNacosDiscovery(globalProperties = @NacosProperties(serverAddr = "127.0.0.1:8848"))\npublic class NacosConfiguration {\n\n}\n\n// Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-example/nacos-spring-discovery-example/src/main/java/com/alibaba/nacos/example/spring/controller\npackage com.alibaba.nacos.example.spring.controller;\n\nimport com.alibaba.nacos.api.annotation.NacosInjected;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\nimport static org.springframework.web.bind.annotation.RequestMethod.GET;\n\n@Controller\n@RequestMapping("discovery")\npublic class DiscoveryController {\n\n @NacosInjected\n private NamingService namingService;\n\n @RequestMapping(value = "/get", method = GET)\n @ResponseBody\n public List get(@RequestParam String serviceName) throws NacosException {\n return namingService.getAllInstances(serviceName);\n }\n}'}},{key:"getSpringBootCode",value:function(e){return'/* Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-boot-example/nacos-spring-boot-discovery-example\n* pom.xml\n \n com.alibaba.boot\n nacos-discovery-spring-boot-starter\n ${latest.version}\n \n*/\n/* Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-boot-example/nacos-spring-boot-discovery-example/src/main/resources\n* application.properties\n nacos.discovery.server-addr=127.0.0.1:8848\n*/\n// Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-boot-example/nacos-spring-boot-discovery-example/src/main/java/com/alibaba/nacos/example/spring/boot/controller\n\npackage com.alibaba.nacos.example.spring.boot.controller;\n\nimport com.alibaba.nacos.api.annotation.NacosInjected;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\nimport static org.springframework.web.bind.annotation.RequestMethod.GET;\n\n@Controller\n@RequestMapping("discovery")\npublic class DiscoveryController {\n\n @NacosInjected\n private NamingService namingService;\n\n @RequestMapping(value = "/get", method = GET)\n @ResponseBody\n public List get(@RequestParam String serviceName) throws NacosException {\n return namingService.getAllInstances(serviceName);\n }\n}'}},{key:"getSpringCloudCode",value:function(e){return"/* Refer to document: https://github.com/nacos-group/nacos-examples/blob/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/\n* pom.xml\n \n org.springframework.cloud\n spring-cloud-starter-alibaba-nacos-discovery\n ${latest.version}\n \n*/\n\n// nacos-spring-cloud-provider-example\n\n/* Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/nacos-spring-cloud-provider-example/src/main/resources\n* application.properties\nserver.port=18080\nspring.application.name=".concat(this.record.name,'\nspring.cloud.nacos.discovery.server-addr=127.0.0.1:8848\n*/\n\n// Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/nacos-spring-cloud-provider-example/src/main/java/com/alibaba/nacos/example/spring/cloud\npackage com.alibaba.nacos.example.spring.cloud;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.discovery.EnableDiscoveryClient;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * @author xiaojing\n */\n@SpringBootApplication\n@EnableDiscoveryClient\npublic class NacosProviderApplication {\n\n public static void main(String[] args) {\n SpringApplication.run(NacosProviderApplication.class, args);\n}\n\n @RestController\n class EchoController {\n @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)\n public String echo(@PathVariable String string) {\n return "Hello Nacos Discovery " + string;\n }\n }\n}\n\n// nacos-spring-cloud-consumer-example\n\n/* Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/nacos-spring-cloud-consumer-example/src/main/resources\n* application.properties\nspring.application.name=micro-service-oauth2\nspring.cloud.nacos.discovery.server-addr=127.0.0.1:8848\n*/\n\n// Refer to document: https://github.com/nacos-group/nacos-examples/tree/master/nacos-spring-cloud-example/nacos-spring-cloud-discovery-example/nacos-spring-cloud-consumer-example/src/main/java/com/alibaba/nacos/example/spring/cloud\npackage com.alibaba.nacos.example.spring.cloud;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.client.discovery.EnableDiscoveryClient;\nimport org.springframework.cloud.client.loadbalancer.LoadBalanced;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\nimport org.springframework.web.client.RestTemplate;\n\n/**\n * @author xiaojing\n */\n@SpringBootApplication\n@EnableDiscoveryClient\npublic class NacosConsumerApplication {\n\n @LoadBalanced\n @Bean\n public RestTemplate restTemplate() {\n return new RestTemplate();\n }\n\n public static void main(String[] args) {\n SpringApplication.run(NacosConsumerApplication.class, args);\n }\n\n @RestController\n public class TestController {\n\n private final RestTemplate restTemplate;\n\n @Autowired\n public TestController(RestTemplate restTemplate) {this.restTemplate = restTemplate;}\n\n @RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)\n public String echo(@PathVariable String str) {\n return restTemplate.getForObject("http://service-provider/echo/" + str, String.class);\n }\n }\n}')}},{key:"getNodejsCode",value:function(e){return"TODO"}},{key:"getCppCode",value:function(e){return"TODO"}},{key:"getShellCode",value:function(e){return"TODO"}},{key:"getPythonCode",value:function(e){return"TODO"}},{key:"getCSharpCode",value:function(e){return'/* Refer to document: https://github.com/nacos-group/nacos-sdk-csharp/\nDemo for Basic Nacos Opreation\nApp.csproj\n\n\n \n\n*/\n\nusing Microsoft.Extensions.DependencyInjection;\nusing Nacos.V2;\nusing Nacos.V2.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nclass Program\n{\n static async Task Main(string[] args)\n {\n IServiceCollection services = new ServiceCollection();\n\n services.AddNacosV2Naming(x =>\n {\n x.ServerAddresses = new List { "http://localhost:8848/" };\n x.Namespace = "cs-test";\n\n // swich to use http or rpc\n x.NamingUseRpc = true;\n });\n\n IServiceProvider serviceProvider = services.BuildServiceProvider();\n var namingSvc = serviceProvider.GetService();\n\n await namingSvc.RegisterInstance("'.concat(this.record.name,'", "11.11.11.11", 8888, "TEST1");\n\n await namingSvc.RegisterInstance("').concat(this.record.name,'", "2.2.2.2", 9999, "DEFAULT");\n\n Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(await namingSvc.GetAllInstances("').concat(this.record.name,'")));\n\n await namingSvc.DeregisterInstance("').concat(this.record.name,'", "2.2.2.2", 9999, "DEFAULT");\n\n var listener = new EventListener();\n\n await namingSvc.Subscribe("').concat(this.record.name,'", listener);\n }\n\n internal class EventListener : IEventListener\n {\n public Task OnEvent(IEvent @event)\n {\n Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(@event));\n return Task.CompletedTask;\n }\n }\n}\n\n/* Refer to document: https://github.com/nacos-group/nacos-sdk-csharp/\nDemo for ASP.NET Core Integration\nApp.csproj\n\n\n \n\n*/\n\n/* Refer to document: https://github.com/nacos-group/nacos-sdk-csharp/blob/dev/samples/App1/appsettings.json\n* appsettings.json\n{\n "nacos": {\n "ServerAddresses": [ "http://localhost:8848" ],\n "DefaultTimeOut": 15000,\n "Namespace": "cs",\n "ServiceName": "App1",\n "GroupName": "DEFAULT_GROUP",\n "ClusterName": "DEFAULT",\n "Port": 0,\n "Weight": 100,\n "RegisterEnabled": true,\n "InstanceEnabled": true,\n "Ephemeral": true,\n "NamingUseRpc": true,\n "NamingLoadCacheAtStart": ""\n }\n}\n*/\n\n// Refer to document: https://github.com/nacos-group/nacos-sdk-csharp/blob/dev/samples/App1/Startup.cs\nusing Nacos.AspNetCore.V2;\n\npublic class Startup\n{\n public Startup(IConfiguration configuration)\n {\n Configuration = configuration;\n }\n\n public IConfiguration Configuration { get; }\n\n public void ConfigureServices(IServiceCollection services)\n {\n // ....\n services.AddNacosAspNet(Configuration);\n }\n\n public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\n {\n // ....\n }\n}\n ')}},{key:"openDialog",value:function(e){var t=this;this.setState({dialogvisible:!0}),this.record=e,setTimeout(function(){t.getData()})}},{key:"closeDialog",value:function(){this.setState({dialogvisible:!1})}},{key:"createCodeMirror",value:function(e,t){var n=this.refs.codepreview;n&&(n.innerHTML="",this.cm=window.CodeMirror(n,{value:t,mode:e,height:400,width:500,lineNumbers:!0,theme:"xq-light",lint:!0,tabMode:"indent",autoMatchParens:!0,textWrapping:!0,gutters:["CodeMirror-lint-markers"],extraKeys:{F1:function(e){e.setOption("fullScreen",!e.getOption("fullScreen"))},Esc:function(e){e.getOption("fullScreen")&&e.setOption("fullScreen",!1)}}}),this.cm.setSize("auto","490px"))}},{key:"changeTab",value:function(e,t){var n=this;setTimeout(function(){n[e]=!0,n.createCodeMirror("text/javascript",t)})}},{key:"render",value:function(){var e=this.props.locale,e=void 0===e?{}:e;return L.a.createElement("div",null,L.a.createElement(o.a,{title:e.sampleCode,style:{width:"80%"},visible:this.state.dialogvisible,footer:L.a.createElement("div",null),onClose:this.closeDialog.bind(this)},L.a.createElement("div",{style:{height:500}},L.a.createElement(h.a,{tip:e.loading,style:{width:"100%"},visible:this.state.loading},L.a.createElement(m.a,{shape:"text",style:{height:40,paddingBottom:10}},L.a.createElement(g,{title:"Java",key:0,onClick:this.changeTab.bind(this,"commoneditor1",this.defaultCode)}),L.a.createElement(g,{title:"Spring",key:1,onClick:this.changeTab.bind(this,"commoneditor1",this.springCode)}),L.a.createElement(g,{title:"Spring Boot",key:2,onClick:this.changeTab.bind(this,"commoneditor2",this.sprigbootCode)}),L.a.createElement(g,{title:"Spring Cloud",key:21,onClick:this.changeTab.bind(this,"commoneditor21",this.sprigcloudCode)}),L.a.createElement(g,{title:"Node.js",key:3,onClick:this.changeTab.bind(this,"commoneditor3",this.nodejsCode)}),L.a.createElement(g,{title:"C++",key:4,onClick:this.changeTab.bind(this,"commoneditor4",this.cppCode)}),L.a.createElement(g,{title:"Shell",key:5,onClick:this.changeTab.bind(this,"commoneditor5",this.shellCode)}),L.a.createElement(g,{title:"Python",key:6,onClick:this.changeTab.bind(this,"commoneditor6",this.pythonCode)}),L.a.createElement(g,{title:"C#",key:7,onClick:this.changeTab.bind(this,"commoneditor7",this.csharpCode)})),L.a.createElement("div",{ref:"codepreview"})))))}}]),n}(L.a.Component)).displayName="ShowServiceCodeing",f=f))||f,P=t(69),j=(t(726),t(24)),Y=C.a.Item,I=a.a.Row,A=a.a.Col,R=E.a.Column,a=(0,n.a.config)(((f=function(e){Object(d.a)(a,e);var t=Object(c.a)(a);function a(e){var n;return Object(l.a)(this,a),(n=t.call(this,e)).getQueryLater=function(){setTimeout(function(){return n.queryServiceList()})},n.showcode=function(){setTimeout(function(){return n.queryServiceList()})},n.setNowNameSpace=function(e,t){return n.setState({nowNamespaceName:e,nowNamespaceId:t})},n.rowColor=function(e){return{className:e.healthyInstanceCount?"":"row-bg-red"}},n.editServiceDialog=L.a.createRef(),n.showcode=L.a.createRef(),n.state={loading:!1,total:0,pageSize:10,currentPage:1,dataSource:[],search:{serviceName:Object(p.a)("serviceNameParam")||"",groupName:Object(p.a)("groupNameParam")||""},hasIpCount:!("false"===localStorage.getItem("hasIpCount"))},n.field=new i.a(Object(u.a)(n)),n}return Object(s.a)(a,[{key:"openLoading",value:function(){this.setState({loading:!0})}},{key:"closeLoading",value:function(){this.setState({loading:!1})}},{key:"openEditServiceDialog",value:function(){try{this.editServiceDialog.current.getInstance().show(this.state.service)}catch(e){}}},{key:"queryServiceList",value:function(){var n=this,e=this.state,t=e.currentPage,a=e.pageSize,r=e.search,o=e.withInstances,o=void 0!==o&&o,e=e.hasIpCount,e=["hasIpCount=".concat(e),"withInstances=".concat(o),"pageNo=".concat(t),"pageSize=".concat(a),"serviceNameParam=".concat(r.serviceName),"groupNameParam=".concat(r.groupName)];Object(p.d)({serviceNameParam:r.serviceName,groupNameParam:r.groupName}),this.openLoading(),Object(p.c)({url:"v1/ns/catalog/services?".concat(e.join("&")),success:function(){var e=0o&&v.a.createElement(u.a,{className:"users-pagination",current:i,total:n.totalCount,pageSize:o,onChange:function(e){return t.setState({pageNo:e},function(){return t.getUsers()})}}),v.a.createElement(x,{visible:l,onOk:function(e){return Object(_.c)(e).then(function(e){return t.setState({pageNo:1},function(){return t.getUsers()}),e})},onCancel:function(){return t.colseCreateUser()}}),v.a.createElement(E.a,{visible:s,username:e,onOk:function(e){return Object(_.k)(e).then(function(e){return t.getUsers(),e})},onCancel:function(){return t.setState({passwordResetUser:void 0,passwordResetUserVisible:!1})}}))}}]),n}(v.a.Component)).displayName="UserManagement",n=o))||n)||n;t.a=r},function(e,t,n){"use strict";n(64);var a=n(46),s=n.n(a),a=(n(35),n(18)),u=n.n(a),d=n(31),a=(n(63),n(20)),c=n.n(a),a=(n(32),n(19)),f=n.n(a),a=(n(88),n(53)),p=n.n(a),a=(n(39),n(5)),h=n.n(a),a=(n(36),n(10)),m=n.n(a),i=n(14),l=n(15),g=n(22),y=n(17),v=n(16),a=(n(27),n(8)),a=n.n(a),r=n(0),_=n.n(r),r=n(37),b=n(45),o=n(83),w=n(48),M=(n(49),n(28)),k=n.n(M),M=(n(59),n(29)),S=n.n(M),x=h.a.Item,E=S.a.Option,C={labelCol:{fixedSpan:4},wrapperCol:{span:19}},L=Object(r.b)(function(e){return{namespaces:e.namespace.namespaces}},{getNamespaces:o.b,searchRoles:b.l})(M=(0,a.a.config)(((M=function(e){Object(y.a)(o,e);var r=Object(v.a)(o);function o(){var t;Object(i.a)(this,o);for(var e=arguments.length,n=new Array(e),a=0;ai&&_.a.createElement(s.a,{className:"users-pagination",current:l,total:t.totalCount,pageSize:i,onChange:function(e){return a.setState({pageNo:e},function(){return a.getPermissions()})}}),_.a.createElement(L,{visible:n,onOk:function(e){return Object(b.a)(e).then(function(e){return a.setState({pageNo:1},function(){return a.getPermissions()}),e})},onCancel:function(){return a.colseCreatePermission()}}))}}]),n}(_.a.Component)).displayName="PermissionsManagement",n=M))||n)||n);t.a=r},function(e,t,n){"use strict";n(64);var a=n(46),s=n.n(a),a=(n(35),n(18)),u=n.n(a),a=(n(63),n(20)),d=n.n(a),a=(n(32),n(19)),c=n.n(a),a=(n(88),n(53)),f=n.n(a),a=(n(39),n(5)),p=n.n(a),a=(n(36),n(10)),h=n.n(a),i=n(14),l=n(15),m=n(22),g=n(17),y=n(16),a=(n(27),n(8)),a=n.n(a),r=n(0),v=n.n(r),r=n(37),_=n(45),b=n(48),o=(n(59),n(29)),w=n.n(o),o=(n(49),n(28)),M=n.n(o),k=p.a.Item,S={labelCol:{fixedSpan:4},wrapperCol:{span:19}},x=Object(r.b)(function(e){return{users:e.authority.users}},{searchUsers:_.m})(o=(0,a.a.config)(((o=function(e){Object(g.a)(o,e);var r=Object(y.a)(o);function o(){var t;Object(i.a)(this,o);for(var e=arguments.length,n=new Array(e),a=0;ao&&v.a.createElement(s.a,{className:"users-pagination",current:i,total:t.totalCount,pageSize:o,onChange:function(e){return a.setState({pageNo:e},function(){return a.getRoles()})}}),v.a.createElement(x,{visible:l,onOk:function(e){return Object(_.b)(e).then(function(e){return a.getRoles(),e})},onCancel:function(){return a.colseCreateRole()}}))}}]),n}(v.a.Component)).displayName="RolesManagement",n=o))||n)||n);t.a=r},function(e,t,n){"use strict";n(50);function o(e){var t=void 0===(t=localStorage.token)?"{}":t,t=(Object(v.c)(t)&&JSON.parse(t)||{}).globalAdmin,n=[];return"naming"===e?n.push(_):"config"===e?n.push(b):n.push(b,_),t&&n.push(w),n.push(M),n.push(k),n.filter(function(e){return e})}var a=n(26),i=n.n(a),a=(n(43),n(25)),l=n.n(a),r=n(14),s=n(15),u=n(17),d=n(16),a=(n(27),n(8)),a=n.n(a),c=n(21),f=(n(81),n(51)),p=n.n(f),f=n(0),h=n.n(f),f=n(40),m=n(37),g=n(133),y=n(74),v=n(47),_={key:"serviceManagementVirtual",children:[{key:"serviceManagement",url:"/serviceManagement"},{key:"subscriberList",url:"/subscriberList"}]},b={key:"configurationManagementVirtual",children:[{key:"configurationManagement",url:"/configurationManagement"},{key:"historyRollback",url:"/historyRollback"},{key:"listeningToQuery",url:"/listeningToQuery"}]},w={key:"authorityControl",children:[{key:"userList",url:"/userManagement"},{key:"roleManagement",url:"/rolesManagement"},{key:"privilegeManagement",url:"/permissionsManagement"}]},M={key:"namespace",url:"/namespace"},k={key:"clusterManagementVirtual",children:[{key:"clusterManagement",url:"/clusterManagement"}]},S=p.a.SubMenu,x=p.a.Item,f=(n=Object(m.b)(function(e){return Object(c.a)(Object(c.a)({},e.locale),e.base)},{getState:y.c,getNotice:y.b}),m=a.a.config,Object(f.g)(a=n(a=m(((y=function(e){Object(u.a)(n,e);var t=Object(d.a)(n);function n(){return Object(r.a)(this,n),t.apply(this,arguments)}return Object(s.a)(n,[{key:"componentDidMount",value:function(){this.props.getState(),this.props.getNotice()}},{key:"goBack",value:function(){this.props.history.goBack()}},{key:"navTo",value:function(e){var t=this.props.location.search,t=new URLSearchParams(t);t.set("namespace",window.nownamespace),t.set("namespaceShowName",window.namespaceShowName),this.props.history.push([e,"?",t.toString()].join(""))}},{key:"isCurrentPath",value:function(e){return e===this.props.location.pathname?"current-path next-selected":void 0}},{key:"defaultOpenKeys",value:function(){for(var t=this,e=o(this.props.functionMode),n=0,a=e.length;nthis.state.pageSize&&M.a.createElement("div",{style:{marginTop:10,textAlign:"right"}},M.a.createElement(g.a,{current:this.state.pageNo,total:a,pageSize:this.state.pageSize,onChange:function(e){return t.setState({pageNo:e},function(){return t.querySubscriberList()})}}))))}}]),a}(M.a.Component)).displayName="SubscriberList",c=n))||c)||c;t.a=f},function(e,t,n){"use strict";n(52);var a=n(33),c=n.n(a),a=(n(64),n(46)),f=n.n(a),a=(n(173),n(75)),p=n.n(a),a=(n(36),n(10)),h=n.n(a),a=(n(32),n(19)),m=n.n(a),a=(n(35),n(18)),r=n.n(a),a=(n(49),n(28)),o=n.n(a),i=n(14),l=n(15),s=n(22),u=n(17),d=n(16),a=(n(27),n(8)),a=n.n(a),g=(n(398),n(115)),y=n.n(g),g=(n(63),n(20)),v=n.n(g),g=(n(66),n(41)),g=n.n(g),_=(n(39),n(5)),b=n.n(_),_=n(0),w=n.n(_),M=n(1),k=n(48),_=n(135),S=n.n(_),x=n(69),E=(n(729),b.a.Item),C=g.a.Row,L=g.a.Col,T=v.a.Column,D=y.a.Panel,g=(0,a.a.config)(((_=function(e){Object(u.a)(a,e);var t=Object(d.a)(a);function a(e){var n;return Object(i.a)(this,a),(n=t.call(this,e)).getQueryLater=function(){setTimeout(function(){return n.queryClusterStateList()})},n.setNowNameSpace=function(e,t){return n.setState({nowNamespaceName:e,nowNamespaceId:t})},n.rowColor=function(e){return{className:(e.voteFor,"")}},n.state={loading:!1,total:0,pageSize:10,currentPage:1,keyword:"",dataSource:[]},n.field=new o.a(Object(s.a)(n)),n}return Object(l.a)(a,[{key:"openLoading",value:function(){this.setState({loading:!0})}},{key:"closeLoading",value:function(){this.setState({loading:!1})}},{key:"openEditServiceDialog",value:function(){try{this.editServiceDialog.current.getInstance().show(this.state.service)}catch(e){}}},{key:"queryClusterStateList",value:function(){var n=this,e=this.state,t=e.currentPage,a=e.pageSize,r=e.keyword,e=e.withInstances,e=["withInstances=".concat(void 0!==e&&e),"pageNo=".concat(t),"pageSize=".concat(a),"keyword=".concat(r)];Object(M.c)({url:"v1/core/cluster/nodes?".concat(e.join("&")),beforeSend:function(){return n.openLoading()},success:function(){var e=0this.state.pageSize&&w.a.createElement("div",{style:{marginTop:10,textAlign:"right"}},w.a.createElement(f.a,{current:this.state.currentPage,total:this.state.total,pageSize:this.state.pageSize,onChange:function(e){return t.setState({currentPage:e},function(){return t.queryClusterStateList()})}}))))}}]),a}(w.a.Component)).displayName="ClusterNodeList",n=_))||n;t.a=g},function(e,t,z){"use strict";z.r(t),function(e){z(52);var t=z(33),a=z.n(t),t=(z(27),z(8)),r=z.n(t),o=z(14),i=z(15),l=z(17),s=z(16),n=z(21),t=z(0),u=z.n(t),t=z(23),t=z.n(t),d=z(117),c=z(406),f=z(417),p=z(37),h=z(40),m=z(82),g=(z(452),z(426)),y=z(24),v=z(427),_=z(420),b=z(428),w=z(429),M=z(421),k=z(430),S=z(431),x=z(432),E=z(433),C=z(434),L=z(418),T=z(422),D=z(419),O=z(435),N=z(436),P=z(423),j=z(424),I=z(425),A=z(415),Y=z(416),R=z(104),H=z(74),e=(z(732),e.hot,localStorage.getItem(y.g)||localStorage.setItem(y.g,"zh-CN"===navigator.language?"zh-CN":"en-US"),Object(d.b)(Object(n.a)(Object(n.a)({},Y.a),{},{routing:c.routerReducer}))),Y=Object(d.d)(e,Object(d.c)(Object(d.a)(f.a),window[y.k]?window[y.k]():function(e){return e})),F=[{path:"/",exact:!0,render:function(){return u.a.createElement(h.a,{to:"/welcome"})}},{path:"/welcome",component:A.a},{path:"/namespace",component:_.a},{path:"/newconfig",component:b.a},{path:"/configsync",component:w.a},{path:"/configdetail",component:M.a},{path:"/configeditor",component:k.a},{path:"/historyDetail",component:S.a},{path:"/configRollback",component:x.a},{path:"/historyRollback",component:E.a},{path:"/listeningToQuery",component:C.a},{path:"/configurationManagement",component:L.a},{path:"/serviceManagement",component:T.a},{path:"/serviceDetail",component:D.a},{path:"/subscriberList",component:O.a},{path:"/clusterManagement",component:N.a},{path:"/userManagement",component:P.a},{path:"/rolesManagement",component:I.a},{path:"/permissionsManagement",component:j.a}],e=Object(p.b)(function(e){return Object(n.a)(Object(n.a)({},e.locale),e.base)},{changeLanguage:R.a,getState:H.c})(c=function(e){Object(l.a)(n,e);var t=Object(s.a)(n);function n(e){return Object(o.a)(this,n),(e=t.call(this,e)).state={shownotice:"none",noticecontent:"",nacosLoading:{}},e}return Object(i.a)(n,[{key:"componentDidMount",value:function(){this.props.getState();var e=localStorage.getItem(y.g);this.props.changeLanguage(e)}},{key:"router",get:function(){var e=this.props.loginPageEnabled;return u.a.createElement(m.a,null,u.a.createElement(h.d,null,e&&"false"===e?null:u.a.createElement(h.b,{path:"/login",component:v.a}),u.a.createElement(g.a,null,F.map(function(e){return u.a.createElement(h.b,Object.assign({key:e.path},e))}))))}},{key:"render",value:function(){var e=this.props,t=e.locale,e=e.loginPageEnabled;return u.a.createElement(a.a,Object.assign({className:"nacos-loading",shape:"flower",tip:"loading...",visible:!e,fullScreen:!0},this.state.nacosLoading),u.a.createElement(r.a,{locale:t},this.router))}}]),n}(u.a.Component))||c;t.a.render(u.a.createElement(p.a,{store:Y},u.a.createElement(e,null)),document.getElementById("root"))}.call(this,z(438)(e))},function(e,t){e.exports=function(e){var t;return e.webpackPolyfill||((t=Object.create(e)).children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),Object.defineProperty(t,"exports",{enumerable:!0}),t.webpackPolyfill=1),t}},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(e,t,n){},function(I,e,t){"use strict"; /** @license React v16.14.0 * react.production.min.js * @@ -295,7 +295,7 @@ var t;e.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var d=t(184),t="function"==typeof Symbol&&Symbol.for,c=t?Symbol.for("react.element"):60103,u=t?Symbol.for("react.portal"):60106,n=t?Symbol.for("react.fragment"):60107,a=t?Symbol.for("react.strict_mode"):60108,r=t?Symbol.for("react.profiler"):60114,o=t?Symbol.for("react.provider"):60109,i=t?Symbol.for("react.context"):60110,l=t?Symbol.for("react.forward_ref"):60112,s=t?Symbol.for("react.suspense"):60113,f=t?Symbol.for("react.memo"):60115,p=t?Symbol.for("react.lazy"):60116,h="function"==typeof Symbol&&Symbol.iterator;function m(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n