1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.common.xml;
20
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Locale;
24 import java.util.Map;
25 import java.util.Optional;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.stream.Collectors;
28
29 import javax.xml.parsers.ParserConfigurationException;
30 import javax.xml.transform.OutputKeys;
31 import javax.xml.transform.TransformerException;
32
33 import org.apache.logging.log4j.LogManager;
34 import org.apache.logging.log4j.Logger;
35 import org.mycore.common.MCRClassTools;
36 import org.mycore.common.MCRException;
37 import org.mycore.common.config.MCRConfiguration2;
38 import org.mycore.common.content.transformer.MCRContentTransformer;
39 import org.mycore.common.content.transformer.MCRContentTransformerFactory;
40 import org.mycore.common.content.transformer.MCRIdentityTransformer;
41 import org.mycore.common.content.transformer.MCRXSLTransformer;
42 import org.xml.sax.SAXException;
43
44 import com.google.common.collect.Lists;
45
46
47
48
49
50
51 public class MCRLayoutTransformerFactory {
52
53 private static Map<String, MCRContentTransformer> transformers = new ConcurrentHashMap<>();
54
55 private static Logger LOGGER = LogManager.getLogger(MCRLayoutTransformerFactory.class);
56
57 protected static final MCRIdentityTransformer NOOP_TRANSFORMER = new MCRIdentityTransformer("text/xml", "xml");
58
59
60
61
62
63 public MCRContentTransformer getTransformer(String id) {
64 return transformers.computeIfAbsent(id, (transformerID) -> {
65 try {
66 Optional<MCRContentTransformer> configuredTransformer = getConfiguredTransformer(id);
67 if (configuredTransformer.isPresent()) {
68 return configuredTransformer.get();
69 }
70 return buildLayoutTransformer(id);
71 } catch (Exception e) {
72 throw new MCRException("Error while creating Transformer!", e);
73 }
74 });
75 }
76
77 protected Optional<MCRContentTransformer> getConfiguredTransformer(String id) {
78 return Optional.ofNullable(MCRContentTransformerFactory.getTransformer(id.replaceAll("-default$", "")));
79 }
80
81 private MCRContentTransformer buildLayoutTransformer(String id)
82 throws ParserConfigurationException, TransformerException, SAXException {
83 String idStripped = id.replaceAll("-default$", "");
84 LOGGER.debug("Configure property MCR.ContentTransformer.{}.Class if you do not want to use default behaviour.",
85 idStripped);
86 String stylesheet = getResourceName(id);
87 if (stylesheet == null) {
88 LOGGER.debug("Using noop transformer for {}", idStripped);
89 return NOOP_TRANSFORMER;
90 }
91 String[] stylesheets = getStylesheets(idStripped, stylesheet);
92 MCRContentTransformer transformer = MCRXSLTransformer.getInstance(stylesheets);
93 LOGGER.debug("Using stylesheet '{}' for {}", Lists.newArrayList(stylesheets), idStripped);
94 return transformer;
95 }
96
97 protected String[] getStylesheets(String id, String stylesheet)
98 throws TransformerException, SAXException, ParserConfigurationException {
99 List<String> ignore = MCRConfiguration2.getString("MCR.LayoutTransformerFactory.Default.Ignore")
100 .map(MCRConfiguration2::splitValue)
101 .map(s1 -> s1.collect(Collectors.toList()))
102 .orElseGet(Collections::emptyList);
103 List<String> defaults = Collections.emptyList();
104 if (!ignore.contains(id)) {
105 MCRXSLTransformer transformerTest = MCRXSLTransformer.getInstance(stylesheet);
106 String outputMethod = transformerTest.getOutputProperties().getProperty(OutputKeys.METHOD, "xml");
107 if (isXMLOutput(outputMethod, transformerTest)) {
108 defaults = MCRConfiguration2.getString("MCR.LayoutTransformerFactory.Default.Stylesheets")
109 .map(MCRConfiguration2::splitValue)
110 .map(s -> s.collect(Collectors.toList()))
111 .orElseGet(Collections::emptyList);
112 }
113 }
114 String[] stylesheets = new String[1 + defaults.size()];
115 stylesheets[0] = stylesheet;
116 for (int i = 0; i < defaults.size(); i++) {
117 stylesheets[i + 1] = defaults.get(i);
118 }
119 return stylesheets;
120 }
121
122 protected boolean isXMLOutput(String outputMethod, MCRXSLTransformer transformerTest)
123 throws ParserConfigurationException, TransformerException, SAXException {
124 return "xml".equals(outputMethod);
125 }
126
127 private String getResourceName(String id) {
128 LOGGER.debug("MCRLayoutService using style {}", id);
129
130 String styleName = buildStylesheetName(id);
131 try {
132 if (MCRXMLResource.instance().exists(styleName, MCRClassTools.getClassLoader())) {
133 return styleName;
134 }
135 } catch (Exception e) {
136 throw new MCRException("Error while loading stylesheet: " + styleName, e);
137 }
138
139
140
141
142 if (id.endsWith("-xml") || id.endsWith("-default")) {
143 LOGGER.warn("XSL stylesheet not found: {}", styleName);
144 return null;
145 }
146 throw new MCRException("XSL stylesheet not found: " + styleName);
147 }
148
149
150
151
152 private String buildStylesheetName(String id) {
153 return String.format(Locale.ROOT, "xsl/%s.xsl", id.replaceAll("-default$", ""));
154 }
155
156 }