Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ISSUE #367]Enhance SPI plugins #419

Merged
merged 1 commit into from
Jul 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eventmesh-common/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
#
group=org.apache.eventmesh
version=1.2.0-SNAPSHOT
jdk=1.7
jdk=1.8
16 changes: 16 additions & 0 deletions eventmesh-spi/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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.
*/
20 changes: 20 additions & 0 deletions eventmesh-spi/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#
# 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.
#
group=org.apache.eventmesh
version=1.2.0-SNAPSHOT
jdk=1.8
snapshot=false
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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 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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.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 {

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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;

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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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 org.junit.Test;

public class EventMeshExtensionFactoryTest {

@Test
public void getExtension() {
TestExtension extensionA = EventMeshExtensionFactory.getExtension(TestExtension.class, "extensionA");
extensionA.hello();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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;

public class ExtensionA implements TestExtension {

@Override
public void hello() {
System.out.println("I am ExtensionA");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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;

@EventMeshSPI
public interface TestExtension {

void hello();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# 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.

extensionA=org.apache.eventmesh.spi.ExtensionA
9 changes: 8 additions & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'