Skip to content

Commit

Permalink
intro PipePluginAnnotationTest & fix show
Browse files Browse the repository at this point in the history
  • Loading branch information
VGalaxies committed Jan 13, 2025
1 parent bf9a0cf commit 01293ce
Show file tree
Hide file tree
Showing 25 changed files with 522 additions and 13 deletions.
5 changes: 5 additions & 0 deletions iotdb-core/confignode/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class PipePluginTableResp implements DataSet {

Expand All @@ -56,13 +57,18 @@ public TGetPipePluginTableResp convertToThriftResponse() throws IOException {
}

public PipePluginTableResp filter(final boolean isTableModel) {
allPipePluginMeta.removeIf(
meta -> {
final String pipePluginName = meta.getPluginName();
final Visibility visibility =
pipePluginNameToVisibilityMap.getOrDefault(pipePluginName, Visibility.TREE_ONLY);
return !VisibilityUtils.isCompatible(visibility, isTableModel);
});
return this;
return new PipePluginTableResp(
status,
allPipePluginMeta.stream()
.filter(
meta -> {
final String pipePluginName = meta.getPluginName();
final Visibility visibility =
pipePluginNameToVisibilityMap.getOrDefault(
pipePluginName, Visibility.TREE_ONLY);
return VisibilityUtils.isCompatible(visibility, isTableModel);
})
.collect(Collectors.toList()),
pipePluginNameToVisibilityMap);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static org.apache.iotdb.commons.pipe.agent.plugin.builtin.BuiltinPipePlugin.DO_NOTHING_PROCESSOR;
import static org.apache.iotdb.commons.pipe.agent.plugin.builtin.BuiltinPipePlugin.IOTDB_EXTRACTOR;
Expand Down Expand Up @@ -274,7 +276,8 @@ public TSStatus dropPipePlugin(final DropPipePluginPlan dropPipePluginPlan) {
public DataSet showPipePlugins() {
return new PipePluginTableResp(
new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()),
Arrays.asList(pipePluginMetaKeeper.getAllPipePluginMeta()),
StreamSupport.stream(pipePluginMetaKeeper.getAllPipePluginMeta().spliterator(), false)
.collect(Collectors.toList()),
pipePluginMetaKeeper.getPipePluginNameToVisibilityMap());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.iotdb.confignode.pipe.annotation;

import org.apache.iotdb.commons.pipe.datastructure.visibility.Visibility;
import org.apache.iotdb.pipe.api.PipePlugin;

import org.junit.Test;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static org.apache.iotdb.commons.pipe.datastructure.visibility.VisibilityUtils.calculateFromPluginClass;
import static org.apache.iotdb.commons.pipe.datastructure.visibility.VisibilityUtils.isCompatible;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

public class PipePluginAnnotationTest {

@Test
public void testPipePluginVisibility() {
// Use the Reflections library to scan the classpath
final Reflections reflections =
new Reflections("org.apache.iotdb.confignode", new SubTypesScanner(false));
final Set<Class<? extends PipePlugin>> subTypes = reflections.getSubTypesOf(PipePlugin.class);

// Create root node
final TreeNode root = new TreeNode(PipePlugin.class);

// Build the tree
final Map<Class<?>, TreeNode> nodeMap = new HashMap<>();
nodeMap.put(PipePlugin.class, root);

for (final Class<?> subType : subTypes) {
final TreeNode node = new TreeNode(subType);
nodeMap.put(subType, node);

if (subType.isInterface()) {
// Handle super interfaces of the interface
final Class<?>[] superInterfaces = subType.getInterfaces();
for (Class<?> superInterface : superInterfaces) {
while (!nodeMap.containsKey(superInterface) && superInterface != null) {
superInterface = getSuperInterface(superInterface);
}

if (superInterface != null) {
nodeMap.get(superInterface).children.put(subType, node);
}
}
} else {
// Handle superclass of the class
Class<?> superClass = subType.getSuperclass();
if (superClass == Object.class) {
// If the superclass is Object, check the implemented interfaces
final Class<?>[] interfaces = subType.getInterfaces();
for (final Class<?> iface : interfaces) {
if (nodeMap.containsKey(iface)) {
nodeMap.get(iface).children.put(subType, node);
}
}
} else {
while (!nodeMap.containsKey(superClass) && superClass != null) {
superClass = superClass.getSuperclass();
}

if (superClass != null) {
nodeMap.get(superClass).children.put(subType, node);
}
}
}
}

root.visibility = Visibility.BOTH;
for (TreeNode node : root.children.values()) {
node.visibility = Visibility.BOTH;
}

// Validate the correctness of the tree
assertNotNull(root);

// Validate the visibility compatibility of the tree
assertTrue(validateTreeNode(root));
}

private static class TreeNode {
Class<?> clazz;
Visibility visibility;
Map<Class<?>, TreeNode> children = new HashMap<>();

TreeNode(final Class<?> clazz) {
this.clazz = clazz;
this.visibility = calculateFromPluginClass(clazz);
}
}

// Get the super interface of an interface
private Class<?> getSuperInterface(final Class<?> interfaceClass) {
final Class<?>[] superInterfaces = interfaceClass.getInterfaces();
return superInterfaces.length > 0 ? superInterfaces[0] : null;
}

private static boolean validateTreeNode(final TreeNode node) {
for (final TreeNode child : node.children.values()) {
if (!isCompatible(node.visibility, child.visibility)) {
assertTrue(
"Incompatible visibility detected:\n"
+ "Parent class: "
+ node.clazz.getName()
+ ", Visibility: "
+ node.visibility
+ "\n"
+ "Child class: "
+ child.clazz.getName()
+ ", Visibility: "
+ child.visibility,
isCompatible(node.visibility, child.visibility));
}
if (!validateTreeNode(child)) {
return false;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import org.apache.iotdb.db.conf.IoTDBConfig;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
import org.apache.iotdb.db.pipe.connector.client.IoTDBDataNodeSyncClientManager;
import org.apache.iotdb.pipe.api.annotation.TableModel;
import org.apache.iotdb.pipe.api.annotation.TreeModel;
import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameterValidator;

import org.slf4j.Logger;
Expand All @@ -37,6 +39,8 @@
import java.util.Set;
import java.util.stream.Collectors;

@TreeModel
@TableModel
public abstract class IoTDBDataNodeSyncConnector extends IoTDBSslSyncConnector {

private static final Logger LOGGER = LoggerFactory.getLogger(IoTDBDataNodeSyncConnector.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.iotdb.db.pipe.plugin.annotation;

import org.apache.iotdb.commons.pipe.datastructure.visibility.Visibility;
import org.apache.iotdb.pipe.api.PipePlugin;

import org.junit.Test;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static org.apache.iotdb.commons.pipe.datastructure.visibility.VisibilityUtils.calculateFromPluginClass;
import static org.apache.iotdb.commons.pipe.datastructure.visibility.VisibilityUtils.isCompatible;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

public class PipePluginAnnotationTest {

@Test
public void testPipePluginVisibility() {
// Use the Reflections library to scan the classpath
final Reflections reflections =
new Reflections("org.apache.iotdb.db", new SubTypesScanner(false));
final Set<Class<? extends PipePlugin>> subTypes = reflections.getSubTypesOf(PipePlugin.class);

// Create root node
final TreeNode root = new TreeNode(PipePlugin.class);

// Build the tree
final Map<Class<?>, TreeNode> nodeMap = new HashMap<>();
nodeMap.put(PipePlugin.class, root);

for (final Class<?> subType : subTypes) {
final TreeNode node = new TreeNode(subType);
nodeMap.put(subType, node);

if (subType.isInterface()) {
// Handle super interfaces of the interface
final Class<?>[] superInterfaces = subType.getInterfaces();
for (Class<?> superInterface : superInterfaces) {
while (!nodeMap.containsKey(superInterface) && superInterface != null) {
superInterface = getSuperInterface(superInterface);
}

if (superInterface != null) {
nodeMap.get(superInterface).children.put(subType, node);
}
}
} else {
// Handle superclass of the class
Class<?> superClass = subType.getSuperclass();
if (superClass == Object.class) {
// If the superclass is Object, check the implemented interfaces
final Class<?>[] interfaces = subType.getInterfaces();
for (final Class<?> iface : interfaces) {
if (nodeMap.containsKey(iface)) {
nodeMap.get(iface).children.put(subType, node);
}
}
} else {
while (!nodeMap.containsKey(superClass) && superClass != null) {
superClass = superClass.getSuperclass();
}

if (superClass != null) {
nodeMap.get(superClass).children.put(subType, node);
}
}
}
}

root.visibility = Visibility.BOTH;
for (TreeNode node : root.children.values()) {
node.visibility = Visibility.BOTH;
}

// Validate the correctness of the tree
assertNotNull(root);

// Validate the visibility compatibility of the tree
assertTrue(validateTreeNode(root));
}

private static class TreeNode {
Class<?> clazz;
Visibility visibility;
Map<Class<?>, TreeNode> children = new HashMap<>();

TreeNode(final Class<?> clazz) {
this.clazz = clazz;
this.visibility = calculateFromPluginClass(clazz);
}
}

// Get the super interface of an interface
private Class<?> getSuperInterface(final Class<?> interfaceClass) {
final Class<?>[] superInterfaces = interfaceClass.getInterfaces();
return superInterfaces.length > 0 ? superInterfaces[0] : null;
}

private static boolean validateTreeNode(final TreeNode node) {
for (final TreeNode child : node.children.values()) {
if (!isCompatible(node.visibility, child.visibility)) {
assertTrue(
"Incompatible visibility detected:\n"
+ "Parent class: "
+ node.clazz.getName()
+ ", Visibility: "
+ node.visibility
+ "\n"
+ "Child class: "
+ child.clazz.getName()
+ ", Visibility: "
+ child.visibility,
isCompatible(node.visibility, child.visibility));
}
if (!validateTreeNode(child)) {
return false;
}
}
return true;
}
}
5 changes: 5 additions & 0 deletions iotdb-core/node-commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@
<groupId>com.github.luben</groupId>
<artifactId>zstd-jni</artifactId>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Expand Down
Loading

0 comments on commit 01293ce

Please sign in to comment.