You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@eventmesh.apache.org by mi...@apache.org on 2025/02/07 04:32:38 UTC
(eventmesh) 06/10: [ISSUE #367]Enhance SPI plugins (#419)
This is an automated email from the ASF dual-hosted git repository.
mikexue pushed a commit to branch 1.3.0
in repository https://gitbox.apache.org/repos/asf/eventmesh.git
commit 348dc3cf1e802c6195353472a9540599bfa843af
Author: Wenjun Ruan <86...@qq.com>
AuthorDate: Wed Jul 7 16:57:02 2021 +0800
[ISSUE #367]Enhance SPI plugins (#419)
---
eventmesh-common/gradle.properties | 2 +-
settings.gradle => eventmesh-spi/build.gradle | 7 +-
.../gradle.properties | 3 +-
.../eventmesh/spi/EventMeshExtensionFactory.java | 22 ++++-
.../eventmesh/spi/EventMeshExtensionLoader.java | 110 +++++++++++++++++++++
.../org/apache/eventmesh/spi/EventMeshSPI.java | 20 +++-
.../apache/eventmesh/spi/ExtensionException.java | 18 +++-
.../spi/EventMeshExtensionFactoryTest.java | 14 ++-
.../java/org/apache/eventmesh/spi/ExtensionA.java | 11 ++-
.../org/apache/eventmesh/spi/TestExtension.java | 9 +-
.../org.apache.eventmesh.spi.TestExtension | 6 +-
settings.gradle | 9 +-
12 files changed, 200 insertions(+), 31 deletions(-)
diff --git a/eventmesh-common/gradle.properties b/eventmesh-common/gradle.properties
index b4202ce82..4117dffc9 100644
--- a/eventmesh-common/gradle.properties
+++ b/eventmesh-common/gradle.properties
@@ -16,4 +16,4 @@
#
group=org.apache.eventmesh
version=1.2.0-SNAPSHOT
-jdk=1.7
+jdk=1.8
diff --git a/settings.gradle b/eventmesh-spi/build.gradle
similarity index 77%
copy from settings.gradle
copy to eventmesh-spi/build.gradle
index ea31ffdc1..d973dceda 100644
--- a/settings.gradle
+++ b/eventmesh-spi/build.gradle
@@ -13,9 +13,4 @@
* 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.
- */
-
-rootProject.name = 'EventMesh'
-String jdkVersion = "${jdk}"
-include 'eventmesh-runtime','eventmesh-connector-rocketmq','eventmesh-sdk-java','eventmesh-common','eventmesh-connector-api','eventmesh-starter','eventmesh-test'
-
+ */
\ No newline at end of file
diff --git a/eventmesh-common/gradle.properties b/eventmesh-spi/gradle.properties
similarity index 97%
copy from eventmesh-common/gradle.properties
copy to eventmesh-spi/gradle.properties
index b4202ce82..d0503c3b7 100644
--- a/eventmesh-common/gradle.properties
+++ b/eventmesh-spi/gradle.properties
@@ -16,4 +16,5 @@
#
group=org.apache.eventmesh
version=1.2.0-SNAPSHOT
-jdk=1.7
+jdk=1.8
+snapshot=false
diff --git a/settings.gradle b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionFactory.java
similarity index 51%
copy from settings.gradle
copy to eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionFactory.java
index ea31ffdc1..96e054bd0 100644
--- a/settings.gradle
+++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionFactory.java
@@ -15,7 +15,23 @@
* limitations under the License.
*/
-rootProject.name = 'EventMesh'
-String jdkVersion = "${jdk}"
-include 'eventmesh-runtime','eventmesh-connector-rocketmq','eventmesh-sdk-java','eventmesh-common','eventmesh-connector-api','eventmesh-starter','eventmesh-test'
+package org.apache.eventmesh.spi;
+import org.apache.commons.lang3.StringUtils;
+
+public enum EventMeshExtensionFactory {
+ ;
+
+ public static <T> T getExtension(Class<T> extensionType, String extensionName) {
+ if (extensionType == null) {
+ throw new ExtensionException("extensionType is null");
+ }
+ if (StringUtils.isEmpty(extensionName)) {
+ throw new ExtensionException("extensionName is null");
+ }
+ if (!extensionType.isInterface() || !extensionType.isAnnotationPresent(EventMeshSPI.class)) {
+ throw new ExtensionException(String.format("extensionType:%s is invalided", extensionType));
+ }
+ return EventMeshExtensionLoader.getExtension(extensionType, extensionName);
+ }
+}
diff --git a/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionLoader.java b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionLoader.java
new file mode 100644
index 000000000..740ecb3f9
--- /dev/null
+++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshExtensionLoader.java
@@ -0,0 +1,110 @@
+/*
+ * 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.eventmesh.spi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+public enum EventMeshExtensionLoader {
+ ;
+
+ private static final ConcurrentHashMap<Class<?>, ConcurrentHashMap<String, Class<?>>> EXTENSION_CLASS_LOAD_CACHE = new ConcurrentHashMap<>(16);
+
+ private static final ConcurrentHashMap<String, Object> EXTENSION_INSTANCE_CACHE = new ConcurrentHashMap<>(16);
+
+ private static final String EVENTMESH_EXTENSION_DIR = "META-INF/eventmesh/";
+
+ @SuppressWarnings("unchecked")
+ public static <T> T getExtension(Class<T> extensionType, String extensionName) {
+ if (!hasLoadExtensionClass(extensionType)) {
+ loadExtensionClass(extensionType);
+ }
+ if (!hasInitializeExtension(extensionName)) {
+ initializeExtension(extensionType, extensionName);
+ }
+ return (T) EXTENSION_INSTANCE_CACHE.get(extensionName);
+ }
+
+ private static <T> void initializeExtension(Class<T> extensionType, String extensionName) {
+ ConcurrentHashMap<String, Class<?>> extensionClassMap = EXTENSION_CLASS_LOAD_CACHE.get(extensionType);
+ if (extensionClassMap == null) {
+ throw new ExtensionException(String.format("Extension type:%s has not been loaded", extensionType));
+ }
+ if (!extensionClassMap.containsKey(extensionName)) {
+ throw new ExtensionException(String.format("Extension name:%s has not been loaded", extensionName));
+ }
+ Class<?> aClass = extensionClassMap.get(extensionName);
+ try {
+ EXTENSION_INSTANCE_CACHE.put(extensionName, aClass.newInstance());
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new ExtensionException("Extension initialize error", e);
+ }
+ }
+
+ public static <T> void loadExtensionClass(Class<T> extensionType) {
+ String extensionFileName = EVENTMESH_EXTENSION_DIR + extensionType.getName();
+ ClassLoader classLoader = EventMeshExtensionLoader.class.getClassLoader();
+ try {
+ Enumeration<URL> extensionUrls = classLoader.getResources(extensionFileName);
+ if (extensionUrls != null) {
+ while (extensionUrls.hasMoreElements()) {
+ URL url = extensionUrls.nextElement();
+ loadResources(url, extensionType);
+ }
+ }
+ } catch (IOException e) {
+ throw new ExtensionException("load extension class error", e);
+ }
+
+
+ }
+
+ private static <T> void loadResources(URL url, Class<T> extensionType) throws IOException {
+ try (InputStream inputStream = url.openStream()) {
+ Properties properties = new Properties();
+ properties.load(inputStream);
+ properties.forEach((extensionName, extensionClass) -> {
+ String extensionNameStr = (String) extensionName;
+ String extensionClassStr = (String) extensionClass;
+ try {
+ Class<?> targetClass = Class.forName(extensionClassStr);
+ if (!extensionType.isAssignableFrom(targetClass)) {
+ throw new ExtensionException(
+ String.format("class: %s is not subClass of %s", targetClass, extensionType));
+ }
+ EXTENSION_CLASS_LOAD_CACHE.computeIfAbsent(extensionType, k -> new ConcurrentHashMap<>())
+ .put(extensionNameStr, targetClass);
+ } catch (ClassNotFoundException e) {
+ throw new ExtensionException("load extension class error", e);
+ }
+ });
+ }
+ }
+
+ private static <T> boolean hasLoadExtensionClass(Class<T> extensionType) {
+ return EXTENSION_CLASS_LOAD_CACHE.containsKey(extensionType);
+ }
+
+ private static boolean hasInitializeExtension(String extensionName) {
+ return EXTENSION_INSTANCE_CACHE.containsKey(extensionName);
+ }
+}
diff --git a/settings.gradle b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshSPI.java
similarity index 67%
copy from settings.gradle
copy to eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshSPI.java
index ea31ffdc1..0ea72d431 100644
--- a/settings.gradle
+++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/EventMeshSPI.java
@@ -15,7 +15,21 @@
* limitations under the License.
*/
-rootProject.name = 'EventMesh'
-String jdkVersion = "${jdk}"
-include 'eventmesh-runtime','eventmesh-connector-rocketmq','eventmesh-sdk-java','eventmesh-common','eventmesh-connector-api','eventmesh-starter','eventmesh-test'
+package org.apache.eventmesh.spi;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Just as a marker for SPI
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface EventMeshSPI {
+
+}
diff --git a/settings.gradle b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/ExtensionException.java
similarity index 70%
copy from settings.gradle
copy to eventmesh-spi/src/main/java/org/apache/eventmesh/spi/ExtensionException.java
index ea31ffdc1..874f03da5 100644
--- a/settings.gradle
+++ b/eventmesh-spi/src/main/java/org/apache/eventmesh/spi/ExtensionException.java
@@ -15,7 +15,19 @@
* limitations under the License.
*/
-rootProject.name = 'EventMesh'
-String jdkVersion = "${jdk}"
-include 'eventmesh-runtime','eventmesh-connector-rocketmq','eventmesh-sdk-java','eventmesh-common','eventmesh-connector-api','eventmesh-starter','eventmesh-test'
+package org.apache.eventmesh.spi;
+public class ExtensionException extends RuntimeException {
+
+ public ExtensionException(Exception e) {
+ super(e);
+ }
+
+ public ExtensionException(String message) {
+ super(message);
+ }
+
+ public ExtensionException(String message, Exception e) {
+ super(message, e);
+ }
+}
diff --git a/settings.gradle b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/EventMeshExtensionFactoryTest.java
similarity index 73%
copy from settings.gradle
copy to eventmesh-spi/src/test/java/org/apache/eventmesh/spi/EventMeshExtensionFactoryTest.java
index ea31ffdc1..649f4b18b 100644
--- a/settings.gradle
+++ b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/EventMeshExtensionFactoryTest.java
@@ -15,7 +15,15 @@
* limitations under the License.
*/
-rootProject.name = 'EventMesh'
-String jdkVersion = "${jdk}"
-include 'eventmesh-runtime','eventmesh-connector-rocketmq','eventmesh-sdk-java','eventmesh-common','eventmesh-connector-api','eventmesh-starter','eventmesh-test'
+package org.apache.eventmesh.spi;
+import org.junit.Test;
+
+public class EventMeshExtensionFactoryTest {
+
+ @Test
+ public void getExtension() {
+ TestExtension extensionA = EventMeshExtensionFactory.getExtension(TestExtension.class, "extensionA");
+ extensionA.hello();
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/ExtensionA.java
similarity index 78%
copy from settings.gradle
copy to eventmesh-spi/src/test/java/org/apache/eventmesh/spi/ExtensionA.java
index ea31ffdc1..03513e620 100644
--- a/settings.gradle
+++ b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/ExtensionA.java
@@ -15,7 +15,12 @@
* limitations under the License.
*/
-rootProject.name = 'EventMesh'
-String jdkVersion = "${jdk}"
-include 'eventmesh-runtime','eventmesh-connector-rocketmq','eventmesh-sdk-java','eventmesh-common','eventmesh-connector-api','eventmesh-starter','eventmesh-test'
+package org.apache.eventmesh.spi;
+public class ExtensionA implements TestExtension {
+
+ @Override
+ public void hello() {
+ System.out.println("I am ExtensionA");
+ }
+}
diff --git a/settings.gradle b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/TestExtension.java
similarity index 78%
copy from settings.gradle
copy to eventmesh-spi/src/test/java/org/apache/eventmesh/spi/TestExtension.java
index ea31ffdc1..c0c988813 100644
--- a/settings.gradle
+++ b/eventmesh-spi/src/test/java/org/apache/eventmesh/spi/TestExtension.java
@@ -15,7 +15,10 @@
* limitations under the License.
*/
-rootProject.name = 'EventMesh'
-String jdkVersion = "${jdk}"
-include 'eventmesh-runtime','eventmesh-connector-rocketmq','eventmesh-sdk-java','eventmesh-common','eventmesh-connector-api','eventmesh-starter','eventmesh-test'
+package org.apache.eventmesh.spi;
+@EventMeshSPI
+public interface TestExtension {
+
+ void hello();
+}
diff --git a/eventmesh-common/gradle.properties b/eventmesh-spi/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.spi.TestExtension
similarity index 92%
copy from eventmesh-common/gradle.properties
copy to eventmesh-spi/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.spi.TestExtension
index b4202ce82..3862ccbb4 100644
--- a/eventmesh-common/gradle.properties
+++ b/eventmesh-spi/src/test/resources/META-INF/eventmesh/org.apache.eventmesh.spi.TestExtension
@@ -13,7 +13,5 @@
# 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.
-#
-group=org.apache.eventmesh
-version=1.2.0-SNAPSHOT
-jdk=1.7
+
+extensionA=org.apache.eventmesh.spi.ExtensionA
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index ea31ffdc1..2b5e0af66 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -17,5 +17,12 @@
rootProject.name = 'EventMesh'
String jdkVersion = "${jdk}"
-include 'eventmesh-runtime','eventmesh-connector-rocketmq','eventmesh-sdk-java','eventmesh-common','eventmesh-connector-api','eventmesh-starter','eventmesh-test'
+include 'eventmesh-runtime'
+include 'eventmesh-connector-rocketmq'
+include 'eventmesh-sdk-java'
+include 'eventmesh-common'
+include 'eventmesh-connector-api'
+include 'eventmesh-starter'
+include 'eventmesh-test'
+include 'eventmesh-spi'
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@eventmesh.apache.org
For additional commands, e-mail: commits-help@eventmesh.apache.org