Add the base interface and entity for ability control.

This commit is contained in:
Daydreamer-ia 2022-08-28 17:35:39 +08:00
parent 0ac96e1602
commit a15ef8eb3a
9 changed files with 652 additions and 0 deletions

View File

@ -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<String, Boolean> CURRENT_SERVER_SUPPORT_ABILITY = new HashMap<>();
private static final HashMap<String, Integer> 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:
* <code>public static final String COMPRESSION = "compression";</code>
* 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:
* <code>CURRENT_NODE_ABILITY_TABLE.put("compression", 1);</code> 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<String, Boolean> 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<String, Integer> offset() {
return CURRENT_SERVER_ABILITY_OFFSET;
}
}

View File

@ -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
}

View File

@ -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<String, Boolean> 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<String, Boolean> 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<String, Boolean> getAbility() {
return ability;
}
public AbilityTable setAbility(Map<String, Boolean> ability) {
this.ability = ability;
return this;
}
}

View File

@ -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<Integer> 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<String, Boolean> getAbilityTableBy(byte[] bits, Map<String, Integer> offsetMap) {
if (bits == null || offsetMap.size() == 0) {
return Collections.emptyMap();
}
int length = bits.length;
Set<Map.Entry<String, Integer>> entries = offsetMap.entrySet();
Map<String, Boolean> res = new HashMap<>(offsetMap.size());
for (Map.Entry<String, Integer> 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;
}
}

View File

@ -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);
}

View File

@ -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!
}
}

View File

@ -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<String, Boolean> 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();
}

View File

@ -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 <p>abilityKey</p>
*
* @param abilityKey ability key
* @return if turn success
*/
boolean enableCurrentNodeAbility(String abilityKey);
/**.
* Turn off the ability whose key is <p>abilityKey</p>
*
* @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 <p>abilityKey</p>.
*
* @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 <p>handlerMappingClazz</p>.
*
* @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<? extends HandlerMapping> 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);
}

View File

@ -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);
}