This is an automated email from the ASF dual-hosted git repository. rec pushed a commit to branch feature/226-Provide-SPI-interfaces-to-locate-descriptors-and-JCas-classes in repository https://gitbox.apache.org/repos/asf/uima-uimaj.git
commit 120124c5be4ffa89c64e303dbf1df164e82c5ae8 Author: Richard Eckart de Castilho <[email protected]> AuthorDate: Fri Jul 29 19:16:11 2022 +0200 Issue #226: Provide SPI interfaces to locate descriptors - Added SPI for JCas classes - Added test that FSClassRegistry is able to load JCas classes through the SPI - Push exclusion of META-INF down into the bundle modules because we do not want to exclude the META-INF/services for SPI testing --- .gitignore | 1 - .../org/apache/uima/cas/impl/FSClassRegistry.java | 31 +++++++++++++++++++ .../org/apache/uima/spi/JCasClassProvider.java | 27 +++++++++++++++++ .../apache/uima/cas/impl/FSClassRegistryTest.java | 16 ++++++++++ .../uima/spi/JCasClassProviderForTesting.java | 35 ++++++++++++++++++++++ .../services/org.apache.uima.spi.JCasClassProvider | 1 + uimaj-ep-cas-editor-ide/.gitignore | 1 + uimaj-ep-cas-editor/.gitignore | 1 + uimaj-ep-configurator/.gitignore | 1 + uimaj-ep-debug/.gitignore | 1 + uimaj-ep-jcasgen/.gitignore | 1 + uimaj-ep-launcher/.gitignore | 1 + uimaj-ep-pear-packager/.gitignore | 1 + uimaj-ep-runtime/.gitignore | 1 + 14 files changed, 118 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 779de2a09..a7ddf4288 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ .project .settings target -META-INF checkpoint_synchPoint.xml checkpoint_synchPoint.xml.prev checkpoint.dat diff --git a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java index ee9824313..bb75e3b66 100644 --- a/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java +++ b/uimaj-core/src/main/java/org/apache/uima/cas/impl/FSClassRegistry.java @@ -41,6 +41,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.ServiceLoader; import org.apache.uima.UIMAFramework; import org.apache.uima.UIMARuntimeException; @@ -52,6 +53,7 @@ import org.apache.uima.internal.util.Misc; import org.apache.uima.internal.util.UIMAClassLoader; import org.apache.uima.internal.util.WeakIdentityMap; import org.apache.uima.jcas.cas.TOP; +import org.apache.uima.spi.JCasClassProvider; import org.apache.uima.util.Level; import org.apache.uima.util.Logger; @@ -194,6 +196,8 @@ public abstract class FSClassRegistry { // abstract to prevent instantiating; th private static final WeakIdentityMap<ClassLoader, Map<String, JCasClassInfo>> cl_to_type2JCas = WeakIdentityMap .newHashMap(); // identity: key is classloader private static final WeakIdentityMap<ClassLoader, StackTraceElement[]> cl_to_type2JCasStacks; + private static final WeakIdentityMap<ClassLoader, Map<String, Class<? extends TOP>>> cl_to_spiJCas = WeakIdentityMap + .newHashMap(); // private static final Map<ClassLoader, Map<String, JCasClassInfo>> cl_4pears_to_type2JCas = // Collections.synchronizedMap(new IdentityHashMap<>()); // identity: key is classloader @@ -921,6 +925,12 @@ public abstract class FSClassRegistry { // abstract to prevent instantiating; th Class<? extends TOP> clazz = null; String className = ti.getJCasClassName(); + Map<String, Class<? extends TOP>> spiJCasClasses = loadJCasClassesFromSPI(cl); + clazz = spiJCasClasses.get(className); + if (clazz != null) { + return clazz; + } + try { clazz = (Class<? extends TOP>) Class.forName(className, true, cl); } catch (ClassNotFoundException e) { @@ -933,6 +943,27 @@ public abstract class FSClassRegistry { // abstract to prevent instantiating; th return clazz; } + static Map<String, Class<? extends TOP>> loadJCasClassesFromSPI(ClassLoader cl) { + synchronized (cl_to_spiJCas) { + Map<String, Class<? extends TOP>> spiJCas = cl_to_spiJCas.get(cl); + if (spiJCas != null) { + return spiJCas; + } + + Map<String, Class<? extends TOP>> spiJCasClasses = new LinkedHashMap<>(); + ServiceLoader<JCasClassProvider> loader = ServiceLoader.load(JCasClassProvider.class, cl); + loader.forEach(provider -> { + List<Class<? extends TOP>> list = provider.listJCasClasses(); + if (list != null) { + list.forEach(item -> spiJCasClasses.put(item.getName(), item)); + } + }); + cl_to_spiJCas.put(cl, spiJCasClasses); + + return spiJCasClasses; + } + } + // SYNCHRONIZED static synchronized MethodHandle getConstantIntMethodHandle(int i) { diff --git a/uimaj-core/src/main/java/org/apache/uima/spi/JCasClassProvider.java b/uimaj-core/src/main/java/org/apache/uima/spi/JCasClassProvider.java new file mode 100644 index 000000000..a1f254523 --- /dev/null +++ b/uimaj-core/src/main/java/org/apache/uima/spi/JCasClassProvider.java @@ -0,0 +1,27 @@ +/* + * 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.uima.spi; + +import java.util.List; + +import org.apache.uima.jcas.cas.TOP; + +public interface JCasClassProvider { + List<Class<? extends TOP>> listJCasClasses(); +} diff --git a/uimaj-core/src/test/java/org/apache/uima/cas/impl/FSClassRegistryTest.java b/uimaj-core/src/test/java/org/apache/uima/cas/impl/FSClassRegistryTest.java index 78379f937..99a37df5d 100644 --- a/uimaj-core/src/test/java/org/apache/uima/cas/impl/FSClassRegistryTest.java +++ b/uimaj-core/src/test/java/org/apache/uima/cas/impl/FSClassRegistryTest.java @@ -19,9 +19,15 @@ package org.apache.uima.cas.impl; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import java.util.Map; import org.apache.uima.UIMAFramework; +import org.apache.uima.cas.test.Sentence; +import org.apache.uima.cas.test.Token; import org.apache.uima.jcas.JCas; +import org.apache.uima.jcas.cas.TOP; import org.apache.uima.resource.ResourceManager; import org.apache.uima.util.CasCreationUtils; import org.apache.uima.util.Level; @@ -84,6 +90,16 @@ public class FSClassRegistryTest { } } + @Test + public void thatJCasClassesCanBeLoadedThroughSPI() throws Exception { + Map<String, Class<? extends TOP>> jcasClasses = FSClassRegistry + .loadJCasClassesFromSPI(getClass().getClassLoader()); + + assertThat(jcasClasses).containsOnly( // + entry(Token.class.getName(), Token.class), // + entry(Sentence.class.getName(), Sentence.class)); + } + private void assertRegisteredClassLoaders(int aExpectedCount, String aDescription) { if (FSClassRegistry.clToType2JCasSize() > aExpectedCount) { FSClassRegistry.log_registered_classloaders(Level.INFO); diff --git a/uimaj-core/src/test/java/org/apache/uima/spi/JCasClassProviderForTesting.java b/uimaj-core/src/test/java/org/apache/uima/spi/JCasClassProviderForTesting.java new file mode 100644 index 000000000..29f5a5095 --- /dev/null +++ b/uimaj-core/src/test/java/org/apache/uima/spi/JCasClassProviderForTesting.java @@ -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.uima.spi; + +import static java.util.Arrays.asList; + +import java.util.List; + +import org.apache.uima.cas.test.Sentence; +import org.apache.uima.cas.test.Token; +import org.apache.uima.jcas.cas.TOP; + +public class JCasClassProviderForTesting implements JCasClassProvider { + + @Override + public List<Class<? extends TOP>> listJCasClasses() { + return asList(Token.class, Sentence.class); + } +} diff --git a/uimaj-core/src/test/resources/META-INF/services/org.apache.uima.spi.JCasClassProvider b/uimaj-core/src/test/resources/META-INF/services/org.apache.uima.spi.JCasClassProvider new file mode 100644 index 000000000..59f27063f --- /dev/null +++ b/uimaj-core/src/test/resources/META-INF/services/org.apache.uima.spi.JCasClassProvider @@ -0,0 +1 @@ +org.apache.uima.spi.JCasClassProviderForTesting diff --git a/uimaj-ep-cas-editor-ide/.gitignore b/uimaj-ep-cas-editor-ide/.gitignore index 00d2ab71d..f837dacf9 100644 --- a/uimaj-ep-cas-editor-ide/.gitignore +++ b/uimaj-ep-cas-editor-ide/.gitignore @@ -1,2 +1,3 @@ /.apt_generated/ /.apt_generated_tests/ +/META-INF/ diff --git a/uimaj-ep-cas-editor/.gitignore b/uimaj-ep-cas-editor/.gitignore index 00d2ab71d..f837dacf9 100644 --- a/uimaj-ep-cas-editor/.gitignore +++ b/uimaj-ep-cas-editor/.gitignore @@ -1,2 +1,3 @@ /.apt_generated/ /.apt_generated_tests/ +/META-INF/ diff --git a/uimaj-ep-configurator/.gitignore b/uimaj-ep-configurator/.gitignore index 00d2ab71d..f837dacf9 100644 --- a/uimaj-ep-configurator/.gitignore +++ b/uimaj-ep-configurator/.gitignore @@ -1,2 +1,3 @@ /.apt_generated/ /.apt_generated_tests/ +/META-INF/ diff --git a/uimaj-ep-debug/.gitignore b/uimaj-ep-debug/.gitignore index 00d2ab71d..f837dacf9 100644 --- a/uimaj-ep-debug/.gitignore +++ b/uimaj-ep-debug/.gitignore @@ -1,2 +1,3 @@ /.apt_generated/ /.apt_generated_tests/ +/META-INF/ diff --git a/uimaj-ep-jcasgen/.gitignore b/uimaj-ep-jcasgen/.gitignore index 00d2ab71d..f837dacf9 100644 --- a/uimaj-ep-jcasgen/.gitignore +++ b/uimaj-ep-jcasgen/.gitignore @@ -1,2 +1,3 @@ /.apt_generated/ /.apt_generated_tests/ +/META-INF/ diff --git a/uimaj-ep-launcher/.gitignore b/uimaj-ep-launcher/.gitignore index 00d2ab71d..f837dacf9 100644 --- a/uimaj-ep-launcher/.gitignore +++ b/uimaj-ep-launcher/.gitignore @@ -1,2 +1,3 @@ /.apt_generated/ /.apt_generated_tests/ +/META-INF/ diff --git a/uimaj-ep-pear-packager/.gitignore b/uimaj-ep-pear-packager/.gitignore index 00d2ab71d..f837dacf9 100644 --- a/uimaj-ep-pear-packager/.gitignore +++ b/uimaj-ep-pear-packager/.gitignore @@ -1,2 +1,3 @@ /.apt_generated/ /.apt_generated_tests/ +/META-INF/ diff --git a/uimaj-ep-runtime/.gitignore b/uimaj-ep-runtime/.gitignore index 00d2ab71d..f837dacf9 100644 --- a/uimaj-ep-runtime/.gitignore +++ b/uimaj-ep-runtime/.gitignore @@ -1,2 +1,3 @@ /.apt_generated/ /.apt_generated_tests/ +/META-INF/
