package org.simantics.scl.osgi.internal; import java.util.ArrayList; import java.util.Collection; import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; import org.simantics.scl.compiler.module.repository.UpdateListener; import org.simantics.scl.compiler.source.ModuleSource; import org.simantics.scl.compiler.source.repository.ModuleSourceRepository; import gnu.trove.procedure.TObjectProcedure; public class ServiceBasedModuleSourceRepository implements ModuleSourceRepository { ServiceTracker sourceRepositories; public ServiceBasedModuleSourceRepository(BundleContext context) { sourceRepositories = new ServiceTracker( context, ModuleSourceRepository.class, null); sourceRepositories.open(); } @Override public ModuleSource getModuleSource(String moduleName, UpdateListener listener) { ModuleSource result = null; ModuleSourceRepository resultRepository = null; Object[] services = sourceRepositories.getServices(); if(services != null) for(Object sourceRepository_ : services) { ModuleSourceRepository sourceLoader = (ModuleSourceRepository)sourceRepository_; ModuleSource source = sourceLoader.getModuleSource(moduleName, listener); if(source != null) { if(result != null) { double resultPriority = result.getPriority(); double sourcePriority = source.getPriority(); if(resultPriority > sourcePriority) continue; if(resultPriority == sourcePriority) throw new RuntimeException("Module " + moduleName + " has two sources " + result + " (from "+resultRepository+"), " + source + " (from "+sourceLoader+") with the same priority."); } result = source; resultRepository = sourceLoader; } } return result; } @Override public String getDocumentation(String documentationName) { // getServices is internally synchronized, so no need to synchronize here Object[] services = sourceRepositories.getServices(); if(services != null) for(Object sourceRepository_ : services) { ModuleSourceRepository sourceLoader = (ModuleSourceRepository)sourceRepository_; String documentation = sourceLoader.getDocumentation(documentationName); if(documentation != null) return documentation; } return null; } @Override public void forAllModules(TObjectProcedure procedure) { // getServices is internally synchronized, so no need to synchronize here Object[] services = sourceRepositories.getServices(); if(services != null) for(Object sourceRepository_ : services) { ModuleSourceRepository sourceLoader = (ModuleSourceRepository)sourceRepository_; sourceLoader.forAllModules(procedure); } } @Override public Collection getModuleNames() { ArrayList result = new ArrayList<>(); forAllModules((String name) -> { result.add(name); return true; }); return result; } @Override public void forAllDocumentations(TObjectProcedure procedure) { Object[] services = sourceRepositories.getServices(); if(services != null) for(Object sourceRepository_ : services) { ModuleSourceRepository sourceLoader = (ModuleSourceRepository)sourceRepository_; sourceLoader.forAllDocumentations(procedure); } } @Override public Collection getDocumentationNames() { ArrayList result = new ArrayList<>(); forAllDocumentations((String name) -> { result.add(name); return true; }); return result; } @Override public void checkUpdates() { for(Object service_ : sourceRepositories.getServices()) { ModuleSourceRepository service = (ModuleSourceRepository)service_; service.checkUpdates(); } } }