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] 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 000000000..0971ca7af --- /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 000000000..825e99a0a --- /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 000000000..921a092a7 --- /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 000000000..11ad28cc0 --- /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 000000000..252f81123 --- /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 000000000..e7623d5e0 --- /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 000000000..15adf7fc9 --- /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 000000000..c27254784 --- /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 000000000..6b87b9b38 --- /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); +}