1 package org.daisy.pipeline.braille.common;
2
3 import java.net.URI;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.function.Supplier;
7 import java.util.List;
8 import java.util.Map;
9
10 import com.google.common.base.Predicates;
11 import com.google.common.collect.Iterables;
12 import com.google.common.collect.Maps;
13
14 import org.daisy.pipeline.braille.common.Query.MutableQuery;
15 import static org.daisy.pipeline.braille.common.Query.util.mutableQuery;
16 import static org.daisy.pipeline.braille.common.TransformProvider.util.dispatch;
17 import static org.daisy.pipeline.braille.common.TransformProvider.util.logCreate;
18 import org.daisy.pipeline.braille.common.TransformProvider.util.Memoize;
19 import static org.daisy.pipeline.braille.common.util.Locales.parseLocale;
20 import org.daisy.pipeline.braille.common.util.Strings;
21
22 import org.osgi.service.component.annotations.Component;
23 import org.osgi.service.component.annotations.Reference;
24 import org.osgi.service.component.annotations.ReferenceCardinality;
25 import org.osgi.service.component.annotations.ReferencePolicy;
26
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 @Component(
31 name = "braille-translator-registry",
32 service = { BrailleTranslatorRegistry.class }
33 )
34 public class BrailleTranslatorRegistry extends Memoize<BrailleTranslator>
35 implements BrailleTranslatorProvider<BrailleTranslator> {
36
37 public BrailleTranslatorRegistry() {
38 super(true);
39 providers = new ArrayList<>();
40 dispatch = dispatch(providers);
41 context = logger;
42 unmodifiable = false;
43 }
44
45 private BrailleTranslatorRegistry(TransformProvider<BrailleTranslator> dispatch,
46 HyphenatorRegistry hyphenatorRegistry,
47 BrailleTranslatorRegistry from,
48 Logger context) {
49 super(from);
50 this.providers = null;
51 this.dispatch = dispatch;
52 this.hyphenatorRegistry = hyphenatorRegistry;
53 this.context = context;
54 this.unmodifiable = true;
55 }
56
57 private final List<TransformProvider<BrailleTranslator>> providers;
58 private final TransformProvider<BrailleTranslator> dispatch;
59 private final Logger context;
60 private final boolean unmodifiable;
61
62 @Reference(
63 name = "BrailleTranslatorProvider",
64 unbind = "-",
65 service = BrailleTranslatorProvider.class,
66 cardinality = ReferenceCardinality.MULTIPLE,
67 policy = ReferencePolicy.STATIC
68 )
69
70
71
72
73 public void addProvider(BrailleTranslatorProvider p) throws UnsupportedOperationException {
74 if (unmodifiable)
75 throw new UnsupportedOperationException("Unmodifiable");
76 providers.add(p);
77 }
78
79 @Override
80 public Iterable<BrailleTranslator> _get(Query q) {
81 return dispatch.get(q);
82 }
83
84 @Override
85 public BrailleTranslatorRegistry withContext(Logger context) {
86 return (BrailleTranslatorRegistry)super.withContext(context);
87 }
88
89 protected BrailleTranslatorRegistry _withContext(Logger context) {
90 if (this.context == context)
91 return this;
92 return new BrailleTranslatorRegistry(dispatch.withContext(context),
93 hyphenatorRegistry.withContext(context),
94 this,
95 context);
96 }
97
98 private HyphenatorRegistry hyphenatorRegistry;
99
100 @Reference(
101 name = "HyphenatorRegistry",
102 unbind = "-",
103 service = HyphenatorRegistry.class,
104 cardinality = ReferenceCardinality.MANDATORY,
105 policy = ReferencePolicy.STATIC
106 )
107
108
109
110
111 public void bindHyphenatorRegistry(HyphenatorRegistry registry) throws UnsupportedOperationException {
112 if (unmodifiable)
113 throw new UnsupportedOperationException("Unmodifiable");
114 hyphenatorRegistry = registry;
115 logger.debug("Binding hyphenator registry: " + registry);
116 }
117
118
119
120
121
122
123
124
125
126 public Iterable<BrailleTranslator> getWithHyphenator(Query query) {
127 return getWithHyphenator(this, hyphenatorRegistry, query, context);
128 }
129
130 private static Iterable<BrailleTranslator> getWithHyphenator(Provider<Query,BrailleTranslator> translatorProvider,
131 Provider<Query,Hyphenator> hyphenatorProvider,
132 Query query,
133 Logger context) {
134 if (query.containsKey("id"))
135 return translatorProvider.get(query);
136 MutableQuery q = mutableQuery(query);
137
138
139 MutableQuery hyphenatorQuery = mutableQuery();
140 String hyphenator = q.containsKey("hyphenator")
141 ? q.removeOnly("hyphenator").getValue().get()
142 : "auto";
143 if (!"auto".equals(hyphenator))
144 hyphenatorQuery.add("hyphenator", hyphenator);
145 String documentLocale; {
146 try {
147 documentLocale = q.containsKey("document-locale")
148 ? parseLocale(q.getOnly("document-locale").getValue().get()).toLanguageTag()
149 : null; }
150 catch (IllegalArgumentException e) {
151 logger.error("Invalid locale", e);
152 return Collections.emptyList(); }
153 }
154 if (documentLocale != null)
155 hyphenatorQuery.add("document-locale", documentLocale);
156 Iterable<Hyphenator> hyphenators; {
157 Iterable<Hyphenator> h = hyphenatorProvider.get(hyphenatorQuery.asImmutable());
158 if (documentLocale != null && !"auto".equals(hyphenator)) {
159
160 hyphenatorQuery.removeAll("document-locale");
161 h = Iterables.concat(h, hyphenatorProvider.get(hyphenatorQuery.asImmutable())); }
162 hyphenators = h;
163 }
164
165
166 Iterable<BrailleTranslator> translators = translatorProvider.get(q);
167 Iterable<BrailleTranslator> translatorsWithHyphenator =
168 Iterables.concat(
169 Iterables.transform(
170 translators,
171 t -> Iterables.filter(
172 Iterables.transform(
173 hyphenators,
174 h -> {
175 try {
176 return logCreate(t.withHyphenator(h), context);
177 } catch (UnsupportedOperationException e) {
178 logger.debug("Could not set hyphenator: " + e.getMessage());
179 return null;
180 }}),
181 Predicates.notNull())));
182 return "auto".equals(hyphenator)
183 ? Iterables.concat(translatorsWithHyphenator, translators)
184 : translatorsWithHyphenator;
185 }
186
187
188
189
190
191
192
193
194
195
196
197
198 public Iterable<BrailleTranslator> get(Query query, String style, URI baseURI, boolean forceMainTranslator) {
199 if (style != null) {
200 Map<String,Query> subQueries = TextTransformParser.getBrailleTranslatorQueries(style, baseURI, query);
201 if (subQueries != null && !subQueries.isEmpty()) {
202 Query mainQuery = subQueries.remove("auto");
203 if (mainQuery == null || forceMainTranslator)
204 mainQuery = query;
205 if (subQueries.isEmpty())
206 return get(mainQuery);
207 else {
208 Map<String,Supplier<BrailleTranslator>> subTranslators
209 = Maps.transformValues(
210 subQueries,
211
212
213 q -> () -> BrailleTranslatorRegistry.this.getWithHyphenator(q).iterator().next());
214 return Iterables.transform(
215 get(mainQuery),
216 t -> logCreate(new CompoundBrailleTranslator(t, subTranslators), context));
217 }
218 }
219 }
220 return get(query);
221 }
222
223
224
225
226
227
228
229
230
231
232 public Iterable<BrailleTranslator> getWithHyphenator(Query query, String style, URI baseURI, boolean forceMainTranslator) {
233 return getWithHyphenator(
234 q -> get(q, style, baseURI, forceMainTranslator),
235 q -> hyphenatorRegistry.get(q, style, baseURI),
236 query,
237 context);
238 }
239
240 @Override
241 public String toString() {
242 return "memoize(dispatch( " + Strings.join(providers, ", ") + " ))";
243 }
244
245 private static final Logger logger = LoggerFactory.getLogger(BrailleTranslatorRegistry.class);
246 }