1   package org.daisy.pipeline.modules.impl;
2   
3   import java.net.URI;
4   import java.util.LinkedList;
5   
6   import org.daisy.pipeline.modules.Component;
7   import org.daisy.pipeline.modules.Module;
8   import org.daisy.pipeline.modules.ModuleRegistry;
9   import org.daisy.pipeline.modules.ResolutionException;
10  import org.daisy.pipeline.xmlcatalog.XmlCatalogParser;
11  import org.osgi.service.component.annotations.Activate;
12  import org.osgi.service.component.annotations.Reference;
13  import org.osgi.service.component.annotations.ReferenceCardinality;
14  import org.osgi.service.component.annotations.ReferencePolicy;
15  import org.slf4j.Logger;
16  import org.slf4j.LoggerFactory;
17  import org.slf4j.helpers.NOPLogger;
18  
19  @org.osgi.service.component.annotations.Component(
20      name = "org.daisy.pipeline.modules.impl.Module_epub_utils",
21      service = { Module.class }
22  )
23  public class Module_epub_utils extends Module {
24  
25      private static final Logger logger = LoggerFactory.getLogger(Module_epub_utils.class);
26  
27      private boolean initialized = false;
28      private XmlCatalogParser catalogParser;
29      private ModuleRegistry moduleRegistry;
30      private final LinkedList<Component> componentsToAdd;
31      private final LinkedList<Component> componentsBeingAdded;
32  
33      public Module_epub_utils() {
34          super("epub-utils",
35                "2.2.1",
36                "DAISY Pipeline 2 module :: EPUB Utilities");
37          componentsToAdd = new LinkedList<>();
38          componentsBeingAdded = new LinkedList<>();
39      }
40  
41      @Reference(
42          name = "XmlCatalogParser",
43          unbind = "-",
44          service = XmlCatalogParser.class,
45          cardinality = ReferenceCardinality.MANDATORY,
46          policy = ReferencePolicy.STATIC
47      )
48      public void setParser(XmlCatalogParser parser) {
49          catalogParser = parser;
50      }
51  
52      @Reference(
53          name = "ModuleRegistry",
54          unbind = "-",
55          service = ModuleRegistry.class,
56          cardinality = ReferenceCardinality.MANDATORY,
57          policy = ReferencePolicy.STATIC
58      )
59      public void setModuleRegistry(ModuleRegistry registry) {
60          moduleRegistry = registry;
61      }
62  
63      private void tryResolveComponent(String uri, String versionRange) throws ResolutionException {
64          if (moduleRegistry.getModuleByComponent(URI.create(uri), versionRange) == null)
65              throw new ResolutionException("Unresolved dependency " + uri + " with version=" + versionRange);
66      }
67  
68      @Activate
69      protected void init() {
70          logger.debug("Initializing module " + getName());
71          Module tmpModule = new Module(getName(), getVersion(), getTitle()) {
72              @Override public void resolveDependencies() {}
73              @Override public Logger getLogger() { return NOPLogger.NOP_LOGGER; }
74          };
75          Module.parseCatalog(tmpModule, catalogParser);
76          for (String e : tmpModule.getEntities()) {
77              addEntity(tmpModule.getEntity(e));
78              logger.debug("Loaded entity: " + e);
79          }
80          for (URI c : tmpModule.getComponents()) {
81              components.put(c, () -> null); // will be replaced during resolveDependencies()
82              componentsToAdd.add(tmpModule.getComponent(c));
83          }
84          logger.debug("Module " + getName() + " initialized, but dependencies have not been resolved yet");
85      }
86  
87      // Not calling resolveDependencies() during object construction yet because it depends
88      // on other modules, and other modules may depend on this module. resolveDependencies()
89      // will be called when the object gets bound in ModuleRegistry. The method may recursively
90      // call itself. It copes with that by activating components in a different order
91      // when called recursively. ModuleRegistry has protection against endless recursion.
92      @Override
93      public void resolveDependencies() {
94          if (!initialized) {
95              boolean recursive = !componentsBeingAdded.isEmpty();
96              if (recursive)
97                  logger.debug("Resolving dependencies of module " + getName() + " (continuing in recursive call)");
98              else
99                  logger.debug("Resolving dependencies of module " + getName());
100             while (true) {
101                 if (componentsToAdd.isEmpty()) {
102                     if (componentsBeingAdded.isEmpty())
103                         break;
104                     componentsToAdd.addAll(componentsBeingAdded);
105                     componentsBeingAdded.clear();
106                 }
107                 Component c = componentsToAdd.poll();
108                 componentsBeingAdded.add(c);
109                 if (addComponent(c)) // may call resolveDependencies() recursively
110                     logger.debug("Loaded component: " + c.getURI());
111                 componentsBeingAdded.remove(c);
112                 componentsToAdd.remove(c);
113             }
114             if (!initialized)
115                 logger.debug("Done resolving dependencies of module " + getName());
116             initialized = true;
117         }
118     }
119 
120     @Override
121     protected boolean addComponent(Component component) {
122         String name = component.getURI().toString();
123         try {
124             if ("http://www.daisy.org/pipeline/modules/epub-utils/library.xpl".equals(name)) {
125                 tryResolveComponent("http://www.daisy.org/pipeline/modules/common-utils/i18n.xsl",
126                                     "[3.1.2,4.0.0)");
127                 tryResolveComponent("http://www.daisy.org/pipeline/modules/mediatype-utils/library.xpl",
128                                     "[2.0.2,3.0.0)");
129                 tryResolveComponent("http://www.daisy.org/pipeline/modules/ace-adapter/library.xpl",
130                                     "[1.0.9,2.0.0)");
131                 tryResolveComponent("http://www.daisy.org/pipeline/modules/file-utils/library.xpl",
132                                     "[4.3.1,5.0.0)");
133                 tryResolveComponent("http://www.daisy.org/pipeline/modules/file-utils/uri-functions.xsl",
134                                     "[4.3.1,5.0.0)");
135                 tryResolveComponent("http://www.daisy.org/pipeline/modules/html-utils/library.xsl",
136                                     "[6.4.1,7.0.0)");
137                 tryResolveComponent("http://www.daisy.org/pipeline/modules/html-utils/library.xpl",
138                                     "[6.4.1,7.0.0)");
139                 tryResolveComponent("http://www.daisy.org/pipeline/modules/common-utils/library.xpl",
140                                     "[3.1.2,4.0.0)");
141                 tryResolveComponent("http://www.daisy.org/pipeline/modules/zip-utils/library.xpl",
142                                     "[2.1.8,3.0.0)");
143                 tryResolveComponent("http://www.daisy.org/pipeline/modules/odf-utils/library.xpl",
144                                     "[1.0.4,2.0.0)");
145                 tryResolveComponent("http://www.daisy.org/pipeline/modules/file-utils/library.xsl",
146                                     "[4.3.1,5.0.0)");
147                 tryResolveComponent("http://www.daisy.org/pipeline/modules/common-utils/library.xsl",
148                                     "[3.1.2,4.0.0)");
149                 tryResolveComponent("http://www.daisy.org/pipeline/modules/common-utils/generate-id.xsl",
150                                     "[3.1.2,4.0.0)");
151                 tryResolveComponent("http://www.daisy.org/pipeline/modules/fileset-utils/library.xpl",
152                                     "[6.1.4,7.0.0)");
153                 tryResolveComponent("http://www.daisy.org/pipeline/modules/validation-utils/library.xpl",
154                                     "[2.0.1,3.0.0)");
155                 tryResolveComponent("http://www.daisy.org/pipeline/modules/smil-utils/library.xpl",
156                                     "[4.0.2,5.0.0)");
157                 tryResolveComponent("http://www.daisy.org/pipeline/modules/smil-utils/clock-functions.xsl",
158                                     "[4.0.2,5.0.0)");
159                 tryResolveComponent("http://www.daisy.org/pipeline/modules/epubcheck-adapter/library.xpl",
160                                     "[1.1.13,2.0.0)");
161                 tryResolveComponent("http://www.daisy.org/pipeline/modules/daisy3-utils/library.xpl",
162                                     "[4.1.6,5.0.0)");
163             }
164         } catch (ResolutionException re) {
165             logger.warn("Component " + component.getURI() + " can not be loaded: " + re.getMessage());
166             return false;
167         }
168         return super.addComponent(component);
169     }
170 }