eu.markov.jenkins.plugin.mvnmeta.MavenMetadataParameterDefinition.java Source code

Java tutorial

Introduction

Here is the source code for eu.markov.jenkins.plugin.mvnmeta.MavenMetadataParameterDefinition.java

Source

/*
 * The MIT License
 *
 * Copyright (c) 2012, AKQA, Georgi "Gesh" Markov
 *
 * 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 eu.markov.jenkins.plugin.mvnmeta;

import hudson.Extension;
import hudson.Util;
import hudson.model.ParameterValue;
import hudson.model.ParameterDefinition;
import hudson.util.FormValidation;
import hudson.cli.CLICommand;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

import lombok.Getter;
import net.sf.json.JSONObject;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.jvnet.localizer.ResourceBundleHolder;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

/**
 * 
 * 
 * @author Gesh Markov <gesh@markov.eu>
 */
@Getter
public class MavenMetadataParameterDefinition extends ParameterDefinition {
    private static final long serialVersionUID = -3820719539319589460L;

    private static final String DEFAULT_FIRST = "FIRST";
    private static final String DEFAULT_LAST = "LAST";
    private static final String DEFAULT_LATEST = "LATEST";
    private static final String DEFAULT_RELEASE = "RELEASE";
    private static final Pattern MATCH_ALL = Pattern.compile(".*");
    private static final Charset UTF8 = Charset.forName("UTF-8");

    private transient int maxVers = Integer.MIN_VALUE;
    private transient Pattern versionFilterPattern = null;

    private final String repoBaseUrl;
    private final String groupId;
    private final String artifactId;
    private final String packaging;
    private final String defaultValue;
    private final String versionFilter;
    private final SortOrder sortOrder;
    private final String maxVersions;

    private final String username;
    private final String password;

    @DataBoundConstructor
    public MavenMetadataParameterDefinition(String name, String description, String repoBaseUrl, String groupId,
            String artifactId, String packaging, String versionFilter, String sortOrder, String defaultValue,
            String maxVersions, String username, String password) {
        super(name, description);
        this.repoBaseUrl = Util.removeTrailingSlash(repoBaseUrl);
        this.groupId = groupId;
        this.artifactId = artifactId;
        this.packaging = packaging;
        this.versionFilter = StringUtils.trim(versionFilter);
        this.sortOrder = SortOrder.valueOf(sortOrder);
        this.defaultValue = StringUtils.trim(defaultValue);
        this.maxVersions = maxVersions;
        this.username = username;
        this.password = password;
    }

    public int getMaxVers() {
        if (this.maxVers == Integer.MIN_VALUE) {
            int maxVers = Integer.MAX_VALUE;
            try {
                maxVers = Integer.parseInt(maxVersions);
            } catch (NumberFormatException e) {
            }
            this.maxVers = maxVers;
        }
        return this.maxVers;
    }

    public Pattern getVersionFilterPattern() {
        if (versionFilterPattern == null) {
            if (StringUtils.isNotBlank(this.versionFilter)) {
                versionFilterPattern = Pattern.compile(this.versionFilter);
            } else {
                versionFilterPattern = MATCH_ALL;
            }
        }
        return versionFilterPattern;
    }

    public String readPackaging() {
        if (StringUtils.isNotBlank(this.packaging)) {
            return this.packaging;
        }
        return "jar";
    }

    private ParameterValue createValue(String version) {
        return new MavenMetadataParameterValue(getName(), getDescription(), getGroupId(), getArtifactId(), version,
                readPackaging(), getFullArtifactUrl(getGroupId(), getArtifactId(), version, readPackaging()));
    }

    // Create a parameter value from the string given in the CLI.
    @Override
    public ParameterValue createValue(CLICommand command, String version) {
        return createValue(version);
    }

    // This method is invoked from a GET or POST HTTP request
    @Override
    public ParameterValue createValue(StaplerRequest req) {
        String[] values = req.getParameterValues(getName());
        if (values == null || values.length != 1) {
            return this.getDefaultParameterValue();
        }

        String version = values[0];

        return createValue(version);
    }

    // This method is invoked when the user clicks on the "Build" button of Hudon's GUI
    @Override
    public ParameterValue createValue(StaplerRequest req, JSONObject formData) {
        MavenMetadataParameterValue value = req.bindJSON(MavenMetadataParameterValue.class, formData);
        value.setDescription(getDescription());
        value.setArtifactUrl(getFullArtifactUrl(value));
        // here, we could validate the parameter value,
        // but it's of no use because if we return null the build still goes on...
        return value;
    }

    @Override
    public ParameterValue getDefaultParameterValue() {
        String defaultVersion = null;
        if (DEFAULT_FIRST.equals(this.defaultValue)) {
            List<String> allVersions = getArtifactMetadata().versioning.versions;
            if (allVersions.size() > 0) {
                defaultVersion = allVersions.get(0);
            }
        } else if (DEFAULT_LAST.equals(this.defaultValue)) {
            List<String> allVersions = getArtifactMetadata().versioning.versions;
            if (allVersions != null && allVersions.size() > 0) {
                defaultVersion = allVersions.get(allVersions.size() - 1);
            }
        } else if (DEFAULT_LATEST.equals(this.defaultValue)) {
            defaultVersion = getArtifactMetadata().versioning.latest;
        } else if (DEFAULT_RELEASE.equals(this.defaultValue)) {
            defaultVersion = getArtifactMetadata().versioning.release;
        } else {
            defaultVersion = this.defaultValue;
        }

        if (StringUtils.isBlank(defaultVersion)) {
            return null;
        }

        return new MavenMetadataParameterValue(getName(), getDescription(), getGroupId(), getArtifactId(),
                defaultVersion, readPackaging(),
                getFullArtifactUrl(getGroupId(), getArtifactId(), defaultVersion, readPackaging()));
    }

    @Override
    public DescriptorImpl getDescriptor() {
        return (DescriptorImpl) super.getDescriptor();
    }

    public List<String> getVersions() {
        return getArtifactMetadata().versioning.versions;
    }

    private MavenMetadataVersions getArtifactMetadata() {
        InputStream input = null;
        try {
            URL url = new URL(getArtifactUrlForPath("maven-metadata.xml"));

            LOGGER.finest("Requesting metadata from URL: " + url.toExternalForm());

            URLConnection conn = url.openConnection();

            if (StringUtils.isNotBlank(url.getUserInfo())) {
                LOGGER.finest("Using implicit UserInfo");
                String encodedAuth = new String(Base64.encodeBase64(url.getUserInfo().getBytes(UTF8)), UTF8);
                conn.addRequestProperty("Authorization", "Basic " + encodedAuth);
            }

            if (StringUtils.isNotBlank(this.username) && StringUtils.isNotBlank(this.password)) {
                LOGGER.finest("Using explicit UserInfo");
                String userpassword = username + ":" + password;
                String encodedAuthorization = new String(Base64.encodeBase64(userpassword.getBytes(UTF8)), UTF8);
                conn.addRequestProperty("Authorization", "Basic " + encodedAuthorization);
            }

            input = conn.getInputStream();
            JAXBContext context = JAXBContext.newInstance(MavenMetadataVersions.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            MavenMetadataVersions metadata = (MavenMetadataVersions) unmarshaller.unmarshal(input);

            if (sortOrder == SortOrder.DESC) {
                Collections.reverse(metadata.versioning.versions);
            }
            metadata.versioning.versions = filterVersions(metadata.versioning.versions);

            return metadata;
        } catch (Exception e) {
            LOGGER.log(Level.WARNING, "Could not parse maven-metadata.xml", e);
            MavenMetadataVersions result = new MavenMetadataVersions();
            result.versioning.versions.add("<" + e.getClass().getName() + ": " + e.getMessage() + ">");
            return result;
        } finally {
            try {
                if (input != null)
                    input.close();
            } catch (IOException e) {
                // ignore
            }
        }
    }

    /**
     * @param all
     * @return
     */
    private List<String> filterVersions(List<String> all) {
        ArrayList<String> filteredList = new ArrayList<String>(all.size());
        for (String version : all) {
            if (getVersionFilterPattern().matcher(version).matches()) {
                filteredList.add(version);
                if (filteredList.size() == getMaxVers()) {
                    break;
                }
            }
        }
        return filteredList;
    }

    /**
     * Creates a full URL based on the given path parameter and the {@link #repoBaseUrl}, {@link #groupId} and {@link #artifactId}
     * of this instance.
     * 
     * @param path
     *          the path for which to create the full URL.
     * @return the full URL for the given version.
     */
    private String getArtifactUrlForPath(String path) {
        StringBuilder versionBuilder = new StringBuilder(getRepoBaseUrl());
        versionBuilder.append("/").append(getGroupId().replaceAll("\\.", "/"));
        versionBuilder.append("/").append(getArtifactId());
        versionBuilder.append("/").append(path);

        return versionBuilder.toString();
    }

    private String getFullArtifactUrl(MavenMetadataParameterValue value) {
        return getFullArtifactUrl(value.getGroupId(), value.getArtifactId(), value.getVersion(),
                value.getPackaging());
    }

    /**
     * Creates a full URL based on the given parameters and the {@link #getRepoBaseUrl()} of this instance.
     * 
     * @param groupId
     *          the group to use for the full version
     * @param artifactId
     *          the artifact to use for the full url
     * @param version
     *          the version to use for the full url
     * @param packaging
     *          the packaging to use for the full url
     * @return the full URL for the given version.
     */
    private String getFullArtifactUrl(String groupId, String artifactId, String version, String packaging) {
        StringBuilder versionBuilder = new StringBuilder(getArtifactUrlForPath(version));
        versionBuilder.append("/").append(artifactId);
        versionBuilder.append("-").append(version);
        versionBuilder.append(".").append(packaging);

        return versionBuilder.toString();
    }

    public static enum SortOrder {
        DESC("Descending"), ASC("Ascending");
        @Getter
        private String displayName;

        private SortOrder(String displayName) {
            this.displayName = displayName;
        }
    }

    @Extension
    public static class DescriptorImpl extends ParameterDescriptor {

        public FormValidation doCheckVersionFilter(@QueryParameter String value) {
            if (StringUtils.isNotBlank(value)) {
                try {
                    Pattern.compile(value);
                } catch (PatternSyntaxException pse) {
                    FormValidation.error(ResourceBundleHolder.get(MavenMetadataParameterDefinition.class)
                            .format("NotValidRegex"));
                }
            }
            return FormValidation.ok();
        }

        public SortOrder[] getSortOrders() {
            return SortOrder.values();
        }

        @Override
        public String getDisplayName() {
            return ResourceBundleHolder.get(MavenMetadataParameterDefinition.class).format("DisplayName");
        }

    }

    private final static Logger LOGGER = Logger.getLogger(MavenMetadataParameterDefinition.class.getName());

}