package org.apache.archiva.repository.metadata; /* * 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. */ import org.apache.archiva.checksum.ChecksumAlgorithm; import org.apache.archiva.checksum.ChecksummedFile; import org.apache.archiva.common.utils.PathUtil; import org.apache.archiva.common.utils.VersionComparator; import org.apache.archiva.common.utils.VersionUtil; import org.apache.archiva.configuration.ArchivaConfiguration; import org.apache.archiva.configuration.ConfigurationNames; import org.apache.archiva.configuration.FileTypes; import org.apache.archiva.configuration.ProxyConnectorConfiguration; import org.apache.archiva.maven2.metadata.MavenMetadataReader; import org.apache.archiva.model.ArchivaRepositoryMetadata; import org.apache.archiva.model.ArtifactReference; import org.apache.archiva.model.Plugin; import org.apache.archiva.model.ProjectReference; import org.apache.archiva.model.SnapshotVersion; import org.apache.archiva.model.VersionedReference; import org.apache.archiva.redback.components.registry.Registry; import org.apache.archiva.redback.components.registry.RegistryListener; import org.apache.archiva.repository.ContentNotFoundException; import org.apache.archiva.repository.ManagedRepositoryContent; import org.apache.archiva.repository.RemoteRepositoryContent; import org.apache.archiva.repository.layout.LayoutException; import org.apache.archiva.xml.XMLException; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.lang.time.DateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Named; import java.io.File; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; /** * MetadataTools * * */ @Service( "metadataTools#default" ) public class MetadataTools implements RegistryListener { private Logger log = LoggerFactory.getLogger( getClass() ); public static final String MAVEN_METADATA = "maven-metadata.xml"; public static final String MAVEN_ARCHETYPE_CATALOG ="archetype-catalog.xml"; private static final char PATH_SEPARATOR = '/'; private static final char GROUP_SEPARATOR = '.'; /** * */ @Inject @Named( value = "archivaConfiguration#default" ) private ArchivaConfiguration configuration; /** * */ @Inject @Named( value = "fileTypes" ) private FileTypes filetypes; private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 }; private List<String> artifactPatterns; private Map<String, Set<String>> proxies; private static final char NUMS[] = new char[]{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; private SimpleDateFormat lastUpdatedFormat; public MetadataTools() { lastUpdatedFormat = new SimpleDateFormat( "yyyyMMddHHmmss" ); lastUpdatedFormat.setTimeZone( DateUtils.UTC_TIME_ZONE ); } @Override public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue ) { if ( ConfigurationNames.isProxyConnector( propertyName ) ) { initConfigVariables(); } } @Override public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue ) { /* nothing to do */ } /** * Gather the set of snapshot versions found in a particular versioned reference. * * @return the Set of snapshot artifact versions found. * @throws LayoutException * @throws ContentNotFoundException */ public Set<String> gatherSnapshotVersions( ManagedRepositoryContent managedRepository, VersionedReference reference ) throws LayoutException, IOException, ContentNotFoundException { Set<String> foundVersions = managedRepository.getVersions( reference ); // Next gather up the referenced 'latest' versions found in any proxied repositories // maven-metadata-${proxyId}.xml files that may be present. // Does this repository have a set of remote proxied repositories? Set<String> proxiedRepoIds = this.proxies.get( managedRepository.getId() ); if ( CollectionUtils.isNotEmpty( proxiedRepoIds ) ) { String baseVersion = VersionUtil.getBaseVersion( reference.getVersion() ); baseVersion = baseVersion.substring( 0, baseVersion.indexOf( VersionUtil.SNAPSHOT ) - 1 ); // Add in the proxied repo version ids too. Iterator<String> it = proxiedRepoIds.iterator(); while ( it.hasNext() ) { String proxyId = it.next(); ArchivaRepositoryMetadata proxyMetadata = readProxyMetadata( managedRepository, reference, proxyId ); if ( proxyMetadata == null ) { // There is no proxy metadata, skip it. continue; } // Is there some snapshot info? SnapshotVersion snapshot = proxyMetadata.getSnapshotVersion(); if ( snapshot != null ) { String timestamp = snapshot.getTimestamp(); int buildNumber = snapshot.getBuildNumber(); // Only interested in the timestamp + buildnumber. if ( StringUtils.isNotBlank( timestamp ) && ( buildNumber > 0 ) ) { foundVersions.add( baseVersion + "-" + timestamp + "-" + buildNumber ); } } } } return foundVersions; } /** * Take a path to a maven-metadata.xml, and attempt to translate it to a VersionedReference. * * @param path * @return */ public VersionedReference toVersionedReference( String path ) throws RepositoryMetadataException { if ( !path.endsWith( "/" + MAVEN_METADATA ) ) { throw new RepositoryMetadataException( "Cannot convert to versioned reference, not a metadata file. " ); } VersionedReference reference = new VersionedReference(); String normalizedPath = StringUtils.replace( path, "\\", "/" ); String pathParts[] = StringUtils.split( normalizedPath, '/' ); int versionOffset = pathParts.length - 2; int artifactIdOffset = versionOffset - 1; int groupIdEnd = artifactIdOffset - 1; reference.setVersion( pathParts[versionOffset] ); if ( !hasNumberAnywhere( reference.getVersion() ) ) { // Scary check, but without it, all paths are version references; throw new RepositoryMetadataException( "Not a versioned reference, as version id on path has no number in it." ); } reference.setArtifactId( pathParts[artifactIdOffset] ); StringBuilder gid = new StringBuilder(); for ( int i = 0; i <= groupIdEnd; i++ ) { if ( i > 0 ) { gid.append( "." ); } gid.append( pathParts[i] ); } reference.setGroupId( gid.toString() ); return reference; } private boolean hasNumberAnywhere( String version ) { return StringUtils.indexOfAny( version, NUMS ) != ( -1 ); } public ProjectReference toProjectReference( String path ) throws RepositoryMetadataException { if ( !path.endsWith( "/" + MAVEN_METADATA ) ) { throw new RepositoryMetadataException( "Cannot convert to versioned reference, not a metadata file. " ); } ProjectReference reference = new ProjectReference(); String normalizedPath = StringUtils.replace( path, "\\", "/" ); String pathParts[] = StringUtils.split( normalizedPath, '/' ); // Assume last part of the path is the version. int artifactIdOffset = pathParts.length - 2; int groupIdEnd = artifactIdOffset - 1; reference.setArtifactId( pathParts[artifactIdOffset] ); StringBuilder gid = new StringBuilder(); for ( int i = 0; i <= groupIdEnd; i++ ) { if ( i > 0 ) { gid.append( "." ); } gid.append( pathParts[i] ); } reference.setGroupId( gid.toString() ); return reference; } public String toPath( ProjectReference reference ) { StringBuilder path = new StringBuilder(); path.append( formatAsDirectory( reference.getGroupId() ) ).append( PATH_SEPARATOR ); path.append( reference.getArtifactId() ).append( PATH_SEPARATOR ); path.append( MAVEN_METADATA ); return path.toString(); } public String toPath( VersionedReference reference ) { StringBuilder path = new StringBuilder(); path.append( formatAsDirectory( reference.getGroupId() ) ).append( PATH_SEPARATOR ); path.append( reference.getArtifactId() ).append( PATH_SEPARATOR ); if ( reference.getVersion() != null ) { // add the version only if it is present path.append( VersionUtil.getBaseVersion( reference.getVersion() ) ).append( PATH_SEPARATOR ); } path.append( MAVEN_METADATA ); return path.toString(); } private String formatAsDirectory( String directory ) { return directory.replace( GROUP_SEPARATOR, PATH_SEPARATOR ); } /** * Adjusts a path for a metadata.xml file to its repository specific path. * * @param repository the repository to base new path off of. * @param path the path to the metadata.xml file to adjust the name of. * @return the newly adjusted path reference to the repository specific metadata path. */ public String getRepositorySpecificName( RemoteRepositoryContent repository, String path ) { return getRepositorySpecificName( repository.getId(), path ); } /** * Adjusts a path for a metadata.xml file to its repository specific path. * * @param proxyId the repository id to base new path off of. * @param path the path to the metadata.xml file to adjust the name of. * @return the newly adjusted path reference to the repository specific metadata path. */ public String getRepositorySpecificName( String proxyId, String path ) { StringBuilder ret = new StringBuilder(); int idx = path.lastIndexOf( '/' ); if ( idx > 0 ) { ret.append( path.substring( 0, idx + 1 ) ); } // TODO: need to filter out 'bad' characters from the proxy id. ret.append( "maven-metadata-" ).append( proxyId ).append( ".xml" ); return ret.toString(); } @PostConstruct public void initialize() { this.artifactPatterns = new ArrayList<>(); this.proxies = new HashMap<>(); initConfigVariables(); configuration.addChangeListener( this ); } public ArchivaRepositoryMetadata readProxyMetadata( ManagedRepositoryContent managedRepository, ProjectReference reference, String proxyId ) { String metadataPath = getRepositorySpecificName( proxyId, toPath( reference ) ); File metadataFile = new File( managedRepository.getRepoRoot(), metadataPath ); if ( !metadataFile.exists() || !metadataFile.isFile() ) { // Nothing to do. return null. return null; } try { return MavenMetadataReader.read( metadataFile ); } catch ( XMLException e ) { // TODO: [monitor] consider a monitor for this event. // TODO: consider a read-redo on monitor return code? log.warn( "Unable to read metadata: {}", metadataFile.getAbsolutePath(), e ); return null; } } public ArchivaRepositoryMetadata readProxyMetadata( ManagedRepositoryContent managedRepository, String logicalResource, String proxyId ) { String metadataPath = getRepositorySpecificName( proxyId, logicalResource ); File metadataFile = new File( managedRepository.getRepoRoot(), metadataPath ); if ( !metadataFile.exists() || !metadataFile.isFile() ) { // Nothing to do. return null. return null; } try { return MavenMetadataReader.read( metadataFile ); } catch ( XMLException e ) { // TODO: [monitor] consider a monitor for this event. // TODO: consider a read-redo on monitor return code? log.warn( "Unable to read metadata: {}", metadataFile.getAbsolutePath(), e ); return null; } } public ArchivaRepositoryMetadata readProxyMetadata( ManagedRepositoryContent managedRepository, VersionedReference reference, String proxyId ) { String metadataPath = getRepositorySpecificName( proxyId, toPath( reference ) ); File metadataFile = new File( managedRepository.getRepoRoot(), metadataPath ); if ( !metadataFile.exists() || !metadataFile.isFile() ) { // Nothing to do. return null. return null; } try { return MavenMetadataReader.read( metadataFile ); } catch ( XMLException e ) { // TODO: [monitor] consider a monitor for this event. // TODO: consider a read-redo on monitor return code? log.warn( "Unable to read metadata: {}", metadataFile.getAbsolutePath(), e ); return null; } } public void updateMetadata( ManagedRepositoryContent managedRepository, String logicalResource ) throws RepositoryMetadataException { final File metadataFile = new File( managedRepository.getRepoRoot(), logicalResource ); ArchivaRepositoryMetadata metadata = null; //Gather and merge all metadata available List<ArchivaRepositoryMetadata> metadatas = getMetadatasForManagedRepository( managedRepository, logicalResource ); for ( ArchivaRepositoryMetadata proxiedMetadata : metadatas ) { if ( metadata == null ) { metadata = proxiedMetadata; continue; } metadata = RepositoryMetadataMerge.merge( metadata, proxiedMetadata ); } if ( metadata == null ) { log.debug( "No metadata to update for {}", logicalResource ); return; } Set<String> availableVersions = new HashSet<String>(); List<String> metadataAvailableVersions = metadata.getAvailableVersions(); if ( metadataAvailableVersions != null ) { availableVersions.addAll( metadataAvailableVersions ); } availableVersions = findPossibleVersions( availableVersions, metadataFile.getParentFile() ); if ( availableVersions.size() > 0 ) { updateMetadataVersions( availableVersions, metadata ); } RepositoryMetadataWriter.write( metadata, metadataFile ); ChecksummedFile checksum = new ChecksummedFile( metadataFile ); checksum.fixChecksums( algorithms ); } /** * Skims the parent directory of a metadata in vain hope of finding * subdirectories that contain poms. * * @param metadataParentDirectory * @return origional set plus newley found versions */ private Set<String> findPossibleVersions( Set<String> versions, File metadataParentDirectory ) { Set<String> result = new HashSet<String>( versions ); for ( File directory : metadataParentDirectory.listFiles() ) { if ( directory.isDirectory() ) { for ( File possiblePom : directory.listFiles() ) { if ( possiblePom.getName().endsWith( ".pom" ) ) { result.add( directory.getName() ); } } } } return result; } private List<ArchivaRepositoryMetadata> getMetadatasForManagedRepository( ManagedRepositoryContent managedRepository, String logicalResource ) { List<ArchivaRepositoryMetadata> metadatas = new ArrayList<>(); File file = new File( managedRepository.getRepoRoot(), logicalResource ); if ( file.exists() ) { try { ArchivaRepositoryMetadata existingMetadata = MavenMetadataReader.read( file ); if ( existingMetadata != null ) { metadatas.add( existingMetadata ); } } catch ( XMLException e ) { log.debug( "Could not read metadata at {}. Metadata will be removed.", file.getAbsolutePath() ); FileUtils.deleteQuietly( file ); } } Set<String> proxyIds = proxies.get( managedRepository.getId() ); if ( proxyIds != null ) { for ( String proxyId : proxyIds ) { ArchivaRepositoryMetadata proxyMetadata = readProxyMetadata( managedRepository, logicalResource, proxyId ); if ( proxyMetadata != null ) { metadatas.add( proxyMetadata ); } } } return metadatas; } /** * Update the metadata to represent the all versions/plugins of * the provided groupId:artifactId project or group reference, * based off of information present in the repository, * the maven-metadata.xml files, and the proxy/repository specific * metadata file contents. * <p> * We must treat this as a group or a project metadata file as there is no way to know in advance * * @param managedRepository the managed repository where the metadata is kept. * @param reference the reference to update. * @throws LayoutException * @throws RepositoryMetadataException * @throws IOException * @throws ContentNotFoundException * @deprecated */ public void updateMetadata( ManagedRepositoryContent managedRepository, ProjectReference reference ) throws LayoutException, RepositoryMetadataException, IOException, ContentNotFoundException { File metadataFile = new File( managedRepository.getRepoRoot(), toPath( reference ) ); long lastUpdated = getExistingLastUpdated( metadataFile ); ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata(); metadata.setGroupId( reference.getGroupId() ); metadata.setArtifactId( reference.getArtifactId() ); // Gather up all versions found in the managed repository. Set<String> allVersions = managedRepository.getVersions( reference ); // Gather up all plugins found in the managed repository. // TODO: do we know this information instead? // Set<Plugin> allPlugins = managedRepository.getPlugins( reference ); Set<Plugin> allPlugins; if ( metadataFile.exists() ) { try { allPlugins = new LinkedHashSet<Plugin>( MavenMetadataReader.read( metadataFile ).getPlugins() ); } catch ( XMLException e ) { throw new RepositoryMetadataException( e.getMessage(), e ); } } else { allPlugins = new LinkedHashSet<Plugin>(); } // Does this repository have a set of remote proxied repositories? Set<String> proxiedRepoIds = this.proxies.get( managedRepository.getId() ); if ( CollectionUtils.isNotEmpty( proxiedRepoIds ) ) { // Add in the proxied repo version ids too. Iterator<String> it = proxiedRepoIds.iterator(); while ( it.hasNext() ) { String proxyId = it.next(); ArchivaRepositoryMetadata proxyMetadata = readProxyMetadata( managedRepository, reference, proxyId ); if ( proxyMetadata != null ) { allVersions.addAll( proxyMetadata.getAvailableVersions() ); allPlugins.addAll( proxyMetadata.getPlugins() ); long proxyLastUpdated = getLastUpdated( proxyMetadata ); lastUpdated = Math.max( lastUpdated, proxyLastUpdated ); } } } if ( !allVersions.isEmpty() ) { updateMetadataVersions( allVersions, metadata ); } else { // Add the plugins to the metadata model. metadata.setPlugins( new ArrayList<>( allPlugins ) ); // artifact ID was actually the last part of the group metadata.setGroupId( metadata.getGroupId() + "." + metadata.getArtifactId() ); metadata.setArtifactId( null ); } if ( lastUpdated > 0 ) { metadata.setLastUpdatedTimestamp( toLastUpdatedDate( lastUpdated ) ); } // Save the metadata model to disk. RepositoryMetadataWriter.write( metadata, metadataFile ); ChecksummedFile checksum = new ChecksummedFile( metadataFile ); checksum.fixChecksums( algorithms ); } private void updateMetadataVersions( Collection<String> allVersions, ArchivaRepositoryMetadata metadata ) { // Sort the versions List<String> sortedVersions = new ArrayList<>( allVersions ); Collections.sort( sortedVersions, VersionComparator.getInstance() ); // Split the versions into released and snapshots. List<String> releasedVersions = new ArrayList<>(); List<String> snapshotVersions = new ArrayList<>(); for ( String version : sortedVersions ) { if ( VersionUtil.isSnapshot( version ) ) { snapshotVersions.add( version ); } else { releasedVersions.add( version ); } } Collections.sort( releasedVersions, VersionComparator.getInstance() ); Collections.sort( snapshotVersions, VersionComparator.getInstance() ); String latestVersion = sortedVersions.get( sortedVersions.size() - 1 ); String releaseVersion = null; if ( CollectionUtils.isNotEmpty( releasedVersions ) ) { releaseVersion = releasedVersions.get( releasedVersions.size() - 1 ); } // Add the versions to the metadata model. metadata.setAvailableVersions( sortedVersions ); metadata.setLatestVersion( latestVersion ); metadata.setReleasedVersion( releaseVersion ); } private Date toLastUpdatedDate( long lastUpdated ) { Calendar cal = Calendar.getInstance( DateUtils.UTC_TIME_ZONE ); cal.setTimeInMillis( lastUpdated ); return cal.getTime(); } private long toLastUpdatedLong( String timestampString ) { try { Date date = lastUpdatedFormat.parse( timestampString ); Calendar cal = Calendar.getInstance( DateUtils.UTC_TIME_ZONE ); cal.setTime( date ); return cal.getTimeInMillis(); } catch ( ParseException e ) { return 0; } } private long getLastUpdated( ArchivaRepositoryMetadata metadata ) { if ( metadata == null ) { // Doesn't exist. return 0; } try { String lastUpdated = metadata.getLastUpdated(); if ( StringUtils.isBlank( lastUpdated ) ) { // Not set. return 0; } Date lastUpdatedDate = lastUpdatedFormat.parse( lastUpdated ); return lastUpdatedDate.getTime(); } catch ( ParseException e ) { // Bad format on the last updated string. return 0; } } private long getExistingLastUpdated( File metadataFile ) { if ( !metadataFile.exists() ) { // Doesn't exist. return 0; } try { ArchivaRepositoryMetadata metadata = MavenMetadataReader.read( metadataFile ); return getLastUpdated( metadata ); } catch ( XMLException e ) { // Error. return 0; } } /** * Update the metadata based on the following rules. * <p> * 1) If this is a SNAPSHOT reference, then utilize the proxy/repository specific * metadata files to represent the current / latest SNAPSHOT available. * 2) If this is a RELEASE reference, and the metadata file does not exist, then * create the metadata file with contents required of the VersionedReference * * @param managedRepository the managed repository where the metadata is kept. * @param reference the versioned reference to update * @throws LayoutException * @throws RepositoryMetadataException * @throws IOException * @throws ContentNotFoundException * @deprecated */ public void updateMetadata( ManagedRepositoryContent managedRepository, VersionedReference reference ) throws LayoutException, RepositoryMetadataException, IOException, ContentNotFoundException { File metadataFile = new File( managedRepository.getRepoRoot(), toPath( reference ) ); long lastUpdated = getExistingLastUpdated( metadataFile ); ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata(); metadata.setGroupId( reference.getGroupId() ); metadata.setArtifactId( reference.getArtifactId() ); if ( VersionUtil.isSnapshot( reference.getVersion() ) ) { // Do SNAPSHOT handling. metadata.setVersion( VersionUtil.getBaseVersion( reference.getVersion() ) ); // Gather up all of the versions found in the reference dir, and any // proxied maven-metadata.xml files. Set<String> snapshotVersions = gatherSnapshotVersions( managedRepository, reference ); if ( snapshotVersions.isEmpty() ) { throw new ContentNotFoundException( "No snapshot versions found on reference [" + VersionedReference.toKey( reference ) + "]." ); } // sort the list to determine to aide in determining the Latest version. List<String> sortedVersions = new ArrayList<>(); sortedVersions.addAll( snapshotVersions ); Collections.sort( sortedVersions, new VersionComparator() ); String latestVersion = sortedVersions.get( sortedVersions.size() - 1 ); if ( VersionUtil.isUniqueSnapshot( latestVersion ) ) { // The latestVersion will contain the full version string "1.0-alpha-5-20070821.213044-8" // This needs to be broken down into ${base}-${timestamp}-${build_number} Matcher m = VersionUtil.UNIQUE_SNAPSHOT_PATTERN.matcher( latestVersion ); if ( m.matches() ) { metadata.setSnapshotVersion( new SnapshotVersion() ); int buildNumber = NumberUtils.toInt( m.group( 3 ), -1 ); metadata.getSnapshotVersion().setBuildNumber( buildNumber ); Matcher mtimestamp = VersionUtil.TIMESTAMP_PATTERN.matcher( m.group( 2 ) ); if ( mtimestamp.matches() ) { String tsDate = mtimestamp.group( 1 ); String tsTime = mtimestamp.group( 2 ); long snapshotLastUpdated = toLastUpdatedLong( tsDate + tsTime ); lastUpdated = Math.max( lastUpdated, snapshotLastUpdated ); metadata.getSnapshotVersion().setTimestamp( m.group( 2 ) ); } } } else if ( VersionUtil.isGenericSnapshot( latestVersion ) ) { // The latestVersion ends with the generic version string. // Example: 1.0-alpha-5-SNAPSHOT metadata.setSnapshotVersion( new SnapshotVersion() ); /* Disabled due to decision in [MRM-535]. * Do not set metadata.lastUpdated to file.lastModified. * * Should this be the last updated timestamp of the file, or in the case of an * archive, the most recent timestamp in the archive? * ArtifactReference artifact = getFirstArtifact( managedRepository, reference ); if ( artifact == null ) { throw new IOException( "Not snapshot artifact found to reference in " + reference ); } File artifactFile = managedRepository.toFile( artifact ); if ( artifactFile.exists() ) { Date lastModified = new Date( artifactFile.lastModified() ); metadata.setLastUpdatedTimestamp( lastModified ); } */ } else { throw new RepositoryMetadataException( "Unable to process snapshot version <" + latestVersion + "> reference <" + reference + ">" ); } } else { // Do RELEASE handling. metadata.setVersion( reference.getVersion() ); } // Set last updated if ( lastUpdated > 0 ) { metadata.setLastUpdatedTimestamp( toLastUpdatedDate( lastUpdated ) ); } // Save the metadata model to disk. RepositoryMetadataWriter.write( metadata, metadataFile ); ChecksummedFile checksum = new ChecksummedFile( metadataFile ); checksum.fixChecksums( algorithms ); } private void initConfigVariables() { synchronized ( this.artifactPatterns ) { this.artifactPatterns.clear(); this.artifactPatterns.addAll( filetypes.getFileTypePatterns( FileTypes.ARTIFACTS ) ); } synchronized ( proxies ) { this.proxies.clear(); List<ProxyConnectorConfiguration> proxyConfigs = configuration.getConfiguration().getProxyConnectors(); for ( ProxyConnectorConfiguration proxyConfig : proxyConfigs ) { String key = proxyConfig.getSourceRepoId(); Set<String> remoteRepoIds = this.proxies.get( key ); if ( remoteRepoIds == null ) { remoteRepoIds = new HashSet<String>(); } remoteRepoIds.add( proxyConfig.getTargetRepoId() ); this.proxies.put( key, remoteRepoIds ); } } } /** * Get the first Artifact found in the provided VersionedReference location. * * @param managedRepository the repository to search within. * @param reference the reference to the versioned reference to search within * @return the ArtifactReference to the first artifact located within the versioned reference. or null if * no artifact was found within the versioned reference. * @throws IOException if the versioned reference is invalid (example: doesn't exist, or isn't a directory) * @throws LayoutException */ public ArtifactReference getFirstArtifact( ManagedRepositoryContent managedRepository, VersionedReference reference ) throws LayoutException, IOException { String path = toPath( reference ); int idx = path.lastIndexOf( '/' ); if ( idx > 0 ) { path = path.substring( 0, idx ); } File repoDir = new File( managedRepository.getRepoRoot(), path ); if ( !repoDir.exists() ) { throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: " + repoDir.getAbsolutePath() ); } if ( !repoDir.isDirectory() ) { throw new IOException( "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.getAbsolutePath() ); } File repoFiles[] = repoDir.listFiles(); for ( int i = 0; i < repoFiles.length; i++ ) { if ( repoFiles[i].isDirectory() ) { // Skip it. it's a directory. continue; } String relativePath = PathUtil.getRelative( managedRepository.getRepoRoot(), repoFiles[i] ); if ( filetypes.matchesArtifactPattern( relativePath ) ) { ArtifactReference artifact = managedRepository.toArtifactReference( relativePath ); return artifact; } } // No artifact was found. return null; } public ArchivaConfiguration getConfiguration() { return configuration; } public void setConfiguration( ArchivaConfiguration configuration ) { this.configuration = configuration; } public FileTypes getFiletypes() { return filetypes; } public void setFiletypes( FileTypes filetypes ) { this.filetypes = filetypes; } }