]> git.argeo.org Git - gpl/argeo-slc.git/blobdiff - runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoUtils.java
Generalize ArchiveWrapper and deprecates ImportBundlesZip
[gpl/argeo-slc.git] / runtime / org.argeo.slc.repo / src / main / java / org / argeo / slc / repo / RepoUtils.java
index 6d22cbe687632ebcff13c7f4df87412ab4e653fd..5f798c1444cc8af171af7469af7873e101c2ee90 100644 (file)
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * 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;
 
 import java.io.ByteArrayOutputStream;
@@ -8,7 +23,9 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Enumeration;
 import java.util.Iterator;
+import java.util.Set;
 import java.util.StringTokenizer;
+import java.util.TreeSet;
 import java.util.jar.Attributes;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
@@ -16,26 +33,41 @@ import java.util.jar.JarInputStream;
 import java.util.jar.JarOutputStream;
 import java.util.jar.Manifest;
 
+import javax.jcr.Credentials;
+import javax.jcr.GuestCredentials;
 import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.nodetype.NodeType;
 
 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.ArgeoJcrUtils;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.ArgeoTypes;
 import org.argeo.jcr.JcrUtils;
-import org.argeo.slc.BasicNameVersion;
+import org.argeo.slc.DefaultNameVersion;
 import org.argeo.slc.NameVersion;
 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.maven.MavenConventionsUtils;
+import org.argeo.util.security.Keyring;
 import org.osgi.framework.Constants;
 import org.sonatype.aether.artifact.Artifact;
 import org.sonatype.aether.util.artifact.DefaultArtifact;
 
 /** Utilities around repo */
-public class RepoUtils implements SlcNames {
+public class RepoUtils implements ArgeoNames, SlcNames {
        private final static Log log = LogFactory.getLog(RepoUtils.class);
 
        /** Packages a regular sources jar as PDE source. */
@@ -209,15 +241,28 @@ public class RepoUtils implements SlcNames {
 
        /** Read the OSGi {@link NameVersion} */
        public static NameVersion readNameVersion(File artifactFile) {
+               try {
+                       return readNameVersion(new FileInputStream(artifactFile));
+               } catch (Exception e) {
+                       // probably not a jar, skipping
+                       if (log.isDebugEnabled()) {
+                               log.debug("Skipping " + artifactFile + " because of " + e);
+                               // e.printStackTrace();
+                       }
+               }
+               return null;
+       }
+
+       /** Read the OSGi {@link NameVersion} */
+       public static NameVersion readNameVersion(InputStream in) {
                JarInputStream jarInputStream = null;
                try {
-                       jarInputStream = new JarInputStream(new FileInputStream(
-                                       artifactFile));
+                       jarInputStream = new JarInputStream(in);
                        return readNameVersion(jarInputStream.getManifest());
                } catch (Exception e) {
                        // probably not a jar, skipping
                        if (log.isDebugEnabled()) {
-                               log.debug("Skipping " + artifactFile + " because of " + e);
+                               log.debug("Skipping because of " + e);
                                // e.printStackTrace();
                        }
                } finally {
@@ -228,7 +273,7 @@ public class RepoUtils implements SlcNames {
 
        /** Read the OSGi {@link NameVersion} */
        public static NameVersion readNameVersion(Manifest manifest) {
-               BasicNameVersion nameVersion = new BasicNameVersion();
+               DefaultNameVersion nameVersion = new DefaultNameVersion();
                nameVersion.setName(manifest.getMainAttributes().getValue(
                                Constants.BUNDLE_SYMBOLICNAME));
 
@@ -270,6 +315,22 @@ public class RepoUtils implements SlcNames {
                }
        }
 
+       /**
+        * The path to the PDE source related to this artifact (or artifact version
+        * base). There may or there may not be a node at this location (the
+        * returned path will typically be used to test whether PDE sources are
+        * attached to this artifact).
+        */
+       public static String relatedPdeSourcePath(String artifactBasePath,
+                       Node artifactNode) throws RepositoryException {
+               Artifact artifact = asArtifact(artifactNode);
+               Artifact pdeSourceArtifact = new DefaultArtifact(artifact.getGroupId(),
+                               artifact.getArtifactId() + ".source", artifact.getExtension(),
+                               artifact.getVersion());
+               return MavenConventionsUtils.artifactPath(artifactBasePath,
+                               pdeSourceArtifact);
+       }
+
        /**
         * Copy this bytes array as an artifact, relative to the root of the
         * repository (typically the workspace root node)
@@ -295,4 +356,214 @@ public class RepoUtils implements SlcNames {
                else
                        return sourceBundleName;
        }
+
+       /*
+        * SOFTWARE REPOSITORIES
+        */
+
+       /** Retrieve repository based on information in the repo node */
+       public static Repository getRepository(RepositoryFactory repositoryFactory,
+                       Keyring keyring, Node repoNode) {
+               try {
+                       Repository repository;
+                       if (repoNode.isNodeType(ArgeoTypes.ARGEO_REMOTE_REPOSITORY)) {
+                               String uri = repoNode.getProperty(ARGEO_URI).getString();
+                               if (uri.startsWith("http")) {// http, https
+                                       repository = ArgeoJcrUtils.getRepositoryByUri(
+                                                       repositoryFactory, uri);
+                               } else if (uri.startsWith("vm:")) {// alias
+                                       repository = ArgeoJcrUtils.getRepositoryByUri(
+                                                       repositoryFactory, uri);
+                               } else {
+                                       throw new SlcException("Unsupported repository uri " + uri);
+                               }
+                               return repository;
+                       } else {
+                               throw new SlcException("Unsupported node type " + repoNode);
+                       }
+               } catch (RepositoryException e) {
+                       throw new SlcException("Cannot connect to repository " + repoNode,
+                                       e);
+               }
+
+       }
+
+       /**
+        * Reads credentials from node, using keyring if there is a password. Cann
+        * return null if no credentials needed (local repo) at all, but returns
+        * {@link GuestCredentials} if user id is 'anonymous' .
+        */
+       public static Credentials getRepositoryCredentials(Keyring keyring,
+                       Node repoNode) {
+               try {
+                       if (repoNode.isNodeType(ArgeoTypes.ARGEO_REMOTE_REPOSITORY)) {
+                               if (!repoNode.hasProperty(ARGEO_USER_ID))
+                                       return null;
+
+                               String userId = repoNode.getProperty(ARGEO_USER_ID).getString();
+                               if (userId.equals("anonymous"))// FIXME hardcoded userId
+                                       return new GuestCredentials();
+                               char[] password = keyring.getAsChars(repoNode.getPath() + '/'
+                                               + ARGEO_PASSWORD);
+                               Credentials credentials = new SimpleCredentials(userId,
+                                               password);
+                               return credentials;
+                       } else {
+                               throw new SlcException("Unsupported node type " + repoNode);
+                       }
+               } catch (RepositoryException e) {
+                       throw new SlcException("Cannot connect to repository " + repoNode,
+                                       e);
+               }
+       }
+
+       /**
+        * Write group indexes: 'binaries' lists all bundles and their versions,
+        * 'sources' list theire sources, and 'sdk' aggregates both.
+        */
+       public static void writeGroupIndexes(Session session,
+                       String artifactBasePath, String groupId, String version,
+                       Set<Artifact> binaries, Set<Artifact> sources) {
+               try {
+                       Set<Artifact> indexes = new TreeSet<Artifact>(
+                                       new ArtifactIdComparator());
+                       Artifact binariesArtifact = writeIndex(session, artifactBasePath,
+                                       groupId, RepoConstants.BINARIES_ARTIFACT_ID, version,
+                                       binaries);
+                       indexes.add(binariesArtifact);
+                       if (sources != null) {
+                               Artifact sourcesArtifact = writeIndex(session,
+                                               artifactBasePath, groupId,
+                                               RepoConstants.SOURCES_ARTIFACT_ID, version, sources);
+                               indexes.add(sourcesArtifact);
+                       }
+                       // sdk
+                       writeIndex(session, artifactBasePath, groupId,
+                                       RepoConstants.SDK_ARTIFACT_ID, version, indexes);
+                       session.save();
+               } catch (RepositoryException e) {
+                       throw new SlcException("Cannot write indexes for group " + groupId,
+                                       e);
+               }
+       }
+
+       /** Write a group index. */
+       private static Artifact writeIndex(Session session,
+                       String artifactBasePath, String groupId, String artifactId,
+                       String version, Set<Artifact> artifacts) throws RepositoryException {
+               Artifact artifact = new DefaultArtifact(groupId, artifactId, "pom",
+                               version);
+               String pom = MavenConventionsUtils.artifactsAsDependencyPom(artifact,
+                               artifacts, null);
+               Node node = RepoUtils.copyBytesAsArtifact(
+                               session.getNode(artifactBasePath), artifact, pom.getBytes());
+               addMavenChecksums(node);
+               return artifact;
+       }
+
+       /** Add files containing the SHA-1 and MD5 checksums. */
+       public static void addMavenChecksums(Node node) throws RepositoryException {
+               // TODO optimize
+               String sha = JcrUtils.checksumFile(node, "SHA-1");
+               JcrUtils.copyBytesAsFile(node.getParent(), node.getName() + ".sha1",
+                               sha.getBytes());
+               String md5 = JcrUtils.checksumFile(node, "MD5");
+               JcrUtils.copyBytesAsFile(node.getParent(), node.getName() + ".md5",
+                               md5.getBytes());
+       }
+
+       /**
+        * Custom copy since the one in commons does not fit the needs when copying
+        * a workspace completely.
+        */
+       public static void copy(Node fromNode, Node toNode) {
+               try {
+                       if (log.isDebugEnabled())
+                               log.debug("copy node :" + fromNode.getPath());
+
+                       // FIXME : small hack to enable specific workspace copy
+                       if (fromNode.isNodeType("rep:ACL")
+                                       || fromNode.isNodeType("rep:system")) {
+                               if (log.isTraceEnabled())
+                                       log.trace("node " + fromNode + " skipped");
+                               return;
+                       }
+
+                       // add mixins
+                       for (NodeType mixinType : fromNode.getMixinNodeTypes()) {
+                               toNode.addMixin(mixinType.getName());
+                       }
+
+                       // Double check
+                       for (NodeType mixinType : toNode.getMixinNodeTypes()) {
+                               if (log.isDebugEnabled())
+                                       log.debug(mixinType.getName());
+                       }
+
+                       // process properties
+                       PropertyIterator pit = fromNode.getProperties();
+                       properties: while (pit.hasNext()) {
+                               Property fromProperty = pit.nextProperty();
+                               String propName = fromProperty.getName();
+                               try {
+                                       String propertyName = fromProperty.getName();
+                                       if (toNode.hasProperty(propertyName)
+                                                       && toNode.getProperty(propertyName).getDefinition()
+                                                                       .isProtected())
+                                               continue properties;
+
+                                       if (fromProperty.getDefinition().isProtected())
+                                               continue properties;
+
+                                       if (propertyName.equals("jcr:created")
+                                                       || propertyName.equals("jcr:createdBy")
+                                                       || propertyName.equals("jcr:lastModified")
+                                                       || propertyName.equals("jcr:lastModifiedBy"))
+                                               continue properties;
+
+                                       if (fromProperty.isMultiple()) {
+                                               toNode.setProperty(propertyName,
+                                                               fromProperty.getValues());
+                                       } else {
+                                               toNode.setProperty(propertyName,
+                                                               fromProperty.getValue());
+                                       }
+                               } catch (RepositoryException e) {
+                                       throw new SlcException("Cannot property " + propName, e);
+                               }
+                       }
+
+                       // recursively process children nodes
+                       NodeIterator nit = fromNode.getNodes();
+                       while (nit.hasNext()) {
+                               Node fromChild = nit.nextNode();
+                               Integer index = fromChild.getIndex();
+                               String nodeRelPath = fromChild.getName() + "[" + index + "]";
+                               Node toChild;
+                               if (toNode.hasNode(nodeRelPath))
+                                       toChild = toNode.getNode(nodeRelPath);
+                               else
+                                       toChild = toNode.addNode(fromChild.getName(), fromChild
+                                                       .getPrimaryNodeType().getName());
+                               copy(fromChild, toChild);
+                       }
+
+                       // update jcr:lastModified and jcr:lastModifiedBy in toNode in
+                       // case
+                       // they existed
+                       if (!toNode.getDefinition().isProtected()
+                                       && toNode.isNodeType(NodeType.MIX_LAST_MODIFIED))
+                               JcrUtils.updateLastModified(toNode);
+
+                       // Workaround to reduce session size: artifact is a saveable
+                       // unity
+                       if (toNode.isNodeType(SlcTypes.SLC_ARTIFACT))
+                               toNode.getSession().save();
+
+               } catch (RepositoryException e) {
+                       throw new SlcException("Cannot copy " + fromNode + " to " + toNode,
+                                       e);
+               }
+       }
+
 }