com.francetelecom.clara.cloud.mvn.consumer.maven.MavenDeployer.java Source code

Java tutorial

Introduction

Here is the source code for com.francetelecom.clara.cloud.mvn.consumer.maven.MavenDeployer.java

Source

/**
 * Copyright (C) 2015 Orange
 * 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 com.francetelecom.clara.cloud.mvn.consumer.maven;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;

import javax.activation.DataHandler;

import com.francetelecom.clara.cloud.mvn.consumer.aether.ProxyManager;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.CompressorOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.commons.lang3.Validate;
import org.eclipse.aether.util.repository.AuthenticationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.deployment.DeployRequest;
import org.eclipse.aether.deployment.DeployResult;
import org.eclipse.aether.deployment.DeploymentException;
import org.eclipse.aether.repository.Authentication;
import org.eclipse.aether.repository.Proxy;
import org.eclipse.aether.repository.ProxySelector;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.util.artifact.SubArtifact;
import org.eclipse.aether.util.repository.DefaultProxySelector;

import com.francetelecom.clara.cloud.commons.MavenReference;
import com.francetelecom.clara.cloud.commons.TechnicalException;
import com.francetelecom.clara.cloud.mvn.consumer.FileRef;
import com.francetelecom.clara.cloud.mvn.consumer.MvnConsumerConfigurer;
import com.francetelecom.clara.cloud.mvn.consumer.aether.AetherConfigurer;
import org.springframework.beans.factory.annotation.Autowired;

public class MavenDeployer {
    /**
     * Implementation class for Maven Repository Data Access Object
     * 
     * - manages remote repo acces (read and write) - manages local working
     * space, and maven local embedded projects builds.
     * 
     * links : http://nexus.sonatype.org/nexus-test-harness.html
     * http://nexus.sonatype.org/oss-repository-hosting.html
     * 
     * http://maven.apache.org/shared/index.html
     * 
     * 
     * https://docs.sonatype.org/display/AETHER/Home
     * 
     * http://maven.apache.org/ref/3.0-beta-3/
     * http://maven.apache.org/docs/3.0-beta-3/release-notes.html
     * 
     * 
     */

    private static final Logger logger = LoggerFactory.getLogger(MavenDeployer.class);

    protected SettingsGenerator settingsGenerator;
    protected PomGenerator pomGenerator;

    protected AetherConfigurer aetherConfigurer;
    protected MvnConsumerConfigurer mvnConsumerConfigurer;

    protected File settingsFile;

    public MavenDeployer(MvnConsumerConfigurer mvnConsumerConfigurer) {
        this.mvnConsumerConfigurer = mvnConsumerConfigurer;

    }

    /**
     * Initial configuration
     * 
     * @throws IOException
     */
    public void init() throws Exception {
        logger.debug("creating settings.xml");
        String settingsFilename = this.mvnConsumerConfigurer.getLocalWorkDir().getAbsolutePath()
                + "/.m2/settings.xml";
        settingsFile = settingsGenerator.generateAndWrite(settingsFilename);
        logger.debug("created settings.xml as " + this.settingsFile.getAbsolutePath());
        logger.debug("creating settings.xml end"); // added to check duration of
        // this method (take 1
        // minute !?)
    }

    private MavenReference convertToMavenReference(Artifact artifact) {
        MavenReference result = new MavenReference(artifact.getGroupId(), artifact.getArtifactId(),
                artifact.getBaseVersion(), artifact.getExtension(), artifact.getClassifier());
        return result.duplicateWithNull();
    }

    private Artifact convertToArtifact(MavenReference mavenReference) {
        MavenReference mavenReferenceEmpty = mavenReference.duplicateWithEmpty();
        Artifact artifact = new DefaultArtifact(mavenReferenceEmpty.getGroupId(),
                mavenReferenceEmpty.getArtifactId(), mavenReferenceEmpty.getClassifier(),
                mavenReferenceEmpty.getExtension(), mavenReferenceEmpty.getVersion());

        return artifact;
    }

    /**
     * Deploy a Maven component reference
     * 
     * @return
     */
    public DeployResult deployFileset(MavenReference mavenReference, List<FileRef> fileset) {
        Validate.notNull(mavenReference, "Shoud not be null");
        Validate.notNull(fileset, "Shoud not be null");
        File projectDirectory = getProjectDirectory(mavenReference);
        return deploy(mavenReference, fileset, projectDirectory);
    }

    public DeployResult deployBin(MavenReference mavenReference, DataHandler binaryContent) {
        Validate.notNull(mavenReference, "Shoud not be null");
        Validate.notNull(binaryContent, "Shoud not be null");

        File projectDirectory = getProjectDirectory(mavenReference);
        File artifact = new File(projectDirectory, mavenReference.getArtifactName());
        try {
            binaryContent.writeTo(new FileOutputStream(artifact));
        } catch (IOException e) {
            logger.error("failure storing artifact stream " + mavenReference, e);
            throw new TechnicalException(e);
        }
        return install(mavenReference, artifact, projectDirectory);
    }

    private File getProjectDirectory(MavenReference mavenReference) {
        return new File(this.mvnConsumerConfigurer.getLocalWorkDir(),
                mavenReference.getGroupId() + "/" + mavenReference.getArtifactId());
    }

    private DeployResult deploy(MavenReference mavenReference, List<FileRef> fileset, File projectDirectory) {

        try {
            File archive = createArchive(projectDirectory, mavenReference, fileset);
            return install(mavenReference, archive, projectDirectory);
        } catch (IOException e) {
            logger.error("failure creating archive from fileset " + mavenReference, e);
            throw new TechnicalException(e);
        }
    }

    private DeployResult install(MavenReference mavenReference, File archive, File projectDirectory) {

        try {
            Artifact artifactToDeploy = convertToArtifact(mavenReference).setFile(archive);
            Artifact pom = new SubArtifact(artifactToDeploy, null, "pom")
                    .setFile(pomGenerator.generatePom(projectDirectory, mavenReference));

            RemoteRepository selectedRepository = selectRepositoryToDeploy(artifactToDeploy);
            DeployResult deploymentResult = deployUsingAether(artifactToDeploy, pom, selectedRepository);
            logger.debug(mavenReference + " has been deployed on " + selectedRepository + " - DeploymentResult: "
                    + deploymentResult.toString());
            return deploymentResult;
            // updateUrl(mavenReference);

        } catch (IOException e) {
            logger.error("failure creating mvn work dir for project " + mavenReference, e);
            throw new TechnicalException(e);
        } catch (DeploymentException e) {
            logger.error("deployment failed for " + mavenReference, e);
            throw new TechnicalException(e);
        }
    }

    private RemoteRepository selectRepositoryToDeploy(Artifact artifactToDeploy) {
        if (artifactToDeploy == null) {
            throw new IllegalArgumentException("artifactToDeploy should not be null");
        }

        RemoteRepository.Builder snapRepoBuilder = new RemoteRepository.Builder("paas.push.snapshot.repo",
                "default", mvnConsumerConfigurer.getPushSnapshotRepositoryUrl());
        RepositoryPolicy disabledRepo = null;
        snapRepoBuilder.setReleasePolicy(disabledRepo);
        Authentication snapshotRepositoryAuthen = new AuthenticationBuilder()
                .addUsername(mvnConsumerConfigurer.getPushSnapshotRepositoryUser())
                .addPassword(mvnConsumerConfigurer.getPushSnapshotRepositoryPassword()).build();
        snapRepoBuilder.setAuthentication(snapshotRepositoryAuthen);

        RemoteRepository.Builder releaseRepoBuilder = new RemoteRepository.Builder("paas.push.release.repo",
                "default", mvnConsumerConfigurer.getPushReleaseRepositoryUrl());
        releaseRepoBuilder.setReleasePolicy(disabledRepo);
        Authentication releaseRepositoryAuthen = new AuthenticationBuilder()
                .addUsername(mvnConsumerConfigurer.getPushReleaseRepositoryUser())
                .addPassword(mvnConsumerConfigurer.getPushReleaseRepositoryPassword()).build();
        releaseRepoBuilder.setAuthentication(releaseRepositoryAuthen);

        RemoteRepository result;
        if (artifactToDeploy.isSnapshot()) {
            result = snapRepoBuilder.build();
        } else {
            result = releaseRepoBuilder.build();
        }

        return result;
    }

    private DeployResult deployUsingAether(Artifact artifact, Artifact pom, RemoteRepository deploymentRepository)
            throws DeploymentException {
        RepositorySystem system = aetherConfigurer.newRepositorySystem();
        RepositorySystemSession session = aetherConfigurer.newSession(system,
                mvnConsumerConfigurer.getLocalM2Repo());
        DeployRequest deployRequest = new DeployRequest();
        deployRequest.addArtifact(artifact).addArtifact(pom);
        deployRequest.setRepository(deploymentRepository);
        DeployResult result = system.deploy(session, deployRequest);
        return result;
    }

    private File createArchive(File projectDirectory, MavenReference mavenReference, List<FileRef> fileset)
            throws IOException {
        File archive = new File(projectDirectory, mavenReference.getArtifactName());
        if ("tar.gz".equals(mavenReference.getExtension())) {
            populateTgzArchive(archive, fileset);
        } else {
            populateJarArchive(archive, fileset);
        }
        return archive;
    }

    private File populateTgzArchive(File archive, List<FileRef> fileset) throws IOException {
        archive.getParentFile().mkdirs();
        CompressorOutputStream zip = new GzipCompressorOutputStream(new FileOutputStream(archive));
        TarArchiveOutputStream tar = new TarArchiveOutputStream(zip);
        for (FileRef fileRef : fileset) {
            TarArchiveEntry entry = new TarArchiveEntry(new File(fileRef.getRelativeLocation()));
            byte[] bytes = fileRef.getContent().getBytes();
            entry.setSize(bytes.length);
            tar.putArchiveEntry(entry);
            tar.write(bytes);
            tar.closeArchiveEntry();
        }
        tar.close();
        return archive;
    }

    private File populateJarArchive(File archive, List<FileRef> fileset) throws IOException {
        archive.getParentFile().mkdirs();
        JarOutputStream target = new JarOutputStream(new FileOutputStream(archive));
        for (FileRef fileRef : fileset) {
            JarEntry jarAdd = new JarEntry(fileRef.getRelativeLocation());
            target.putNextEntry(jarAdd);
            target.write(fileRef.getContent().getBytes());
        }
        target.close();
        return archive;
    }

    private URI convertDosPathToUri(String dosPath) throws URISyntaxException {
        return new URI(dosPath.replaceAll("\\\\", "/"));
    }

    public void setMvnConsumerConfigurer(MvnConsumerConfigurer mvnConsumerConfigurer) {
        this.mvnConsumerConfigurer = mvnConsumerConfigurer;
    }

    public void setSettingsGenerator(SettingsGenerator settingsGenerator) {
        this.settingsGenerator = settingsGenerator;
    }

    public void setPomGenerator(PomGenerator pomGenerator) {
        this.pomGenerator = pomGenerator;
    }

    public void setAetherConfigurer(AetherConfigurer aetherConfigurer) {
        this.aetherConfigurer = aetherConfigurer;
    }

    /**
     * Verify that artifact referenced by a given {@link MavenReference} is
     * available
     * 
     * @param mavenRef
     * @return true if available, false if not
     */
    boolean isArtifactAvailable(MavenReference mavenRef) {
        if (mavenRef.getAccessUrl() == null)
            return false;
        return isValidUrl(mavenRef.getAccessUrl());
    }

    /**
     * Verify that a given url can be reached
     * 
     * @param url
     * @return true if valid, false if not
     */
    boolean isValidUrl(URL url) {
        logger.debug("Testing url: " + url);
        HttpURLConnection huc = null;
        int responseCode = 0;
        try {
            huc = openHttpUrlConnection(url);
            huc.setRequestMethod("HEAD");
            // set a long enough timeout to be protected against slow
            // network/server response time
            huc.setReadTimeout(30000);
            huc.connect();
            responseCode = huc.getResponseCode();
        } catch (IOException e) {
            logger.error("unable to test url " + url, e);
        } finally {
            if (huc != null)
                huc.disconnect();
        }
        boolean isValid = (responseCode == 200);
        if (!isValid)
            logger.warn("Http HEAD on Url " + url + " returns " + responseCode);
        return isValid;
    }

    /**
     * Wrap {@link URL#openConnection()} so that this method can be mocked in
     * tests
     */
    HttpURLConnection openHttpUrlConnection(URL url) throws IOException {
        return (HttpURLConnection) url.openConnection();
    }
}