blob: 70a00555a552d6821e92628be14e01595636172b [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.maven.mercury.artifact;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.maven.mercury.artifact.version.DefaultArtifactVersion;
import org.apache.maven.mercury.artifact.version.VersionException;
import org.apache.maven.mercury.artifact.version.VersionRange;
import org.apache.maven.mercury.artifact.version.VersionRangeFactory;
import org.codehaus.plexus.lang.DefaultLanguage;
import org.codehaus.plexus.lang.Language;
/**
* this is the most primitive metadata there is, usually used to query repository for "real" metadata. It holds
* everything a project.dependencies.dependency element can have
*
* @author Oleg Gusakov
* @version $Id$
*/
public class ArtifactMetadata
{
public static final String DEFAULT_ARTIFACT_TYPE = "jar";
private static final Language LANG = new DefaultLanguage( ArtifactMetadata.class );
/**
* standard glorified artifact coordinates
*/
protected String groupId;
protected String artifactId;
private String version;
private transient VersionRange versionRange;
private Quality quality;
/**
* relocation chain after processing by ProjectBuilder
*/
protected List<ArtifactCoordinates> relocations;
protected ArtifactCoordinates effectiveCoordinates;
// This is Maven specific. jvz/
protected String classifier;
protected String type = DEFAULT_ARTIFACT_TYPE;
protected ArtifactScopeEnum artifactScope;
// protected String scope;
protected boolean optional;
protected Collection<ArtifactMetadata> inclusions;
protected Collection<ArtifactMetadata> exclusions;
protected Map<String, String> attributes;
/** conveniency for SNAPSHOT file timestamp */
private String timeStamp;
/**
* transient helper objects, used by DependencyBuilder.
*/
transient Object tracker;
transient Boolean local = false;
/**
* transient external datum to carry along
*/
transient Object datum;
/** dependencies of the artifact behind this metadata */
protected List<ArtifactMetadata> dependencies;
/** artifact URI */
protected String artifactUri;
// ------------------------------------------------------------------
public ArtifactMetadata()
{
}
// ------------------------------------------------------------------
private void processAttributes( String as )
{
if ( as == null || as.length() < 1 )
{
return;
}
String attrString = as.trim();
if ( attrString == null || attrString.length() < 1 )
{
return;
}
int fromCh = attrString.indexOf( '{' );
int toCh = attrString.indexOf( '}' );
if ( fromCh != -1 && toCh != -1 )
{
attrString = attrString.substring( fromCh + 1, toCh );
}
String[] entries = attrString.split( "," );
if ( entries != null )
{
for ( int i = 0; i < entries.length; i++ )
{
String e = entries[i];
if ( e == null )
{
continue;
}
int eq = e.indexOf( '=' );
if ( eq == -1 )
{
continue;
}
if ( attributes == null )
{
attributes = new LinkedHashMap<String, String>( entries.length );
}
String name = e.substring( 0, eq );
if ( name == null )
{
continue;
}
name = name.trim();
String val = e.substring( eq + 1 );
if ( val != null )
{
val = val.trim();
}
attributes.put( name, val );
}
}
}
// ------------------------------------------------------------------
/**
* create basic out of <b>group:artifact:version:classifier:type</b> string, use empty string to specify missing
* component - for instance query for common-1.3.zip can be specified as ":common:1.3::zip" - note missing groupId
* and classifier.
*/
public ArtifactMetadata( String gavQuery )
{
if ( gavQuery == null )
{
return;
}
String[] tokens = gavQuery.split( ":" );
if ( tokens == null || tokens.length < 1 )
{
return;
}
int count = tokens.length;
this.groupId = nullify( tokens[0] );
if ( count > 1 )
{
this.artifactId = nullify( tokens[1] );
}
if ( count > 2 )
{
this.version = nullify( tokens[2] );
}
if ( count > 3 )
{
this.classifier = nullify( tokens[3] );
}
if ( count > 4 )
{
setType( nullify( tokens[4] ) );
}
if ( this.type == null || this.type.length() < 1 )
{
this.type = DEFAULT_ARTIFACT_TYPE;
}
if ( count > 5 )
{
this.artifactScope = ArtifactScopeEnum.valueOf( nullify( tokens[5] ) );
}
if ( count > 6 )
{
processAttributes( nullify( tokens[6] ) );
}
}
/**
* copy constructor
*
* @param copyFrom
*/
public ArtifactMetadata( ArtifactMetadata copyFrom )
{
if ( copyFrom == null )
throw new IllegalArgumentException( LANG.getMessage( "null.copy.from.md" ) );
setGroupId( copyFrom.getGroupId() );
setArtifactId( copyFrom.getArtifactId() );
setVersion( copyFrom.getVersion() );
setClassifier( copyFrom.getClassifier() );
setType( copyFrom.getType() );
setScope( copyFrom.getScope() );
Map<String, String> a = copyFrom.getAttributes();
if ( a != null && a.size() > 0 )
{
attributes = new HashMap<String, String>( a.size() );
attributes.putAll( a );
}
setTracker( copyFrom.getTracker() );
}
// ------------------------------------------------------------------
/**
* create basic out of <b>group:artifact:version:classifier:type</b> string, use empty string to specify missing
* component - for instance query for common-1.3.zip can be specified as ":common:1.3::zip" - note missing groupId
* and classifier.
*/
public static ArtifactMetadata create( String query )
{
ArtifactMetadata mdq = new ArtifactMetadata( query );
return mdq;
}
// ---------------------------------------------------------------------------
private static final String nullify( String s )
{
if ( s == null || s.length() < 1 )
{
return null;
}
return s;
}
// ---------------------------------------------------------------------
public boolean sameGAV( ArtifactMetadata md )
{
if ( md == null )
{
return false;
}
return sameGA( md ) && version != null && version.equals( md.getVersion() );
}
// ---------------------------------------------------------------------
public boolean sameGA( ArtifactMetadata md )
{
if ( md == null )
{
return false;
}
return groupId != null && artifactId != null && groupId.equals( md.getGroupId() )
&& artifactId.equals( md.getArtifactId() );
}
public String getGA()
{
return toDomainString();
}
public String getGAV()
{
return toString();
}
private static final String nvl( String val, String dflt )
{
return val == null ? dflt : val;
}
private static final String nvl( String val )
{
return nvl( val, "" );
}
@Override
public String toString()
{
return nvl( groupId ) + ":" + nvl( artifactId ) + ":" + nvl( version ) + ":" + nvl( classifier ) + ":"
+ nvl( type, DEFAULT_ARTIFACT_TYPE );
}
public String toScopedString()
{
return toString() + "-scope:" + getArtifactScope();
}
public String toDomainString()
{
return groupId + ":" + artifactId;
}
public String toManagementString()
{
return groupId + ":" + artifactId + ":" + type + ( classifier != null ? ":" + classifier : "" );
}
public String getBaseName()
{
return artifactId + "-" + version + ( classifier == null ? "" : "-" + classifier );
}
public String getFileName()
{
return getBaseName() + "." + ( type == null ? DEFAULT_ARTIFACT_TYPE : type );
}
public String getBaseName( String classifier )
{
return artifactId + "-" + version
+ ( ( classifier == null || classifier.length() < 1 ) ? "" : "-" + classifier );
}
public String getCheckedType()
{
return type == null ? "jar" : type;
}
// ---------------------------------------------------------------------------
public String getGroupId()
{
return groupId;
}
public void setGroupId( String groupId )
{
this.groupId = groupId;
}
public String getArtifactId()
{
return artifactId;
}
public void setArtifactId( String artifactId )
{
this.artifactId = artifactId;
}
public String getVersion()
{
return version;
}
public boolean hasVersion()
{
return version != null && version.length() > 0;
}
public void setVersion( String version )
{
this.version = version;
}
private void checkRangeExists()
{
if ( versionRange == null )
{
if ( version == null )
throw new IllegalArgumentException( LANG.getMessage( "artifact.metadata.no.version", toString() ) );
else
{
try
{
versionRange = VersionRangeFactory.create( version );
}
catch ( VersionException e )
{
throw new IllegalArgumentException( e.getMessage() );
}
}
}
}
public boolean isSingleton()
{
checkRangeExists();
return versionRange.isSingleton();
}
public boolean isRange()
{
return !isSingleton();
}
/** code quality used to decide whether try or skip a repository - see repository code quality */
public Quality getRequestedQuality()
{
if ( isRange() )
return null;
if ( isVirtual() )
{
if ( isVirtualSnapshot() )
return Quality.SNAPSHOT_QUALITY;
else if ( isVirtualRelease() )
return Quality.RELEASE_QUALITY;
return null;
}
if ( quality != null )
return quality;
quality = new Quality( getVersion() );
return quality;
}
public String getClassifier()
{
return classifier;
}
public void setClassifier( String classifier )
{
this.classifier = classifier;
}
public String getType()
{
return type;
}
public void setType( String type )
{
if ( "test-jar".equals( type ) )
{
setClassifier( "tests" );
setType( "jar" );
}
else
this.type = type;
}
public Map<String, String> getAttributes()
{
return attributes;
}
public String getScope()
{
return getArtifactScope().getScope();
}
public ArtifactScopeEnum getScopeAsEnum()
{
return artifactScope == null ? ArtifactScopeEnum.DEFAULT_SCOPE : artifactScope;
}
public ArtifactScopeEnum getArtifactScope()
{
return artifactScope == null ? ArtifactScopeEnum.DEFAULT_SCOPE : artifactScope;
}
public void setArtifactScope( ArtifactScopeEnum artifactScope )
{
this.artifactScope = artifactScope;
}
public void setScope( String scope )
{
this.artifactScope = scope == null ? ArtifactScopeEnum.DEFAULT_SCOPE : ArtifactScopeEnum.valueOf( scope );
}
public boolean isOptional()
{
return optional;
}
public void setOptional( boolean optional )
{
this.optional = optional;
}
public void setOptional( String optional )
{
this.optional = "true".equals( optional );
}
public Object getTracker()
{
return tracker;
}
public void setTracker( Object tracker )
{
this.tracker = tracker;
}
public boolean hasClassifier()
{
return classifier != null && classifier.length() > 0;
}
public Boolean isLocal()
{
return local;
}
public void setLocal( Boolean local )
{
this.local = local;
}
public boolean isPom()
{
return "pom".regionMatches( 0, type, 0, 3 );
}
public boolean isVirtual()
{
return DefaultArtifactVersion.isVirtual( version );
}
public boolean isVirtualSnapshot()
{
return DefaultArtifactVersion.isVirtualSnapshot( version );
}
public boolean isVirtualRelease()
{
return DefaultArtifactVersion.isVirtualRelease( version );
}
public boolean isVirtualLatest()
{
return DefaultArtifactVersion.isVirtualLatest( version );
}
public ArtifactCoordinates getEffectiveCoordinates()
{
if ( relocations == null || relocations.isEmpty() )
{
return new ArtifactCoordinates( groupId, artifactId, version );
}
return relocations.get( relocations.size() - 1 );
}
public ArtifactMetadata addRelocation( ArtifactCoordinates coord )
{
if ( coord == null )
{
return this;
}
if ( relocations == null )
{
relocations = new ArrayList<ArtifactCoordinates>( 2 );
}
if ( coord.getGroupId() == null )
{
coord.setGroupId( groupId );
}
if ( coord.getArtifactId() == null )
{
coord.setArtifactId( artifactId );
}
if ( coord.getVersion() == null )
{
coord.setVersion( version );
}
relocations.add( coord );
effectiveCoordinates = coord;
return this;
}
public String getEffectiveGroupId()
{
return effectiveCoordinates == null ? groupId : effectiveCoordinates.getGroupId();
}
public String getEffectiveArtifactId()
{
return effectiveCoordinates == null ? artifactId : effectiveCoordinates.getArtifactId();
}
public String getEffectiveersion()
{
return effectiveCoordinates == null ? version : effectiveCoordinates.getVersion();
}
public boolean hasInclusions()
{
return inclusions == null ? false : !inclusions.isEmpty();
}
public Collection<ArtifactMetadata> getInclusions()
{
return inclusions;
}
public void setInclusions( Collection<ArtifactMetadata> inclusions )
{
this.inclusions = inclusions;
}
public boolean hasExclusions()
{
return exclusions == null ? false : !exclusions.isEmpty();
}
public Collection<ArtifactMetadata> getExclusions()
{
return exclusions;
}
public void setExclusions( Collection<ArtifactMetadata> exclusions )
{
this.exclusions = exclusions;
}
/**
* run dependency through inclusion/exclusion filters. Inclusion filter is always a "hole"-filter, which is then
* enhanced by exclusion "cork"-filter
*
* @param dep dependency to vet
* @return vet result
* @throws VersionException
*/
public boolean allowDependency( ArtifactMetadata dep )
throws VersionException
{
boolean includeDependency = true;
if ( hasInclusions() )
{
includeDependency = !passesFilter( inclusions, dep );
}
if ( !includeDependency )
{
return false;
}
if ( !hasExclusions() )
{
return true;
}
if ( passesFilter( exclusions, dep ) )
{
return true;
}
return false;
}
private boolean passesFilter( Collection<ArtifactMetadata> filter, ArtifactMetadata dep )
throws VersionException
{
for ( ArtifactMetadata filterMd : filter )
{
if ( filterMd.sameGA( dep ) )
{
if ( !filterMd.hasVersion() )
{
return false; // no version in the filter - catch by GA
}
VersionRange vr = VersionRangeFactory.create( filterMd.getVersion() );
if ( vr.includes( dep.getVersion() ) )
{
return false; // catch by version query
}
}
}
return true;
}
@Override
public boolean equals( Object obj )
{
if ( obj == null || !( obj instanceof ArtifactMetadata ) )
{
return false;
}
return toString().equals( obj.toString() );
}
@Override
public int hashCode()
{
return toString().hashCode();
}
public List<ArtifactMetadata> getDependencies()
{
return dependencies;
}
public void setDependencies( List<ArtifactMetadata> dependencies )
{
this.dependencies = dependencies;
}
public String getArtifactUri()
{
return artifactUri;
}
public void setArtifactUri( String artifactUri )
{
this.artifactUri = artifactUri;
}
public Object getDatum()
{
return datum;
}
public void setDatum( Object datum )
{
this.datum = datum;
}
public String getTimeStamp()
{
return timeStamp;
}
public void setTimeStamp( String timeStamp )
{
this.timeStamp = timeStamp;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
}