org.ops4j.pax.url.maven.commons.MavenSettingsImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.ops4j.pax.url.maven.commons.MavenSettingsImpl.java

Source

/*
 * Copyright 2007 Alin Dreghiciu.
 *
 * 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.ops4j.pax.url.maven.commons;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ops4j.util.xml.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

/**
 * Default implementation of Settings.
 *
 * @author Alin Dreghiciu
 * @see MavenSettings
 * @since August 10, 2007
 */
public class MavenSettingsImpl implements MavenSettings {

    /**
     * Logger.
     */
    private static final Log LOGGER = LogFactory.getLog(MavenSettingsImpl.class);
    /**
     * Path of local repository tag.
     */
    private static final String LOCAL_REPOSITORY_TAG = "localRepository";
    /**
     * Path to server tag.
     */
    private static final String SERVER_TAG = "servers/server";

    /**
     * Path to profiles tag.
     */
    private static final String PROFILE_TAG = "profiles/profile";

    /**
     * Path to repository tag.
     */
    private static final String REPOSITORY_TAG = "repositories/repository";

    /**
     * Path to activeProfiles tag.
     */
    private static final String ACTIVE_PROFILES_TAG = "activeProfiles/activeProfile";

    /**
     * Path to proxy tag.
     */
    private static final String PROXY_TAG = "proxies/proxy";

    /**
     * Fallback Maven repositories.
     */
    private static final String FALLBACK_REPOSITORIES = "http://osgi.sonatype.org/content/groups/pax-runner,"
            + "http://repo1.maven.org/maven2," + "http://repository.ops4j.org/maven2,"
            + "http://repository.springsource.com/maven/bundles/release,"
            + "http://repository.springsource.com/maven/bundles/external";

    /**
     * The settings.xml DOM Document. Null if there is no settings.xml.
     */
    private Document m_document;
    /**
     * The settings.xml file url. Can be null if no settings.xml was resolved.
     */
    private URL m_settingsURL;
    /**
     * Forces uses of fallback repositories instead of default repositories.
     */
    private final boolean m_useFallbackRepositories;
    /**
     * The local repository spec.
     */
    private String m_localRepository;
    /**
     * Comma separated list of repositories. Null if there is no settings xml or settings.xml does not contain
     * repositories.
     */
    private String m_repositories;
    /**
     * Map of known proxies for various protocols
     */
    private Map<String, Map<String, String>> m_proxySettings;

    /**
     * Creates new settings with the following resolution:<br/>
     * 1. looks for the specified url
     * 2. if not found looks for ${user.home}/.m2/settings.xml
     * 3. if not found looks for ${maven.home}/conf/settings.xml
     * 4. if not found looks for ${M2_HOME}/conf/settings.xml
     *
     * @param settingsURL             prefered settings.xml file
     * @param useFallbackRepositories if fallback repositories should be used instead of default repositories
     */
    public MavenSettingsImpl(final URL settingsURL, final boolean useFallbackRepositories) {
        m_settingsURL = settingsURL;
        m_useFallbackRepositories = useFallbackRepositories;
        if (m_settingsURL == null) {
            m_settingsURL = safeGetFile(System.getProperty("user.home") + "/.m2/settings.xml");
            if (m_settingsURL == null) {
                m_settingsURL = safeGetFile(System.getProperty("maven.home") + "/conf/settings.xml");
                if (m_settingsURL == null) {
                    try {
                        m_settingsURL = safeGetFile(System.getenv("M2_HOME") + "/conf/settings.xml");
                    } catch (Error e) {
                        // ignore error - probably running on Java 1.4.x
                    }
                }
            }
        }
    }

    /**
     * See {@link #MavenSettingsImpl(java.net.URL, boolean)}.
     * Forces use of default repositories.
     *
     * @param settingsURL prefered settings.xml file
     */
    public MavenSettingsImpl(final URL settingsURL) {
        this(settingsURL, false);
    }

    /**
     * Returns the local repository directory from settings.xml. If there is no settings.xml file, or the settings.xml
     * does not caontain an <localRepository> tag or the value of that tag is empty it will return the hardcoded
     * standard location: ${user.home}/.m2/repository
     *
     * @return the local repository directory
     */
    public String getLocalRepository() {
        if (m_localRepository == null) {
            readSettings();
            if (m_document != null) {
                Element settingsElement = XmlUtils.getElement(m_document, LOCAL_REPOSITORY_TAG);
                if (settingsElement != null) {
                    m_localRepository = XmlUtils.getTextContent(settingsElement);
                }
            }
            if (m_localRepository == null || m_localRepository.trim().length() == 0) {
                m_localRepository = System.getProperty("user.home") + "/.m2/repository";
            }
        }
        return m_localRepository;
    }

    /**
     * Gets the list of repositories from settings.xml.
     * If there is no settings.xml file or there are no repositories in settings.xml the list returned will be null.
     * 
     * If there are repositories in settings.xml and those repositories have user and password the user and password
     * will be included in the repository url as for example http://user:password@repository.ops4j.org/maven2.
     *
     * Repositories are organized in profiles.
     * Active profiles are selected by looking at activeProfiles tag (just under <settings>)
     *
     * @return a comma separated list of repositories from settings.xml
     */
    public String getRepositories() {
        if (m_repositories == null) {
            readSettings();
            if (m_document != null) {
                Set<String> activeProfiles = getActiveProfiles();
                Map<String, String> repositories = null;
                List<String> order = null;
                List<Element> profiles = XmlUtils.getElements(m_document, PROFILE_TAG);
                // first look for profiles
                if (profiles != null) {
                    for (Element profile : profiles) {
                        Element profileIdElement = XmlUtils.getElement(profile, "id");
                        if (profileIdElement != null) {
                            String profileId = XmlUtils.getTextContent(profileIdElement);
                            if (profileId != null) {
                                if (activeProfiles.contains(profileId)) {
                                    List<Element> repos = XmlUtils.getElements(profile, REPOSITORY_TAG);
                                    if (repos != null) {
                                        for (Element repo : repos) {
                                            Element element = XmlUtils.getElement(repo, "id");
                                            if (element != null) {
                                                String id = XmlUtils.getTextContent(element);
                                                element = XmlUtils.getElement(repo, "layout");
                                                String layout = null;
                                                if (element != null) {
                                                    layout = XmlUtils.getTextContent(element);
                                                }
                                                // take only repositories with a default layout (skip legacy ones)
                                                if (layout == null || "default".equals(layout)) {
                                                    String snapshots = XmlUtils.getTextContentOfElement(repo,
                                                            "snapshots/enabled");
                                                    String releases = XmlUtils.getTextContentOfElement(repo,
                                                            "releases/enabled");
                                                    element = XmlUtils.getElement(repo, "url");
                                                    if (element != null) {
                                                        String url = XmlUtils.getTextContent(element);
                                                        if (url != null) {
                                                            if (repositories == null) {
                                                                repositories = new HashMap<String, String>();
                                                                order = new ArrayList<String>();
                                                            }
                                                            if (snapshots != null && Boolean.valueOf(snapshots)) {
                                                                url += MavenConstants.SEPARATOR_OPTIONS
                                                                        + MavenConstants.OPTION_ALLOW_SNAPSHOTS;
                                                            }
                                                            if (releases != null && !Boolean.valueOf(releases)) {
                                                                url += MavenConstants.SEPARATOR_OPTIONS
                                                                        + MavenConstants.OPTION_DISALLOW_RELEASES;
                                                            }
                                                            repositories.put(id, url);
                                                            order.add(id);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                } else {
                                    LOGGER.debug("Profile " + "[" + profileId + "] is inactive (ignored).");
                                }
                            }
                        }
                    }

                    // then look for user / passwords but only if we have repositories
                    if (repositories != null) {
                        List<Element> servers = XmlUtils.getElements(m_document, SERVER_TAG);
                        if (servers != null) {
                            for (Element server : servers) {
                                Element element = XmlUtils.getElement(server, "id");
                                if (element != null) {
                                    String id = XmlUtils.getTextContent(element);
                                    // if we do not find a corresponding repository don't go furter
                                    String repository = repositories.get(id);
                                    if (repository != null && repository.contains("://")) {
                                        element = XmlUtils.getElement(server, "username");
                                        if (element != null) {
                                            String username = XmlUtils.getTextContent(element);
                                            // if there is no username stop the search
                                            if (username != null) {
                                                element = XmlUtils.getElement(server, "password");
                                                if (element != null) {
                                                    String password = XmlUtils.getTextContent(element);
                                                    if (password != null) {
                                                        username = username + ":" + password;
                                                    }
                                                }
                                                // PAXURL-86: treat string as
                                                // literal
                                                String repo = "://" + username + "@";
                                                repo = Matcher.quoteReplacement(repo);
                                                repositories.put(id, repository.replaceFirst("://", repo));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // build the list of repositories
                    final StringBuilder builder = new StringBuilder();
                    if (order != null) {
                        for (String repositoryId : order) {
                            if (builder.length() > 0) {
                                builder.append(",");
                            }
                            builder.append(repositories.get(repositoryId));
                        }
                    }
                    m_repositories = builder.toString();
                }
            }

            // PAXURL-92 Have the ability to only use a local repository, by
            // not requiring the use of a DEFAULT_REPOSITORY.  Helps with
            // users who have proxies and want to lockdown their repos.
            if (m_useFallbackRepositories) {
                if (m_repositories == null || m_repositories.length() == 0) {
                    m_repositories = FALLBACK_REPOSITORIES;
                } else {
                    m_repositories = m_repositories + "," + FALLBACK_REPOSITORIES;
                }
            }
        }
        return m_repositories;
    }

    private Set<String> getActiveProfiles() {
        Set<String> ret = new HashSet<String>();
        List<Element> activeProfiles = XmlUtils.getElements(m_document, ACTIVE_PROFILES_TAG);
        if (activeProfiles != null) {
            for (Element active : activeProfiles) {
                ret.add(XmlUtils.getTextContent(active));
            }
        }

        return ret;
    }

    /**
     * Reads the settings.xml file. All exceptions raised during acces or parsing are rethrown as RuntimeException.
     */

    private void readSettings() {
        if (m_document == null && m_settingsURL != null) {
            try {
                m_document = XmlUtils.parseDoc(m_settingsURL.openStream());
            } catch (ParserConfigurationException e) {
                throw new RuntimeException("Could not parse settings [" + m_settingsURL + "]", e);
            } catch (SAXException e) {
                throw new RuntimeException("Could not parse settings [" + m_settingsURL + "]", e);
            } catch (IOException e) {
                throw new RuntimeException("Could not parse settings [" + m_settingsURL + "]", e);
            }
        }

    }

    /**
     * Looks for the file denoted by file path and returns the corresponding file if the file exists, is a file and can
     * be read. Otherwise returns null.
     *
     * @param filePath the path to the file
     *
     * @return the file denoted by the file path if can be read or null otherwise
     */
    private static URL safeGetFile(final String filePath) {
        if (filePath != null) {
            File file = new File(filePath);
            if (file.exists() && file.canRead() && file.isFile()) {
                try {
                    return file.toURL();
                } catch (MalformedURLException e) {
                    // do nothing
                }
            }
        }
        return null;
    }

    private String getSetting(Element element, String settingName, String defaultSetting) {
        final String setting = XmlUtils.getTextContentOfElement(element, settingName);
        if (setting == null) {
            return defaultSetting;
        }
        return setting;
    }

    /**
     * Returns the active proxy settings from settings.xml
     *
     * @return the active proxy settings
     */
    public Map<String, Map<String, String>> getProxySettings() {
        if (m_proxySettings == null) {
            m_proxySettings = new HashMap<String, Map<String, String>>();

            readSettings();
            if (m_document != null) {
                List<Element> proxies = XmlUtils.getElements(m_document, PROXY_TAG);
                if (proxies != null) {
                    for (Element proxy : proxies) {
                        String active = getSetting(proxy, "active", "false");
                        String protocol = getSetting(proxy, "protocol", "http");

                        if (!m_proxySettings.containsKey(protocol) || "true".equalsIgnoreCase(active)) {
                            Map<String, String> proxyDetails = new HashMap<String, String>();

                            proxyDetails.put("user", getSetting(proxy, "username", ""));
                            proxyDetails.put("pass", getSetting(proxy, "password", ""));
                            proxyDetails.put("host", getSetting(proxy, "host", "127.0.0.1"));
                            proxyDetails.put("port", getSetting(proxy, "port", "8080"));

                            proxyDetails.put("nonProxyHosts", getSetting(proxy, "nonProxyHosts", ""));

                            m_proxySettings.put(protocol, proxyDetails);
                        }
                    }
                }
            }
        }

        return Collections.unmodifiableMap(m_proxySettings);
    }
}