1   package nl.dedicon.pipeline.braille.calabash.impl;
2   
3   import com.xmlcalabash.core.XProcException;
4   import com.xmlcalabash.core.XProcRuntime;
5   import com.xmlcalabash.core.XProcStep;
6   import com.xmlcalabash.io.ReadablePipe;
7   import com.xmlcalabash.io.WritablePipe;
8   import com.xmlcalabash.library.DefaultStep;
9   import com.xmlcalabash.runtime.XAtomicStep;
10  import java.io.InputStream;
11  import java.net.URL;
12  import java.util.ArrayList;
13  import java.util.List;
14  import net.sf.saxon.om.NodeInfo;
15  import net.sf.saxon.s9api.QName;
16  import net.sf.saxon.s9api.SaxonApiException;
17  import net.sf.saxon.s9api.XQueryCompiler;
18  import net.sf.saxon.s9api.XQueryEvaluator;
19  import net.sf.saxon.s9api.XQueryExecutable;
20  import net.sf.saxon.s9api.XdmAtomicValue;
21  import net.sf.saxon.s9api.XdmItem;
22  import net.sf.saxon.s9api.XdmNode;
23  import net.sf.saxon.s9api.XdmValue;
24  import org.daisy.braille.api.embosser.FileFormat;
25  import org.daisy.common.xproc.calabash.XProcStepProvider;
26  import static org.daisy.pipeline.braille.common.Provider.util.dispatch;
27  import static org.daisy.pipeline.braille.common.Provider.util.memoize;
28  import org.daisy.pipeline.braille.common.Provider.util.MemoizingProvider;
29  import org.daisy.pipeline.braille.common.Query;
30  import static org.daisy.pipeline.braille.common.Query.util.mutableQuery;
31  import static org.daisy.pipeline.braille.common.Query.util.query;
32  import org.daisy.pipeline.braille.pef.FileFormatProvider;
33  import org.osgi.service.component.annotations.Component;
34  import org.osgi.service.component.annotations.Reference;
35  import org.osgi.service.component.annotations.ReferenceCardinality;
36  import org.osgi.service.component.annotations.ReferencePolicy;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  /**
41   * XProc step that returns the URIs of the generated BRL files
42   * 
43   * @author Paul Rambags
44   */
45  public class BrlUrisStep extends DefaultStep {
46  
47      private static final String DEDICON_NAMESPACE = "http://www.dedicon.nl";
48  
49      private static final Logger logger = LoggerFactory.getLogger(MetadataStep.class);
50  
51      private static final QName _xquery = new QName("xquery");
52      private static final QName _brf_dir_href = new QName("brf-dir-href");
53      private static final QName _brf_file_extension = new QName("brf-file-extension");
54      private static final QName _brf_file_format = new QName("brf-file-format");
55      private static final QName _brf_name_pattern = new QName("brf-name-pattern");
56      private static final QName _brf_number_width = new QName("brf-number-width");
57  
58      private final MemoizingProvider<Query,FileFormat> fileFormatProvider;
59  
60      private ReadablePipe source = null;
61      private WritablePipe result = null;
62      
63      private BrlUrisStep(XProcRuntime runtime, XAtomicStep step, MemoizingProvider<Query,FileFormat> fileFormatProvider) {
64          super(runtime, step);
65          this.fileFormatProvider = fileFormatProvider;
66      }
67  
68      @Override
69      public void setInput(String port, ReadablePipe pipe) {
70          source = pipe;
71      }
72  
73      @Override
74      public void setOutput(String port, WritablePipe pipe) {
75          result = pipe;
76      }
77  
78      @Override
79      public void reset() {
80          source.resetReader();
81          result.resetWriter();
82      }
83  
84      @Override
85      public void run() throws SaxonApiException {
86          super.run();
87  
88          try {
89              
90              XdmNode pef = source.read();
91              
92              String xquery = getOption(_xquery, "");
93              String brfDirHref = getOption(_brf_dir_href, "");
94              String brfFileFormat = getOption(_brf_file_format, "");
95              String brfNamePattern = getOption(_brf_name_pattern, "");
96              int brfNumberWidth = getOption(_brf_number_width, 0);
97  
98              String brfFileExtension = getFileExtension(brfFileFormat);
99              InputStream query = new URL(xquery).openConnection().getInputStream();
100             
101             XQueryCompiler xqCompiler = runtime.getProcessor().newXQueryCompiler();
102 
103             XQueryExecutable xqExecutable = xqCompiler.compile(query);
104             XQueryEvaluator xqEvaluator = xqExecutable.load();
105 
106             xqEvaluator.setSource(pef.asSource());
107             xqEvaluator.setExternalVariable(_brf_dir_href, new XdmAtomicValue(brfDirHref));
108             xqEvaluator.setExternalVariable(_brf_name_pattern, new XdmAtomicValue(brfNamePattern));
109             xqEvaluator.setExternalVariable(_brf_number_width, new XdmAtomicValue(brfNumberWidth));
110             xqEvaluator.setExternalVariable(_brf_file_extension, new XdmAtomicValue(brfFileExtension));
111 
112             XdmValue xqResult = xqEvaluator.evaluate();
113             
114             for (XdmValue xqValue : xqResult) {
115                 if (xqValue instanceof XdmNode) {
116                     result.write((XdmNode)xqValue);
117                 }
118             };
119             
120         } catch (Exception e) {
121 
122             logger.error("dedicon:brl-uris failed", e);
123             throw new XProcException(step.getNode(), e);
124 
125         }
126     }
127 
128     private String getFileExtension (String fileFormatQuery) {
129         Query.MutableQuery q = mutableQuery(query(fileFormatQuery));
130         Iterable<FileFormat> fileFormats = fileFormatProvider.get(q);
131         String fileExtension = "";
132         for (FileFormat fileFormat : fileFormats) {
133             fileExtension = fileFormat.getFileExtension();
134             break;
135         }
136         return fileExtension;
137     }
138     
139     @Component(
140             name = "dedicon:brl-uris",
141             service = {XProcStepProvider.class},
142             property = {"type:String={http://www.dedicon.nl}brl-uris"}
143     )
144     public static class Provider implements XProcStepProvider {
145 
146         private List<FileFormatProvider> fileFormatProviders = new ArrayList<>();
147         private MemoizingProvider<Query,FileFormat> fileFormatProvider = memoize(dispatch(fileFormatProviders));
148 
149         @Override
150         public XProcStep newStep(XProcRuntime runtime, XAtomicStep step) {
151             return new BrlUrisStep(runtime, step, fileFormatProvider);
152         }
153 
154         @Reference(
155                 name = "FileFormatProvider",
156                 unbind = "unbindFileFormatProvider",
157                 service = FileFormatProvider.class,
158                 cardinality = ReferenceCardinality.MULTIPLE,
159                 policy = ReferencePolicy.DYNAMIC
160         )
161         protected void bindFileFormatProvider(FileFormatProvider provider) {
162                 fileFormatProviders.add(provider);
163         }
164 
165         protected void unbindFileFormatProvider(FileFormatProvider provider) {
166                 fileFormatProviders.remove(provider);
167                 this.fileFormatProvider.invalidateCache();
168         }
169     }
170 }