]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/ImportMavenDependencies.java
Improve packaging (esp. security)
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / maven / ImportMavenDependencies.java
1 package org.argeo.slc.repo.maven;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.util.Comparator;
7 import java.util.HashSet;
8 import java.util.Properties;
9 import java.util.Set;
10 import java.util.TreeSet;
11
12 import javax.jcr.Binary;
13 import javax.jcr.Node;
14 import javax.jcr.Property;
15 import javax.jcr.Session;
16 import javax.jcr.nodetype.NodeType;
17 import javax.xml.parsers.DocumentBuilder;
18 import javax.xml.parsers.DocumentBuilderFactory;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.argeo.jcr.JcrUtils;
23 import org.argeo.slc.SlcException;
24 import org.argeo.slc.aether.AetherTemplate;
25 import org.sonatype.aether.artifact.Artifact;
26 import org.sonatype.aether.graph.DependencyNode;
27 import org.sonatype.aether.util.artifact.DefaultArtifact;
28 import org.w3c.dom.Document;
29 import org.w3c.dom.Element;
30 import org.w3c.dom.NodeList;
31
32 public class ImportMavenDependencies implements Runnable {
33 private final static Log log = LogFactory
34 .getLog(ImportMavenDependencies.class);
35
36 private AetherTemplate aetherTemplate;
37 private String rootCoordinates;
38 private Set<String> excludedArtifacts = new HashSet<String>();
39
40 private Session jcrSession;
41 private String artifactBasePath = "/slc/repo/artifacts";
42
43 public void run() {
44 Set<Artifact> artifacts = resolveDistribution();
45 syncDistribution(artifacts);
46 }
47
48 public Set<Artifact> resolveDistribution() {
49 try {
50 Artifact pomArtifact = new DefaultArtifact(rootCoordinates);
51 Comparator<Artifact> artifactComparator = new Comparator<Artifact>() {
52 public int compare(Artifact o1, Artifact o2) {
53 return o1.getArtifactId().compareTo(o2.getArtifactId());
54 }
55 };
56
57 Set<Artifact> registeredArtifacts = new TreeSet<Artifact>(
58 artifactComparator);
59 parsePom(aetherTemplate, registeredArtifacts, pomArtifact);
60 if (log.isDebugEnabled())
61 log.debug("Gathered " + registeredArtifacts.size()
62 + " artifacts");
63
64 // Resolve and add non-optional dependencies
65 Set<Artifact> artifacts = new TreeSet<Artifact>(artifactComparator);
66 for (Artifact artifact : registeredArtifacts) {
67 try {
68 addArtifact(artifacts, artifact);
69 DependencyNode node = aetherTemplate
70 .resolveDependencies(artifact);
71 addDependencies(artifacts, node);
72 } catch (Exception e) {
73 log.error("Could not resolve dependencies of " + artifact
74 + ": " + e.getCause().getMessage());
75 }
76
77 }
78
79 if (log.isDebugEnabled())
80 log.debug("Resolved " + artifacts.size() + " artifacts");
81 Properties distributionDescriptor = new Properties();
82 for (Artifact artifact : artifacts) {
83 log.debug(artifact.getArtifactId() + " ["
84 + artifact.getVersion() + "]\t(" + artifact + ")");
85 distributionDescriptor.setProperty(artifact.getArtifactId()
86 + ":" + artifact.getVersion(), artifact.toString());
87 }
88
89 ByteArrayOutputStream out = new ByteArrayOutputStream();
90 distributionDescriptor.store(out, "");
91 log.debug(new String(out.toByteArray()));
92 out.close();
93
94 return artifacts;
95 } catch (Exception e) {
96 throw new SlcException("Cannot resolve distribution", e);
97 }
98 }
99
100 protected void syncDistribution(Set<Artifact> artifacts) {
101 Long begin = System.currentTimeMillis();
102 try {
103 JcrUtils.mkdirs(jcrSession, artifactBasePath);
104 for (Artifact artifact : artifacts) {
105 String parentPath = artifactBasePath + '/'
106 + artifactParentPath(artifact);
107 Node parentNode;
108 if (!jcrSession.itemExists(parentPath)) {
109 parentNode = JcrUtils.mkdirs(jcrSession, parentPath,
110 NodeType.NT_FOLDER, false);
111 } else {
112 parentNode = jcrSession.getNode(parentPath);
113 }
114
115 File file = artifact.getFile();
116 Node fileNode;
117 if (!parentNode.hasNode(file.getName())) {
118 fileNode = createFileNode(parentNode, file);
119 } else {
120 fileNode = parentNode.getNode(file.getName());
121 }
122 }
123
124 Long duration = (System.currentTimeMillis() - begin) / 1000;
125 if (log.isDebugEnabled())
126 log.debug("Synchronized distribution in " + duration + "s");
127 } catch (Exception e) {
128 throw new SlcException("Cannot synchronize distribution", e);
129 }
130 }
131
132 protected String artifactParentPath(Artifact artifact) {
133 return artifact.getGroupId().replace('.', '/') + '/'
134 + artifact.getArtifactId() + '/' + artifact.getVersion();
135 }
136
137 protected Node createFileNode(Node parentNode, File file) {
138 try {
139 Node fileNode = parentNode
140 .addNode(file.getName(), NodeType.NT_FILE);
141 Node contentNode = fileNode.addNode(Node.JCR_CONTENT,
142 NodeType.NT_RESOURCE);
143 Binary binary = jcrSession.getValueFactory().createBinary(
144 new FileInputStream(file));
145 contentNode.setProperty(Property.JCR_DATA, binary);
146 binary.dispose();
147 return fileNode;
148 } catch (Exception e) {
149 throw new SlcException("Cannot create file node based on " + file
150 + " under " + parentNode, e);
151 }
152 }
153
154 /** Recursively adds non optional dependencies */
155 private void addDependencies(Set<Artifact> artifacts, DependencyNode node) {
156 for (DependencyNode child : node.getChildren()) {
157 if (!child.getDependency().isOptional()) {
158 addArtifact(artifacts, child.getDependency().getArtifact());
159 addDependencies(artifacts, child);
160 }
161 }
162 }
163
164 private void addArtifact(Set<Artifact> artifacts, Artifact artifact) {
165 if (!excludedArtifacts.contains(artifact.getGroupId() + ":"
166 + artifact.getArtifactId()))
167 artifacts.add(artifact);
168 }
169
170 /**
171 * Directly parses Maven POM XML format in order to find all artifacts
172 * references under the dependency and dependencyManagement tags. This is
173 * meant to migrate existing pom registering a lot of artifacts, not to
174 * replace Maven resolving.
175 */
176 protected void parsePom(AetherTemplate aetherTemplate,
177 Set<Artifact> artifacts, Artifact pomArtifact) {
178 if (log.isDebugEnabled())
179 log.debug("Gather dependencies for " + pomArtifact);
180
181 try {
182 File file = aetherTemplate.getResolvedFile(pomArtifact);
183 DocumentBuilder documentBuilder = DocumentBuilderFactory
184 .newInstance().newDocumentBuilder();
185 Document doc = documentBuilder.parse(file);
186
187 // properties
188 Properties props = new Properties();
189 props.setProperty("project.version", pomArtifact.getBaseVersion());
190 NodeList properties = doc.getElementsByTagName("properties");
191 if (properties.getLength() > 0) {
192 NodeList propertiesElems = properties.item(0).getChildNodes();
193 for (int i = 0; i < propertiesElems.getLength(); i++) {
194 if (propertiesElems.item(i) instanceof Element) {
195 Element property = (Element) propertiesElems.item(i);
196 props.put(property.getNodeName(),
197 property.getTextContent());
198 }
199 }
200 }
201
202 // dependencies (direct and dependencyManagement)
203 NodeList dependencies = doc.getElementsByTagName("dependency");
204 for (int i = 0; i < dependencies.getLength(); i++) {
205 Element dependency = (Element) dependencies.item(i);
206 String groupId = dependency.getElementsByTagName("groupId")
207 .item(0).getTextContent().trim();
208 String artifactId = dependency
209 .getElementsByTagName("artifactId").item(0)
210 .getTextContent().trim();
211 String version = dependency.getElementsByTagName("version")
212 .item(0).getTextContent().trim();
213 if (version.startsWith("${")) {
214 String versionKey = version.substring(0,
215 version.length() - 1).substring(2);
216 if (!props.containsKey(versionKey))
217 throw new SlcException("Cannot interpret version "
218 + version);
219 version = props.getProperty(versionKey);
220 }
221 NodeList scopes = dependency.getElementsByTagName("scope");
222 if (scopes.getLength() > 0
223 && scopes.item(0).getTextContent().equals("import")) {
224 // recurse
225 parsePom(aetherTemplate, artifacts, new DefaultArtifact(
226 groupId, artifactId, "pom", version));
227 } else {
228 // TODO: deal with scope?
229 // TODO: deal with type
230 String type = "jar";
231 Artifact artifact = new DefaultArtifact(groupId,
232 artifactId, type, version);
233 artifacts.add(artifact);
234 }
235 }
236 } catch (Exception e) {
237 throw new SlcException("Cannot process " + pomArtifact, e);
238 }
239 }
240
241 public void setAetherTemplate(AetherTemplate aetherTemplate) {
242 this.aetherTemplate = aetherTemplate;
243 }
244
245 public void setExcludedArtifacts(Set<String> excludedArtifactIds) {
246 this.excludedArtifacts = excludedArtifactIds;
247 }
248
249 public void setRootCoordinates(String rootCoordinates) {
250 this.rootCoordinates = rootCoordinates;
251 }
252
253 public void setJcrSession(Session jcrSession) {
254 this.jcrSession = jcrSession;
255 }
256
257 }