diff --git a/modules/siddhi-annotations/src/main/java/io/siddhi/annotation/Extension.java b/modules/siddhi-annotations/src/main/java/io/siddhi/annotation/Extension.java index 7308a38656..fa873c388f 100644 --- a/modules/siddhi-annotations/src/main/java/io/siddhi/annotation/Extension.java +++ b/modules/siddhi-annotations/src/main/java/io/siddhi/annotation/Extension.java @@ -62,6 +62,8 @@ boolean deprecated() default false; + String deprecationNotice() default ""; + Parameter[] parameters() default {}; ParameterOverload[] parameterOverloads() default {}; diff --git a/modules/siddhi-core/src/main/java/io/siddhi/core/SiddhiAppRuntime.java b/modules/siddhi-core/src/main/java/io/siddhi/core/SiddhiAppRuntime.java index ed9a7d3ba7..2a1ace2370 100644 --- a/modules/siddhi-core/src/main/java/io/siddhi/core/SiddhiAppRuntime.java +++ b/modules/siddhi-core/src/main/java/io/siddhi/core/SiddhiAppRuntime.java @@ -193,4 +193,10 @@ public interface SiddhiAppRuntime { */ void enablePlayBack(boolean playBackEnabled, Long idleTime, Long incrementInMilliseconds); + /** + * Method to get Siddhi App runtime warnings. + * + * @return list of recorded runtime warnings. + */ + Set getWarnings(); } diff --git a/modules/siddhi-core/src/main/java/io/siddhi/core/SiddhiAppRuntimeImpl.java b/modules/siddhi-core/src/main/java/io/siddhi/core/SiddhiAppRuntimeImpl.java index 17cf650bf6..40a03e3c4c 100644 --- a/modules/siddhi-core/src/main/java/io/siddhi/core/SiddhiAppRuntimeImpl.java +++ b/modules/siddhi-core/src/main/java/io/siddhi/core/SiddhiAppRuntimeImpl.java @@ -19,6 +19,7 @@ package io.siddhi.core; import com.lmax.disruptor.ExceptionHandler; +import io.siddhi.annotation.Extension; import io.siddhi.core.aggregation.AggregationRuntime; import io.siddhi.core.config.SiddhiAppContext; import io.siddhi.core.debugger.SiddhiDebugger; @@ -67,6 +68,7 @@ import io.siddhi.core.util.statistics.metrics.Level; import io.siddhi.core.window.Window; import io.siddhi.query.api.SiddhiApp; +import io.siddhi.query.api.annotation.Annotation; import io.siddhi.query.api.definition.AbstractDefinition; import io.siddhi.query.api.definition.AggregationDefinition; import io.siddhi.query.api.definition.Attribute; @@ -84,6 +86,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -136,6 +139,7 @@ public class SiddhiAppRuntimeImpl implements SiddhiAppRuntime { private boolean runningWithoutSources = false; private Future futureIncrementalPersistor; private boolean incrementalDataPurging = true; + private Set warnings = new HashSet<>(); public SiddhiAppRuntimeImpl(Map streamDefinitionMap, @@ -176,7 +180,7 @@ public SiddhiAppRuntimeImpl(Map streamDefinitionMap, onDemandQueryLatencyTracker = QueryParserHelper.createLatencyTracker(siddhiAppContext, "query", SiddhiConstants.METRIC_INFIX_ON_DEMAND_QUERIES, null); } - + collectDeprecateWarnings(); for (Map.Entry> sinkEntries : sinkMap.entrySet()) { addCallback(sinkEntries.getKey(), new SinkCallback(sinkEntries.getValue(), streamDefinitionMap.get(sinkEntries.getKey()))); @@ -925,4 +929,41 @@ public void enablePlayBack(boolean playBackEnabled, Long idleTime, Long incremen } } } + + private void collectDeprecateWarnings() { + Map deprecatedExtensions = siddhiAppContext.getSiddhiContext().getDeprecatedSiddhiExtensions(); + List extensionsInUse = new ArrayList<>(); + extensionsInUse.addAll(streamDefinitionMap.values()); + extensionsInUse.addAll(tableDefinitionMap.values()); + extensionsInUse.addAll(windowDefinitionMap.values()); + extensionsInUse.addAll(aggregationDefinitionMap.values()); + for (AbstractDefinition extDefinition : extensionsInUse) { + for (Annotation annotation : extDefinition.getAnnotations()) { + String type = annotation.getElement(SiddhiConstants.ANNOTATION_ELEMENT_TYPE); + if (annotation.getName().equalsIgnoreCase(SiddhiConstants.ANNOTATION_SOURCE)) { + type = "source:" + type; + } + if (annotation.getName().equalsIgnoreCase(SiddhiConstants.ANNOTATION_SINK)) { + type = "sink:" + type; + } + if (annotation.getName().equalsIgnoreCase(SiddhiConstants.ANNOTATION_STORE)) { + type = "store:" + type; + } + if (type != null && deprecatedExtensions.containsKey(type)) { + Class ext = deprecatedExtensions.get(type); + Extension extAnnotation = (Extension) ext.getAnnotation(Extension.class); + String warning = extAnnotation.deprecationNotice().isEmpty() + ? type + " is being deprecated." + : extAnnotation.deprecationNotice(); + warnings.add(warning); + log.warn(warning); + } + } + } + } + + @Override + public Set getWarnings() { + return warnings; + } } diff --git a/modules/siddhi-core/src/main/java/io/siddhi/core/config/SiddhiContext.java b/modules/siddhi-core/src/main/java/io/siddhi/core/config/SiddhiContext.java index e39d897653..d2eb682093 100644 --- a/modules/siddhi-core/src/main/java/io/siddhi/core/config/SiddhiContext.java +++ b/modules/siddhi-core/src/main/java/io/siddhi/core/config/SiddhiContext.java @@ -48,6 +48,7 @@ public class SiddhiContext { private ExceptionHandler defaultDisrupterExceptionHandler; private Map siddhiExtensions = new HashMap<>(); + private Map deprecatedSiddhiExtensions = new HashMap<>(); private PersistenceStore persistenceStore = null; private IncrementalPersistenceStore incrementalPersistenceStore = null; private ErrorStore errorStore = null; @@ -62,7 +63,7 @@ public class SiddhiContext { private Map attributes; public SiddhiContext() { - SiddhiExtensionLoader.loadSiddhiExtensions(siddhiExtensions, extensionHolderMap); + SiddhiExtensionLoader.loadSiddhiExtensions(siddhiExtensions, extensionHolderMap, deprecatedSiddhiExtensions); siddhiDataSources = new ConcurrentHashMap(); statisticsConfiguration = new StatisticsConfiguration(new SiddhiMetricsFactory()); configManager = new InMemoryConfigManager(); @@ -154,6 +155,10 @@ public ConcurrentHashMap getExtensionHolderMap() return extensionHolderMap; } + public Map getDeprecatedSiddhiExtensions() { + return deprecatedSiddhiExtensions; + } + public ExceptionHandler getDefaultDisrupterExceptionHandler() { return defaultDisrupterExceptionHandler; } diff --git a/modules/siddhi-core/src/main/java/io/siddhi/core/util/SiddhiExtensionLoader.java b/modules/siddhi-core/src/main/java/io/siddhi/core/util/SiddhiExtensionLoader.java index 178716ec52..8c1fb0fa1a 100644 --- a/modules/siddhi-core/src/main/java/io/siddhi/core/util/SiddhiExtensionLoader.java +++ b/modules/siddhi-core/src/main/java/io/siddhi/core/util/SiddhiExtensionLoader.java @@ -58,7 +58,6 @@ public class SiddhiExtensionLoader { private static final Logger log = Logger.getLogger(SiddhiExtensionLoader.class); - private static List extensionNameSpaceList = new ArrayList<>(); private static final Class ATTRIBUTE_AGGREGATOR_EXECUTOR_CLASS = AttributeAggregatorExecutor.class; private static final Class DISTRIBUTION_STRATEGY_CLASS = DistributionStrategy.class; private static final Class FUNCTION_EXECUTOR_CLASS = FunctionExecutor.class; @@ -72,6 +71,7 @@ public class SiddhiExtensionLoader { private static final Class STREAM_PROCESSOR_CLASS = StreamProcessor.class; private static final Class TABLE_CLASS = Table.class; private static final Class WINDOW_PROCESSOR_CLASS = WindowProcessor.class; + private static List extensionNameSpaceList = new ArrayList<>(); static { extensionNameSpaceList.add(DISTRIBUTION_STRATEGY_CLASS); @@ -92,30 +92,34 @@ public class SiddhiExtensionLoader { /** * Helper method to load the Siddhi extensions. * - * @param siddhiExtensionsMap reference map for the Siddhi extension - * @param extensionHolderMap reference map for the Siddhi extension holder + * @param siddhiExtensionsMap reference map for the Siddhi extension + * @param extensionHolderMap reference map for the Siddhi extension holder + * @param deprecatedSiddhiExtensionsMap reference map for the deprecated Siddhi extensions */ public static void loadSiddhiExtensions(Map siddhiExtensionsMap, - ConcurrentHashMap extensionHolderMap) { - loadLocalExtensions(siddhiExtensionsMap, extensionHolderMap); + ConcurrentHashMap extensionHolderMap, + Map deprecatedSiddhiExtensionsMap) { + loadLocalExtensions(siddhiExtensionsMap, extensionHolderMap, deprecatedSiddhiExtensionsMap); BundleContext bundleContext = ReferenceHolder.getInstance().getBundleContext(); if (bundleContext != null) { - loadExtensionOSGI(bundleContext, siddhiExtensionsMap, extensionHolderMap); + loadExtensionOSGI(bundleContext, siddhiExtensionsMap, extensionHolderMap, deprecatedSiddhiExtensionsMap); } } /** * Load Extensions in OSGi environment. * - * @param bundleContext OSGi bundleContext - * @param siddhiExtensionsMap reference map for the Siddhi extension - * @param extensionHolderMap reference map for the Siddhi extension holder + * @param bundleContext OSGi bundleContext + * @param siddhiExtensionsMap reference map for the Siddhi extension + * @param extensionHolderMap reference map for the Siddhi extension holder + * @param deprecatedSiddhiExtensionsMap reference map for the deprecated Siddhi extensions */ private static void loadExtensionOSGI(BundleContext bundleContext, Map siddhiExtensionsMap, - ConcurrentHashMap extensionHolderMap) { + ConcurrentHashMap extensionHolderMap, + Map deprecatedSiddhiExtensionsMap) { ExtensionBundleListener extensionBundleListener - = new ExtensionBundleListener(siddhiExtensionsMap, extensionHolderMap); + = new ExtensionBundleListener(siddhiExtensionsMap, extensionHolderMap, deprecatedSiddhiExtensionsMap); bundleContext.addBundleListener(extensionBundleListener); extensionBundleListener.loadAllExtensions(bundleContext); } @@ -123,14 +127,16 @@ private static void loadExtensionOSGI(BundleContext bundleContext, /** * Load Siddhi extensions in java non OSGi environment. * - * @param siddhiExtensionsMap reference map for the Siddhi extension - * @param extensionHolderMap reference map for the Siddhi extension holder + * @param siddhiExtensionsMap reference map for the Siddhi extension + * @param extensionHolderMap reference map for the Siddhi extension holder + * @param deprecatedSiddhiExtensionsMap reference map for the deprecated Siddhi extensions */ private static void loadLocalExtensions(Map siddhiExtensionsMap, - ConcurrentHashMap extensionHolderMap) { + ConcurrentHashMap extensionHolderMap, + Map deprecatedSiddhiExtensionsMap) { Iterable> extensions = ClassIndex.getAnnotated(Extension.class); for (Class extension : extensions) { - addExtensionToMap(extension, siddhiExtensionsMap, extensionHolderMap); + addExtensionToMap(extension, siddhiExtensionsMap, extensionHolderMap, deprecatedSiddhiExtensionsMap); } // load extensions related to incremental aggregation @@ -149,13 +155,14 @@ private static void loadLocalExtensions(Map siddhiExtensionsMap, /** * Adding extensions to Siddhi siddhiExtensionsMap. * - * @param extensionClass extension class - * @param siddhiExtensionsMap reference map for the Siddhi extension - * @param extensionHolderMap reference map for the Siddhi extension holder + * @param extensionClass extension class + * @param siddhiExtensionsMap reference map for the Siddhi extension + * @param extensionHolderMap reference map for the Siddhi extension holder + * @param deprecatedSiddhiExtensionsMap reference map for the deprecated Siddhi extensions */ private static void addExtensionToMap(Class extensionClass, Map siddhiExtensionsMap, - ConcurrentHashMap - extensionHolderMap) { + ConcurrentHashMap extensionHolderMap, + Map deprecatedSiddhiExtensionsMap) { Extension siddhiExtensionAnnotation = (Extension) extensionClass.getAnnotation(Extension.class); if (siddhiExtensionAnnotation != null) { if (!siddhiExtensionAnnotation.name().isEmpty()) { @@ -166,6 +173,9 @@ private static void addExtensionToMap(Class extensionClass, Map s Class existingValue = siddhiExtensionsMap.get(key); if (existingValue == null) { previousClass = siddhiExtensionsMap.put(key, extensionClass); + if (siddhiExtensionAnnotation.deprecated()) { + deprecatedSiddhiExtensionsMap.put(key, extensionClass); + } for (Class clazz : extensionNameSpaceList) { putToExtensionHolderMap(clazz, extensionClass, key, extensionHolderMap); @@ -179,6 +189,9 @@ private static void addExtensionToMap(Class extensionClass, Map s } } else { previousClass = siddhiExtensionsMap.put(siddhiExtensionAnnotation.name(), extensionClass); + if (siddhiExtensionAnnotation.deprecated()) { + deprecatedSiddhiExtensionsMap.put(siddhiExtensionAnnotation.name(), extensionClass); + } if (previousClass != null) { log.warn("Dropping extension '" + previousClass + "' as '" + extensionClass + "' is " + "loaded with the same name '" + siddhiExtensionAnnotation.name() + "'"); @@ -220,6 +233,7 @@ private static void putToExtensionHolderMap( /** * Remove extensions to Siddhi siddhiExtensionsHolderMap. + * * @param extensionKey fully qualified extension name (namespace:extensionName) * @param extension extension class (eg:HttpSource) * @param extensionHolderConcurrentHashMap reference map for the Siddhi extension holder @@ -265,12 +279,15 @@ private static class ExtensionBundleListener implements BundleListener { private Map bundleExtensions = new HashMap(); private Map siddhiExtensionsMap; + private Map deprecatedSiddhiExtensionsMap; private ConcurrentHashMap extensionHolderConcurrentHashMap; ExtensionBundleListener(Map siddhiExtensionsMap, - ConcurrentHashMap extensionHolderConcurrentHashMap) { + ConcurrentHashMap extensionHolderConcurrentHashMap, + Map deprecatedSiddhiExtensionsMap) { this.siddhiExtensionsMap = siddhiExtensionsMap; this.extensionHolderConcurrentHashMap = extensionHolderConcurrentHashMap; + this.deprecatedSiddhiExtensionsMap = deprecatedSiddhiExtensionsMap; } @Override @@ -286,7 +303,8 @@ private void addExtensions(Bundle bundle) { ClassLoader classLoader = bundle.adapt(BundleWiring.class).getClassLoader(); Iterable> extensions = ClassIndex.getAnnotated(Extension.class, classLoader); for (Class extension : extensions) { - addExtensionToMap(extension, siddhiExtensionsMap, extensionHolderConcurrentHashMap); + addExtensionToMap(extension, siddhiExtensionsMap, + extensionHolderConcurrentHashMap, deprecatedSiddhiExtensionsMap); bundleExtensions.put(extension, (int) bundle.getBundleId()); } } diff --git a/modules/siddhi-core/src/test/java/io/siddhi/core/managment/WarningTestCase.java b/modules/siddhi-core/src/test/java/io/siddhi/core/managment/WarningTestCase.java new file mode 100644 index 0000000000..c1f3e0660f --- /dev/null +++ b/modules/siddhi-core/src/test/java/io/siddhi/core/managment/WarningTestCase.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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 io.siddhi.core.managment; + +import io.siddhi.core.SiddhiAppRuntime; +import io.siddhi.core.SiddhiManager; +import io.siddhi.core.event.Event; +import io.siddhi.core.stream.input.InputHandler; +import io.siddhi.core.util.EventPrinter; +import org.apache.log4j.Logger; +import org.testng.AssertJUnit; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class WarningTestCase { + private static final Logger log = Logger.getLogger(WarningTestCase.class); + + @BeforeMethod + public void init() { + // do nothing. + } + + @Test + public void warningTest() throws InterruptedException { + log.info("warningTest"); + SiddhiManager siddhiManager = new SiddhiManager(); + String streams = "" + + "define stream StockStream (symbol string, price float, volume long); " + + "@Store(type=\"testStoreContainingInMemoryTable\")\n" + + "define table StockTable (symbol string, volume long); "; + + String query1 = "" + + "@info(name = 'query1') " + + "from StockStream\n" + + "select symbol, volume\n" + + "insert into StockTable ;"; + SiddhiAppRuntime siddhiAppRuntime = siddhiManager.createSiddhiAppRuntime(streams + query1); + InputHandler stockStream = siddhiAppRuntime.getInputHandler("StockStream"); + siddhiAppRuntime.start(); + + stockStream.send(new Object[]{"WSO2", 55.6f, 100L}); + stockStream.send(new Object[]{"IBM", 75.6f, 100L}); + Thread.sleep(1000); + + Event[] events = siddhiAppRuntime.query("" + + "from StockTable "); + EventPrinter.print(events); + AssertJUnit.assertEquals(2, events.length); + AssertJUnit.assertEquals(1, siddhiAppRuntime.getWarnings().size()); + AssertJUnit.assertTrue(siddhiAppRuntime.getWarnings() + .contains("store:testStoreContainingInMemoryTable is being deprecated for testing purposes.")); + siddhiAppRuntime.shutdown(); + } +} diff --git a/modules/siddhi-core/src/test/java/io/siddhi/core/query/table/util/TestStoreContainingInMemoryTable.java b/modules/siddhi-core/src/test/java/io/siddhi/core/query/table/util/TestStoreContainingInMemoryTable.java index 9ee27f96df..0ce01e0191 100644 --- a/modules/siddhi-core/src/test/java/io/siddhi/core/query/table/util/TestStoreContainingInMemoryTable.java +++ b/modules/siddhi-core/src/test/java/io/siddhi/core/query/table/util/TestStoreContainingInMemoryTable.java @@ -69,6 +69,8 @@ */ @Extension( name = "testStoreContainingInMemoryTable", + deprecated = true, + deprecationNotice = "store:testStoreContainingInMemoryTable is being deprecated for testing purposes.", namespace = "store", description = "Using this implementation a testing for store extension can be done.", examples = { diff --git a/modules/siddhi-query-compiler/pom.xml b/modules/siddhi-query-compiler/pom.xml index ef93e10f12..de102d700c 100644 --- a/modules/siddhi-query-compiler/pom.xml +++ b/modules/siddhi-query-compiler/pom.xml @@ -147,6 +147,6 @@ - findbugs-exclude.xml + ../../findbugs-exclude.xml