Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.eclipse.aether.internal.impl.DefaultUpdateCheckManager Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2010, 2014 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
*
* Contributors:
* Sonatype, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.aether.internal.impl;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.SessionData;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.impl.UpdateCheck;
import org.eclipse.aether.impl.UpdateCheckManager;
import org.eclipse.aether.impl.UpdatePolicyAnalyzer;
import org.eclipse.aether.metadata.Metadata;
import org.eclipse.aether.repository.AuthenticationDigest;
import org.eclipse.aether.repository.Proxy;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ResolutionErrorPolicy;
import org.eclipse.aether.spi.locator.Service;
import org.eclipse.aether.spi.locator.ServiceLocator;
import org.eclipse.aether.spi.log.Logger;
import org.eclipse.aether.spi.log.LoggerFactory;
import org.eclipse.aether.spi.log.NullLoggerFactory;
import org.eclipse.aether.transfer.ArtifactNotFoundException;
import org.eclipse.aether.transfer.ArtifactTransferException;
import org.eclipse.aether.transfer.MetadataNotFoundException;
import org.eclipse.aether.transfer.MetadataTransferException;
import org.eclipse.aether.util.ConfigUtils;
/**
*/
@Named
public class DefaultUpdateCheckManager
implements UpdateCheckManager, Service
{
private Logger logger = NullLoggerFactory.LOGGER;
private UpdatePolicyAnalyzer updatePolicyAnalyzer;
private static final String UPDATED_KEY_SUFFIX = ".lastUpdated";
private static final String ERROR_KEY_SUFFIX = ".error";
private static final String NOT_FOUND = "";
private static final String SESSION_CHECKS = "updateCheckManager.checks";
static final String CONFIG_PROP_SESSION_STATE = "aether.updateCheckManager.sessionState";
private static final int STATE_ENABLED = 0;
private static final int STATE_BYPASS = 1;
private static final int STATE_DISABLED = 2;
public DefaultUpdateCheckManager()
{
// enables default constructor
}
@Inject
DefaultUpdateCheckManager( UpdatePolicyAnalyzer updatePolicyAnalyzer, LoggerFactory loggerFactory )
{
setUpdatePolicyAnalyzer( updatePolicyAnalyzer );
setLoggerFactory( loggerFactory );
}
public void initService( ServiceLocator locator )
{
setLoggerFactory( locator.getService( LoggerFactory.class ) );
setUpdatePolicyAnalyzer( locator.getService( UpdatePolicyAnalyzer.class ) );
}
public DefaultUpdateCheckManager setLoggerFactory( LoggerFactory loggerFactory )
{
this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() );
return this;
}
public DefaultUpdateCheckManager setUpdatePolicyAnalyzer( UpdatePolicyAnalyzer updatePolicyAnalyzer )
{
if ( updatePolicyAnalyzer == null )
{
throw new IllegalArgumentException( "update policy analyzer has not been specified" );
}
this.updatePolicyAnalyzer = updatePolicyAnalyzer;
return this;
}
public void checkArtifact( RepositorySystemSession session, UpdateCheck check )
{
if ( check.getLocalLastUpdated() != 0
&& !isUpdatedRequired( session, check.getLocalLastUpdated(), check.getPolicy() ) )
{
if ( logger.isDebugEnabled() )
{
logger.debug( "Skipped remote request for " + check.getItem()
+ ", locally installed artifact up-to-date." );
}
check.setRequired( false );
return;
}
Artifact artifact = check.getItem();
RemoteRepository repository = check.getRepository();
File artifactFile = check.getFile();
if ( artifactFile == null )
{
throw new IllegalArgumentException( String.format( "The artifact '%s' has no file attached", artifact ) );
}
boolean fileExists = check.isFileValid() && artifactFile.exists();
File touchFile = getTouchFile( artifact, artifactFile );
Properties props = read( touchFile );
String updateKey = getUpdateKey( session, artifactFile, repository );
String dataKey = getDataKey( artifact, artifactFile, repository );
String error = getError( props, dataKey );
long lastUpdated;
if ( error == null )
{
if ( fileExists )
{
// last update was successful
lastUpdated = artifactFile.lastModified();
}
else
{
// this is the first attempt ever
lastUpdated = 0;
}
}
else if ( error.length() <= 0 )
{
// artifact did not exist
lastUpdated = getLastUpdated( props, dataKey );
}
else
{
// artifact could not be transferred
String transferKey = getTransferKey( session, artifact, artifactFile, repository );
lastUpdated = getLastUpdated( props, transferKey );
}
if ( lastUpdated == 0 )
{
check.setRequired( true );
}
else if ( isAlreadyUpdated( session, updateKey ) )
{
if ( logger.isDebugEnabled() )
{
logger.debug( "Skipped remote request for " + check.getItem()
+ ", already updated during this session." );
}
check.setRequired( false );
if ( error != null )
{
check.setException( newException( error, artifact, repository ) );
}
}
else if ( isUpdatedRequired( session, lastUpdated, check.getPolicy() ) )
{
check.setRequired( true );
}
else if ( fileExists )
{
if ( logger.isDebugEnabled() )
{
logger.debug( "Skipped remote request for " + check.getItem() + ", locally cached artifact up-to-date." );
}
check.setRequired( false );
}
else
{
int errorPolicy = Utils.getPolicy( session, artifact, repository );
int cacheFlag = getCacheFlag( error );
if ( ( errorPolicy & cacheFlag ) != 0 )
{
check.setRequired( false );
check.setException( newException( error, artifact, repository ) );
}
else
{
check.setRequired( true );
}
}
}
private static int getCacheFlag( String error )
{
if ( error == null || error.length() <= 0 )
{
return ResolutionErrorPolicy.CACHE_NOT_FOUND;
}
else
{
return ResolutionErrorPolicy.CACHE_TRANSFER_ERROR;
}
}
private ArtifactTransferException newException( String error, Artifact artifact, RemoteRepository repository )
{
if ( error == null || error.length() <= 0 )
{
return new ArtifactNotFoundException( artifact, repository, "Failure to find " + artifact + " in "
+ repository.getUrl() + " was cached in the local repository, "
+ "resolution will not be reattempted until the update interval of " + repository.getId()
+ " has elapsed or updates are forced", true );
}
else
{
return new ArtifactTransferException( artifact, repository, "Failure to transfer " + artifact + " from "
+ repository.getUrl() + " was cached in the local repository, "
+ "resolution will not be reattempted until the update interval of " + repository.getId()
+ " has elapsed or updates are forced. Original error: " + error, true );
}
}
public void checkMetadata( RepositorySystemSession session, UpdateCheck check )
{
if ( check.getLocalLastUpdated() != 0
&& !isUpdatedRequired( session, check.getLocalLastUpdated(), check.getPolicy() ) )
{
if ( logger.isDebugEnabled() )
{
logger.debug( "Skipped remote request for " + check.getItem()
+ ", locally installed metadata up-to-date." );
}
check.setRequired( false );
return;
}
Metadata metadata = check.getItem();
RemoteRepository repository = check.getRepository();
File metadataFile = check.getFile();
if ( metadataFile == null )
{
throw new IllegalArgumentException( String.format( "The metadata '%s' has no file attached", metadata ) );
}
boolean fileExists = check.isFileValid() && metadataFile.exists();
File touchFile = getTouchFile( metadata, metadataFile );
Properties props = read( touchFile );
String updateKey = getUpdateKey( session, metadataFile, repository );
String dataKey = getDataKey( metadata, metadataFile, check.getAuthoritativeRepository() );
String error = getError( props, dataKey );
long lastUpdated;
if ( error == null )
{
if ( fileExists )
{
// last update was successful
lastUpdated = getLastUpdated( props, dataKey );
}
else
{
// this is the first attempt ever
lastUpdated = 0;
}
}
else if ( error.length() <= 0 )
{
// metadata did not exist
lastUpdated = getLastUpdated( props, dataKey );
}
else
{
// metadata could not be transferred
String transferKey = getTransferKey( session, metadata, metadataFile, repository );
lastUpdated = getLastUpdated( props, transferKey );
}
if ( lastUpdated == 0 )
{
check.setRequired( true );
}
else if ( isAlreadyUpdated( session, updateKey ) )
{
if ( logger.isDebugEnabled() )
{
logger.debug( "Skipped remote request for " + check.getItem()
+ ", already updated during this session." );
}
check.setRequired( false );
if ( error != null )
{
check.setException( newException( error, metadata, repository ) );
}
}
else if ( isUpdatedRequired( session, lastUpdated, check.getPolicy() ) )
{
check.setRequired( true );
}
else if ( fileExists )
{
if ( logger.isDebugEnabled() )
{
logger.debug( "Skipped remote request for " + check.getItem() + ", locally cached metadata up-to-date." );
}
check.setRequired( false );
}
else
{
int errorPolicy = Utils.getPolicy( session, metadata, repository );
int cacheFlag = getCacheFlag( error );
if ( ( errorPolicy & cacheFlag ) != 0 )
{
check.setRequired( false );
check.setException( newException( error, metadata, repository ) );
}
else
{
check.setRequired( true );
}
}
}
private MetadataTransferException newException( String error, Metadata metadata, RemoteRepository repository )
{
if ( error == null || error.length() <= 0 )
{
return new MetadataNotFoundException( metadata, repository, "Failure to find " + metadata + " in "
+ repository.getUrl() + " was cached in the local repository, "
+ "resolution will not be reattempted until the update interval of " + repository.getId()
+ " has elapsed or updates are forced", true );
}
else
{
return new MetadataTransferException( metadata, repository, "Failure to transfer " + metadata + " from "
+ repository.getUrl() + " was cached in the local repository, "
+ "resolution will not be reattempted until the update interval of " + repository.getId()
+ " has elapsed or updates are forced. Original error: " + error, true );
}
}
private long getLastUpdated( Properties props, String key )
{
String value = props.getProperty( key + UPDATED_KEY_SUFFIX, "" );
try
{
return ( value.length() > 0 ) ? Long.parseLong( value ) : 1;
}
catch ( NumberFormatException e )
{
logger.debug( "Cannot parse lastUpdated date: \'" + value + "\'. Ignoring.", e );
return 1;
}
}
private String getError( Properties props, String key )
{
return props.getProperty( key + ERROR_KEY_SUFFIX );
}
private File getTouchFile( Artifact artifact, File artifactFile )
{
return new File( artifactFile.getPath() + ".lastUpdated" );
}
private File getTouchFile( Metadata metadata, File metadataFile )
{
return new File( metadataFile.getParent(), "resolver-status.properties" );
}
private String getDataKey( Artifact artifact, File artifactFile, RemoteRepository repository )
{
Set mirroredUrls = Collections.emptySet();
if ( repository.isRepositoryManager() )
{
mirroredUrls = new TreeSet();
for ( RemoteRepository mirroredRepository : repository.getMirroredRepositories() )
{
mirroredUrls.add( normalizeRepoUrl( mirroredRepository.getUrl() ) );
}
}
StringBuilder buffer = new StringBuilder( 1024 );
buffer.append( normalizeRepoUrl( repository.getUrl() ) );
for ( String mirroredUrl : mirroredUrls )
{
buffer.append( '+' ).append( mirroredUrl );
}
return buffer.toString();
}
private String getTransferKey( RepositorySystemSession session, Artifact artifact, File artifactFile,
RemoteRepository repository )
{
return getRepoKey( session, repository );
}
private String getDataKey( Metadata metadata, File metadataFile, RemoteRepository repository )
{
return metadataFile.getName();
}
private String getTransferKey( RepositorySystemSession session, Metadata metadata, File metadataFile,
RemoteRepository repository )
{
return metadataFile.getName() + '/' + getRepoKey( session, repository );
}
private String getRepoKey( RepositorySystemSession session, RemoteRepository repository )
{
StringBuilder buffer = new StringBuilder( 128 );
Proxy proxy = repository.getProxy();
if ( proxy != null )
{
buffer.append( AuthenticationDigest.forProxy( session, repository ) ).append( '@' );
buffer.append( proxy.getHost() ).append( ':' ).append( proxy.getPort() ).append( '>' );
}
buffer.append( AuthenticationDigest.forRepository( session, repository ) ).append( '@' );
buffer.append( repository.getContentType() ).append( '-' );
buffer.append( repository.getId() ).append( '-' );
buffer.append( normalizeRepoUrl( repository.getUrl() ) );
return buffer.toString();
}
private String normalizeRepoUrl( String url )
{
String result = url;
if ( url != null && url.length() > 0 && !url.endsWith( "/" ) )
{
result = url + '/';
}
return result;
}
private String getUpdateKey( RepositorySystemSession session, File file, RemoteRepository repository )
{
return file.getAbsolutePath() + '|' + getRepoKey( session, repository );
}
private int getSessionState( RepositorySystemSession session )
{
String mode = ConfigUtils.getString( session, "true", CONFIG_PROP_SESSION_STATE );
if ( Boolean.parseBoolean( mode ) )
{
// perform update check at most once per session, regardless of update policy
return STATE_ENABLED;
}
else if ( "bypass".equalsIgnoreCase( mode ) )
{
// evaluate update policy but record update in session to prevent potential future checks
return STATE_BYPASS;
}
else
{
// no session state at all, always evaluate update policy
return STATE_DISABLED;
}
}
private boolean isAlreadyUpdated( RepositorySystemSession session, Object updateKey )
{
if ( getSessionState( session ) >= STATE_BYPASS )
{
return false;
}
SessionData data = session.getData();
Object checkedFiles = data.get( SESSION_CHECKS );
if ( !( checkedFiles instanceof Map ) )
{
return false;
}
return ( (Map, ?>) checkedFiles ).containsKey( updateKey );
}
@SuppressWarnings( "unchecked" )
private void setUpdated( RepositorySystemSession session, Object updateKey )
{
if ( getSessionState( session ) >= STATE_DISABLED )
{
return;
}
SessionData data = session.getData();
Object checkedFiles = data.get( SESSION_CHECKS );
while ( !( checkedFiles instanceof Map ) )
{
Object old = checkedFiles;
checkedFiles = new ConcurrentHashMap( 256 );
if ( data.set( SESSION_CHECKS, old, checkedFiles ) )
{
break;
}
checkedFiles = data.get( SESSION_CHECKS );
}
( (Map) checkedFiles ).put( updateKey, Boolean.TRUE );
}
private boolean isUpdatedRequired( RepositorySystemSession session, long lastModified, String policy )
{
return updatePolicyAnalyzer.isUpdatedRequired( session, lastModified, policy );
}
private Properties read( File touchFile )
{
Properties props = new TrackingFileManager().setLogger( logger ).read( touchFile );
return ( props != null ) ? props : new Properties();
}
public void touchArtifact( RepositorySystemSession session, UpdateCheck check )
{
Artifact artifact = check.getItem();
File artifactFile = check.getFile();
File touchFile = getTouchFile( artifact, artifactFile );
String updateKey = getUpdateKey( session, artifactFile, check.getRepository() );
String dataKey = getDataKey( artifact, artifactFile, check.getAuthoritativeRepository() );
String transferKey = getTransferKey( session, artifact, artifactFile, check.getRepository() );
setUpdated( session, updateKey );
Properties props = write( touchFile, dataKey, transferKey, check.getException() );
if ( artifactFile.exists() && !hasErrors( props ) )
{
touchFile.delete();
}
}
private boolean hasErrors( Properties props )
{
for ( Object key : props.keySet() )
{
if ( key.toString().endsWith( ERROR_KEY_SUFFIX ) )
{
return true;
}
}
return false;
}
public void touchMetadata( RepositorySystemSession session, UpdateCheck check )
{
Metadata metadata = check.getItem();
File metadataFile = check.getFile();
File touchFile = getTouchFile( metadata, metadataFile );
String updateKey = getUpdateKey( session, metadataFile, check.getRepository() );
String dataKey = getDataKey( metadata, metadataFile, check.getAuthoritativeRepository() );
String transferKey = getTransferKey( session, metadata, metadataFile, check.getRepository() );
setUpdated( session, updateKey );
write( touchFile, dataKey, transferKey, check.getException() );
}
private Properties write( File touchFile, String dataKey, String transferKey, Exception error )
{
Map updates = new HashMap();
String timestamp = Long.toString( System.currentTimeMillis() );
if ( error == null )
{
updates.put( dataKey + ERROR_KEY_SUFFIX, null );
updates.put( dataKey + UPDATED_KEY_SUFFIX, timestamp );
updates.put( transferKey + UPDATED_KEY_SUFFIX, null );
}
else if ( error instanceof ArtifactNotFoundException || error instanceof MetadataNotFoundException )
{
updates.put( dataKey + ERROR_KEY_SUFFIX, NOT_FOUND );
updates.put( dataKey + UPDATED_KEY_SUFFIX, timestamp );
updates.put( transferKey + UPDATED_KEY_SUFFIX, null );
}
else
{
String msg = error.getMessage();
if ( msg == null || msg.length() <= 0 )
{
msg = error.getClass().getSimpleName();
}
updates.put( dataKey + ERROR_KEY_SUFFIX, msg );
updates.put( dataKey + UPDATED_KEY_SUFFIX, null );
updates.put( transferKey + UPDATED_KEY_SUFFIX, timestamp );
}
return new TrackingFileManager().setLogger( logger ).update( touchFile, updates );
}
}