2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.repo
.osgi
;
18 import java
.util
.ArrayList
;
19 import java
.util
.HashMap
;
20 import java
.util
.List
;
23 import java
.util
.TreeSet
;
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
;
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
.ArgeoMonitor
;
35 import org
.argeo
.jcr
.JcrUtils
;
36 import org
.argeo
.slc
.SlcException
;
37 import org
.argeo
.slc
.aether
.ArtifactIdComparator
;
38 import org
.argeo
.slc
.jcr
.SlcNames
;
39 import org
.argeo
.slc
.jcr
.SlcTypes
;
40 import org
.argeo
.slc
.repo
.ArtifactIndexer
;
41 import org
.argeo
.slc
.repo
.JarFileIndexer
;
42 import org
.argeo
.slc
.repo
.RepoUtils
;
43 import org
.argeo
.slc
.repo
.maven
.MavenConventionsUtils
;
44 import org
.osgi
.framework
.Constants
;
45 import org
.sonatype
.aether
.artifact
.Artifact
;
46 import org
.sonatype
.aether
.util
.artifact
.DefaultArtifact
;
49 * Make sure that all JCR metadata and Maven metadata are consistent for this
50 * group of OSGi bundles.
52 public class NormalizeGroup
implements Runnable
, SlcNames
{
53 public final static String BINARIES_ARTIFACT_ID
= "binaries";
54 public final static String SOURCES_ARTIFACT_ID
= "sources";
55 public final static String SDK_ARTIFACT_ID
= "sdk";
57 private final static Log log
= LogFactory
.getLog(NormalizeGroup
.class);
59 private Repository repository
;
60 private String workspace
;
61 private String groupId
;
62 private String artifactBasePath
= "/";
63 private String version
= null;
64 private String parentPomCoordinates
;
66 private List
<String
> excludedSuffixes
= new ArrayList
<String
>();
68 private ArtifactIndexer artifactIndexer
= new ArtifactIndexer();
69 private JarFileIndexer jarFileIndexer
= new JarFileIndexer();
71 private List
<String
> systemPackages
= OsgiProfile
.PROFILE_JAVA_SE_1_6
75 private Map
<String
, String
> packagesToSymbolicNames
= new HashMap
<String
, String
>();
76 private Map
<String
, Node
> symbolicNamesToNodes
= new HashMap
<String
, Node
>();
78 private Set
<Artifact
> binaries
= new TreeSet
<Artifact
>(
79 new ArtifactIdComparator());
80 private Set
<Artifact
> sources
= new TreeSet
<Artifact
>(
81 new ArtifactIdComparator());
84 Session session
= null;
86 session
= repository
.login(workspace
);
87 Node groupNode
= session
.getNode(MavenConventionsUtils
.groupPath(
88 artifactBasePath
, groupId
));
89 processGroupNode(groupNode
, null);
90 } catch (Exception e
) {
91 throw new SlcException("Cannot normalize group " + groupId
+ " in "
94 JcrUtils
.logoutQuietly(session
);
98 public synchronized void processGroupNode(Node groupNode
, String version
,
99 ArgeoMonitor monitor
) throws RepositoryException
{
100 // FIXME better encapsulate
101 groupId
= groupNode
.getProperty(SlcNames
.SLC_GROUP_BASE_ID
).getString();
102 this.version
= version
;
103 processGroupNode(groupNode
, monitor
);
106 protected void processGroupNode(Node groupNode
, ArgeoMonitor monitor
)
107 throws RepositoryException
{
109 monitor
.subTask("Group " + groupId
);
110 Session session
= groupNode
.getSession();
111 for (NodeIterator artifactBases
= groupNode
.getNodes(); artifactBases
113 Node artifactBase
= artifactBases
.nextNode();
114 if (artifactBase
.isNodeType(SlcTypes
.SLC_ARTIFACT_BASE
)) {
115 for (NodeIterator artifactVersions
= artifactBase
.getNodes(); artifactVersions
117 Node artifactVersion
= artifactVersions
.nextNode();
119 .isNodeType(SlcTypes
.SLC_ARTIFACT_VERSION_BASE
))
120 for (NodeIterator files
= artifactVersion
.getNodes(); files
122 Node file
= files
.nextNode();
123 if (file
.isNodeType(SlcTypes
.SLC_BUNDLE_ARTIFACT
)) {
124 preProcessBundleArtifact(file
);
125 file
.getSession().save();
126 if (log
.isDebugEnabled())
127 log
.debug("Pre-processed " + file
.getName());
134 // NodeIterator bundlesIt = listBundleArtifacts(session);
136 // while (bundlesIt.hasNext()) {
137 // Node bundleNode = bundlesIt.nextNode();
138 // preProcessBundleArtifact(bundleNode);
139 // bundleNode.getSession().save();
140 // if (log.isDebugEnabled())
141 // log.debug("Pre-processed " + bundleNode.getName());
144 int bundleCount
= symbolicNamesToNodes
.size();
145 if (log
.isDebugEnabled())
146 log
.debug("Indexed " + bundleCount
+ " bundles");
149 for (Node bundleNode
: symbolicNamesToNodes
.values()) {
150 processBundleArtifact(bundleNode
);
151 bundleNode
.getSession().save();
152 if (log
.isDebugEnabled())
153 log
.debug(count
+ "/" + bundleCount
+ " Processed "
154 + bundleNode
.getName());
159 Set
<Artifact
> indexes
= new TreeSet
<Artifact
>(
160 new ArtifactIdComparator());
161 Artifact indexArtifact
= writeIndex(session
, BINARIES_ARTIFACT_ID
,
163 indexes
.add(indexArtifact
);
164 indexArtifact
= writeIndex(session
, SOURCES_ARTIFACT_ID
, sources
);
165 indexes
.add(indexArtifact
);
167 writeIndex(session
, SDK_ARTIFACT_ID
, indexes
);
172 private Artifact
writeIndex(Session session
, String artifactId
,
173 Set
<Artifact
> artifacts
) throws RepositoryException
{
174 Artifact artifact
= new DefaultArtifact(groupId
, artifactId
, "pom",
176 Artifact parentArtifact
= parentPomCoordinates
!= null ?
new DefaultArtifact(
177 parentPomCoordinates
) : null;
178 String pom
= MavenConventionsUtils
.artifactsAsDependencyPom(artifact
,
179 artifacts
, parentArtifact
);
180 Node node
= RepoUtils
.copyBytesAsArtifact(
181 session
.getNode(artifactBasePath
), artifact
, pom
.getBytes());
182 artifactIndexer
.index(node
);
185 String pomSha
= JcrUtils
.checksumFile(node
, "SHA-1");
186 JcrUtils
.copyBytesAsFile(node
.getParent(), node
.getName() + ".sha1",
192 protected void preProcessBundleArtifact(Node bundleNode
)
193 throws RepositoryException
{
194 artifactIndexer
.index(bundleNode
);
195 jarFileIndexer
.index(bundleNode
);
197 String symbolicName
= JcrUtils
.get(bundleNode
, SLC_SYMBOLIC_NAME
);
199 if (symbolicName
.endsWith(".source")) {
200 // TODO make a shared node with classifier 'sources'
201 String bundleName
= RepoUtils
202 .extractBundleNameFromSourceName(symbolicName
);
203 for (String excludedSuffix
: excludedSuffixes
) {
204 if (bundleName
.endsWith(excludedSuffix
))
205 return;// skip adding to sources
207 sources
.add(RepoUtils
.asArtifact(bundleNode
));
211 NodeIterator exportPackages
= bundleNode
.getNodes(SLC_
212 + Constants
.EXPORT_PACKAGE
);
213 while (exportPackages
.hasNext()) {
214 Node exportPackage
= exportPackages
.nextNode();
215 String pkg
= JcrUtils
.get(exportPackage
, SLC_NAME
);
216 packagesToSymbolicNames
.put(pkg
, symbolicName
);
219 symbolicNamesToNodes
.put(symbolicName
, bundleNode
);
220 for (String excludedSuffix
: excludedSuffixes
) {
221 if (symbolicName
.endsWith(excludedSuffix
))
222 return;// skip adding to binaries
224 binaries
.add(RepoUtils
.asArtifact(bundleNode
));
226 if (bundleNode
.getSession().hasPendingChanges())
227 bundleNode
.getSession().save();
230 protected void processBundleArtifact(Node bundleNode
)
231 throws RepositoryException
{
232 Node artifactFolder
= bundleNode
.getParent();
233 String baseName
= FilenameUtils
.getBaseName(bundleNode
.getName());
236 String pom
= generatePomForBundle(bundleNode
);
237 String pomName
= baseName
+ ".pom";
238 Node pomNode
= JcrUtils
.copyBytesAsFile(artifactFolder
, pomName
,
242 String bundleSha
= JcrUtils
.checksumFile(bundleNode
, "SHA-1");
243 JcrUtils
.copyBytesAsFile(artifactFolder
,
244 bundleNode
.getName() + ".sha1", bundleSha
.getBytes());
245 String pomSha
= JcrUtils
.checksumFile(pomNode
, "SHA-1");
246 JcrUtils
.copyBytesAsFile(artifactFolder
, pomNode
.getName() + ".sha1",
250 private String
generatePomForBundle(Node n
) throws RepositoryException
{
251 String ownSymbolicName
= JcrUtils
.get(n
, SLC_SYMBOLIC_NAME
);
253 StringBuffer p
= new StringBuffer();
256 p
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
257 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");
258 p
.append("<modelVersion>4.0.0</modelVersion>");
261 // p.append("<parent><groupId>org.argeo</groupId><artifactId>parent</artifactId><version>1.2.0</version></parent>\n");
262 p
.append("<groupId>").append(JcrUtils
.get(n
, SLC_GROUP_ID
))
263 .append("</groupId>\n");
264 p
.append("<artifactId>").append(JcrUtils
.get(n
, SLC_ARTIFACT_ID
))
265 .append("</artifactId>\n");
266 p
.append("<version>").append(JcrUtils
.get(n
, SLC_ARTIFACT_VERSION
))
267 .append("</version>\n");
268 p
.append("<packaging>pom</packaging>\n");
269 if (n
.hasProperty(SLC_
+ Constants
.BUNDLE_NAME
))
271 .append(JcrUtils
.get(n
, SLC_
+ Constants
.BUNDLE_NAME
))
272 .append("</name>\n");
273 if (n
.hasProperty(SLC_
+ Constants
.BUNDLE_DESCRIPTION
))
274 p
.append("<description>")
276 .get(n
, SLC_
+ Constants
.BUNDLE_DESCRIPTION
))
277 .append("</description>\n");
280 Set
<String
> dependenciesSymbolicNames
= new TreeSet
<String
>();
281 Set
<String
> optionalSymbolicNames
= new TreeSet
<String
>();
282 NodeIterator importPackages
= n
.getNodes(SLC_
283 + Constants
.IMPORT_PACKAGE
);
284 while (importPackages
.hasNext()) {
285 Node importPackage
= importPackages
.nextNode();
286 String pkg
= JcrUtils
.get(importPackage
, SLC_NAME
);
287 if (packagesToSymbolicNames
.containsKey(pkg
)) {
288 String dependencySymbolicName
= packagesToSymbolicNames
290 if (JcrUtils
.check(importPackage
, SLC_OPTIONAL
))
291 optionalSymbolicNames
.add(dependencySymbolicName
);
293 dependenciesSymbolicNames
.add(dependencySymbolicName
);
295 if (!JcrUtils
.check(importPackage
, SLC_OPTIONAL
)
296 && !systemPackages
.contains(pkg
))
297 log
.warn("No bundle found for pkg " + pkg
);
301 if (n
.hasNode(SLC_
+ Constants
.FRAGMENT_HOST
)) {
302 String fragmentHost
= JcrUtils
.get(
303 n
.getNode(SLC_
+ Constants
.FRAGMENT_HOST
),
305 dependenciesSymbolicNames
.add(fragmentHost
);
308 // TODO require bundles
310 List
<Node
> dependencyNodes
= new ArrayList
<Node
>();
311 for (String depSymbName
: dependenciesSymbolicNames
) {
312 if (depSymbName
.equals(ownSymbolicName
))
313 continue;// skip self
315 if (symbolicNamesToNodes
.containsKey(depSymbName
))
316 dependencyNodes
.add(symbolicNamesToNodes
.get(depSymbName
));
318 log
.warn("Could not find node for " + depSymbName
);
320 List
<Node
> optionalDependencyNodes
= new ArrayList
<Node
>();
321 for (String depSymbName
: optionalSymbolicNames
) {
322 if (symbolicNamesToNodes
.containsKey(depSymbName
))
323 optionalDependencyNodes
.add(symbolicNamesToNodes
326 log
.warn("Could not find node for " + depSymbName
);
329 p
.append("<dependencies>\n");
330 for (Node dependencyNode
: dependencyNodes
) {
331 p
.append("<dependency>\n");
332 p
.append("\t<groupId>")
333 .append(JcrUtils
.get(dependencyNode
, SLC_GROUP_ID
))
334 .append("</groupId>\n");
335 p
.append("\t<artifactId>")
336 .append(JcrUtils
.get(dependencyNode
, SLC_ARTIFACT_ID
))
337 .append("</artifactId>\n");
338 p
.append("</dependency>\n");
341 if (optionalDependencyNodes
.size() > 0)
342 p
.append("<!-- OPTIONAL -->\n");
343 for (Node dependencyNode
: optionalDependencyNodes
) {
344 p
.append("<dependency>\n");
345 p
.append("\t<groupId>")
346 .append(JcrUtils
.get(dependencyNode
, SLC_GROUP_ID
))
347 .append("</groupId>\n");
348 p
.append("\t<artifactId>")
349 .append(JcrUtils
.get(dependencyNode
, SLC_ARTIFACT_ID
))
350 .append("</artifactId>\n");
351 p
.append("\t<optional>true</optional>\n");
352 p
.append("</dependency>\n");
354 p
.append("</dependencies>\n");
356 // Dependency management
357 p
.append("<dependencyManagement>\n");
358 p
.append("<dependencies>\n");
359 p
.append("<dependency>\n");
360 p
.append("\t<groupId>").append(groupId
).append("</groupId>\n");
361 p
.append("\t<artifactId>")
362 .append(ownSymbolicName
.endsWith(".source") ? SOURCES_ARTIFACT_ID
363 : BINARIES_ARTIFACT_ID
).append("</artifactId>\n");
364 p
.append("\t<version>").append(version
).append("</version>\n");
365 p
.append("\t<type>pom</type>\n");
366 p
.append("\t<scope>import</scope>\n");
367 p
.append("</dependency>\n");
368 p
.append("</dependencies>\n");
369 p
.append("</dependencyManagement>\n");
371 p
.append("</project>\n");
375 public void setRepository(Repository repository
) {
376 this.repository
= repository
;
379 public void setWorkspace(String workspace
) {
380 this.workspace
= workspace
;
383 public void setGroupId(String groupId
) {
384 this.groupId
= groupId
;
387 public void setParentPomCoordinates(String parentPomCoordinates
) {
388 this.parentPomCoordinates
= parentPomCoordinates
;
391 public void setArtifactBasePath(String artifactBasePath
) {
392 this.artifactBasePath
= artifactBasePath
;
395 public void setVersion(String version
) {
396 this.version
= version
;
399 public void setExcludedSuffixes(List
<String
> excludedSuffixes
) {
400 this.excludedSuffixes
= excludedSuffixes
;