com.buisonje.AutoProxyMojo.java Source code

Java tutorial

Introduction

Here is the source code for com.buisonje.AutoProxyMojo.java

Source

/*
 * Copyright 2014 Volkert de Buisonjé
 * 
 * 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.
 * 
 * NOTE: proxy-vole has a different license. See the license.txt file bundled
 *       with the proxy-vole dependency in the bundled-repo folder.
 */
package com.buisonje;

/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * 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.
 */

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.settings.Settings;
import org.apache.maven.settings.TrackableBase;

import com.btr.proxy.search.ProxySearch;
import com.btr.proxy.util.Logger;

/**
 * Goal which automatically detects and configures the current system proxy
 * server.
 * 
 * @author Volkert de Buisonjé
 *
 */
@Mojo(name = "detectProxy", defaultPhase = LifecyclePhase.VALIDATE, aggregator = false)
public class AutoProxyMojo extends AbstractMojo {

    private static final String BASIC_HTTP_URL_TO_TRY = "http://www.ams-ix.net";
    private static final String PROXY_DETECTION_TIME_KEY = Date.class.getName();
    private static final String PROXY_SELECTOR_KEY = ProxySelector.class.getName();

    /**
     * The Maven Settings.
     */
    @Parameter(defaultValue = "${settings}", readonly = false)
    private Settings settings;

    @Parameter(defaultValue = "${session}", readonly = true)
    private MavenSession session;

    Map<String, Object> sessionMap = null;

    @Override
    public void execute() throws MojoExecutionException {

        final Log mojoLog = getLog();

        ProxySelector myProxySelector = null;

        if (isProxyDetectionAlreadyAttempted()) {
            mojoLog.info("Proxy server detection already attempted in this session. Reapplying result(s)...");
            myProxySelector = (ProxySelector) session.getSystemProperties().get(PROXY_SELECTOR_KEY);
        } else {
            showMavenProxySettings(mojoLog);
            // showCurrentSystemWideProxiesInfo(mojoLog);
            mojoLog.info("Autodetecting system proxy server(s)...");
            myProxySelector = autodetectProxySettings(mojoLog);
            session.getSystemProperties().put(PROXY_DETECTION_TIME_KEY, new Date());
        }

        if (myProxySelector == null) {
            mojoLog.warn("Could not detect proxy server(s) automatically. Falling back to the initial settings...");
        } else {

            session.getSystemProperties().put(PROXY_SELECTOR_KEY, myProxySelector);

            /*
             * NOTE: It seems that Maven either ignores the system-wide
             * (default) {@link ProxySelector} entirely, or doesn't update it
             * with the initial proxy settings until it actually starts
             * downloading something. Either way, replacing the default {@link
             * ProxySelector} might therefore be pointless here. But it
             * shouldn't hurt, either.
             */
            ProxySelector.setDefault(myProxySelector);

            mojoLog.info("Detected available proxy server(s) for HTTP connections:");
            List<Proxy> detectedAvailableProxies = getAvailableProxies(myProxySelector);
            showAvailableProxies(mojoLog, detectedAvailableProxies);
            Proxy firstDetectedAvailableProxy = detectedAvailableProxies.get(0);
            mojoLog.info(
                    String.format("Overriding Maven proxy settings with the first detected available proxy (%s)...",
                            firstDetectedAvailableProxy.address().toString()));
            overrideMavenProxySettings(firstDetectedAvailableProxy, mojoLog);
        }
    }

    private boolean isProxyDetectionAlreadyAttempted() {
        return session.getSystemProperties().get(PROXY_DETECTION_TIME_KEY) != null;
    }

    /**
     * Override the Maven proxy settings with the first available (actual)
     * Proxy.
     * 
     * @param overridingProxy
     *            The {@link Proxy} to use instead of whatever is configured in
     *            the initial Maven settings (settings.xml).
     */
    private void overrideMavenProxySettings(Proxy overridingProxy, Log mojoLog) {

        org.apache.maven.settings.Proxy mavenProxy = settings.getActiveProxy();

        if (mavenProxy.getSourceLevel() == null) {
            /*
             * User level should be enough for overriding the proxy for the
             * Maven goals/commands currently being executed.
             */
            mavenProxy.setSourceLevel(TrackableBase.USER_LEVEL);
        }

        if (Proxy.NO_PROXY.equals(overridingProxy)) {
            mojoLog.info(
                    "The detected proxy configuration is a direct connection. Overriding active proxy configured in Maven settings...");
            /*
             * There can be only one active proxy in the Maven settings at a
             * time, so if the currently active one is set to inactive, that
             * should imply a direct connection.
             */
            mavenProxy.setActive(false);
        } else {

            final String nonProxyHosts = mavenProxy.getNonProxyHosts();
            if (nonProxyHosts != null && !nonProxyHosts.isEmpty()) {
                mojoLog.info(
                        "Non-proxy hosts appear to have been specified in settings.xml. Leaving those untouched.");
            }

            mavenProxy.setActive(true);
            mavenProxy.setProtocol(overridingProxy.type().name().toLowerCase());

            SocketAddress overridingProxyAddress = overridingProxy.address();
            if (overridingProxyAddress instanceof InetSocketAddress) {
                InetSocketAddress overridingInetSocketAddress = (InetSocketAddress) overridingProxyAddress;
                mavenProxy.setHost(overridingInetSocketAddress.getHostName());
                mavenProxy.setPort(overridingInetSocketAddress.getPort());
            } else {
                /*
                 * Unlikely that the {@link SocketAddress} of the detected
                 * {@link java.net.Proxy} would be anything other than its
                 * subclass {@link InetSocketAddress}, but just in case, handle
                 * it somehow:
                 */
                mavenProxy.setHost(overridingProxyAddress.toString());
                mavenProxy.setPort(0);
            }

        }

    }

    /**
     * @param mojoLog
     * @return
     */
    private ProxySelector autodetectProxySettings(final Log mojoLog) {
        // Let proxy-vole log to the Maven plugin logger.
        Logger.setBackend(new MojoLogBackEnd(mojoLog));

        // Let Proxy Vole try to detect the system proxy settings automatically.
        ProxySearch proxySearch = ProxySearch.getDefaultProxySearch();

        // Set the default proxy server as determined by Proxy Vole:
        ProxySelector myProxySelector = proxySearch.getProxySelector();
        return myProxySelector;
    }

    /**
     * @param proxySelector
     * @return
     */
    private List<Proxy> getAvailableProxies(ProxySelector proxySelector) {
        return proxySelector.select(getBasicHttpURIForProxySelection());
    }

    /**
     * @param mojoLog
     * @param availableProxies
     */
    private void showAvailableProxies(final Log mojoLog, List<Proxy> availableProxies) {
        for (int i = 0; i < availableProxies.size(); i++) {
            final Proxy proxy = availableProxies.get(i);
            mojoLog.info(String.format("Available proxy %d:", i + 1));
            mojoLog.info("  * Proxy type: " + proxy.type().name());
            String proxyAddress = proxy.type() == Type.DIRECT ? "n/a (Direct connection)"
                    : proxy.address().toString();
            mojoLog.info("  * Proxy address: " + proxyAddress);
        }
    }

    private void showMavenProxySettings(final Log mojoLog) {
        final org.apache.maven.settings.Proxy manuallyConfiguredActiveMavenProxy = settings.getActiveProxy();

        if (manuallyConfiguredActiveMavenProxy != null) {
            mojoLog.info("Manually configured active proxy found in settings.xml. Details:");
            mojoLog.info("  * Hostname: " + manuallyConfiguredActiveMavenProxy.getHost());
            mojoLog.info("  * Port    : " + manuallyConfiguredActiveMavenProxy.getPort());
            mojoLog.info("  * Protocol: " + manuallyConfiguredActiveMavenProxy.getProtocol());
        } else {
            mojoLog.info("No currently active proxy found in settings.xml.");
        }
    }

    private boolean isDirectConnection(List<Proxy> availableProxies) {
        return (availableProxies.size() == 1 && availableProxies.get(0).type() == Type.DIRECT);
    }

    private static final URI getBasicHttpURIForProxySelection() {
        URI validHttpUri;
        try {
            validHttpUri = new URI(BASIC_HTTP_URL_TO_TRY);
        } catch (URISyntaxException e) {
            throw new IllegalStateException(
                    "The String " + BASIC_HTTP_URL_TO_TRY + " is not considered a valid URI.");
        }
        return validHttpUri;
    }

}