/****************************************************************************** * Copyright (c) 2006, 2010 VMware Inc., Oracle Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0 * is available at http://www.opensource.org/licenses/apache2.0.php. * You may elect to redistribute this code under either of these licenses. * * Contributors: * VMware Inc. * Oracle Inc. *****************************************************************************/ package org.eclipse.gemini.blueprint.test.provisioning.internal; import java.io.File; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.gemini.blueprint.test.provisioning.ArtifactLocator; import org.springframework.beans.factory.xml.DefaultDocumentLoader; import org.springframework.beans.factory.xml.DocumentLoader; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.util.xml.DomUtils; import org.springframework.util.xml.XmlValidationModeDetector; import org.w3c.dom.Document; import org.xml.sax.InputSource; /** * Locator for artifacts found in the local maven repository. Does <strong>not</strong> * use Maven libraries, it rather uses the maven patterns and conventions to * identify the artifacts. * * @author Hal Hildebrand * @author Costin Leau * */ public class LocalFileSystemMavenRepository implements ArtifactLocator { private static final char SLASH_CHAR = '/'; private static final String LOCAL_REPOSITORY_ELEM = "localRepository"; private static final Log log = LogFactory.getLog(LocalFileSystemMavenRepository.class); /** local repo system property */ private static final String SYS_PROPERTY = LOCAL_REPOSITORY_ELEM; /** user home system property */ private static final String USER_HOME_PROPERTY = "user.home"; /** m2 local user settings */ private static final String M2_DIR = ".m2"; /** maven settings xml */ private static final String M2_SETTINGS = M2_DIR.concat("/settings.xml"); /** default local repository */ private static final String DEFAULT_DIR = M2_DIR.concat("/repository"); /** discovered local m2 repository home */ private String repositoryHome; /** * Initialization method It determines the repository path by checking the * existence of <code>localRepository</code> system property and falling * back to the <code>settings.xml</code> file and then the traditional * <code>user.home/.m2/repository</code>. * * <p/> This method is used to postpone initialization until an artifact is * actually located. As the test class is instantiated on each test run, the * init() method prevents repetitive, waste-less initialization. * */ private void init() { // already discovered a repository home, bailing out if (repositoryHome != null) return; boolean trace = log.isDebugEnabled(); final String[] sysProperties = new String[2]; // check system property AccessController.doPrivileged(new PrivilegedAction() { public Object run() { sysProperties[0] = System.getProperty(SYS_PROPERTY); sysProperties[1] = System.getProperty(USER_HOME_PROPERTY); return null; } }); String localRepository = sysProperties[0]; String userHome = sysProperties[1]; if (trace) log.trace("M2 system property [" + SYS_PROPERTY + "] has value=" + localRepository); if (localRepository == null) { // if it's not present then check settings.xml local repository property Resource settingsFile = new FileSystemResource(new File(userHome, M2_SETTINGS)); localRepository = getMavenSettingsLocalRepository(settingsFile); if (trace) log.trace("Falling back to M2 settings.xml [" + settingsFile + "]; found value=" + localRepository); if (localRepository == null) { // fall back to the default location localRepository = new File(userHome, DEFAULT_DIR).getAbsolutePath(); if (trace) log.trace("No custom setting found; using default M2 local repository=" + localRepository); } } repositoryHome = localRepository; log.info("Local Maven2 repository used: [" + repositoryHome + "]"); } /** * Returns the <code>localRepository</code> settings as indicated by the * <code>settings.xml</code> file. * * @return local repository as indicated by a Maven settings.xml file */ String getMavenSettingsLocalRepository(Resource m2Settings) { // no file found, return null to continue the discovery process if (!m2Settings.exists()) return null; try { DocumentLoader docLoader = new DefaultDocumentLoader(); Document document = docLoader.loadDocument(new InputSource(m2Settings.getInputStream()), null, null, XmlValidationModeDetector.VALIDATION_NONE, false); return (DomUtils.getChildElementValueByTagName(document.getDocumentElement(), LOCAL_REPOSITORY_ELEM)); } catch (Exception ex) { throw (RuntimeException) new RuntimeException(new ParserConfigurationException("error parsing resource=" + m2Settings).initCause(ex)); } } /** * Find a local maven artifact. First tries to find the resource as a * packaged artifact produced by a local maven build, and if that fails will * search the local maven repository. * * @param groupId - the groupId of the organization supplying the bundle * @param artifactId - the artifact id of the bundle * @param version - the version of the bundle * @return the String representing the URL location of this bundle */ public Resource locateArtifact(String groupId, String artifactId, String version) { return locateArtifact(groupId, artifactId, version, DEFAULT_ARTIFACT_TYPE); } /** * Find a local maven artifact. First tries to find the resource as a * packaged artifact produced by a local maven build, and if that fails will * search the local maven repository. * * @param groupId - the groupId of the organization supplying the bundle * @param artifactId - the artifact id of the bundle * @param version - the version of the bundle * @param type - the extension type of the artifact * @return */ public Resource locateArtifact(final String groupId, final String artifactId, final String version, final String type) { init(); return (Resource) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { return localMavenBuildArtifact(groupId, artifactId, version, type); } catch (IllegalStateException illStateEx) { Resource localMavenBundle = localMavenBundle(groupId, artifactId, version, type); if (log.isDebugEnabled()) { StringBuilder buf = new StringBuilder(); buf.append("["); buf.append(groupId); buf.append("|"); buf.append(artifactId); buf.append("|"); buf.append(version); buf.append("]"); log.debug(buf + " local maven build artifact detection failed, falling back to local maven bundle " + localMavenBundle.getDescription()); } return localMavenBundle; } } }); } /** * Return the resource of the indicated bundle in the local Maven repository * * @param groupId - the groupId of the organization supplying the bundle * @param artifact - the artifact id of the bundle * @param version - the version of the bundle * @return */ protected Resource localMavenBundle(String groupId, String artifact, String version, String type) { StringBuilder location = new StringBuilder(groupId.replace('.', SLASH_CHAR)); location.append(SLASH_CHAR); location.append(artifact); location.append(SLASH_CHAR); location.append(version); location.append(SLASH_CHAR); location.append(artifact); location.append('-'); location.append(version); location.append("."); location.append(type); return new FileSystemResource(new File(repositoryHome, location.toString())); } /** * Find a local maven artifact in the current build tree. This searches for * resources produced by the package phase of a maven build. * * @param artifactId * @param version * @param type * @return */ protected Resource localMavenBuildArtifact(String groupId, String artifactId, String version, String type) { try { File found = new MavenPackagedArtifactFinder(groupId, artifactId, version, type).findPackagedArtifact(new File( ".")); Resource res = new FileSystemResource(found); if (log.isDebugEnabled()) { log.debug("[" + artifactId + "|" + version + "] resolved to " + res.getDescription() + " as a local maven artifact"); } return res; } catch (IOException ioEx) { throw (RuntimeException) new IllegalStateException("Artifact " + artifactId + "-" + version + "." + type + " could not be found").initCause(ioEx); } } }