]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/NormalizeGroup.java
Alpha version of SLC Repo: can serve as backend for building Argeo Commons Basic
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / osgi / 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 = "1.3.0";
63 private String parentPomCoordinates = "org.argeo:parent:1.3.0";
64
65 private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
66 private JarFileIndexer jarFileIndexer = new JarFileIndexer();
67
68 private List<String> systemPackages = OsgiProfile.PROFILE_JAVA_SE_1_6
69 .getSystemPackages();
70
71 // indexes
72 private Map<String, String> packagesToSymbolicNames = new HashMap<String, String>();
73 private Map<String, Node> symbolicNamesToNodes = new HashMap<String, Node>();
74
75 private Set<Artifact> binaries = new TreeSet<Artifact>(
76 new ArtifactIdComparator());
77 private Set<Artifact> sources = new TreeSet<Artifact>(
78 new ArtifactIdComparator());
79
80 public void run() {
81 Session session = null;
82 try {
83 session = repository.login(workspace);
84
85 Node groupNode = session.getNode(MavenConventionsUtils.groupPath(
86 artifactBasePath, groupId));
87 // TODO factorize with a traverser pattern?
88 for (NodeIterator artifactBases = groupNode.getNodes(); artifactBases
89 .hasNext();) {
90 Node artifactBase = artifactBases.nextNode();
91 if (artifactBase.isNodeType(SlcTypes.SLC_ARTIFACT_BASE)) {
92 for (NodeIterator artifactVersions = artifactBase
93 .getNodes(); artifactVersions.hasNext();) {
94 Node artifactVersion = artifactVersions.nextNode();
95 if (artifactVersion
96 .isNodeType(SlcTypes.SLC_ARTIFACT_VERSION_BASE))
97 for (NodeIterator files = artifactVersion
98 .getNodes(); files.hasNext();) {
99 Node file = files.nextNode();
100 if (file.isNodeType(SlcTypes.SLC_BUNDLE_ARTIFACT)) {
101 preProcessBundleArtifact(file);
102 file.getSession().save();
103 if (log.isDebugEnabled())
104 log.debug("Pre-processed "
105 + file.getName());
106 }
107
108 }
109 }
110 }
111 }
112 // NodeIterator bundlesIt = listBundleArtifacts(session);
113 //
114 // while (bundlesIt.hasNext()) {
115 // Node bundleNode = bundlesIt.nextNode();
116 // preProcessBundleArtifact(bundleNode);
117 // bundleNode.getSession().save();
118 // if (log.isDebugEnabled())
119 // log.debug("Pre-processed " + bundleNode.getName());
120 // }
121
122 int bundleCount = symbolicNamesToNodes.size();
123 if (log.isDebugEnabled())
124 log.debug("Indexed " + bundleCount + " bundles");
125
126 int count = 1;
127 for (Node bundleNode : symbolicNamesToNodes.values()) {
128 processBundleArtifact(bundleNode);
129 bundleNode.getSession().save();
130 if (log.isDebugEnabled())
131 log.debug(count + "/" + bundleCount + " Processed "
132 + bundleNode.getName());
133 count++;
134 }
135
136 // indexes
137 Set<Artifact> indexes = new TreeSet<Artifact>(
138 new ArtifactIdComparator());
139 Artifact indexArtifact = writeIndex(session, BINARIES_ARTIFACT_ID,
140 binaries);
141 indexes.add(indexArtifact);
142 indexArtifact = writeIndex(session, SOURCES_ARTIFACT_ID, sources);
143 indexes.add(indexArtifact);
144 // sdk
145 writeIndex(session, SDK_ARTIFACT_ID, indexes);
146 } catch (Exception e) {
147 throw new SlcException("Cannot normalize group " + groupId + " in "
148 + workspace, e);
149 } finally {
150 JcrUtils.logoutQuietly(session);
151 }
152 }
153
154 private Artifact writeIndex(Session session, String artifactId,
155 Set<Artifact> artifacts) throws RepositoryException {
156 Artifact artifact = new DefaultArtifact(groupId, artifactId, "pom",
157 version);
158 String pom = MavenConventionsUtils.artifactsAsDependencyPom(artifact,
159 artifacts, new DefaultArtifact(parentPomCoordinates));
160 Node node = RepoUtils.copyBytesAsArtifact(
161 session.getNode(artifactBasePath), artifact, pom.getBytes());
162 artifactIndexer.index(node);
163
164 // FIXME factorize
165 String pomSha = JcrUtils.checksumFile(node, "SHA-1");
166 JcrUtils.copyBytesAsFile(node.getParent(), node.getName() + ".sha1",
167 pomSha.getBytes());
168 session.save();
169 return artifact;
170 }
171
172 protected void preProcessBundleArtifact(Node bundleNode)
173 throws RepositoryException {
174 artifactIndexer.index(bundleNode);
175 jarFileIndexer.index(bundleNode);
176
177 String symbolicName = JcrUtils.get(bundleNode, SLC_SYMBOLIC_NAME);
178
179 if (symbolicName.endsWith(".source")) {
180 // TODO make a shared node with classifier 'sources'
181 sources.add(RepoUtils.asArtifact(bundleNode));
182 return;
183 }
184
185 NodeIterator exportPackages = bundleNode.getNodes(SLC_
186 + Constants.EXPORT_PACKAGE);
187 while (exportPackages.hasNext()) {
188 Node exportPackage = exportPackages.nextNode();
189 String pkg = JcrUtils.get(exportPackage, SLC_NAME);
190 packagesToSymbolicNames.put(pkg, symbolicName);
191 }
192
193 symbolicNamesToNodes.put(symbolicName, bundleNode);
194 binaries.add(RepoUtils.asArtifact(bundleNode));
195 }
196
197 protected void processBundleArtifact(Node bundleNode)
198 throws RepositoryException {
199 Node artifactFolder = bundleNode.getParent();
200 String baseName = FilenameUtils.getBaseName(bundleNode.getName());
201
202 // pom
203 String pom = generatePomForBundle(bundleNode);
204 String pomName = baseName + ".pom";
205 Node pomNode = JcrUtils.copyBytesAsFile(artifactFolder, pomName,
206 pom.getBytes());
207
208 // checksum
209 String bundleSha = JcrUtils.checksumFile(bundleNode, "SHA-1");
210 JcrUtils.copyBytesAsFile(artifactFolder,
211 bundleNode.getName() + ".sha1", bundleSha.getBytes());
212 String pomSha = JcrUtils.checksumFile(pomNode, "SHA-1");
213 JcrUtils.copyBytesAsFile(artifactFolder, pomNode.getName() + ".sha1",
214 pomSha.getBytes());
215 }
216
217 private String generatePomForBundle(Node n) throws RepositoryException {
218 String ownSymbolicName = JcrUtils.get(n, SLC_SYMBOLIC_NAME);
219
220 StringBuffer p = new StringBuffer();
221
222 // XML header
223 p.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
224 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");
225 p.append("<modelVersion>4.0.0</modelVersion>");
226
227 // Artifact
228 // p.append("<parent><groupId>org.argeo</groupId><artifactId>parent</artifactId><version>1.2.0</version></parent>\n");
229 p.append("<groupId>").append(JcrUtils.get(n, SLC_GROUP_ID))
230 .append("</groupId>\n");
231 p.append("<artifactId>").append(JcrUtils.get(n, SLC_ARTIFACT_ID))
232 .append("</artifactId>\n");
233 p.append("<version>").append(JcrUtils.get(n, SLC_ARTIFACT_VERSION))
234 .append("</version>\n");
235 p.append("<packaging>pom</packaging>\n");
236 if (n.hasProperty(SLC_ + Constants.BUNDLE_NAME))
237 p.append("<name>")
238 .append(JcrUtils.get(n, SLC_ + Constants.BUNDLE_NAME))
239 .append("</name>\n");
240 if (n.hasProperty(SLC_ + Constants.BUNDLE_DESCRIPTION))
241 p.append("<description>")
242 .append(JcrUtils
243 .get(n, SLC_ + Constants.BUNDLE_DESCRIPTION))
244 .append("</description>\n");
245
246 // Dependencies
247 Set<String> dependenciesSymbolicNames = new TreeSet<String>();
248 Set<String> optionalSymbolicNames = new TreeSet<String>();
249 NodeIterator importPackages = n.getNodes(SLC_
250 + Constants.IMPORT_PACKAGE);
251 while (importPackages.hasNext()) {
252 Node importPackage = importPackages.nextNode();
253 String pkg = JcrUtils.get(importPackage, SLC_NAME);
254 if (packagesToSymbolicNames.containsKey(pkg)) {
255 String dependencySymbolicName = packagesToSymbolicNames
256 .get(pkg);
257 if (JcrUtils.check(importPackage, SLC_OPTIONAL))
258 optionalSymbolicNames.add(dependencySymbolicName);
259 else
260 dependenciesSymbolicNames.add(dependencySymbolicName);
261 } else {
262 if (!JcrUtils.check(importPackage, SLC_OPTIONAL)
263 && !systemPackages.contains(pkg))
264 log.warn("No bundle found for pkg " + pkg);
265 }
266 }
267
268 if (n.hasNode(SLC_ + Constants.FRAGMENT_HOST)) {
269 String fragmentHost = JcrUtils.get(
270 n.getNode(SLC_ + Constants.FRAGMENT_HOST),
271 SLC_SYMBOLIC_NAME);
272 dependenciesSymbolicNames.add(fragmentHost);
273 }
274
275 // TODO require bundles
276
277 List<Node> dependencyNodes = new ArrayList<Node>();
278 for (String depSymbName : dependenciesSymbolicNames) {
279 if (depSymbName.equals(ownSymbolicName))
280 continue;// skip self
281
282 if (symbolicNamesToNodes.containsKey(depSymbName))
283 dependencyNodes.add(symbolicNamesToNodes.get(depSymbName));
284 else
285 log.warn("Could not find node for " + depSymbName);
286 }
287 List<Node> optionalDependencyNodes = new ArrayList<Node>();
288 for (String depSymbName : optionalSymbolicNames) {
289 if (symbolicNamesToNodes.containsKey(depSymbName))
290 optionalDependencyNodes.add(symbolicNamesToNodes
291 .get(depSymbName));
292 else
293 log.warn("Could not find node for " + depSymbName);
294 }
295
296 p.append("<dependencies>\n");
297 for (Node dependencyNode : dependencyNodes) {
298 p.append("<dependency>\n");
299 p.append("\t<groupId>")
300 .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID))
301 .append("</groupId>\n");
302 p.append("\t<artifactId>")
303 .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID))
304 .append("</artifactId>\n");
305 p.append("</dependency>\n");
306 }
307
308 if (optionalDependencyNodes.size() > 0)
309 p.append("<!-- OPTIONAL -->\n");
310 for (Node dependencyNode : optionalDependencyNodes) {
311 p.append("<dependency>\n");
312 p.append("\t<groupId>")
313 .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID))
314 .append("</groupId>\n");
315 p.append("\t<artifactId>")
316 .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID))
317 .append("</artifactId>\n");
318 p.append("\t<optional>true</optional>\n");
319 p.append("</dependency>\n");
320 }
321 p.append("</dependencies>\n");
322
323 // Dependency management
324 p.append("<dependencyManagement>\n");
325 p.append("<dependencies>\n");
326 p.append("<dependency>\n");
327 p.append("\t<groupId>").append(groupId).append("</groupId>\n");
328 p.append("\t<artifactId>")
329 .append(ownSymbolicName.endsWith(".source") ? SOURCES_ARTIFACT_ID
330 : BINARIES_ARTIFACT_ID).append("</artifactId>\n");
331 p.append("\t<version>").append(version).append("</version>\n");
332 p.append("\t<type>pom</type>\n");
333 p.append("\t<scope>import</scope>\n");
334 p.append("</dependency>\n");
335 p.append("</dependencies>\n");
336 p.append("</dependencyManagement>\n");
337
338 p.append("</project>\n");
339 return p.toString();
340 }
341
342 public void setRepository(Repository repository) {
343 this.repository = repository;
344 }
345
346 public void setWorkspace(String workspace) {
347 this.workspace = workspace;
348 }
349
350 public void setGroupId(String groupId) {
351 this.groupId = groupId;
352 }
353
354 public void setParentPomCoordinates(String parentPomCoordinates) {
355 this.parentPomCoordinates = parentPomCoordinates;
356 }
357
358 }