Fixing a deadlock. Some improvements to ModuleSourceRepository API
[simantics/platform.git] / bundles / org.simantics.scl.osgi / src / org / simantics / scl / osgi / internal / ServiceBasedModuleSourceRepository.java
1 package org.simantics.scl.osgi.internal;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5
6 import org.osgi.framework.BundleContext;
7 import org.osgi.util.tracker.ServiceTracker;
8 import org.simantics.scl.compiler.module.repository.UpdateListener;
9 import org.simantics.scl.compiler.source.ModuleSource;
10 import org.simantics.scl.compiler.source.repository.ModuleSourceRepository;
11
12 import gnu.trove.procedure.TObjectProcedure;
13
14 public class ServiceBasedModuleSourceRepository implements ModuleSourceRepository {
15
16     ServiceTracker<ModuleSourceRepository, ModuleSourceRepository> sourceRepositories;
17
18     public ServiceBasedModuleSourceRepository(BundleContext context) {
19         sourceRepositories = new ServiceTracker<ModuleSourceRepository, ModuleSourceRepository>(
20                 context, ModuleSourceRepository.class, null);
21         sourceRepositories.open();
22     }
23
24     @Override
25     public ModuleSource getModuleSource(String moduleName,
26             UpdateListener listener) {
27         ModuleSource result = null;
28         Object[] services = sourceRepositories.getServices();
29         if(services != null)
30             for(Object sourceRepository_ : services) {
31                 ModuleSourceRepository sourceLoader = (ModuleSourceRepository)sourceRepository_;
32                 ModuleSource source = sourceLoader.getModuleSource(moduleName, listener);
33                 if(source != null) {
34                     if(result != null) {
35                         double resultPriority = result.getPriority();
36                         double sourcePriority = source.getPriority();
37                         if(resultPriority > sourcePriority)
38                             continue;
39                         if(resultPriority == sourcePriority)
40                             throw new RuntimeException("Module " + moduleName + " has two sources " + result + ", " +
41                                     source + " with the same priority.");
42                     }
43                     result = source;
44                 }
45             }
46         return result;
47     }
48     
49     @Override
50     public String getDocumentation(String documentationName) {
51         // getServices is internally synchronized, so no need to synchronize here
52         Object[] services = sourceRepositories.getServices();
53         if(services != null)
54             for(Object sourceRepository_ : services) {
55                 ModuleSourceRepository sourceLoader = (ModuleSourceRepository)sourceRepository_;
56                 String documentation = sourceLoader.getDocumentation(documentationName);
57                 if(documentation != null)
58                     return documentation;
59             }
60         return null;
61     }
62
63     @Override
64     public void forAllModules(TObjectProcedure<String> procedure) {
65         // getServices is internally synchronized, so no need to synchronize here
66         Object[] services = sourceRepositories.getServices();
67         if(services != null)
68             for(Object sourceRepository_ : services) {
69                 ModuleSourceRepository sourceLoader = (ModuleSourceRepository)sourceRepository_;
70                 sourceLoader.forAllModules(procedure);
71             }
72     }
73     
74     @Override
75     public Collection<String> getModuleNames() {
76         ArrayList<String> result = new ArrayList<>();
77         forAllModules((String name) -> {
78             result.add(name);
79             return true;
80         });
81         return result;
82     }
83     
84     @Override
85     public void forAllDocumentations(TObjectProcedure<String> procedure) {
86         Object[] services = sourceRepositories.getServices();
87         if(services != null)
88             for(Object sourceRepository_ : services) {
89                 ModuleSourceRepository sourceLoader = (ModuleSourceRepository)sourceRepository_;
90                 sourceLoader.forAllDocumentations(procedure);
91             }
92     }
93     
94     @Override
95     public Collection<String> getDocumentationNames() {
96         ArrayList<String> result = new ArrayList<>();
97         forAllDocumentations((String name) -> {
98             result.add(name);
99             return true;
100         });
101         return result;
102     }
103
104     @Override
105     public void checkUpdates() {
106         for(Object service_ : sourceRepositories.getServices()) {
107             ModuleSourceRepository service = (ModuleSourceRepository)service_;
108             service.checkUpdates();
109         }
110     }
111
112 }