1 package org.daisy.pipeline.braille.common.impl;
2
3 import java.net.URI;
4 import java.util.Map;
5
6 import javax.xml.namespace.QName;
7
8 import com.google.common.base.MoreObjects;
9 import com.google.common.base.MoreObjects.ToStringHelper;
10 import com.google.common.collect.ImmutableMap;
11
12 import com.xmlcalabash.core.XProcRuntime;
13 import com.xmlcalabash.runtime.XAtomicStep;
14
15 import org.daisy.common.file.URLs;
16 import org.daisy.common.saxon.SaxonInputValue;
17 import org.daisy.common.transform.InputValue;
18 import org.daisy.common.transform.Mult;
19 import org.daisy.common.transform.SingleInSingleOutXMLTransformer;
20 import org.daisy.common.transform.TransformerException;
21 import org.daisy.common.transform.XMLInputValue;
22 import org.daisy.common.transform.XMLOutputValue;
23 import org.daisy.common.xproc.calabash.XProcStep;
24 import org.daisy.common.xproc.calabash.XProcStepProvider;
25 import org.daisy.common.xproc.XProcMonitor;
26 import org.daisy.pipeline.braille.common.AbstractBrailleTranslator;
27 import org.daisy.pipeline.braille.common.AbstractTransformProvider;
28 import org.daisy.pipeline.braille.common.AbstractTransformProvider.util.Function;
29 import org.daisy.pipeline.braille.common.AbstractTransformProvider.util.Iterables;
30 import static org.daisy.pipeline.braille.common.AbstractTransformProvider.util.Iterables.transform;
31 import static org.daisy.pipeline.braille.common.AbstractTransformProvider.util.logCreate;
32 import static org.daisy.pipeline.braille.common.AbstractTransformProvider.util.logSelect;
33 import org.daisy.pipeline.braille.common.BrailleTranslator;
34 import org.daisy.pipeline.braille.common.BrailleTranslatorProvider;
35 import org.daisy.pipeline.braille.common.BrailleTranslatorRegistry;
36 import org.daisy.pipeline.braille.common.calabash.CxEvalBasedTransformer;
37 import org.daisy.pipeline.braille.common.Hyphenator;
38 import org.daisy.pipeline.braille.common.HyphenatorRegistry;
39 import org.daisy.pipeline.braille.common.Query;
40 import org.daisy.pipeline.braille.common.Query.Feature;
41 import org.daisy.pipeline.braille.common.Query.MutableQuery;
42 import static org.daisy.pipeline.braille.common.Query.util.mutableQuery;
43 import org.daisy.pipeline.braille.common.TransformProvider;
44 import org.daisy.pipeline.braille.common.util.Function0;
45 import org.daisy.pipeline.braille.common.util.Functions;
46
47 import org.osgi.service.component.annotations.Activate;
48 import org.osgi.service.component.annotations.Component;
49 import org.osgi.service.component.annotations.Reference;
50 import org.osgi.service.component.annotations.ReferenceCardinality;
51 import org.osgi.service.component.annotations.ReferencePolicy;
52
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 import org.w3c.dom.Document;
57 import org.w3c.dom.Node;
58
59
60
61
62
63 public interface CSSBlockTransform {
64
65 @Component(
66 name = "org.daisy.pipeline.braille.common.impl.CSSBlockTransform.Provider",
67 service = {
68 BrailleTranslatorProvider.class,
69 TransformProvider.class
70 }
71 )
72 public class Provider extends AbstractTransformProvider<BrailleTranslator> implements BrailleTranslatorProvider<BrailleTranslator> {
73
74 private URI href;
75
76 @Activate
77 protected void activate(final Map<?,?> properties) {
78 href = URLs.asURI(URLs.getResourceFromJAR("xml/block-translator.xpl", CSSBlockTransform.class));
79 translatorRegistry = translatorRegistry.withContext(logger);
80 }
81
82 private final static Iterable<BrailleTranslator> empty = Iterables.<BrailleTranslator>empty();
83
84 protected Iterable<BrailleTranslator> _get(Query query) {
85 final MutableQuery q = mutableQuery(query);
86 for (Feature f : q.removeAll("input"))
87 if ("html".equals(f.getValue().get())) {}
88 else if (!"css".equals(f.getValue().get()))
89 return empty;
90 boolean braille = false; {
91 for (Feature f : q.removeAll("output"))
92 if ("css".equals(f.getValue().get())) {}
93 else if ("html".equals(f.getValue().get())) {}
94 else if ("braille".equals(f.getValue().get()))
95 braille = true;
96 else
97 return empty;
98 }
99 final String brailleCharset = q.containsKey("braille-charset") ? q.getOnly("braille-charset").getValue().get() : null;
100 q.add("input", "text-css");
101 if (braille)
102 q.add("output", "braille");
103 return transform(
104 logSelect(q, translatorRegistry.getWithHyphenator(q)),
105 new Function<BrailleTranslator,BrailleTranslator>() {
106 public BrailleTranslator _apply(BrailleTranslator translator) {
107 return __apply(
108 logCreate(new TransformImpl(translator, false, brailleCharset, q))
109 );
110 }
111 }
112 );
113 }
114
115 @Override
116 public ToStringHelper toStringHelper() {
117 return MoreObjects.toStringHelper("CSSBlockTransform$Provider");
118 }
119
120 private class TransformImpl extends AbstractBrailleTranslator implements XProcStepProvider {
121
122 private final Query mainQuery;
123 private final BrailleTranslator mainTranslator;
124 private final boolean forceMainTranslator;
125 private final Map<String,String> options;
126 private final String brailleCharset;
127
128
129
130
131
132
133
134
135 private TransformImpl(BrailleTranslator mainTranslator, boolean forceMainTranslator,
136 String brailleCharset, Query query) {
137 options = ImmutableMap.of("braille-charset", brailleCharset != null ? brailleCharset : "");
138 this.mainTranslator = mainTranslator;
139 this.forceMainTranslator = forceMainTranslator;
140 mainQuery = query;
141 this.brailleCharset = brailleCharset;
142 }
143
144 private Hyphenator hyphenator = null;
145
146 private TransformImpl(TransformImpl from, BrailleTranslator mainTranslator) {
147 super(from);
148 this.mainQuery = from.mainQuery;
149 this.mainTranslator = mainTranslator;
150 this.forceMainTranslator = from.forceMainTranslator;
151 this.options = from.options;
152 this.brailleCharset = from.brailleCharset;
153 }
154
155
156
157
158
159 public TransformImpl _withHyphenator(Hyphenator hyphenator) throws UnsupportedOperationException {
160 TransformImpl t = new TransformImpl(this, mainTranslator.withHyphenator(hyphenator));
161 Provider.this.rememberId(t);
162 return t;
163 }
164
165 @Override
166 public XProcStep newStep(XProcRuntime runtime, XAtomicStep step, XProcMonitor monitor, Map<String,String> properties) {
167 return XProcStep.of(
168 new SingleInSingleOutXMLTransformer() {
169 public Runnable transform(XMLInputValue<?> source, XMLOutputValue<?> result, InputValue<?> params) {
170 return () -> {
171 if (!(source instanceof SaxonInputValue))
172 throw new IllegalArgumentException();
173 Mult<SaxonInputValue> mult = ((SaxonInputValue)source).mult(2);
174
175
176 Node doc = mult.get().ensureSingleItem().asNodeIterator().next();
177 if (!(doc instanceof Document))
178 throw new TransformerException(new IllegalArgumentException());
179 String style = (((Document)doc).getDocumentElement()).getAttribute("style");
180 URI styleBaseURI = URLs.asURI(((Document)doc).getBaseURI());
181 BrailleTranslator compoundTranslator
182 = translatorRegistry.getWithHyphenator(mainQuery, style, styleBaseURI, forceMainTranslator)
183 .iterator().next();
184 if (hyphenator != null)
185 compoundTranslator = compoundTranslator.withHyphenator(hyphenator);
186 Function0<Void> evictTempTranslator; {
187 if (compoundTranslator != mainTranslator)
188
189 evictTempTranslator = Provider.this.provideTemporarily(compoundTranslator);
190 else
191 evictTempTranslator = Functions.noOp;
192 }
193
194
195 new CxEvalBasedTransformer(
196 href,
197 null,
198 ImmutableMap.<String,String>builder()
199 .putAll(options)
200 .put("text-transform",
201 mutableQuery().add("id", compoundTranslator.getIdentifier()).toString())
202 .build()
203 ).newStep(runtime, step, monitor, properties).transform(
204 ImmutableMap.of(
205 new QName("source"), mult.get(),
206 new QName("parameters"), params),
207 ImmutableMap.of(
208 new QName("result"), result)
209 ).run();
210 evictTempTranslator.apply();
211 };
212 }
213 },
214 runtime,
215 step
216 );
217 }
218
219 @Override
220 public ToStringHelper toStringHelper() {
221 return MoreObjects.toStringHelper("CSSBlockTransform$Provider$TransformImpl")
222 .add("translator", mainTranslator);
223 }
224 }
225
226
227
228
229 @Reference(
230 name = "BrailleTranslatorProvider",
231 unbind = "-",
232 service = BrailleTranslatorProvider.class,
233 cardinality = ReferenceCardinality.MULTIPLE,
234 policy = ReferencePolicy.STATIC
235 )
236 protected void bindBrailleTranslatorProvider(BrailleTranslatorProvider<?> provider) {
237 translatorRegistry.addProvider(provider);
238 }
239
240 @Reference(
241 name = "HyphenatorRegistry",
242 unbind = "-",
243 service = HyphenatorRegistry.class,
244 cardinality = ReferenceCardinality.MANDATORY,
245 policy = ReferencePolicy.STATIC
246 )
247 protected void bindHyphenatorRegistry(HyphenatorRegistry registry) {
248 translatorRegistry.bindHyphenatorRegistry(registry);
249 }
250
251 private BrailleTranslatorRegistry translatorRegistry = new BrailleTranslatorRegistry();
252
253 private static final Logger logger = LoggerFactory.getLogger(Provider.class);
254
255 }
256 }