Skip to content

Commit

Permalink
Merge pull request #394 from apache/feature/385-Allow-import-of-type-…
Browse files Browse the repository at this point in the history
…systems-published-through-SPI

Issue #385: Allow import of type systems published through SPI
  • Loading branch information
reckart authored Sep 30, 2024
2 parents 49d52e7 + a7e0743 commit 4f0776c
Show file tree
Hide file tree
Showing 17 changed files with 643 additions and 254 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
Expand All @@ -48,6 +50,7 @@
import org.apache.uima.resource.metadata.impl.FsIndexKeyDescription_impl;
import org.apache.uima.resource.metadata.impl.Import_impl;
import org.apache.uima.spi.FsIndexCollectionProvider;
import org.apache.uima.spi.TypeSystemProvider;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
import org.slf4j.Logger;
Expand Down Expand Up @@ -330,10 +333,26 @@ static void loadFsIndexCollectionsFromScannedLocations(List<FsIndexDescription>
}

static void loadFsIndexCollectionsfromSPIs(List<FsIndexDescription> fsIndexList) {
ServiceLoader<FsIndexCollectionProvider> loader = ServiceLoader
.load(FsIndexCollectionProvider.class);
loader.forEach(provider -> {
for (FsIndexCollection fsIdxCol : provider.listFsIndexCollections()) {
var loaded = Collections.newSetFromMap(new IdentityHashMap<>());

ServiceLoader.load(FsIndexCollectionProvider.class).forEach(provider -> {
loaded.add(provider);
for (var fsIdxCol : provider.listFsIndexCollections()) {
loaded.add(fsIdxCol);
fsIndexList.addAll(asList(fsIdxCol.getFsIndexes()));
LOG.debug("Loaded SPI-provided index collection at [{}]", fsIdxCol.getSourceUrlString());
}
});

ServiceLoader.load(TypeSystemProvider.class).forEach(provider -> {
if (loaded.contains(provider)) {
return;
}

for (var fsIdxCol : provider.listFsIndexCollections()) {
if (loaded.contains(fsIdxCol)) {
continue;
}
fsIndexList.addAll(asList(fsIdxCol.getFsIndexes()));
LOG.debug("Loaded SPI-provided index collection at [{}]", fsIdxCol.getSourceUrlString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
Expand All @@ -40,6 +42,7 @@
import org.apache.uima.resource.metadata.TypePriorityList;
import org.apache.uima.resource.metadata.impl.TypePriorities_impl;
import org.apache.uima.spi.TypePrioritiesProvider;
import org.apache.uima.spi.TypeSystemProvider;
import org.apache.uima.util.CasCreationUtils;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
Expand Down Expand Up @@ -143,9 +146,9 @@ public static TypePriorities createTypePriorities() throws ResourceInitializatio

static void loadTypePrioritiesFromScannedLocations(List<TypePriorities> typePrioritiesList,
ResourceManager aResMgr) throws ResourceInitializationException {
for (String location : scanTypePrioritiesDescriptors()) {
for (var location : scanTypePrioritiesDescriptors()) {
try {
TypePriorities priorities = typePriorities.get(location);
var priorities = typePriorities.get(location);

if (priorities == PLACEHOLDER) {
// If the description has not yet been loaded, load it
Expand All @@ -165,9 +168,27 @@ static void loadTypePrioritiesFromScannedLocations(List<TypePriorities> typePrio
}

static void loadTypePrioritiesFromSPIs(List<TypePriorities> typePrioritiesList) {
ServiceLoader<TypePrioritiesProvider> loader = ServiceLoader.load(TypePrioritiesProvider.class);
loader.forEach(provider -> {
for (TypePriorities desc : provider.listTypePriorities()) {
var loaded = Collections.newSetFromMap(new IdentityHashMap<>());

ServiceLoader.load(TypePrioritiesProvider.class).forEach(provider -> {
loaded.add(provider);

for (var desc : provider.listTypePriorities()) {
loaded.add(desc);
typePrioritiesList.add(desc);
LOG.debug("Loaded SPI-provided type priorities at [{}]", desc.getSourceUrlString());
}
});

ServiceLoader.load(TypeSystemProvider.class).forEach(provider -> {
if (loaded.contains(provider)) {
return;
}

for (var desc : provider.listTypePriorities()) {
if (loaded.contains(desc)) {
continue;
}
typePrioritiesList.add(desc);
LOG.debug("Loaded SPI-provided type priorities at [{}]", desc.getSourceUrlString());
}
Expand All @@ -185,8 +206,8 @@ static void loadTypePrioritiesFromSPIs(List<TypePriorities> typePrioritiesList)
*/
public static String[] scanTypePrioritiesDescriptors() throws ResourceInitializationException {
synchronized (SCAN_LOCK) {
ClassLoader cl = ClassLoaderUtils.findClassloader();
String[] typePrioritesLocations = typePrioritesLocationsByClassloader.get(cl);
var cl = ClassLoaderUtils.findClassloader();
var typePrioritesLocations = typePrioritesLocationsByClassloader.get(cl);
if (typePrioritesLocations == null) {
typePrioritesLocations = scanDescriptors(MetaDataType.TYPE_PRIORITIES);
internTypePrioritiesLocations(typePrioritesLocations);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.WeakHashMap;

Expand All @@ -40,6 +41,7 @@
import org.apache.uima.resource.metadata.impl.Import_impl;
import org.apache.uima.resource.metadata.impl.TypeSystemDescription_impl;
import org.apache.uima.spi.TypeSystemDescriptionProvider;
import org.apache.uima.spi.TypeSystemProvider;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
import org.slf4j.Logger;
Expand Down Expand Up @@ -81,14 +83,14 @@ private TypeSystemDescriptionFactory() {
*/
public static TypeSystemDescription createTypeSystemDescription(String... descriptorNames) {

TypeSystemDescription typeSystem = new TypeSystemDescription_impl();
List<Import> imports = new ArrayList<>();
for (String descriptorName : descriptorNames) {
Import imp = new Import_impl();
var typeSystem = new TypeSystemDescription_impl();
var imports = new ArrayList<Import>();
for (var descriptorName : descriptorNames) {
var imp = new Import_impl();
imp.setName(descriptorName);
imports.add(imp);
}
Import[] importArray = new Import[imports.size()];
var importArray = new Import[imports.size()];
typeSystem.setImports(imports.toArray(importArray));
return typeSystem;
}
Expand All @@ -103,14 +105,14 @@ public static TypeSystemDescription createTypeSystemDescription(String... descri
public static TypeSystemDescription createTypeSystemDescriptionFromPath(
String... descriptorURIs) {

TypeSystemDescription typeSystem = new TypeSystemDescription_impl();
List<Import> imports = new ArrayList<>();
for (String descriptorURI : descriptorURIs) {
Import imp = new Import_impl();
var typeSystem = new TypeSystemDescription_impl();
var imports = new ArrayList<Import>();
for (var descriptorURI : descriptorURIs) {
var imp = new Import_impl();
imp.setLocation(descriptorURI);
imports.add(imp);
}
Import[] importArray = new Import[imports.size()];
var importArray = new Import[imports.size()];
typeSystem.setImports(imports.toArray(importArray));
return typeSystem;
}
Expand All @@ -127,12 +129,12 @@ public static TypeSystemDescription createTypeSystemDescriptionFromPath(
public static TypeSystemDescription createTypeSystemDescription()
throws ResourceInitializationException {

ClassLoader cl = ClassLoaderUtils.findClassloader();
TypeSystemDescription tsd = typeDescriptorByClassloader.get(cl);
var cl = ClassLoaderUtils.findClassloader();
var tsd = typeDescriptorByClassloader.get(cl);
if (tsd == null) {
synchronized (CREATE_LOCK) {
ResourceManager resMgr = ResourceManagerFactory.newResourceManager();
List<TypeSystemDescription> tsdList = new ArrayList<>();
var resMgr = ResourceManagerFactory.newResourceManager();
var tsdList = new ArrayList<TypeSystemDescription>();

loadTypeSystemDescriptionsFromScannedLocations(tsdList, resMgr);
loadTypeSystemDescriptionsFromSPIs(tsdList);
Expand All @@ -147,9 +149,9 @@ public static TypeSystemDescription createTypeSystemDescription()

static void loadTypeSystemDescriptionsFromScannedLocations(List<TypeSystemDescription> tsdList,
ResourceManager aResMgr) throws ResourceInitializationException {
for (String location : scanTypeDescriptors()) {
for (var location : scanTypeDescriptors()) {
try {
TypeSystemDescription description = typeDescriptors.get(location);
var description = typeDescriptors.get(location);

if (description == PLACEHOLDER) {
// If the description has not yet been loaded, load it
Expand All @@ -169,10 +171,26 @@ static void loadTypeSystemDescriptionsFromScannedLocations(List<TypeSystemDescri
}

static void loadTypeSystemDescriptionsFromSPIs(List<TypeSystemDescription> tsdList) {
ServiceLoader<TypeSystemDescriptionProvider> loader = ServiceLoader
.load(TypeSystemDescriptionProvider.class);
loader.forEach(provider -> {
for (TypeSystemDescription desc : provider.listTypeSystemDescriptions()) {
var loaded = Collections.newSetFromMap(new IdentityHashMap<>());

ServiceLoader.load(TypeSystemDescriptionProvider.class).forEach(provider -> {
loaded.add(provider);
for (var desc : provider.listTypeSystemDescriptions()) {
loaded.add(desc);
tsdList.add(desc);
LOG.debug("Loaded SPI-provided type system at [{}]", desc.getSourceUrlString());
}
});

ServiceLoader.load(TypeSystemProvider.class).forEach(provider -> {
if (loaded.contains(provider)) {
return;
}

for (var desc : provider.listTypeSystemDescriptions()) {
if (loaded.contains(desc)) {
continue;
}
tsdList.add(desc);
LOG.debug("Loaded SPI-provided type system at [{}]", desc.getSourceUrlString());
}
Expand All @@ -191,8 +209,8 @@ static void loadTypeSystemDescriptionsFromSPIs(List<TypeSystemDescription> tsdLi
public static String[] scanTypeDescriptors() throws ResourceInitializationException {

synchronized (SCAN_LOCK) {
ClassLoader cl = ClassLoaderUtils.findClassloader();
String[] typeDescriptorLocations = typeDescriptorLocationsByClassloader.get(cl);
var cl = ClassLoaderUtils.findClassloader();
var typeDescriptorLocations = typeDescriptorLocationsByClassloader.get(cl);

if (typeDescriptorLocations == null) {
typeDescriptorLocations = scanDescriptors(MetaDataType.TYPE_SYSTEM);
Expand All @@ -210,10 +228,10 @@ private static void internTypeDescriptorLocations(String[] typeDescriptorLocatio
// We "intern" the location strings because we will use them as keys in the WeakHashMap
// caching the parsed type systems. As part of this process, we put a PLACEHOLDER into the
// map which is replaced when the type system is actually loaded
Map<String, String> locationStrings = new HashMap<>();
var locationStrings = new HashMap<String, String>();
typeDescriptors.keySet().stream().forEach(loc -> locationStrings.put(loc, loc));
for (int i = 0; i < typeDescriptorLocations.length; i++) {
String existingLocString = locationStrings.get(typeDescriptorLocations[i]);
var existingLocString = locationStrings.get(typeDescriptorLocations[i]);
if (existingLocString == null) {
typeDescriptors.put(typeDescriptorLocations[i], PLACEHOLDER);
locationStrings.put(typeDescriptorLocations[i], typeDescriptorLocations[i]);
Expand Down
5 changes: 4 additions & 1 deletion uimaj-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,10 @@
</Export-Package>
<Require-Capability>
osgi.extender;filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional,
osgi.serviceloader;filter:="(osgi.serviceloader=org.apache.uima.spi.JCasClassProvider)";cardinality:=multiple;resolution:=optional
osgi.serviceloader;filter:="(osgi.serviceloader=org.apache.uima.spi.JCasClassProvider)";cardinality:=multiple;resolution:=optional,
osgi.serviceloader;filter:="(osgi.serviceloader=org.apache.uima.spi.TypeSystemDescriptionProvider)";cardinality:=multiple;resolution:=optional,
osgi.serviceloader;filter:="(osgi.serviceloader=org.apache.uima.spi.TypePrioritiesProvider)";cardinality:=multiple;resolution:=optional,
osgi.serviceloader;filter:="(osgi.serviceloader=org.apache.uima.spi.FsIndexCollectionProvider)";cardinality:=multiple;resolution:=optional
</Require-Capability>
</instructions>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.apache.uima.internal.util.WeakIdentityMap;
import org.apache.uima.jcas.cas.TOP;
import org.apache.uima.spi.JCasClassProvider;
import org.apache.uima.spi.TypeSystemProvider;
import org.apache.uima.util.Level;
import org.apache.uima.util.Logger;

Expand Down Expand Up @@ -980,13 +981,21 @@ static Map<String, Class<? extends TOP>> loadJCasClassesFromSPI(ClassLoader cl)
}

var spiJCasClasses = new LinkedHashMap<String, Class<? extends TOP>>();
var loader = ServiceLoader.load(JCasClassProvider.class, cl);
loader.forEach(provider -> {

ServiceLoader.load(JCasClassProvider.class, cl).forEach(provider -> {
var list = provider.listJCasClasses();
if (list != null) {
list.forEach(item -> spiJCasClasses.put(item.getName(), item));
}
});

ServiceLoader.load(TypeSystemProvider.class, cl).forEach(provider -> {
var list = provider.listJCasClasses();
if (list != null) {
list.forEach(item -> spiJCasClasses.put(item.getName(), item));
}
});

cl_to_spiJCas.put(cl, spiJCasClasses);

return spiJCasClasses;
Expand Down
Loading

0 comments on commit 4f0776c

Please sign in to comment.