1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.enforcer.rules;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.xml.transform.Transformer;
24 import javax.xml.transform.TransformerConfigurationException;
25 import javax.xml.transform.TransformerException;
26 import javax.xml.transform.TransformerFactory;
27 import javax.xml.transform.TransformerFactoryConfigurationError;
28 import javax.xml.transform.stream.StreamResult;
29 import javax.xml.transform.stream.StreamSource;
30
31 import java.io.ByteArrayInputStream;
32 import java.io.ByteArrayOutputStream;
33 import java.io.File;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.nio.charset.StandardCharsets;
37 import java.nio.file.Files;
38 import java.util.Objects;
39
40 import org.apache.maven.enforcer.rule.api.AbstractEnforcerRuleConfigProvider;
41 import org.apache.maven.enforcer.rule.api.EnforcerRuleError;
42 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
43 import org.apache.maven.enforcer.rules.utils.ExpressionEvaluator;
44 import org.apache.maven.plugin.MojoExecution;
45 import org.codehaus.plexus.util.xml.Xpp3Dom;
46 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
47 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
48
49
50
51
52
53
54
55 @Named("externalRules")
56 public final class ExternalRules extends AbstractEnforcerRuleConfigProvider {
57 private static final String LOCATION_PREFIX_CLASSPATH = "classpath:";
58
59
60
61
62
63
64
65 private String location;
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 private String xsltLocation;
128
129 private final MojoExecution mojoExecution;
130
131 private final ExpressionEvaluator evaluator;
132
133 @Inject
134 public ExternalRules(MojoExecution mojoExecution, ExpressionEvaluator evaluator) {
135 this.mojoExecution = Objects.requireNonNull(mojoExecution);
136 this.evaluator = Objects.requireNonNull(evaluator);
137 }
138
139 public void setLocation(String location) {
140 this.location = location;
141 }
142
143 public void setXsltLocation(String xsltLocation) {
144 this.xsltLocation = xsltLocation;
145 }
146
147 @Override
148 public Xpp3Dom getRulesConfig() throws EnforcerRuleError {
149
150 try (InputStream descriptorStream = transform(location, resolveDescriptor(location), xsltLocation)) {
151 Xpp3Dom enforcerRules = Xpp3DomBuilder.build(descriptorStream, "UTF-8");
152 if (enforcerRules.getChildCount() == 1 && "enforcer".equals(enforcerRules.getName())) {
153 return enforcerRules.getChild(0);
154 } else {
155 throw new EnforcerRuleError("Enforcer rules configuration not found in: " + location);
156 }
157 } catch (IOException | XmlPullParserException e) {
158 throw new EnforcerRuleError(e);
159 }
160 }
161
162 private InputStream resolveDescriptor(String path) throws EnforcerRuleError {
163 InputStream descriptorStream;
164 if (path != null) {
165 if (path.startsWith(LOCATION_PREFIX_CLASSPATH)) {
166 String classpathLocation = path.substring(LOCATION_PREFIX_CLASSPATH.length());
167 getLog().debug("Read rules form classpath location: " + classpathLocation);
168 ClassLoader classRealm = mojoExecution.getMojoDescriptor().getRealm();
169 descriptorStream = classRealm.getResourceAsStream(classpathLocation);
170 if (descriptorStream == null) {
171 throw new EnforcerRuleError("Location '" + classpathLocation + "' not found in classpath");
172 }
173 } else {
174 File descriptorFile = evaluator.alignToBaseDirectory(new File(path));
175 getLog().debug("Read rules form file location: " + descriptorFile);
176 try {
177 descriptorStream = Files.newInputStream(descriptorFile.toPath());
178 } catch (IOException e) {
179 throw new EnforcerRuleError("Could not read descriptor in " + descriptorFile, e);
180 }
181 }
182 } else {
183 throw new EnforcerRuleError("No location provided");
184 }
185 return descriptorStream;
186 }
187
188 @Override
189 public String toString() {
190 return String.format("ExternalRules[location=%s, xsltLocation=%s]", location, xsltLocation);
191 }
192
193 InputStream transform(String sourceLocation, InputStream sourceXml, String xsltLocation) {
194 if (xsltLocation == null || xsltLocation.trim().isEmpty()) {
195 return sourceXml;
196 }
197
198 try (InputStream in = resolveDescriptor(xsltLocation);
199 ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
200 Transformer transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(in));
201 transformer.transform(new StreamSource(sourceXml), new StreamResult(baos));
202 final byte[] bytes = baos.toByteArray();
203 getLog().info(() -> ("Rules transformed by " + xsltLocation + " from " + location + ":\n\n"
204 + new String(bytes, StandardCharsets.UTF_8)));
205 return new ByteArrayInputStream(bytes);
206 } catch (IOException
207 | EnforcerRuleException
208 | TransformerConfigurationException
209 | TransformerFactoryConfigurationError e) {
210 throw new RuntimeException("Could not open resource " + xsltLocation);
211 } catch (TransformerException e) {
212 throw new RuntimeException("Could not transform " + sourceLocation + " usinng XSLT " + xsltLocation);
213 }
214 }
215 }