]> git.argeo.org Git - gpl/argeo-slc.git/blob - NormalizeGroup.java
347e79be9917c2a13fc464060d75dc90828ae42a
[gpl/argeo-slc.git] / NormalizeGroup.java
1 /*
2 * Copyright (C) 2007-2012 Mathieu Baudier
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.slc.repo.osgi;
17
18 import java.util.ArrayList;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.TreeSet;
24
25 import javax.jcr.Node;
26 import javax.jcr.NodeIterator;
27 import javax.jcr.Repository;
28 import javax.jcr.RepositoryException;
29 import javax.jcr.Session;
30
31 import org.apache.commons.io.FilenameUtils;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.argeo.jcr.JcrUtils;
35 import org.argeo.slc.SlcException;
36 import org.argeo.slc.aether.ArtifactIdComparator;
37 import org.argeo.slc.jcr.SlcNames;
38 import org.argeo.slc.jcr.SlcTypes;
39 import org.argeo.slc.repo.ArtifactIndexer;
40 import org.argeo.slc.repo.JarFileIndexer;
41 import org.argeo.slc.repo.RepoUtils;
42 import org.argeo.slc.repo.maven.MavenConventionsUtils;
43 import org.osgi.framework.Constants;
44 import org.sonatype.aether.artifact.Artifact;
45 import org.sonatype.aether.util.artifact.DefaultArtifact;
46
47 /**
48 * Make sure that all JCR metadata and Maven metadata are consistent for this
49 * group of OSGi bundles.
50 */
51 public class NormalizeGroup implements Runnable, SlcNames {
52 public final static String BINARIES_ARTIFACT_ID = "binaries";
53 public final static String SOURCES_ARTIFACT_ID = "sources";
54 public final static String SDK_ARTIFACT_ID = "sdk";
55
56 private final static Log log = LogFactory.getLog(NormalizeGroup.class);
57
58 private Repository repository;
59 private String workspace;
60 private String groupId;
61 private String artifactBasePath = "/";
62 private String version = null;
63 private String parentPomCoordinates;
64
65 private List<String> excludedSuffixes = new ArrayList<String>();
66
67 private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
68 private JarFileIndexer jarFileIndexer = new JarFileIndexer();
69
70 private List<String> systemPackages = OsgiProfile.PROFILE_JAVA_SE_1_6
71 .getSystemPackages();
72
73 // indexes
74 private Map<String, String> packagesToSymbolicNames = new HashMap<String, String>();
75 private Map<String, Node> symbolicNamesToNodes = new HashMap<String, Node>();
76
77 private Set<Artifact> binaries = new TreeSet<Artifact>(
78 new ArtifactIdComparator());
79 private Set<Artifact> sources = new TreeSet<Artifact>(
80 new ArtifactIdComparator());
81
82 public void run() {
83 Session session = null;
84 try {
85 session = repository.login(workspace);
86
87 Node groupNode = session.getNode(MavenConventionsUtils.groupPath(
88 artifactBasePath, groupId));
89 // TODO factorize with a traverser pattern?
90 for (NodeIterator artifactBases = groupNode.getNodes(); artifactBases
91 .hasNext();) {
92 Node artifactBase = artifactBases.nextNode();
93 if (artifactBase.isNodeType(SlcTypes.SLC_ARTIFACT_BASE)) {
94 for (NodeIterator artifactVersions = artifactBase
95 .getNodes(); artifactVersions.hasNext();) {
96 Node artifactVersion = artifactVersions.nextNode();
97 if (artifactVersion
98 .isNodeType(SlcTypes.SLC_ARTIFACT_VERSION_BASE))
99 for (NodeIterator files = artifactVersion
100 .getNodes(); files.hasNext();) {
101 Node file = files.nextNode();
102 if (file.isNodeType(SlcTypes.SLC_BUNDLE_ARTIFACT)) {
103 preProcessBundleArtifact(file);
104 file.getSession().save();
105 if (log.isDebugEnabled())
106 log.debug("Pre-processed "
107 + file.getName());
108 }
109
110 }
111 }
112 }
113 }
114 // NodeIterator bundlesIt = listBundleArtifacts(session);
115 //
116 // while (bundlesIt.hasNext()) {
117 // Node bundleNode = bundlesIt.nextNode();
118 // preProcessBundleArtifact(bundleNode);
119 // bundleNode.getSession().save();
120 // if (log.isDebugEnabled())
121 // log.debug("Pre-processed " + bundleNode.getName());
122 // }
123
124 int bundleCount = symbolicNamesToNodes.size();
125 if (log.isDebugEnabled())
126 log.debug("Indexed " + bundleCount + " bundles");
127
128 int count = 1;
129 for (Node bundleNode : symbolicNamesToNodes.values()) {
130 processBundleArtifact(bundleNode);
131 bundleNode.getSession().save();
132 if (log.isDebugEnabled())
133 log.debug(count + "/" + bundleCount + " Processed "
134 + bundleNode.getName());
135 count++;
136 }
137
138 // indexes
139 Set<Artifact> indexes = new TreeSet<Artifact>(
140 new ArtifactIdComparator());
141 Artifact indexArtifact = writeIndex(session, BINARIES_ARTIFACT_ID,
142 binaries);
143 indexes.add(indexArtifact);
144 indexArtifact = writeIndex(session, SOURCES_ARTIFACT_ID, sources);
145 indexes.add(indexArtifact);
146 // sdk
147 writeIndex(session, SDK_ARTIFACT_ID, indexes);
148 } catch (Exception e) {
149 throw new SlcException("Cannot normalize group " + groupId + " in "
150 + workspace, e);
151 } finally {
152 JcrUtils.logoutQuietly(session);
153 }
154 }
155
156 private Artifact writeIndex(Session session, String artifactId,
157 Set<Artifact> artifacts) throws RepositoryException {
158 Artifact artifact = new DefaultArtifact(groupId, artifactId, "pom",
159 version);
160 Artifact parentArtifact = parentPomCoordinates != null ? new DefaultArtifact(
161 parentPomCoordinates) : null;
162 String pom = MavenConventionsUtils.artifactsAsDependencyPom(artifact,
163 artifacts, parentArtifact);
164 Node node = RepoUtils.copyBytesAsArtifact(
165 session.getNode(artifactBasePath), artifact, pom.getBytes());
166 artifactIndexer.index(node);
167
168 // FIXME factorize
169 String pomSha = JcrUtils.checksumFile(node, "SHA-1");
170 JcrUtils.copyBytesAsFile(node.getParent(), node.getName() + ".sha1",
171 pomSha.getBytes());
172 session.save();
173 return artifact;
174 }
175
176 protected void preProcessBundleArtifact(Node bundleNode)
177 throws RepositoryException {
178 artifactIndexer.index(bundleNode);
179 jarFileIndexer.index(bundleNode);
180
181 String symbolicName = JcrUtils.get(bundleNode, SLC_SYMBOLIC_NAME);
182
183 if (symbolicName.endsWith(".source")) {
184 // TODO make a shared node with classifier 'sources'
185 String bundleName = RepoUtils
186 .extractBundleNameFromSourceName(symbolicName);
187 for (String excludedSuffix : excludedSuffixes) {
188 if (bundleName.endsWith(excludedSuffix))
189 return;// skip adding to sources
190 }
191 sources.add(RepoUtils.asArtifact(bundleNode));
192 return;
193 }
194
195 NodeIterator exportPackages = bundleNode.getNodes(SLC_
196 + Constants.EXPORT_PACKAGE);
197 while (exportPackages.hasNext()) {
198 Node exportPackage = exportPackages.nextNode();
199 String pkg = JcrUtils.get(exportPackage, SLC_NAME);
200 packagesToSymbolicNames.put(pkg, symbolicName);
201 }
202
203 symbolicNamesToNodes.put(symbolicName, bundleNode);
204 for (String excludedSuffix : excludedSuffixes) {
205 if (symbolicName.endsWith(excludedSuffix))
206 return;// skip adding to binaries
207 }
208 binaries.add(RepoUtils.asArtifact(bundleNode));
209
210 if (bundleNode.getSession().hasPendingChanges())
211 bundleNode.getSession().save();
212 }
213
214 protected void processBundleArtifact(Node bundleNode)
215 throws RepositoryException {
216 Node artifactFolder = bundleNode.getParent();
217 String baseName = FilenameUtils.getBaseName(bundleNode.getName());
218
219 // pom
220 String pom = generatePomForBundle(bundleNode);
221 String pomName = baseName + ".pom";
222 Node pomNode = JcrUtils.copyBytesAsFile(artifactFolder, pomName,
223 pom.getBytes());
224
225 // checksum
226 String bundleSha = JcrUtils.checksumFile(bundleNode, "SHA-1");
227 JcrUtils.copyBytesAsFile(artifactFolder,
228 bundleNode.getName() + ".sha1", bundleSha.getBytes());
229 String pomSha = JcrUtils.checksumFile(pomNode, "SHA-1");
230 JcrUtils.copyBytesAsFile(artifactFolder, pomNode.getName() + ".sha1",
231 pomSha.getBytes());
232 }
233
234 private String generatePomForBundle(Node n) throws RepositoryException {
235 String ownSymbolicName = JcrUtils.get(n, SLC_SYMBOLIC_NAME);
236
237 StringBuffer p = new StringBuffer();
238
239 // XML header
240 p.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
241 p.append("<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n");
242 p.append("<modelVersion>4.0.0</modelVersion>");
243
244 // Artifact
245 // p.append("<parent><groupId>org.argeo</groupId><artifactId>parent</artifactId><version>1.2.0</version></parent>\n");
246 p.append("<groupId>").append(JcrUtils.get(n, SLC_GROUP_ID))
247 .append("</groupId>\n");
248 p.append("<artifactId>").append(JcrUtils.get(n, SLC_ARTIFACT_ID))
249 .append("</artifactId>\n");
250 p.append("<version>").append(JcrUtils.get(n, SLC_ARTIFACT_VERSION))
251 .append("</version>\n");
252 p.append("<packaging>pom</packaging>\n");
253 if (n.hasProperty(SLC_ + Constants.BUNDLE_NAME))
254 p.append("<name>")
255 .append(JcrUtils.get(n, SLC_ + Constants.BUNDLE_NAME))
256 .append("</name>\n");
257 if (n.hasProperty(SLC_ + Constants.BUNDLE_DESCRIPTION))
258 p.append("<description>")
259 .append(JcrUtils
260 .get(n, SLC_ + Constants.BUNDLE_DESCRIPTION))
261 .append("</description>\n");
262
263 // Dependencies
264 Set<String> dependenciesSymbolicNames = new TreeSet<String>();
265 Set<String> optionalSymbolicNames = new TreeSet<String>();
266 NodeIterator importPackages = n.getNodes(SLC_
267 + Constants.IMPORT_PACKAGE);
268 while (importPackages.hasNext()) {
269 Node importPackage = importPackages.nextNode();
270 String pkg = JcrUtils.get(importPackage, SLC_NAME);
271 if (packagesToSymbolicNames.containsKey(pkg)) {
272 String dependencySymbolicName = packagesToSymbolicNames
273 .get(pkg);
274 if (JcrUtils.check(importPackage, SLC_OPTIONAL))
275 optionalSymbolicNames.add(dependencySymbolicName);
276 else
277 dependenciesSymbolicNames.add(dependencySymbolicName);
278 } else {
279 if (!JcrUtils.check(importPackage, SLC_OPTIONAL)
280 && !systemPackages.contains(pkg))
281 log.warn("No bundle found for pkg " + pkg);
282 }
283 }
284
285 if (n.hasNode(SLC_ + Constants.FRAGMENT_HOST)) {
286 String fragmentHost = JcrUtils.get(
287 n.getNode(SLC_ + Constants.FRAGMENT_HOST),
288 SLC_SYMBOLIC_NAME);
289 dependenciesSymbolicNames.add(fragmentHost);
290 }
291
292 // TODO require bundles
293
294 List<Node> dependencyNodes = new ArrayList<Node>();
295 for (String depSymbName : dependenciesSymbolicNames) {
296 if (depSymbName.equals(ownSymbolicName))
297 continue;// skip self
298
299 if (symbolicNamesToNodes.containsKey(depSymbName))
300 dependencyNodes.add(symbolicNamesToNodes.get(depSymbName));
301 else
302 log.warn("Could not find node for " + depSymbName);
303 }
304 List<Node> optionalDependencyNodes = new ArrayList<Node>();
305 for (String depSymbName : optionalSymbolicNames) {
306 if (symbolicNamesToNodes.containsKey(depSymbName))
307 optionalDependencyNodes.add(symbolicNamesToNodes
308 .get(depSymbName));
309 else
310 log.warn("Could not find node for " + depSymbName);
311 }
312
313 p.append("<dependencies>\n");
314 for (Node dependencyNode : dependencyNodes) {
315 p.append("<dependency>\n");
316 p.append("\t<groupId>")
317 .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID))
318 .append("</groupId>\n");
319 p.append("\t<artifactId>")
320 .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID))
321 .append("</artifactId>\n");
322 p.append("</dependency>\n");
323 }
324
325 if (optionalDependencyNodes.size() > 0)
326 p.append("<!-- OPTIONAL -->\n");
327 for (Node dependencyNode : optionalDependencyNodes) {
328 p.append("<dependency>\n");
329 p.append("\t<groupId>")
330 .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID))
331 .append("</groupId>\n");
332 p.append("\t<artifactId>")
333 .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID))
334 .append("</artifactId>\n");
335 p.append("\t<optional>true</optional>\n");
336 p.append("</dependency>\n");
337 }
338 p.append("</dependencies>\n");
339
340 // Dependency management
341 p.append("<dependencyManagement>\n");
342 p.append("<dependencies>\n");
343 p.append("<dependency>\n");
344 p.append("\t<groupId>").append(groupId).append("</groupId>\n");
345 p.append("\t<artifactId>")
346 .append(ownSymbolicName.endsWith(".source") ? SOURCES_ARTIFACT_ID
347 : BINARIES_ARTIFACT_ID).append("</artifactId>\n");
348 p.append("\t<version>").append(version).append("</version>\n");
349 p.append("\t<type>pom</type>\n");
350 p.append("\t<scope>import</scope>\n");
351 p.append("</dependency>\n");
352 p.append("</dependencies>\n");
353 p.append("</dependencyManagement>\n");
354
355 p.append("</project>\n");
356 return p.toString();
357 }
358
359 public void setRepository(Repository repository) {
360 this.repository = repository;
361 }
362
363 public void setWorkspace(String workspace) {
364 this.workspace = workspace;
365 }
366
367 public void setGroupId(String groupId) {
368 this.groupId = groupId;
369 }
370
371 public void setParentPomCoordinates(String parentPomCoordinates) {
372 this.parentPomCoordinates = parentPomCoordinates;
373 }
374
375 public void setArtifactBasePath(String artifactBasePath) {
376 this.artifactBasePath = artifactBasePath;
377 }
378
379 public void setVersion(String version) {
380 this.version = version;
381 }
382
383 public void setExcludedSuffixes(List<String> excludedSuffixes) {
384 this.excludedSuffixes = excludedSuffixes;
385 }
386
387 }