1 package net.sf.okapi.common.filters;
2
3 import java.lang.reflect.InvocationTargetException;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.Iterator;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.Spliterator;
13 import java.util.concurrent.ConcurrentHashMap;
14 import java.util.function.Consumer;
15 import java.util.function.Function;
16 import java.util.function.Supplier;
17
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 import net.sf.okapi.common.IParameters;
22 import net.sf.okapi.common.IParametersEditor;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public class SharedFilterConfigurationMapper implements IFilterConfigurationMapper {
50 private static final Logger logger = LoggerFactory
51 .getLogger(SharedFilterConfigurationMapper.class);
52
53
54
55
56
57 private final Map<String, FilterConfiguration> configMap;
58
59
60
61
62
63 public SharedFilterConfigurationMapper() {
64 this.configMap = new ConcurrentHashMap<>();
65 }
66
67
68
69
70
71
72 public SharedFilterConfigurationMapper(Map<String, FilterConfiguration> initialConfigs) {
73 this.configMap = new ConcurrentHashMap<>(initialConfigs);
74 }
75
76
77
78
79
80
81 public SharedFilterConfigurationMapper(Supplier<Map<String, FilterConfiguration>> fcSupplier) {
82 this.configMap = new ConcurrentHashMap<>(fcSupplier.get());
83 }
84
85
86
87
88
89
90
91
92
93
94
95
96
97 private static IParameters createDefaultParameters(FilterConfiguration fc) {
98
99 try (IFilter filter = instantiateFilter(fc.filterClass)) {
100 IParameters params = filter.getParameters();
101
102
103 if (fc.parameters != null) {
104
105 params.fromString(fc.parameters.toString());
106 return params;
107 }
108
109 else if (fc.parametersLocation != null) {
110 params.load(filter.getClass().getResourceAsStream(fc.parametersLocation), false);
111 return params;
112 }
113
114
115 if (params != null) {
116 params.reset();
117 }
118
119 return params;
120 }
121 }
122
123
124
125
126
127
128
129
130
131 private static IFilter instantiateFilter(String filterClass) {
132 try {
133 return (IFilter) Thread.currentThread().getContextClassLoader().loadClass(filterClass)
134 .getDeclaredConstructor().newInstance();
135 } catch (InstantiationException | IllegalAccessException | NoSuchMethodException
136 | InvocationTargetException | ClassNotFoundException e) {
137 throw new IllegalArgumentException("Could not instantiate: " + filterClass, e);
138 }
139 }
140
141 @Override
142 public void addCustomConfiguration(String configId, IParameters parameters) {
143
144 if (configMap.containsKey(configId)) {
145 return;
146 }
147
148 FilterConfiguration fc = new FilterConfiguration();
149 fc.custom = true;
150 fc.configId = configId;
151
152
153 String[] res = IFilterConfigurationMapper.splitFilterFromConfiguration(fc.configId);
154
155
156 try (IFilter filter = createFilter(res[0])) {
157
158 fc.filterClass = filter.getClass().getName();
159 fc.mimeType = filter.getMimeType();
160 fc.description = "Configuration " + fc.configId;
161 fc.name = fc.configId;
162 fc.parameters = filter.getParameters();
163 fc.parameters.fromString(parameters.toString());
164
165
166 configMap.putIfAbsent(fc.configId, fc);
167 logger.debug("Added custom config: {} with parameters: {}", configId, parameters);
168 }
169 }
170
171 @Override
172 public void addCustomConfiguration(String configId, String parameters) {
173
174 if (configMap.containsKey(configId)) {
175 return;
176 }
177
178 FilterConfiguration fc = new FilterConfiguration();
179 fc.custom = true;
180 fc.configId = configId;
181
182
183 String[] res = IFilterConfigurationMapper.splitFilterFromConfiguration(fc.configId);
184
185
186 try (IFilter filter = createFilter(res[0])) {
187
188 fc.filterClass = filter.getClass().getName();
189 fc.mimeType = filter.getMimeType();
190 fc.description = "Configuration " + fc.configId;
191 fc.name = fc.configId;
192 fc.parameters = filter.getParameters();
193 fc.parameters.fromString(parameters);
194
195
196 configMap.putIfAbsent(fc.configId, fc);
197 logger.debug("Added custom config: {} with parameters: {}", configId, parameters);
198 }
199 }
200
201 @Override
202 public void addConfigurations(String filterClass) {
203
204 try (IFilter filter = instantiateFilter(filterClass)) {
205
206 List<FilterConfiguration> list = filter.getConfigurations();
207 if ((list == null) || (list.isEmpty())) {
208 logger.warn("No configuration provided for '{}'", filterClass);
209 return;
210 }
211
212 for (FilterConfiguration config : list) {
213
214 if (configMap.containsKey(config.configId)) {
215 continue;
216 }
217
218
219 config.parameters = createDefaultParameters(config);
220
221
222 if (config.filterClass == null) {
223 logger.warn("Configuration without filter class name in '{}'", config);
224 config.filterClass = filterClass;
225 }
226 if (config.name == null) {
227 logger.warn("Configuration without name in '{}'", config);
228 config.name = config.toString();
229 }
230 if (config.description == null) {
231 logger.warn("Configuration without description in '{}'", config);
232 config.description = config.toString();
233 }
234
235
236 configMap.putIfAbsent(config.configId, config);
237 logger.debug("Added config: {} with parameters: {}", config.configId, config.parameters);
238 }
239 }
240 }
241
242 @Override
243 public void addConfiguration(FilterConfiguration config) {
244
245 configMap.putIfAbsent(config.configId, config);
246 logger.debug("Added config: {} with parameters: {}", config.configId, config.parameters);
247 }
248
249 @Override
250 public IFilter createFilter(String configId, IFilter existingFilter) {
251
252 FilterConfiguration fc = getConfiguration(configId);
253 if (fc == null) {
254 logger.error("Cannot find filter configuration '{}'", configId);
255 return null;
256 }
257
258
259 try {
260 IFilter filter = instantiateFilter(fc.filterClass);
261 filter.setFilterConfigurationMapper(this);
262
263
264 IParameters params = filter.getParameters();
265 if (params != null && fc.parameters != null) {
266 params.fromString(fc.parameters.toString());
267 filter.setParameters(params);
268 }
269
270 return filter;
271
272 } catch (Exception e) {
273 logger.error("Error creating filter for configuration '{}'", configId, e);
274 return null;
275 }
276 }
277
278 @Override
279 public void clearConfigurations(boolean customOnly) {
280 if (customOnly) {
281
282 configMap.entrySet().removeIf(entry -> entry.getValue().custom);
283 } else {
284
285 configMap.clear();
286 }
287 }
288
289 @Override
290 public IFilter createFilter(String configId) {
291 return createFilter(configId, null);
292 }
293
294 @Override
295 public FilterConfiguration getConfiguration(String configId) {
296
297 return configMap.get(configId);
298 }
299
300 @Override
301 public FilterConfiguration getDefaultConfiguration(String mimeType) {
302
303
304 FilterConfiguration autoXliff = getConfiguration("okf_autoxliff");
305 if (autoXliff != null && autoXliff.mimeType != null && autoXliff.mimeType.equals(mimeType)) {
306 return autoXliff;
307 }
308
309 FilterConfiguration defaultConfig = null;
310 for (FilterConfiguration config : configMap.values()) {
311 if (config.mimeType == null || !config.mimeType.equals(mimeType)) {
312 continue;
313 }
314
315
316 if (config.parametersLocation == null) {
317 return config;
318 }
319
320
321 if (defaultConfig == null) {
322 defaultConfig = config;
323 }
324 }
325
326 return defaultConfig;
327 }
328
329 @Override
330 public FilterConfiguration getDefaultConfigurationFromExtension(String ext) {
331
332 String tmp = ext.toLowerCase() + ";";
333 if (tmp.charAt(0) != '.') {
334 tmp = ".".concat(tmp);
335 }
336
337
338
339 FilterConfiguration autoXliff = getConfiguration("okf_autoxliff");
340 if (autoXliff != null && autoXliff.extensions != null && autoXliff.extensions.contains(tmp)) {
341 return autoXliff;
342 }
343
344
345 for (FilterConfiguration config : configMap.values()) {
346 if (config.extensions != null) {
347
348 String configExtensions = config.extensions + ";";
349 if (configExtensions.contains(tmp)) {
350 return config;
351 }
352 }
353 }
354 return null;
355 }
356
357 @Override
358 public IParameters getParameters(FilterConfiguration config) {
359 if (config == null) {
360 return null;
361 }
362
363 try (IFilter filter = instantiateFilter(config.filterClass)) {
364 IParameters params = filter.getParameters();
365 if (params == null) {
366 return null;
367 }
368
369
370 if (config.parameters != null) {
371 params.fromString(config.parameters.toString());
372 } else if (config.parametersLocation != null) {
373 params.load(filter.getClass().getResourceAsStream(config.parametersLocation), false);
374 } else {
375 params.reset();
376 }
377
378 return params;
379 }
380 }
381
382 @Override
383 public IParameters getParameters(FilterConfiguration config, IFilter existingFilter) {
384
385 return getParameters(config);
386 }
387
388 @Override
389 public FilterConfiguration createCustomConfiguration(FilterConfiguration baseConfig) {
390
391 FilterConfiguration newConfig = new FilterConfiguration();
392 String[] res = IFilterConfigurationMapper.splitFilterFromConfiguration(baseConfig.configId);
393 if (res == null) {
394 return null;
395 }
396
397 newConfig.custom = true;
398
399 if (res[1] == null) {
400 newConfig.configId = String.format("%s%ccopy-of-default",
401 res[0], IFilterConfigurationMapper.CONFIGFILE_SEPARATOR);
402 } else {
403 newConfig.configId = String.format("%s%ccopy-of-%s",
404 res[0], IFilterConfigurationMapper.CONFIGFILE_SEPARATOR, res[1]);
405 }
406
407
408 newConfig.classLoader = baseConfig.classLoader;
409 newConfig.name = newConfig.configId;
410 newConfig.description = "Copy of " + baseConfig.description;
411 newConfig.filterClass = baseConfig.filterClass;
412 newConfig.mimeType = baseConfig.mimeType;
413 newConfig.extensions = baseConfig.extensions;
414
415
416 if (baseConfig.parameters != null) {
417 try (IFilter filter = instantiateFilter(baseConfig.filterClass)) {
418 IParameters params = filter.getParameters();
419 if (params != null) {
420 params.fromString(baseConfig.parameters.toString());
421 newConfig.parameters = params;
422 }
423 }
424 }
425
426 return newConfig;
427 }
428
429 @Override
430 public IParameters getCustomParameters(FilterConfiguration config, IFilter existingFilter) {
431
432 if (config.custom && config.parameters != null) {
433 return config.parameters;
434 }
435 return null;
436 }
437
438 @Override
439 public IParameters getCustomParameters(FilterConfiguration config) {
440 return getCustomParameters(config, null);
441 }
442
443 @Override
444 public Iterator<FilterConfiguration> getAllConfigurations() {
445 return configMap.values().iterator();
446 }
447
448 @Override
449 public List<FilterConfiguration> getFilterConfigurations(String filterClass) {
450 List<FilterConfiguration> list = new ArrayList<>();
451
452 for (FilterConfiguration config : configMap.values()) {
453 if (config.filterClass != null && config.filterClass.equals(filterClass)) {
454 list.add(config);
455 }
456 }
457 return list;
458 }
459
460 @Override
461 public IParametersEditor createConfigurationEditor(String configId, IFilter existingFilter) {
462 throw new UnsupportedOperationException(
463 "Configuration editors are not supported in this implementation");
464 }
465
466 @Override
467 public IParametersEditor createConfigurationEditor(String configId) {
468 throw new UnsupportedOperationException(
469 "Configuration editors are not supported in this implementation");
470 }
471
472 @Override
473 public List<FilterInfo> getFiltersInfo() {
474 List<FilterInfo> filtersInfo = new ArrayList<>();
475 Set<String> processedFilterClasses = new HashSet<>();
476
477
478 for (FilterConfiguration config : configMap.values()) {
479 if (config.filterClass != null && !processedFilterClasses.contains(config.filterClass)) {
480 try (IFilter filter = instantiateFilter(config.filterClass)) {
481 FilterInfo info = new FilterInfo();
482 info.className = config.filterClass;
483 info.name = filter.getName();
484 info.displayName = filter.getDisplayName();
485 filtersInfo.add(info);
486 processedFilterClasses.add(config.filterClass);
487 } catch (Exception e) {
488 logger.warn("Could not create filter info for {}", config.filterClass, e);
489 }
490 }
491 }
492
493
494 Collections.sort(filtersInfo);
495 return filtersInfo;
496 }
497
498 @Override
499 public List<FilterConfiguration> getMimeConfigurations(String mimeType) {
500 List<FilterConfiguration> list = new ArrayList<>();
501
502 for (FilterConfiguration config : configMap.values()) {
503 if (config.mimeType != null && config.mimeType.equals(mimeType)) {
504 list.add(config);
505 }
506 }
507 return list;
508 }
509
510 @Override
511 public void removeConfiguration(String configId) {
512 configMap.remove(configId);
513 }
514
515 @Override
516 public Iterator<FilterConfiguration> iterator() {
517 return configMap.values().iterator();
518 }
519
520 @Override
521 public void forEach(Consumer<? super FilterConfiguration> action) {
522 configMap.values().forEach(action);
523 }
524
525 @Override
526 public Spliterator<FilterConfiguration> spliterator() {
527 return configMap.values().spliterator();
528 }
529
530 @Override
531 public void removeConfigurations(String filterClass) {
532
533 configMap.entrySet().removeIf(entry -> entry.getValue().filterClass.equals(filterClass));
534 }
535
536 @Override
537 public void saveCustomParameters(FilterConfiguration config, IParameters params) {
538 if (config != null && params != null) {
539
540 FilterConfiguration existingConfig = configMap.get(config.configId);
541 if (existingConfig != null) {
542 synchronized (existingConfig) {
543 existingConfig.parameters = params;
544 }
545 }
546 }
547 }
548
549 @Override
550 public void deleteCustomParameters(FilterConfiguration config) {
551 if (config != null) {
552
553 FilterConfiguration existingConfig = configMap.get(config.configId);
554 if (existingConfig != null) {
555 synchronized (existingConfig) {
556 existingConfig.parameters = null;
557 }
558 }
559 }
560 }
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580 public static class ConfigBuilder {
581 private final Map<String, FilterConfiguration> configs = new HashMap<>();
582
583
584
585
586
587
588
589
590
591 public ConfigBuilder addConfigurations(Class<? extends IFilter> filterClass) {
592 try {
593 try (IFilter filter = instantiateFilter(filterClass.getCanonicalName())) {
594 for (FilterConfiguration config : filter.getConfigurations()) {
595 if (configs.containsKey(config.configId)) {
596 continue;
597 }
598
599 config.parameters = createDefaultParameters(config);
600 configs.put(config.configId, config);
601 }
602 }
603 return this;
604 } catch (Exception e) {
605 throw new IllegalArgumentException(
606 "Couldn't add configurations for " + filterClass.getName(), e);
607 }
608 }
609
610
611
612
613
614
615
616
617
618 public ConfigBuilder updateConfiguration(String configId, String params) {
619 try {
620 String[] parts = IFilterConfigurationMapper.splitFilterFromConfiguration(configId);
621
622 FilterConfiguration baseFilter = configs.get(parts[0]);
623 if (baseFilter == null) {
624 throw new IllegalArgumentException("Couldn't find base filter for " + configId);
625 }
626 FilterConfiguration fc = configs.get(configId);
627 if (fc == null) {
628 throw new IllegalArgumentException("Couldn't find filter configuration for " + configId);
629 }
630
631 fc.parameters.fromString(params);
632 configs.put(configId, fc);
633 return this;
634 } catch (Exception e) {
635 throw new IllegalArgumentException("Couldn't update configurations for " + configId, e);
636 }
637 }
638
639
640
641
642
643
644
645 public ConfigBuilder updateConfigurations(Function<IParameters, IParameters> function) {
646 for (FilterConfiguration config : configs.values()) {
647 config.parameters = function.apply(config.parameters);
648 }
649 return this;
650 }
651
652
653
654
655
656
657 public Map<String, FilterConfiguration> build() {
658 return new HashMap<>(configs);
659 }
660
661
662
663
664
665
666 public SharedFilterConfigurationMapper buildMapper() {
667 return new SharedFilterConfigurationMapper(build());
668 }
669 }
670 }