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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to