Introduce NormalizeGroup
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 19 May 2012 10:54:55 +0000 (10:54 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 19 May 2012 10:54:55 +0000 (10:54 +0000)
Group indexes (binaries, sources, sdk)

git-svn-id: https://svn.argeo.org/slc/trunk@5307 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

eclipse/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/NormalizeDistribution.java
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoUtils.java
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/ImportMavenDependencies.java
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/MavenConventionsUtils.java
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/Migration_01_03.java
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/NormalizeGroup.java [new file with mode: 0644]
runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/OsgiProfile.java [new file with mode: 0644]
runtime/org.argeo.slc.support.aether/src/main/java/org/argeo/slc/aether/ArtifactIdComparator.java [new file with mode: 0644]

index 3dfee960ed2e6f660ad2d1319d739ea38d20036d..85a336e8d96197adaae42a1bf96a4c6c0d6415eb 100644 (file)
@@ -54,6 +54,7 @@ public class NormalizeDistribution extends AbstractHandler implements SlcNames {
 
        private Repository repository;
        private String workspace;
+       private String groupId;
 
        private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
        private JarFileIndexer jarFileIndexer = new JarFileIndexer();
index 242cbe0e4242a86412e20e2761bd48b26ead64ce..df8a01daa956db7507cbdd184107e8ff430d02ed 100644 (file)
@@ -23,11 +23,13 @@ import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.BasicNameVersion;
 import org.argeo.slc.NameVersion;
 import org.argeo.slc.SlcException;
 import org.argeo.slc.jcr.SlcNames;
 import org.argeo.slc.jcr.SlcTypes;
+import org.argeo.slc.repo.maven.MavenConventionsUtils;
 import org.osgi.framework.Constants;
 import org.sonatype.aether.artifact.Artifact;
 import org.sonatype.aether.util.artifact.DefaultArtifact;
@@ -268,6 +270,16 @@ public class RepoUtils implements SlcNames {
                }
        }
 
+       public static Node copyBytesAsArtifact(Node artifactsBase,
+                       Artifact artifact, byte[] bytes) throws RepositoryException {
+               String parentPath = MavenConventionsUtils.artifactParentPath(
+                               artifactsBase.getPath(), artifact);
+               Node folderNode = JcrUtils.mkfolders(artifactsBase.getSession(),
+                               parentPath);
+               return JcrUtils.copyBytesAsFile(folderNode,
+                               MavenConventionsUtils.artifactFileName(artifact), bytes);
+       }
+       
        private RepoUtils() {
        }
 }
index 0bda72b7e87e91d272eaa86e0cf7d5b99f767345..684e75cdaed2761f152987e7f9df11c514cfc791 100644 (file)
@@ -36,6 +36,7 @@ import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.NameVersion;
 import org.argeo.slc.SlcException;
 import org.argeo.slc.aether.AetherTemplate;
+import org.argeo.slc.aether.ArtifactIdComparator;
 import org.argeo.slc.repo.ArtifactIndexer;
 import org.argeo.slc.repo.JarFileIndexer;
 import org.argeo.slc.repo.RepoConstants;
@@ -64,11 +65,7 @@ public class ImportMavenDependencies implements Runnable {
 
        private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
        private JarFileIndexer jarFileIndexer = new JarFileIndexer();
-       private Comparator<Artifact> artifactComparator = new Comparator<Artifact>() {
-               public int compare(Artifact o1, Artifact o2) {
-                       return o1.getArtifactId().compareTo(o2.getArtifactId());
-               }
-       };
+       private Comparator<Artifact> artifactComparator = new ArtifactIdComparator();
 
        public void run() {
                // resolve
index 5296895a6b0bc7352e9ed8f37cbb859ce1f3f750..a19e0725a6fafa08bf55daba74f5c61f3dba3f68 100644 (file)
@@ -76,6 +76,12 @@ public class MavenConventionsUtils {
                                + artifactParentPath(artifact);
        }
 
+       /** Absolute path to the directory of this group */
+       public static String groupPath(String artifactBasePath, String groupId) {
+               return artifactBasePath + (artifactBasePath.endsWith("/") ? "" : "/")
+                               + groupId.replace('.', '/');
+       }
+
        /** Relative path to the directories where the files will be stored */
        public static String artifactParentPath(Artifact artifact) {
                return artifact.getGroupId().replace('.', '/') + '/'
@@ -84,58 +90,61 @@ public class MavenConventionsUtils {
 
        public static String artifactsAsDependencyPom(Artifact pomArtifact,
                        Set<Artifact> artifacts) {
-               StringBuffer b = new StringBuffer();
+               StringBuffer p = new StringBuffer();
 
                // XML header
-               b.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
-               b.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");
-               b.append("<modelVersion>4.0.0</modelVersion>");
+               p.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+               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");
+               p.append("<modelVersion>4.0.0</modelVersion>");
 
                // Artifact
-               b.append("<parent><groupId>org.argeo</groupId><artifactId>parent</artifactId><version>1.2.0</version></parent>\n");
-               b.append("<groupId>").append(pomArtifact.getGroupId())
+               p.append("<parent><groupId>org.argeo</groupId><artifactId>parent</artifactId><version>1.2.0</version></parent>\n");
+               p.append("<groupId>").append(pomArtifact.getGroupId())
                                .append("</groupId>\n");
-               b.append("<artifactId>").append(pomArtifact.getArtifactId())
+               p.append("<artifactId>").append(pomArtifact.getArtifactId())
                                .append("</artifactId>\n");
-               b.append("<version>").append(pomArtifact.getVersion())
+               p.append("<version>").append(pomArtifact.getVersion())
                                .append("</version>\n");
-               b.append("<packaging>pom</packaging>\n");
+               p.append("<packaging>pom</packaging>\n");
 
                // Dependencies
-               b.append("<dependencies>\n");
-               for (Artifact artifact : artifacts) {
-                       b.append("\t<dependency>");
-                       b.append("<artifactId>").append(artifact.getArtifactId())
+               p.append("<dependencies>\n");
+               for (Artifact a : artifacts) {
+                       p.append("\t<dependency>");
+                       p.append("<artifactId>").append(a.getArtifactId())
                                        .append("</artifactId>");
-                       b.append("<groupId>").append(artifact.getGroupId())
-                                       .append("</groupId>");
-                       b.append("</dependency>\n");
+                       p.append("<groupId>").append(a.getGroupId()).append("</groupId>");
+                       if (!a.getExtension().equals("jar"))
+                               p.append("<type>").append(a.getExtension()).append("</type>");
+                       p.append("</dependency>\n");
                }
-               b.append("</dependencies>\n");
+               p.append("</dependencies>\n");
 
                // Dependency management
-               b.append("<dependencyManagement>\n");
-               b.append("<dependencies>\n");
-               for (Artifact artifact : artifacts) {
-                       b.append("\t<dependency>");
-                       b.append("<artifactId>").append(artifact.getArtifactId())
+               p.append("<dependencyManagement>\n");
+               p.append("<dependencies>\n");
+               for (Artifact a : artifacts) {
+                       p.append("\t<dependency>");
+                       p.append("<artifactId>").append(a.getArtifactId())
                                        .append("</artifactId>");
-                       b.append("<version>").append(artifact.getVersion())
-                                       .append("</version>");
-                       b.append("<groupId>").append(artifact.getGroupId())
-                                       .append("</groupId>");
-                       b.append("</dependency>\n");
+                       p.append("<version>").append(a.getVersion()).append("</version>");
+                       p.append("<groupId>").append(a.getGroupId()).append("</groupId>");
+                       if (a.getExtension().equals("pom")) {
+                               p.append("<type>").append(a.getExtension()).append("</type>");
+                               p.append("<scope>import</scope>");
+                       }
+                       p.append("</dependency>\n");
                }
-               b.append("</dependencies>\n");
-               b.append("</dependencyManagement>\n");
+               p.append("</dependencies>\n");
+               p.append("</dependencyManagement>\n");
 
                // Repositories
-               b.append("<repositories>\n");
-               b.append("<repository><id>argeo</id><url>http://maven.argeo.org/argeo</url></repository>\n");
-               b.append("</repositories>\n");
+               p.append("<repositories>\n");
+               p.append("<repository><id>argeo</id><url>http://maven.argeo.org/argeo</url></repository>\n");
+               p.append("</repositories>\n");
 
-               b.append("</project>\n");
-               return b.toString();
+               p.append("</project>\n");
+               return p.toString();
        }
 
        /**
index 1f59f82bda7a0d47cb0ef9db99c335d3ad602733..325d352b0fecf2557f7cc399b150f6f33c43c911 100644 (file)
@@ -34,6 +34,7 @@ import org.argeo.slc.jcr.SlcTypes;
 import org.argeo.slc.repo.ArtifactIndexer;
 import org.argeo.slc.repo.JarFileIndexer;
 import org.argeo.slc.repo.RepoUtils;
+import org.argeo.slc.repo.osgi.OsgiProfile;
 import org.osgi.framework.Constants;
 import org.sonatype.aether.artifact.Artifact;
 import org.sonatype.aether.util.artifact.DefaultArtifact;
@@ -54,6 +55,7 @@ public class Migration_01_03 implements Runnable, SlcNames {
        private Repository repository;
        private String sourceWorkspace;
        private String targetWorkspace;
+       private String osgiProfile = "JavaSE-1.6.profile";
 
        private List<String> excludedBundles = new ArrayList<String>();
        private Map<String, String> symbolicNamesMapping = new HashMap<String, String>();
@@ -61,7 +63,8 @@ public class Migration_01_03 implements Runnable, SlcNames {
        private Session origSession;
        private Session targetSession;
 
-       private List<String> systemPackages;
+       private List<String> systemPackages = OsgiProfile.PROFILE_JAVA_SE_1_6
+                       .getSystemPackages();
 
        private String artifactBasePath = "/";
 
@@ -75,8 +78,8 @@ public class Migration_01_03 implements Runnable, SlcNames {
                                targetWorkspace);
 
                // works only in OSGi!!
-               systemPackages = Arrays.asList(System.getProperty(
-                               "org.osgi.framework.system.packages").split(","));
+               // systemPackages = Arrays.asList(System.getProperty(
+               // "org.osgi.framework.system.packages").split(","));
        }
 
        public void destroy() {
@@ -121,6 +124,16 @@ public class Migration_01_03 implements Runnable, SlcNames {
        protected void processOrigArtifactVersion(Node origArtifactNode)
                        throws RepositoryException, IOException {
                Artifact origArtifact = RepoUtils.asArtifact(origArtifactNode);
+
+               // skip eclipse artifacts
+               if ((origArtifact.getGroupId().startsWith("org.eclipse") && !origArtifact
+                               .getArtifactId().equals("org.eclipse.osgi"))
+                               || (origArtifact.getArtifactId().startsWith("org.polymap"))) {
+                       if (log.isDebugEnabled())
+                               log.debug("Skip " + origArtifact);
+                       return;
+               }
+
                String origJarNodeName = MavenConventionsUtils
                                .artifactFileName(origArtifact);
                if (!origArtifactNode.hasNode(origJarNodeName))
diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/NormalizeGroup.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/NormalizeGroup.java
new file mode 100644 (file)
index 0000000..4c9a3d5
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.slc.repo.osgi;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.aether.ArtifactIdComparator;
+import org.argeo.slc.jcr.SlcNames;
+import org.argeo.slc.jcr.SlcTypes;
+import org.argeo.slc.repo.ArtifactIndexer;
+import org.argeo.slc.repo.JarFileIndexer;
+import org.argeo.slc.repo.RepoUtils;
+import org.argeo.slc.repo.maven.MavenConventionsUtils;
+import org.osgi.framework.Constants;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+
+/**
+ * Make sure that all JCR metadata and Maven metadata are consistent for this
+ * group of OSGi bundles.
+ */
+public class NormalizeGroup implements Runnable, SlcNames {
+       public final static String BINARIES_ARTIFACT_ID = "binaries";
+       public final static String SOURCES_ARTIFACT_ID = "sources";
+       public final static String SDK_ARTIFACT_ID = "sdk";
+
+       private final static Log log = LogFactory.getLog(NormalizeGroup.class);
+
+       private Repository repository;
+       private String workspace;
+       private String groupId;
+       private String artifactBasePath = "/";
+       private String version = "1.3.0";
+
+       private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
+       private JarFileIndexer jarFileIndexer = new JarFileIndexer();
+
+       private List<String> systemPackages = OsgiProfile.PROFILE_JAVA_SE_1_6
+                       .getSystemPackages();
+
+       // indexes
+       private Map<String, String> packagesToSymbolicNames = new HashMap<String, String>();
+       private Map<String, Node> symbolicNamesToNodes = new HashMap<String, Node>();
+
+       private Set<Artifact> binaries = new TreeSet<Artifact>(
+                       new ArtifactIdComparator());
+       private Set<Artifact> sources = new TreeSet<Artifact>(
+                       new ArtifactIdComparator());
+
+       public void run() {
+               Session session = null;
+               try {
+                       session = repository.login(workspace);
+
+                       Node groupNode = session.getNode(MavenConventionsUtils.groupPath(
+                                       artifactBasePath, groupId));
+                       // TODO factorize with a traverser pattern?
+                       for (NodeIterator artifactBases = groupNode.getNodes(); artifactBases
+                                       .hasNext();) {
+                               Node artifactBase = artifactBases.nextNode();
+                               if (artifactBase.isNodeType(SlcTypes.SLC_ARTIFACT_BASE)) {
+                                       for (NodeIterator artifactVersions = artifactBase
+                                                       .getNodes(); artifactVersions.hasNext();) {
+                                               Node artifactVersion = artifactVersions.nextNode();
+                                               if (artifactVersion
+                                                               .isNodeType(SlcTypes.SLC_ARTIFACT_VERSION_BASE))
+                                                       for (NodeIterator files = artifactVersion
+                                                                       .getNodes(); files.hasNext();) {
+                                                               Node file = files.nextNode();
+                                                               if (file.isNodeType(SlcTypes.SLC_BUNDLE_ARTIFACT)) {
+                                                                       preProcessBundleArtifact(file);
+                                                                       file.getSession().save();
+                                                                       if (log.isDebugEnabled())
+                                                                               log.debug("Pre-processed "
+                                                                                               + file.getName());
+                                                               }
+
+                                                       }
+                                       }
+                               }
+                       }
+                       // NodeIterator bundlesIt = listBundleArtifacts(session);
+                       //
+                       // while (bundlesIt.hasNext()) {
+                       // Node bundleNode = bundlesIt.nextNode();
+                       // preProcessBundleArtifact(bundleNode);
+                       // bundleNode.getSession().save();
+                       // if (log.isDebugEnabled())
+                       // log.debug("Pre-processed " + bundleNode.getName());
+                       // }
+
+                       int bundleCount = symbolicNamesToNodes.size();
+                       if (log.isDebugEnabled())
+                               log.debug("Indexed " + bundleCount + " bundles");
+
+                       int count = 1;
+                       for (Node bundleNode : symbolicNamesToNodes.values()) {
+                               processBundleArtifact(bundleNode);
+                               bundleNode.getSession().save();
+                               if (log.isDebugEnabled())
+                                       log.debug(count + "/" + bundleCount + " Processed "
+                                                       + bundleNode.getName());
+                               count++;
+                       }
+
+                       // indexes
+                       Set<Artifact> indexes = new TreeSet<Artifact>(
+                                       new ArtifactIdComparator());
+                       Artifact indexArtifact = writeIndex(session, BINARIES_ARTIFACT_ID,
+                                       binaries);
+                       indexes.add(indexArtifact);
+                       indexArtifact = writeIndex(session, SOURCES_ARTIFACT_ID, sources);
+                       indexes.add(indexArtifact);
+                       // sdk
+                       writeIndex(session, SDK_ARTIFACT_ID, indexes);
+               } catch (Exception e) {
+                       throw new SlcException("Cannot normalize group " + groupId + " in "
+                                       + workspace, e);
+               } finally {
+                       JcrUtils.logoutQuietly(session);
+               }
+       }
+
+       private Artifact writeIndex(Session session, String artifactId,
+                       Set<Artifact> artifacts) throws RepositoryException {
+               Artifact artifact = new DefaultArtifact(groupId, artifactId, "pom",
+                               version);
+               String pom = MavenConventionsUtils.artifactsAsDependencyPom(artifact,
+                               artifacts);
+               Node node = RepoUtils.copyBytesAsArtifact(
+                               session.getNode(artifactBasePath), artifact, pom.getBytes());
+               artifactIndexer.index(node);
+               session.save();
+               return artifact;
+       }
+
+       protected void preProcessBundleArtifact(Node bundleNode)
+                       throws RepositoryException {
+               artifactIndexer.index(bundleNode);
+               jarFileIndexer.index(bundleNode);
+
+               String symbolicName = JcrUtils.get(bundleNode, SLC_SYMBOLIC_NAME);
+
+               if (symbolicName.endsWith(".source")) {
+                       // TODO make a shared node with classifier 'sources'
+                       sources.add(RepoUtils.asArtifact(bundleNode));
+                       return;
+               }
+
+               NodeIterator exportPackages = bundleNode.getNodes(SLC_
+                               + Constants.EXPORT_PACKAGE);
+               while (exportPackages.hasNext()) {
+                       Node exportPackage = exportPackages.nextNode();
+                       String pkg = JcrUtils.get(exportPackage, SLC_NAME);
+                       packagesToSymbolicNames.put(pkg, symbolicName);
+               }
+
+               symbolicNamesToNodes.put(symbolicName, bundleNode);
+               binaries.add(RepoUtils.asArtifact(bundleNode));
+       }
+
+       protected void processBundleArtifact(Node bundleNode)
+                       throws RepositoryException {
+               Node artifactFolder = bundleNode.getParent();
+               String baseName = FilenameUtils.getBaseName(bundleNode.getName());
+
+               // pom
+               String pom = generatePomForBundle(bundleNode);
+               String pomName = baseName + ".pom";
+               Node pomNode = JcrUtils.copyBytesAsFile(artifactFolder, pomName,
+                               pom.getBytes());
+
+               // checksum
+               String bundleSha = JcrUtils.checksumFile(bundleNode, "SHA-1");
+               JcrUtils.copyBytesAsFile(artifactFolder,
+                               bundleNode.getName() + ".sha1", bundleSha.getBytes());
+               String pomSha = JcrUtils.checksumFile(bundleNode, "SHA-1");
+               JcrUtils.copyBytesAsFile(artifactFolder, pomNode.getName() + ".sha1",
+                               pomSha.getBytes());
+       }
+
+       private String generatePomForBundle(Node n) throws RepositoryException {
+               String ownSymbolicName = JcrUtils.get(n, SLC_SYMBOLIC_NAME);
+
+               StringBuffer p = new StringBuffer();
+
+               // XML header
+               p.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+               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");
+               p.append("<modelVersion>4.0.0</modelVersion>");
+
+               // Artifact
+               // p.append("<parent><groupId>org.argeo</groupId><artifactId>parent</artifactId><version>1.2.0</version></parent>\n");
+               p.append("<groupId>").append(JcrUtils.get(n, SLC_GROUP_ID))
+                               .append("</groupId>\n");
+               p.append("<artifactId>").append(JcrUtils.get(n, SLC_ARTIFACT_ID))
+                               .append("</artifactId>\n");
+               p.append("<version>").append(JcrUtils.get(n, SLC_ARTIFACT_VERSION))
+                               .append("</version>\n");
+               p.append("<packaging>pom</packaging>\n");
+               if (n.hasProperty(SLC_ + Constants.BUNDLE_NAME))
+                       p.append("<name>")
+                                       .append(JcrUtils.get(n, SLC_ + Constants.BUNDLE_NAME))
+                                       .append("</name>\n");
+               if (n.hasProperty(SLC_ + Constants.BUNDLE_DESCRIPTION))
+                       p.append("<description>")
+                                       .append(JcrUtils
+                                                       .get(n, SLC_ + Constants.BUNDLE_DESCRIPTION))
+                                       .append("</description>\n");
+
+               // Dependencies
+               Set<String> dependenciesSymbolicNames = new TreeSet<String>();
+               Set<String> optionalSymbolicNames = new TreeSet<String>();
+               NodeIterator importPackages = n.getNodes(SLC_
+                               + Constants.IMPORT_PACKAGE);
+               while (importPackages.hasNext()) {
+                       Node importPackage = importPackages.nextNode();
+                       String pkg = JcrUtils.get(importPackage, SLC_NAME);
+                       if (packagesToSymbolicNames.containsKey(pkg)) {
+                               String dependencySymbolicName = packagesToSymbolicNames
+                                               .get(pkg);
+                               if (JcrUtils.check(importPackage, SLC_OPTIONAL))
+                                       optionalSymbolicNames.add(dependencySymbolicName);
+                               else
+                                       dependenciesSymbolicNames.add(dependencySymbolicName);
+                       } else {
+                               if (!JcrUtils.check(importPackage, SLC_OPTIONAL)
+                                               && !systemPackages.contains(importPackage))
+                                       log.warn("No bundle found for pkg " + pkg);
+                       }
+               }
+
+               if (n.hasNode(SLC_ + Constants.FRAGMENT_HOST)) {
+                       String fragmentHost = JcrUtils.get(
+                                       n.getNode(SLC_ + Constants.FRAGMENT_HOST),
+                                       SLC_SYMBOLIC_NAME);
+                       dependenciesSymbolicNames.add(fragmentHost);
+               }
+
+               // TODO require bundles
+
+               List<Node> dependencyNodes = new ArrayList<Node>();
+               for (String depSymbName : dependenciesSymbolicNames) {
+                       if (depSymbName.equals(ownSymbolicName))
+                               continue;// skip self
+
+                       if (symbolicNamesToNodes.containsKey(depSymbName))
+                               dependencyNodes.add(symbolicNamesToNodes.get(depSymbName));
+                       else
+                               log.warn("Could not find node for " + depSymbName);
+               }
+               List<Node> optionalDependencyNodes = new ArrayList<Node>();
+               for (String depSymbName : optionalSymbolicNames) {
+                       if (symbolicNamesToNodes.containsKey(depSymbName))
+                               optionalDependencyNodes.add(symbolicNamesToNodes
+                                               .get(depSymbName));
+                       else
+                               log.warn("Could not find node for " + depSymbName);
+               }
+
+               p.append("<dependencies>\n");
+               for (Node dependencyNode : dependencyNodes) {
+                       p.append("<dependency>\n");
+                       p.append("\t<groupId>")
+                                       .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID))
+                                       .append("</groupId>\n");
+                       p.append("\t<artifactId>")
+                                       .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID))
+                                       .append("</artifactId>\n");
+                       p.append("</dependency>\n");
+               }
+
+               if (optionalDependencyNodes.size() > 0)
+                       p.append("<!-- OPTIONAL -->\n");
+               for (Node dependencyNode : optionalDependencyNodes) {
+                       p.append("<dependency>\n");
+                       p.append("\t<groupId>")
+                                       .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID))
+                                       .append("</groupId>\n");
+                       p.append("\t<artifactId>")
+                                       .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID))
+                                       .append("</artifactId>\n");
+                       p.append("\t<optional>true</optional>\n");
+                       p.append("</dependency>\n");
+               }
+               p.append("</dependencies>\n");
+
+               // Dependency management
+               p.append("<dependencyManagement>\n");
+               p.append("<dependencies>\n");
+               // TODO import SDK
+               p.append("</dependencies>\n");
+               p.append("</dependencyManagement>\n");
+
+               p.append("</project>\n");
+               return p.toString();
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+       public void setWorkspace(String workspace) {
+               this.workspace = workspace;
+       }
+
+       public void setGroupId(String groupId) {
+               this.groupId = groupId;
+       }
+
+}
diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/OsgiProfile.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/OsgiProfile.java
new file mode 100644 (file)
index 0000000..b15ed5d
--- /dev/null
@@ -0,0 +1,55 @@
+package org.argeo.slc.repo.osgi;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.io.IOUtils;
+import org.argeo.slc.SlcException;
+
+/**
+ * Wraps an OSGi profile, simplifying access to its values such as system
+ * packages, etc.
+ */
+public class OsgiProfile {
+       public final static String PROP_SYSTEM_PACKAGES = "org.osgi.framework.system.packages";
+
+       public final static OsgiProfile PROFILE_JAVA_SE_1_6 = new OsgiProfile(
+                       "JavaSE-1.6.profile");
+
+       private final URL url;
+       private final Properties properties;
+
+       public OsgiProfile(URL url) {
+               this.url = url;
+               properties = new Properties();
+               InputStream in = null;
+               try {
+                       properties.load(this.url.openStream());
+               } catch (Exception e) {
+                       throw new SlcException("Cannot initalize OSGi profile " + url, e);
+               } finally {
+                       IOUtils.closeQuietly(in);
+               }
+       }
+
+       public OsgiProfile(String name) {
+               this(OsgiProfile.class.getClassLoader().getResource(
+                               '/'
+                                               + OsgiProfile.class.getPackage().getName()
+                                                               .replace('.', '/') + '/' + name));
+       }
+
+       public List<String> getSystemPackages() {
+               String[] splitted = properties.getProperty(PROP_SYSTEM_PACKAGES).split(
+                               ",");
+               List<String> res = new ArrayList<String>();
+               for (String pkg : splitted) {
+                       res.add(pkg.trim());
+               }
+               return Collections.unmodifiableList(res);
+       }
+}
diff --git a/runtime/org.argeo.slc.support.aether/src/main/java/org/argeo/slc/aether/ArtifactIdComparator.java b/runtime/org.argeo.slc.support.aether/src/main/java/org/argeo/slc/aether/ArtifactIdComparator.java
new file mode 100644 (file)
index 0000000..649e011
--- /dev/null
@@ -0,0 +1,20 @@
+package org.argeo.slc.aether;
+
+import java.util.Comparator;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.sonatype.aether.artifact.Artifact;
+
+/**
+ * Compare two artifacts, for use in {@link TreeSet} / {@link TreeMap}, consider
+ * artifactId first THEN groupId
+ */
+public class ArtifactIdComparator implements Comparator<Artifact> {
+       public int compare(Artifact o1, Artifact o2) {
+               if (o1.getArtifactId().equals(o2.getArtifactId()))
+                       return o1.getGroupId().compareTo(o2.getGroupId());
+               return o1.getArtifactId().compareTo(o2.getArtifactId());
+       }
+
+}