/*
* JBoss, Home of Professional Open Source
* Copyright 2016, Red Hat, Inc., and individual contributors as indicated
* by the @authors tag.
*
* 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.jboss.as.model.test;
import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT;
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.UndeclaredThrowableException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
/**
* @author Tomaz Cerar (c) 2014 Red Hat Inc.
*/
final class MavenSettings {
private static final Object settingLoaderMutex = new Object();
private static volatile MavenSettings mavenSettings;
private Path localRepository = null;
private final List<String> remoteRepositories = new LinkedList<>();
private final Map<String, Profile> profiles = new HashMap<>();
private final List<String> activeProfileNames = new LinkedList<>();
MavenSettings() {
configureDefaults();
}
static MavenSettings getSettings() {
if (mavenSettings != null) {
return mavenSettings;
}
synchronized (settingLoaderMutex) {
if (mavenSettings != null) {
return mavenSettings;
}
return mavenSettings = doIo(() -> {
MavenSettings settings = new MavenSettings();
Path m2 = Paths.get(System.getProperty("user.home"), ".m2");
Path settingsPath = m2.resolve("settings.xml");
if (Files.notExists(settingsPath)) {
String mavenHome = System.getenv("M2_HOME");
if (mavenHome != null) {
settingsPath = Paths.get(mavenHome, "conf", "settings.xml");
}
}
if (Files.exists(settingsPath)) {
parseSettingsXml(settingsPath, settings);
}
if (settings.getLocalRepository() == null) {
Path repository = m2.resolve("repository");
settings.setLocalRepository(repository);
}
settings.resolveActiveSettings();
return settings;
});
}
}
private static <T> T doIo(PrivilegedExceptionAction<T> action) throws RuntimeException {
try {
return AccessController.doPrivileged(action);
} catch (PrivilegedActionException e) {
try {
throw e.getCause();
} catch (IOException | RuntimeException | Error e1) {
throw new RuntimeException(e1);
} catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
}
static MavenSettings parseSettingsXml(Path settings, MavenSettings mavenSettings) throws IOException {
try {
//reader.setFeature(FEATURE_PROCESS_NAMESPACES, false);
InputStream source = Files.newInputStream(settings, StandardOpenOption.READ);
XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(source);
int eventType;
while ((eventType = reader.next()) != END_DOCUMENT) {
switch (eventType) {
case START_ELEMENT: {
switch (reader.getLocalName()) {
case "settings": {
parseSettings(reader, mavenSettings);
break;
}
}
}
default: {
break;
}
}
}
return mavenSettings;
} catch (XMLStreamException e) {
throw new IOException("Could not parse maven settings.xml", e);
}
}
private static void parseSettings(final XMLStreamReader reader, MavenSettings mavenSettings) throws XMLStreamException, IOException {
int eventType;
while ((eventType = reader.nextTag()) != END_DOCUMENT) {
switch (eventType) {
case END_ELEMENT: {
return;
}
case START_ELEMENT: {
switch (reader.getLocalName()) {
case "localRepository": {
String localRepository = reader.getElementText();
if (localRepository != null && !localRepository.trim().isEmpty()) {
mavenSettings.setLocalRepository(Paths.get(localRepository));
}
break;
}
case "profiles": {
while ((eventType = reader.nextTag()) != END_DOCUMENT) {
if (eventType == START_ELEMENT) {
switch (reader.getLocalName()) {
case "profile": {
parseProfile(reader, mavenSettings);
break;
}
}
} else {
break;
}
}
break;
}
case "activeProfiles": {
while ((eventType = reader.nextTag()) != END_DOCUMENT) {
if (eventType == START_ELEMENT) {
switch (reader.getLocalName()) {
case "activeProfile": {
mavenSettings.addActiveProfile(reader.getElementText());
break;
}
}
} else {
break;
}
}
break;
}
default: {
skip(reader);
}
}
break;
}
default: {
throw new XMLStreamException("Unexpected content", reader.getLocation());
}
}
}
throw new XMLStreamException("Unexpected end of document", reader.getLocation());
}
private static void parseProfile(final XMLStreamReader reader, MavenSettings mavenSettings) throws XMLStreamException, IOException {
int eventType;
Profile profile = new Profile();
while ((eventType = reader.nextTag()) != END_DOCUMENT) {
if (eventType == START_ELEMENT) {
switch (reader.getLocalName()) {
case "id": {
profile.setId(reader.getElementText());
break;
}
case "repositories": {
while ((eventType = reader.nextTag()) != END_DOCUMENT) {
if (eventType == START_ELEMENT) {
switch (reader.getLocalName()) {
case "repository": {
parseRepository(reader, profile);
break;
}
}
} else {
break;
}
}
break;
}
default: {
skip(reader);
}
}
} else {
break;
}
}
mavenSettings.addProfile(profile);
}
private static void parseRepository(final XMLStreamReader reader, Profile profile) throws XMLStreamException, IOException {
int eventType;
while ((eventType = reader.nextTag()) != END_DOCUMENT) {
if (eventType == START_ELEMENT) {
switch (reader.getLocalName()) {
case "url": {
profile.addRepository(reader.getElementText());
break;
}
default: {
skip(reader);
}
}
} else {
break;
}
}
}
private static void skip(XMLStreamReader parser) throws XMLStreamException, IOException {
if (parser.getEventType() != XMLStreamReader.START_ELEMENT) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XMLStreamReader.END_ELEMENT:
depth--;
break;
case XMLStreamReader.START_ELEMENT:
depth++;
break;
}
}
}
private void configureDefaults() {
//always add maven central
remoteRepositories.add("https://repo1.maven.org/maven2/");
String localRepositoryPath = System.getProperty("localRepository");
if (localRepositoryPath != null && !localRepositoryPath.trim().isEmpty()) {
localRepository = Paths.get(localRepositoryPath);
}
localRepositoryPath = System.getProperty("maven.repo.local");
if (localRepositoryPath != null && !localRepositoryPath.trim().isEmpty()) {
localRepository = Paths.get(localRepositoryPath);
}
String remoteRepository = System.getProperty("remote.maven.repo");
if (remoteRepository != null) {
for (String repo : remoteRepository.split(",")) {
if (!repo.endsWith("/")) {
repo += "/";
}
remoteRepositories.add(repo);
}
}
}
private void setLocalRepository(Path localRepository) {
this.localRepository = localRepository;
}
Path getLocalRepository() {
return localRepository;
}
List<String> getRemoteRepositories() {
return remoteRepositories;
}
private void addProfile(Profile profile) {
this.profiles.put(profile.getId(), profile);
}
private void addActiveProfile(String profileName) {
activeProfileNames.add(profileName);
}
private void resolveActiveSettings() {
for (String name : activeProfileNames) {
Profile p = profiles.get(name);
if (p != null) {
remoteRepositories.addAll(p.getRepositories());
}
}
}
static final class Profile {
private String id;
final List<String> repositories = new LinkedList<>();
Profile() {
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
void addRepository(String url) {
if (!url.endsWith("/")) {
url += "/";
}
repositories.add(url);
}
List<String> getRepositories() {
return repositories;
}
}
}