/*******************************************************************************
* Copyright (c) 2008 Sonatype, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.maven.ide.eclipse.internal.project;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.DefaultArtifactResolver;
import org.apache.maven.embedder.MavenEmbedder;
import org.apache.maven.settings.Profile;
import org.apache.maven.settings.Settings;
import org.maven.ide.eclipse.MavenPlugin;
import org.maven.ide.eclipse.embedder.ArtifactKey;
/**
* The MyEclipseArtifactResolver is basically a copy of
* EclipseArtifactResolver with the addition of handling
* reading properties from the active profiles available and substituting
* those variables, if there is a match.
*
The other class affected by the scheme implemented here is:
* MavenProjectManagerImpl, whose line 1137 is altered
* to instantiate this class instead of the copied resolver.
*
* @author original author unascribed
* @author rova
*/
public class MyEclipseArtifactResolver extends DefaultArtifactResolver {
public void resolve(Artifact artifact, List remoteRepositories, ArtifactRepository localRepository) throws ArtifactResolutionException, ArtifactNotFoundException {
artifact = this.checkArtifact4Variables(artifact);
if(!resolveAsEclipseProject(artifact)) {
super.resolve(artifact, remoteRepositories, localRepository);
}
}
public void resolveAlways(Artifact artifact, List remoteRepositories, ArtifactRepository localRepository) throws ArtifactResolutionException, ArtifactNotFoundException {
artifact = this.checkArtifact4Variables(artifact);
if(!resolveAsEclipseProject( artifact ) ) {
super.resolveAlways(artifact, remoteRepositories, localRepository);
}
}
protected static boolean resolveAsEclipseProject(Artifact artifact) {
MavenProjectManagerImpl.Context context = MavenProjectManagerImpl.getContext();
if(context == null) { // XXX this is actually a bug
return false;
}
if(artifact == null) {
// according to the DefaultArtifactResolver source code, it looks like artifact can be null
return false;
}
// check in the workspace, note that workspace artifacts never have classifiers
ArtifactKey key = new ArtifactKey(artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(), null);
IPath pomPath = context.state.getWorkspaceArtifact(key);
if( pomPath == null ) {
return false;
}
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IFile pom = root.getFile(pomPath);
if( pom == null || !pom.isAccessible() ) {
// XXX this is really a bug, need to throw something meaningful
return false;
}
if( context.resolverConfiguration.shouldResolveWorkspaceProjects() ||
( context.resolverConfiguration.shouldIncludeModules() &&
WorkspaceState.isSameProject( context.pom, pom ) ) ){
IPath file = pom.getLocation();
if( !"pom".equals( artifact.getType() ) ) {
MavenProjectFacade facade = context.state.getProjectFacade( pom );
IFolder outputLocation = root.getFolder( facade.getOutputLocation() );
if(outputLocation.exists()) {
file = outputLocation.getLocation();
}
}
artifact.setFile( file.toFile() );
artifact.setResolved( true );
return true;
}
return false;
}
/**
* Check whether an artifact holds potential variables for replacement
* from an active profile. if there no such variables, the artifact is
* left intact.
*
* @param artifact artifact to check
* @return checked artifact, possible variables substituted
*/
@SuppressWarnings("unchecked")
private Artifact checkArtifact4Variables( Artifact artifact ){
ArtifactKey key = new ArtifactKey(artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(), null);
if( key.toString().indexOf('$') >= 0 ) {
// Unresolved property, for example ${parentversion}
// Find out which property of the artifact key which
// is to be substituted with a variable value...
String groupId = key.getGroupId();
String artifactId = key.getArtifactId();
String version = key.getVersion();
MavenPlugin plugin = MavenPlugin.getDefault();
try{
MavenEmbedder embedder = plugin.getMavenEmbedderManager().getWorkspaceEmbedder();
Settings s = embedder.getSettings();
List actProfiles = s.getActiveProfiles();
// TODO: If there are no active profiles, we can skip the rest ...
List profiles = s.getProfiles();
for(Object profile : profiles) {
Profile p = ( Profile ) profile;
for(Object actProfile : actProfiles) {
String id = ( String ) actProfile;
if( p.getId().equals( id ) ){
// This profile is active ...
Properties props = p.getProperties();
for( Enumeration e = props.keys(); e.hasMoreElements() ;){
String propKey = ( String ) e.nextElement();
if( groupId.indexOf('$') >= 0 ){
// groupId potential variable
if( strip( groupId ).equals( propKey ) ){
groupId = props.getProperty( propKey );
artifact.setGroupId( groupId );
}
}else if( artifactId.indexOf('$') >= 0 ){
// artifactId potential variable
if( strip( artifactId ).equals( propKey ) ){
artifactId = props.getProperty( propKey );
artifact.setArtifactId( artifactId );
}
}else if( version.indexOf('$') >= 0 ) {
// version potential variable
if( strip( version ).equals( propKey ) ){
version = props.getProperty( propKey );
artifact.setVersion( version );
}
}
}
}
}
}
}catch (Exception ex) {
// TODO: handle exception
}
}
return artifact;
}
/**
* If a string is a potential variable for substitution, strip away
* the variable admin. stuff.
* Please keep in mind that there is no check whether this is a
* potential variable or not. It assumed that this check is done
* prior to calling this method.
*
* @param entity potential variable
* @return stripped from variable enclosing brackets etc.
*/
private String strip( String entity ){
String s = entity.substring( 2 ); // Skip the '${
return s.substring( 0, ( s.length() - 1 ) ); // Strip away the trailing '}'
}
}