org.jenkins_ci.update_center.repo.NexusRepositoryImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.jenkins_ci.update_center.repo.NexusRepositoryImpl.java

Source

/*
 * The MIT License
 *
 * Copyright (c) 2004-2009, Sun Microsystems, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.jenkins_ci.update_center.repo;

import hudson.util.VersionNumber;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.store.FSDirectory;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.transform.ArtifactTransformationManager;
import org.apache.tools.ant.taskdefs.Expand;
import org.codehaus.plexus.ContainerConfiguration;
import org.codehaus.plexus.DefaultContainerConfiguration;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.component.repository.ComponentDescriptor;
import org.jenkins_ci.update_center.model.GenericArtifactInfo;
import org.jenkins_ci.update_center.model.HPI;
import org.jenkins_ci.update_center.model.HudsonWar;
import org.jenkins_ci.update_center.model.PluginHistory;
import org.sonatype.nexus.index.ArtifactInfo;
import org.sonatype.nexus.index.FlatSearchRequest;
import org.sonatype.nexus.index.FlatSearchResponse;
import org.sonatype.nexus.index.NexusIndexer;
import org.sonatype.nexus.index.context.DefaultIndexingContext;
import org.sonatype.nexus.index.context.IndexUtils;
import org.sonatype.nexus.index.context.NexusAnalyzer;
import org.sonatype.nexus.index.context.NexusIndexWriter;
import org.sonatype.nexus.index.context.UnsupportedExistingLuceneIndexException;
import org.sonatype.nexus.index.updater.IndexDataReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * Maven repository and its nexus index.
 * <p/>
 * Using Maven embedder 2.0.4 results in problem caused by Plexus incompatibility.
 *
 * @author Kohsuke Kawaguchi
 */
public class NexusRepositoryImpl extends MavenRepository {
    private NexusIndexer indexer;
    private ArtifactFactory af;
    private ArtifactResolver ar;
    private List<ArtifactRepository> remoteRepositories = new ArrayList<ArtifactRepository>();
    private ArtifactRepository local;
    private ArtifactRepositoryFactory arf;

    public NexusRepositoryImpl() throws Exception {
        ClassWorld classWorld = new ClassWorld("plexus.core", NexusRepositoryImpl.class.getClassLoader());
        ContainerConfiguration configuration = new DefaultContainerConfiguration().setClassWorld(classWorld);
        PlexusContainer plexus = new DefaultPlexusContainer(configuration);
        ComponentDescriptor<ArtifactTransformationManager> componentDescriptor = plexus.getComponentDescriptor(
                ArtifactTransformationManager.class, ArtifactTransformationManager.class.getName(), "default");
        if (componentDescriptor == null) {
            throw new IllegalArgumentException(
                    "Unable to find maven default ArtifactTransformationManager component. You might get this if you run the program from within the exec:java mojo.");
        }
        componentDescriptor.setImplementationClass(DefaultArtifactTransformationManager.class);

        indexer = plexus.lookup(NexusIndexer.class);

        af = plexus.lookup(ArtifactFactory.class);
        ar = plexus.lookup(ArtifactResolver.class);
        arf = plexus.lookup(ArtifactRepositoryFactory.class);

        local = arf.createArtifactRepository("local",
                new File(new File(System.getProperty("user.home")), ".m2/repository").toURI().toURL()
                        .toExternalForm(),
                new DefaultRepositoryLayout(), POLICY, POLICY);
        addRemoteRepositories();
    }

    /**
     * Loads a remote repository index (.zip or .gz), convert it to Lucene index and return it.
     */
    private static File loadIndex(String id, URL url) throws IOException, UnsupportedExistingLuceneIndexException {
        File dir = new File(new File(System.getProperty("java.io.tmpdir")), "maven-index/" + id);
        File local = new File(dir, "index" + getExtension(url));
        File expanded = new File(dir, "expanded");

        URLConnection con = url.openConnection();
        if (url.getUserInfo() != null) {
            con.setRequestProperty("Authorization",
                    "Basic " + new sun.misc.BASE64Encoder().encode(url.getUserInfo().getBytes()));
        }

        if (!expanded.exists() || !local.exists() || local.lastModified() != con.getLastModified()) {
            System.out.println("Downloading " + url);
            // if the download fail in the middle, only leave a broken tmp file
            dir.mkdirs();
            File tmp = new File(dir, "index_" + getExtension(url));
            FileOutputStream o = new FileOutputStream(tmp);
            try {
                IOUtils.copy(con.getInputStream(), o);
            } finally {
                o.close();
            }

            if (expanded.exists()) {
                FileUtils.deleteDirectory(expanded);
            }
            expanded.mkdirs();

            if (url.toExternalForm().endsWith(".gz")) {
                FSDirectory directory = FSDirectory.getDirectory(expanded);
                NexusIndexWriter w = new NexusIndexWriter(directory, new NexusAnalyzer(), true);
                FileInputStream in = new FileInputStream(tmp);
                try {
                    IndexDataReader dr = new IndexDataReader(in);
                    dr.readIndex(w, new DefaultIndexingContext(id, id, null, expanded, null, null,
                            NexusIndexer.DEFAULT_INDEX, true));
                } finally {
                    IndexUtils.close(w);
                    IOUtils.closeQuietly(in);
                    directory.close();
                }
            } else if (url.toExternalForm().endsWith(".zip")) {
                Expand e = new Expand();
                e.setSrc(tmp);
                e.setDest(expanded);
                e.execute();
            } else {
                throw new UnsupportedOperationException("Unsupported index format: " + url);
            }

            // as a proof that the expansion was properly completed
            tmp.renameTo(local);
            local.setLastModified(con.getLastModified());
        } else {
            System.out.println("Reusing the locally cached " + url + " at " + local);
        }

        return expanded;
    }

    private static String getExtension(URL url) {
        String s = url.toExternalForm();
        int idx = s.lastIndexOf('.');
        if (idx < 0) {
            return "";
        } else {
            return s.substring(idx);
        }
    }

    public File resolve(GenericArtifactInfo a, String type, String classifier) throws IOException {
        Artifact artifact = af.createArtifactWithClassifier(a.groupId, a.artifactId, a.version, type, classifier);
        try {
            ar.resolve(artifact, remoteRepositories, local);
        } catch (AbstractArtifactResolutionException e) {
            throw (IOException) new IOException("Failed to resolve artifact " + artifact.getId()).initCause(e);
        }
        return artifact.getFile();
    }

    protected void listHudsonPlugins(Map<String, PluginHistory> plugins) throws IOException {
        BooleanQuery q = new BooleanQuery();
        q.add(indexer.constructQuery(ArtifactInfo.PACKAGING, "hpi"), Occur.MUST);

        FlatSearchRequest request = new FlatSearchRequest(q);
        FlatSearchResponse response = indexer.searchFlat(request);

        for (ArtifactInfo a : response.getResults()) {
            HPI hpiInfo = createHpiArtifact(a);
            if (isHpiValid(hpiInfo)) {
                PluginHistory p = plugins.get(hpiInfo.artifact.artifactId);
                if (p == null) {
                    plugins.put(hpiInfo.artifact.artifactId, p = new PluginHistory(hpiInfo.artifact.artifactId));
                }
                p.addArtifact(hpiInfo);
                p.groupId.add(hpiInfo.artifact.groupId);
            }
        }
    }

    protected void listWar(TreeMap<VersionNumber, HudsonWar> r, String groupId, VersionNumber cap)
            throws IOException {
        BooleanQuery q = new BooleanQuery();
        q.add(indexer.constructQuery(ArtifactInfo.GROUP_ID, groupId), Occur.MUST);
        q.add(indexer.constructQuery(ArtifactInfo.PACKAGING, "war"), Occur.MUST);

        FlatSearchRequest request = new FlatSearchRequest(q);
        FlatSearchResponse response = indexer.searchFlat(request);

        for (ArtifactInfo a : response.getResults()) {
            HudsonWar warInfo = createHudsonWarArtifact(a);
            if (isWarValid(warInfo, cap)) {
                VersionNumber v = new VersionNumber(warInfo.version);
                r.put(v, warInfo);
            }
        }
    }

    /*
       Hook for subtypes to use customized implementations.
    */

    protected HPI createHpiArtifact(ArtifactInfo a) throws IOException {
        return new HPI(getGenericArtifactInfo(a));
    }

    protected HudsonWar createHudsonWarArtifact(ArtifactInfo a) throws IOException {
        return new HudsonWar(getGenericArtifactInfo(a));
    }

    protected static final ArtifactRepositoryPolicy POLICY = new ArtifactRepositoryPolicy(true, "daily", "warn");

    private GenericArtifactInfo getGenericArtifactInfo(ArtifactInfo a) {
        return new GenericArtifactInfo(a.repository, a.groupId, a.artifactId, a.version, a.classifier, a.packaging);
    }

    private void addRemoteRepositories() throws Exception {
        String id = "java.net2";
        File indexDirectory = loadIndex(id,
                new URL("http://updates.jenkins-ci.org/.index/nexus-maven-repository-index.gz"));
        URL repository = new URL("http://repo.jenkins-ci.org/public/");
        indexer.addIndexingContext(id, id, null, indexDirectory, null, null, NexusIndexer.DEFAULT_INDEX);
        remoteRepositories.add(arf.createArtifactRepository(id, repository.toExternalForm(),
                new DefaultRepositoryLayout(), POLICY, POLICY));
    }
}