1 package org.daisy.pipeline.braille.common.calabash.impl;
2
3 import java.util.ArrayList;
4 import java.util.Hashtable;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.NoSuchElementException;
9
10 import com.google.common.collect.ImmutableMap;
11 import com.xmlcalabash.core.XProcException;
12 import com.xmlcalabash.core.XProcRuntime;
13 import com.xmlcalabash.io.ReadablePipe;
14 import com.xmlcalabash.io.WritablePipe;
15 import com.xmlcalabash.model.RuntimeValue;
16 import com.xmlcalabash.runtime.XAtomicStep;
17
18 import net.sf.saxon.om.Item;
19 import net.sf.saxon.om.NodeInfo;
20 import net.sf.saxon.om.SequenceIterator;
21 import net.sf.saxon.s9api.QName;
22 import net.sf.saxon.s9api.SaxonApiException;
23 import net.sf.saxon.s9api.XdmNode;
24 import net.sf.saxon.value.StringValue;
25
26 import org.daisy.common.saxon.SaxonHelper;
27 import org.daisy.common.saxon.SaxonInputValue;
28 import org.daisy.common.transform.SingleInSingleOutXMLTransformer;
29 import org.daisy.common.transform.TransformerException;
30 import org.daisy.common.xproc.calabash.XMLCalabashInputValue;
31 import org.daisy.common.xproc.calabash.XMLCalabashOutputValue;
32 import org.daisy.common.xproc.calabash.XMLCalabashParameterInputValue;
33 import org.daisy.common.xproc.calabash.XProcStep;
34 import org.daisy.common.xproc.calabash.XProcStepProvider;
35 import org.daisy.common.xproc.XProcMonitor;
36 import org.daisy.pipeline.braille.common.Transform;
37 import org.daisy.pipeline.braille.common.TransformProvider;
38 import org.daisy.pipeline.braille.common.Query.MutableQuery;
39 import org.daisy.pipeline.braille.common.Query;
40 import static org.daisy.pipeline.braille.common.Query.util.mutableQuery;
41 import static org.daisy.pipeline.braille.common.Query.util.query;
42 import static org.daisy.pipeline.braille.common.TransformProvider.util.dispatch;
43 import static org.daisy.pipeline.braille.common.TransformProvider.util.logSelect;
44 import org.daisy.pipeline.braille.common.XMLTransform;
45
46 import org.osgi.service.component.annotations.Component;
47 import org.osgi.service.component.annotations.Reference;
48 import org.osgi.service.component.annotations.ReferenceCardinality;
49 import org.osgi.service.component.annotations.ReferencePolicy;
50
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 public class PxTransformStep implements XProcStep {
55
56 private final XProcMonitor monitor;
57 private final Map<String,String> properties;
58 private final TransformProvider<Transform> provider;
59 private final XProcRuntime runtime;
60 private final XAtomicStep step;
61 private ReadablePipe source = null;
62 private WritablePipe result = null;
63 private final Hashtable<QName,RuntimeValue> params = new Hashtable<>();
64 private final Hashtable<QName,RuntimeValue> options = new Hashtable<>();
65
66 private static final QName _query = new QName("query");
67
68
69
70
71 public PxTransformStep(XProcRuntime runtime,
72 XAtomicStep step,
73 XProcMonitor monitor,
74 Map<String,String> properties,
75 TransformProvider<Transform> provider) {
76 if (runtime == null)
77 throw new NullPointerException("runtime may not be null");
78 else
79 this.runtime = runtime;
80 this.step = step;
81 this.monitor = monitor;
82 this.properties = properties;
83 this.provider = provider;
84 }
85
86 @Override
87 public void setInput(String port, ReadablePipe pipe) {
88 source = pipe;
89 }
90
91 @Override
92 public void setOutput(String port, WritablePipe pipe) {
93 result = pipe;
94 }
95
96 @Override
97 public void reset() {
98 source.resetReader();
99 result.resetWriter();
100 }
101
102 @Override
103 public void setParameter(QName name, RuntimeValue value) {
104 params.put(name, value);
105 }
106
107 @Override
108 public void setParameter(String port, QName name, RuntimeValue value) {
109 setParameter(name, value);
110 }
111
112 @Override
113 public void setOption(QName name, RuntimeValue value) {
114 options.put(name, value);
115 }
116
117 @Override
118 public void run() throws SaxonApiException {
119 try {
120 Query query = null; {
121 RuntimeValue queryOption = options.get(_query);
122 if (queryOption != null) {
123 SequenceIterator iterator = queryOption.getValue().getUnderlyingValue().iterate();
124 Item i;
125 while ((i = iterator.next()) != null) {
126 Query q; {
127 if (i instanceof StringValue)
128 q = query(((StringValue)i).getStringValue());
129 else if (i instanceof NodeInfo)
130 q = query(
131 new SaxonInputValue(
132 (Iterator<XdmNode>)SaxonHelper.iteratorFromSequence(i, XdmNode.class)
133 ).asXMLStreamReader());
134 else
135 throw new IllegalArgumentException();
136 }
137 if (query == null)
138 query = q;
139 else if (query instanceof MutableQuery)
140 query = ((MutableQuery)query).addAll(q);
141 else
142 query = mutableQuery().addAll(query).addAll(q);
143 }
144 }
145 if (query instanceof MutableQuery)
146 query = ((MutableQuery)query).asImmutable();
147 }
148 SingleInSingleOutXMLTransformer xmlTransformer = null;
149 try {
150 for (Transform t : logSelect(query, provider, logger))
151 if (t instanceof XProcStepProvider) {
152
153 xmlTransformer = SingleInSingleOutXMLTransformer.from(
154 ((XProcStepProvider)t).newStep(runtime, step, monitor, properties));
155 break; }
156 else if (t instanceof XMLTransform) {
157
158
159 xmlTransformer = SingleInSingleOutXMLTransformer.from(
160 ((XMLTransform)t).fromXmlToXml());
161 break; }}
162 catch (NoSuchElementException e) {}
163 if (xmlTransformer == null)
164 throw new XProcException(step, "Could not find a Transform for query: " + query);
165 xmlTransformer.transform(
166 XMLCalabashInputValue.of(source),
167 XMLCalabashOutputValue.of(result, runtime),
168 XMLCalabashParameterInputValue.of(params)
169 ).run();
170 } catch (Throwable e) {
171 if (e instanceof TransformerException && e.getCause() instanceof XProcException)
172
173 throw (XProcException)e.getCause();
174 else
175 throw XProcStep.raiseError(e, step);
176 }
177 }
178
179 @Component(
180 name = "px:transform",
181 service = { XProcStepProvider.class },
182 property = { "type:String={http://www.daisy.org/ns/pipeline/xproc}transform" }
183 )
184 public static class StepProvider implements XProcStepProvider {
185
186 @Override
187 public XProcStep newStep(XProcRuntime runtime, XAtomicStep step, XProcMonitor monitor, Map<String,String> properties) {
188 return new PxTransformStep(runtime, step, monitor, properties, provider);
189 }
190
191 @Reference(
192 name = "TransformProvider",
193 unbind = "-",
194 service = TransformProvider.class,
195 cardinality = ReferenceCardinality.MULTIPLE,
196 policy = ReferencePolicy.STATIC
197 )
198 @SuppressWarnings(
199 "unchecked"
200 )
201 public void bindTransformProvider(TransformProvider<?> provider) {
202 providers.add((TransformProvider<Transform>)provider);
203 logger.debug("Adding Transform provider: {}", provider);
204 }
205
206 private List<TransformProvider<Transform>> providers = new ArrayList<>();
207 private TransformProvider<Transform> provider = dispatch(providers).withContext(logger);
208
209 }
210
211 private static final Logger logger = LoggerFactory.getLogger(PxTransformStep.class);
212
213 }