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/

Reply via email to