1 package org.apache.archiva.repository.metadata;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import org.apache.archiva.checksum.ChecksumAlgorithm;
23 import org.apache.archiva.checksum.ChecksummedFile;
24 import org.apache.archiva.common.utils.PathUtil;
25 import org.apache.archiva.common.utils.VersionComparator;
26 import org.apache.archiva.common.utils.VersionUtil;
27 import org.apache.archiva.configuration.ArchivaConfiguration;
28 import org.apache.archiva.configuration.ConfigurationNames;
29 import org.apache.archiva.configuration.FileTypes;
30 import org.apache.archiva.configuration.ProxyConnectorConfiguration;
31 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
32 import org.apache.archiva.model.ArchivaRepositoryMetadata;
33 import org.apache.archiva.model.ArtifactReference;
34 import org.apache.archiva.model.Plugin;
35 import org.apache.archiva.model.ProjectReference;
36 import org.apache.archiva.model.SnapshotVersion;
37 import org.apache.archiva.model.VersionedReference;
38 import org.apache.archiva.redback.components.registry.Registry;
39 import org.apache.archiva.redback.components.registry.RegistryListener;
40 import org.apache.archiva.repository.ContentNotFoundException;
41 import org.apache.archiva.repository.ManagedRepositoryContent;
42 import org.apache.archiva.repository.RemoteRepositoryContent;
43 import org.apache.archiva.repository.layout.LayoutException;
44 import org.apache.archiva.xml.XMLException;
45 import org.apache.commons.collections.CollectionUtils;
46 import org.apache.commons.io.FileUtils;
47 import org.apache.commons.lang.StringUtils;
48 import org.apache.commons.lang.math.NumberUtils;
49 import org.apache.commons.lang.time.DateUtils;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52 import org.springframework.stereotype.Service;
54 import javax.annotation.PostConstruct;
55 import javax.inject.Inject;
56 import javax.inject.Named;
58 import java.io.IOException;
59 import java.text.ParseException;
60 import java.text.SimpleDateFormat;
61 import java.util.ArrayList;
62 import java.util.Calendar;
63 import java.util.Collection;
64 import java.util.Collections;
65 import java.util.Date;
66 import java.util.HashMap;
67 import java.util.HashSet;
68 import java.util.Iterator;
69 import java.util.LinkedHashSet;
70 import java.util.List;
73 import java.util.regex.Matcher;
80 @Service( "metadataTools#default" )
81 public class MetadataTools
82 implements RegistryListener
84 private Logger log = LoggerFactory.getLogger( getClass() );
86 public static final String MAVEN_METADATA = "maven-metadata.xml";
88 public static final String MAVEN_ARCHETYPE_CATALOG ="archetype-catalog.xml";
90 private static final char PATH_SEPARATOR = '/';
92 private static final char GROUP_SEPARATOR = '.';
98 @Named( value = "archivaConfiguration#default" )
99 private ArchivaConfiguration configuration;
105 @Named( value = "fileTypes" )
106 private FileTypes filetypes;
108 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
110 private List<String> artifactPatterns;
112 private Map<String, Set<String>> proxies;
114 private static final char NUMS[] = new char[]{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
116 private SimpleDateFormat lastUpdatedFormat;
118 public MetadataTools()
120 lastUpdatedFormat = new SimpleDateFormat( "yyyyMMddHHmmss" );
121 lastUpdatedFormat.setTimeZone( DateUtils.UTC_TIME_ZONE );
124 public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
126 if ( ConfigurationNames.isProxyConnector( propertyName ) )
128 initConfigVariables();
132 public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
138 * Gather the set of snapshot versions found in a particular versioned reference.
140 * @return the Set of snapshot artifact versions found.
141 * @throws LayoutException
142 * @throws ContentNotFoundException
144 public Set<String> gatherSnapshotVersions( ManagedRepositoryContent managedRepository,
145 VersionedReference reference )
146 throws LayoutException, IOException, ContentNotFoundException
148 Set<String> foundVersions = managedRepository.getVersions( reference );
150 // Next gather up the referenced 'latest' versions found in any proxied repositories
151 // maven-metadata-${proxyId}.xml files that may be present.
153 // Does this repository have a set of remote proxied repositories?
154 Set<String> proxiedRepoIds = this.proxies.get( managedRepository.getId() );
156 if ( CollectionUtils.isNotEmpty( proxiedRepoIds ) )
158 String baseVersion = VersionUtil.getBaseVersion( reference.getVersion() );
159 baseVersion = baseVersion.substring( 0, baseVersion.indexOf( VersionUtil.SNAPSHOT ) - 1 );
161 // Add in the proxied repo version ids too.
162 Iterator<String> it = proxiedRepoIds.iterator();
163 while ( it.hasNext() )
165 String proxyId = it.next();
167 ArchivaRepositoryMetadata proxyMetadata = readProxyMetadata( managedRepository, reference, proxyId );
168 if ( proxyMetadata == null )
170 // There is no proxy metadata, skip it.
174 // Is there some snapshot info?
175 SnapshotVersion snapshot = proxyMetadata.getSnapshotVersion();
176 if ( snapshot != null )
178 String timestamp = snapshot.getTimestamp();
179 int buildNumber = snapshot.getBuildNumber();
181 // Only interested in the timestamp + buildnumber.
182 if ( StringUtils.isNotBlank( timestamp ) && ( buildNumber > 0 ) )
184 foundVersions.add( baseVersion + "-" + timestamp + "-" + buildNumber );
190 return foundVersions;
194 * Take a path to a maven-metadata.xml, and attempt to translate it to a VersionedReference.
199 public VersionedReference toVersionedReference( String path )
200 throws RepositoryMetadataException
202 if ( !path.endsWith( "/" + MAVEN_METADATA ) )
204 throw new RepositoryMetadataException( "Cannot convert to versioned reference, not a metadata file. " );
207 VersionedReference reference = new VersionedReference();
209 String normalizedPath = StringUtils.replace( path, "\\", "/" );
210 String pathParts[] = StringUtils.split( normalizedPath, '/' );
212 int versionOffset = pathParts.length - 2;
213 int artifactIdOffset = versionOffset - 1;
214 int groupIdEnd = artifactIdOffset - 1;
216 reference.setVersion( pathParts[versionOffset] );
218 if ( !hasNumberAnywhere( reference.getVersion() ) )
220 // Scary check, but without it, all paths are version references;
221 throw new RepositoryMetadataException(
222 "Not a versioned reference, as version id on path has no number in it." );
225 reference.setArtifactId( pathParts[artifactIdOffset] );
227 StringBuilder gid = new StringBuilder();
228 for ( int i = 0; i <= groupIdEnd; i++ )
234 gid.append( pathParts[i] );
237 reference.setGroupId( gid.toString() );
242 private boolean hasNumberAnywhere( String version )
244 return StringUtils.indexOfAny( version, NUMS ) != ( -1 );
247 public ProjectReference toProjectReference( String path )
248 throws RepositoryMetadataException
250 if ( !path.endsWith( "/" + MAVEN_METADATA ) )
252 throw new RepositoryMetadataException( "Cannot convert to versioned reference, not a metadata file. " );
255 ProjectReference reference = new ProjectReference();
257 String normalizedPath = StringUtils.replace( path, "\\", "/" );
258 String pathParts[] = StringUtils.split( normalizedPath, '/' );
260 // Assume last part of the path is the version.
262 int artifactIdOffset = pathParts.length - 2;
263 int groupIdEnd = artifactIdOffset - 1;
265 reference.setArtifactId( pathParts[artifactIdOffset] );
267 StringBuilder gid = new StringBuilder();
268 for ( int i = 0; i <= groupIdEnd; i++ )
274 gid.append( pathParts[i] );
277 reference.setGroupId( gid.toString() );
282 public String toPath( ProjectReference reference )
284 StringBuilder path = new StringBuilder();
286 path.append( formatAsDirectory( reference.getGroupId() ) ).append( PATH_SEPARATOR );
287 path.append( reference.getArtifactId() ).append( PATH_SEPARATOR );
288 path.append( MAVEN_METADATA );
290 return path.toString();
293 public String toPath( VersionedReference reference )
295 StringBuilder path = new StringBuilder();
297 path.append( formatAsDirectory( reference.getGroupId() ) ).append( PATH_SEPARATOR );
298 path.append( reference.getArtifactId() ).append( PATH_SEPARATOR );
299 if ( reference.getVersion() != null )
301 // add the version only if it is present
302 path.append( VersionUtil.getBaseVersion( reference.getVersion() ) ).append( PATH_SEPARATOR );
304 path.append( MAVEN_METADATA );
306 return path.toString();
309 private String formatAsDirectory( String directory )
311 return directory.replace( GROUP_SEPARATOR, PATH_SEPARATOR );
315 * Adjusts a path for a metadata.xml file to its repository specific path.
317 * @param repository the repository to base new path off of.
318 * @param path the path to the metadata.xml file to adjust the name of.
319 * @return the newly adjusted path reference to the repository specific metadata path.
321 public String getRepositorySpecificName( RemoteRepositoryContent repository, String path )
323 return getRepositorySpecificName( repository.getId(), path );
327 * Adjusts a path for a metadata.xml file to its repository specific path.
329 * @param proxyId the repository id to base new path off of.
330 * @param path the path to the metadata.xml file to adjust the name of.
331 * @return the newly adjusted path reference to the repository specific metadata path.
333 public String getRepositorySpecificName( String proxyId, String path )
335 StringBuilder ret = new StringBuilder();
337 int idx = path.lastIndexOf( "/" );
340 ret.append( path.substring( 0, idx + 1 ) );
343 // TODO: need to filter out 'bad' characters from the proxy id.
344 ret.append( "maven-metadata-" ).append( proxyId ).append( ".xml" );
346 return ret.toString();
350 public void initialize()
352 this.artifactPatterns = new ArrayList<String>();
353 this.proxies = new HashMap<String, Set<String>>();
354 initConfigVariables();
356 configuration.addChangeListener( this );
359 public ArchivaRepositoryMetadata readProxyMetadata( ManagedRepositoryContent managedRepository,
360 ProjectReference reference, String proxyId )
362 String metadataPath = getRepositorySpecificName( proxyId, toPath( reference ) );
363 File metadataFile = new File( managedRepository.getRepoRoot(), metadataPath );
365 if ( !metadataFile.exists() || !metadataFile.isFile() )
367 // Nothing to do. return null.
373 return MavenMetadataReader.read( metadataFile );
375 catch ( XMLException e )
377 // TODO: [monitor] consider a monitor for this event.
378 // TODO: consider a read-redo on monitor return code?
379 log.warn( "Unable to read metadata: " + metadataFile.getAbsolutePath(), e );
384 public ArchivaRepositoryMetadata readProxyMetadata( ManagedRepositoryContent managedRepository,
385 String logicalResource, String proxyId )
387 String metadataPath = getRepositorySpecificName( proxyId, logicalResource );
388 File metadataFile = new File( managedRepository.getRepoRoot(), metadataPath );
390 if ( !metadataFile.exists() || !metadataFile.isFile() )
392 // Nothing to do. return null.
398 return MavenMetadataReader.read( metadataFile );
400 catch ( XMLException e )
402 // TODO: [monitor] consider a monitor for this event.
403 // TODO: consider a read-redo on monitor return code?
404 log.warn( "Unable to read metadata: " + metadataFile.getAbsolutePath(), e );
409 public ArchivaRepositoryMetadata readProxyMetadata( ManagedRepositoryContent managedRepository,
410 VersionedReference reference, String proxyId )
412 String metadataPath = getRepositorySpecificName( proxyId, toPath( reference ) );
413 File metadataFile = new File( managedRepository.getRepoRoot(), metadataPath );
415 if ( !metadataFile.exists() || !metadataFile.isFile() )
417 // Nothing to do. return null.
423 return MavenMetadataReader.read( metadataFile );
425 catch ( XMLException e )
427 // TODO: [monitor] consider a monitor for this event.
428 // TODO: consider a read-redo on monitor return code?
429 log.warn( "Unable to read metadata: " + metadataFile.getAbsolutePath(), e );
434 public void updateMetadata( ManagedRepositoryContent managedRepository, String logicalResource )
435 throws RepositoryMetadataException
437 final File metadataFile = new File( managedRepository.getRepoRoot(), logicalResource );
438 ArchivaRepositoryMetadata metadata = null;
440 //Gather and merge all metadata available
441 List<ArchivaRepositoryMetadata> metadatas =
442 getMetadatasForManagedRepository( managedRepository, logicalResource );
443 for ( ArchivaRepositoryMetadata proxiedMetadata : metadatas )
445 if ( metadata == null )
447 metadata = proxiedMetadata;
450 metadata = RepositoryMetadataMerge.merge( metadata, proxiedMetadata );
453 if ( metadata == null )
455 log.debug( "No metadata to update for {}", logicalResource );
459 Set<String> availableVersions = new HashSet<String>();
460 List<String> metadataAvailableVersions = metadata.getAvailableVersions();
461 if ( metadataAvailableVersions != null )
463 availableVersions.addAll( metadataAvailableVersions );
465 availableVersions = findPossibleVersions( availableVersions, metadataFile.getParentFile() );
467 if ( availableVersions.size() > 0 )
469 updateMetadataVersions( availableVersions, metadata );
472 RepositoryMetadataWriter.write( metadata, metadataFile );
474 ChecksummedFile checksum = new ChecksummedFile( metadataFile );
475 checksum.fixChecksums( algorithms );
479 * Skims the parent directory of a metadata in vain hope of finding
480 * subdirectories that contain poms.
482 * @param metadataParentDirectory
483 * @return origional set plus newley found versions
485 private Set<String> findPossibleVersions( Set<String> versions, File metadataParentDirectory )
487 Set<String> result = new HashSet<String>( versions );
488 for ( File directory : metadataParentDirectory.listFiles() )
490 if ( directory.isDirectory() )
492 for ( File possiblePom : directory.listFiles() )
494 if ( possiblePom.getName().endsWith( ".pom" ) )
496 result.add( directory.getName() );
504 private List<ArchivaRepositoryMetadata> getMetadatasForManagedRepository(
505 ManagedRepositoryContent managedRepository, String logicalResource )
507 List<ArchivaRepositoryMetadata> metadatas = new ArrayList<ArchivaRepositoryMetadata>();
508 File file = new File( managedRepository.getRepoRoot(), logicalResource );
513 ArchivaRepositoryMetadata existingMetadata = MavenMetadataReader.read( file );
514 if ( existingMetadata != null )
516 metadatas.add( existingMetadata );
519 catch ( XMLException e )
521 log.debug( "Could not read metadata at {}. Metadata will be removed.", file.getAbsolutePath() );
522 FileUtils.deleteQuietly( file );
526 Set<String> proxyIds = proxies.get( managedRepository.getId() );
527 if ( proxyIds != null )
529 for ( String proxyId : proxyIds )
531 ArchivaRepositoryMetadata proxyMetadata =
532 readProxyMetadata( managedRepository, logicalResource, proxyId );
533 if ( proxyMetadata != null )
535 metadatas.add( proxyMetadata );
545 * Update the metadata to represent the all versions/plugins of
546 * the provided groupId:artifactId project or group reference,
547 * based off of information present in the repository,
548 * the maven-metadata.xml files, and the proxy/repository specific
549 * metadata file contents.
551 * We must treat this as a group or a project metadata file as there is no way to know in advance
553 * @param managedRepository the managed repository where the metadata is kept.
554 * @param reference the reference to update.
555 * @throws LayoutException
556 * @throws RepositoryMetadataException
557 * @throws IOException
558 * @throws ContentNotFoundException
561 public void updateMetadata( ManagedRepositoryContent managedRepository, ProjectReference reference )
562 throws LayoutException, RepositoryMetadataException, IOException, ContentNotFoundException
564 File metadataFile = new File( managedRepository.getRepoRoot(), toPath( reference ) );
566 long lastUpdated = getExistingLastUpdated( metadataFile );
568 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
569 metadata.setGroupId( reference.getGroupId() );
570 metadata.setArtifactId( reference.getArtifactId() );
572 // Gather up all versions found in the managed repository.
573 Set<String> allVersions = managedRepository.getVersions( reference );
575 // Gather up all plugins found in the managed repository.
576 // TODO: do we know this information instead?
577 // Set<Plugin> allPlugins = managedRepository.getPlugins( reference );
578 Set<Plugin> allPlugins;
579 if ( metadataFile.exists() )
583 allPlugins = new LinkedHashSet<Plugin>( MavenMetadataReader.read( metadataFile ).getPlugins() );
585 catch ( XMLException e )
587 throw new RepositoryMetadataException( e.getMessage(), e );
592 allPlugins = new LinkedHashSet<Plugin>();
595 // Does this repository have a set of remote proxied repositories?
596 Set<String> proxiedRepoIds = this.proxies.get( managedRepository.getId() );
598 if ( CollectionUtils.isNotEmpty( proxiedRepoIds ) )
600 // Add in the proxied repo version ids too.
601 Iterator<String> it = proxiedRepoIds.iterator();
602 while ( it.hasNext() )
604 String proxyId = it.next();
606 ArchivaRepositoryMetadata proxyMetadata = readProxyMetadata( managedRepository, reference, proxyId );
607 if ( proxyMetadata != null )
609 allVersions.addAll( proxyMetadata.getAvailableVersions() );
610 allPlugins.addAll( proxyMetadata.getPlugins() );
611 long proxyLastUpdated = getLastUpdated( proxyMetadata );
613 lastUpdated = Math.max( lastUpdated, proxyLastUpdated );
618 if ( !allVersions.isEmpty() )
620 updateMetadataVersions( allVersions, metadata );
624 // Add the plugins to the metadata model.
625 metadata.setPlugins( new ArrayList<Plugin>( allPlugins ) );
627 // artifact ID was actually the last part of the group
628 metadata.setGroupId( metadata.getGroupId() + "." + metadata.getArtifactId() );
629 metadata.setArtifactId( null );
632 if ( lastUpdated > 0 )
634 metadata.setLastUpdatedTimestamp( toLastUpdatedDate( lastUpdated ) );
637 // Save the metadata model to disk.
638 RepositoryMetadataWriter.write( metadata, metadataFile );
639 ChecksummedFile checksum = new ChecksummedFile( metadataFile );
640 checksum.fixChecksums( algorithms );
643 private void updateMetadataVersions( Collection<String> allVersions, ArchivaRepositoryMetadata metadata )
646 List<String> sortedVersions = new ArrayList<String>( allVersions );
647 Collections.sort( sortedVersions, VersionComparator.getInstance() );
649 // Split the versions into released and snapshots.
650 List<String> releasedVersions = new ArrayList<String>();
651 List<String> snapshotVersions = new ArrayList<String>();
653 for ( String version : sortedVersions )
655 if ( VersionUtil.isSnapshot( version ) )
657 snapshotVersions.add( version );
661 releasedVersions.add( version );
665 Collections.sort( releasedVersions, VersionComparator.getInstance() );
666 Collections.sort( snapshotVersions, VersionComparator.getInstance() );
668 String latestVersion = sortedVersions.get( sortedVersions.size() - 1 );
669 String releaseVersion = null;
671 if ( CollectionUtils.isNotEmpty( releasedVersions ) )
673 releaseVersion = releasedVersions.get( releasedVersions.size() - 1 );
676 // Add the versions to the metadata model.
677 metadata.setAvailableVersions( sortedVersions );
679 metadata.setLatestVersion( latestVersion );
680 metadata.setReleasedVersion( releaseVersion );
683 private Date toLastUpdatedDate( long lastUpdated )
685 Calendar cal = Calendar.getInstance( DateUtils.UTC_TIME_ZONE );
686 cal.setTimeInMillis( lastUpdated );
688 return cal.getTime();
691 private long toLastUpdatedLong( String timestampString )
695 Date date = lastUpdatedFormat.parse( timestampString );
696 Calendar cal = Calendar.getInstance( DateUtils.UTC_TIME_ZONE );
699 return cal.getTimeInMillis();
701 catch ( ParseException e )
707 private long getLastUpdated( ArchivaRepositoryMetadata metadata )
709 if ( metadata == null )
717 String lastUpdated = metadata.getLastUpdated();
718 if ( StringUtils.isBlank( lastUpdated ) )
724 Date lastUpdatedDate = lastUpdatedFormat.parse( lastUpdated );
725 return lastUpdatedDate.getTime();
727 catch ( ParseException e )
729 // Bad format on the last updated string.
734 private long getExistingLastUpdated( File metadataFile )
736 if ( !metadataFile.exists() )
744 ArchivaRepositoryMetadata metadata = MavenMetadataReader.read( metadataFile );
746 return getLastUpdated( metadata );
748 catch ( XMLException e )
756 * Update the metadata based on the following rules.
758 * 1) If this is a SNAPSHOT reference, then utilize the proxy/repository specific
759 * metadata files to represent the current / latest SNAPSHOT available.
760 * 2) If this is a RELEASE reference, and the metadata file does not exist, then
761 * create the metadata file with contents required of the VersionedReference
763 * @param managedRepository the managed repository where the metadata is kept.
764 * @param reference the versioned reference to update
765 * @throws LayoutException
766 * @throws RepositoryMetadataException
767 * @throws IOException
768 * @throws ContentNotFoundException
771 public void updateMetadata( ManagedRepositoryContent managedRepository, VersionedReference reference )
772 throws LayoutException, RepositoryMetadataException, IOException, ContentNotFoundException
774 File metadataFile = new File( managedRepository.getRepoRoot(), toPath( reference ) );
776 long lastUpdated = getExistingLastUpdated( metadataFile );
778 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
779 metadata.setGroupId( reference.getGroupId() );
780 metadata.setArtifactId( reference.getArtifactId() );
782 if ( VersionUtil.isSnapshot( reference.getVersion() ) )
784 // Do SNAPSHOT handling.
785 metadata.setVersion( VersionUtil.getBaseVersion( reference.getVersion() ) );
787 // Gather up all of the versions found in the reference dir, and any
788 // proxied maven-metadata.xml files.
789 Set<String> snapshotVersions = gatherSnapshotVersions( managedRepository, reference );
791 if ( snapshotVersions.isEmpty() )
793 throw new ContentNotFoundException(
794 "No snapshot versions found on reference [" + VersionedReference.toKey( reference ) + "]." );
797 // sort the list to determine to aide in determining the Latest version.
798 List<String> sortedVersions = new ArrayList<String>();
799 sortedVersions.addAll( snapshotVersions );
800 Collections.sort( sortedVersions, new VersionComparator() );
802 String latestVersion = sortedVersions.get( sortedVersions.size() - 1 );
804 if ( VersionUtil.isUniqueSnapshot( latestVersion ) )
806 // The latestVersion will contain the full version string "1.0-alpha-5-20070821.213044-8"
807 // This needs to be broken down into ${base}-${timestamp}-${build_number}
809 Matcher m = VersionUtil.UNIQUE_SNAPSHOT_PATTERN.matcher( latestVersion );
812 metadata.setSnapshotVersion( new SnapshotVersion() );
813 int buildNumber = NumberUtils.toInt( m.group( 3 ), -1 );
814 metadata.getSnapshotVersion().setBuildNumber( buildNumber );
816 Matcher mtimestamp = VersionUtil.TIMESTAMP_PATTERN.matcher( m.group( 2 ) );
817 if ( mtimestamp.matches() )
819 String tsDate = mtimestamp.group( 1 );
820 String tsTime = mtimestamp.group( 2 );
822 long snapshotLastUpdated = toLastUpdatedLong( tsDate + tsTime );
824 lastUpdated = Math.max( lastUpdated, snapshotLastUpdated );
826 metadata.getSnapshotVersion().setTimestamp( m.group( 2 ) );
830 else if ( VersionUtil.isGenericSnapshot( latestVersion ) )
832 // The latestVersion ends with the generic version string.
833 // Example: 1.0-alpha-5-SNAPSHOT
835 metadata.setSnapshotVersion( new SnapshotVersion() );
837 /* Disabled due to decision in [MRM-535].
838 * Do not set metadata.lastUpdated to file.lastModified.
840 * Should this be the last updated timestamp of the file, or in the case of an
841 * archive, the most recent timestamp in the archive?
843 ArtifactReference artifact = getFirstArtifact( managedRepository, reference );
845 if ( artifact == null )
847 throw new IOException( "Not snapshot artifact found to reference in " + reference );
850 File artifactFile = managedRepository.toFile( artifact );
852 if ( artifactFile.exists() )
854 Date lastModified = new Date( artifactFile.lastModified() );
855 metadata.setLastUpdatedTimestamp( lastModified );
861 throw new RepositoryMetadataException(
862 "Unable to process snapshot version <" + latestVersion + "> reference <" + reference + ">" );
867 // Do RELEASE handling.
868 metadata.setVersion( reference.getVersion() );
872 if ( lastUpdated > 0 )
874 metadata.setLastUpdatedTimestamp( toLastUpdatedDate( lastUpdated ) );
877 // Save the metadata model to disk.
878 RepositoryMetadataWriter.write( metadata, metadataFile );
879 ChecksummedFile checksum = new ChecksummedFile( metadataFile );
880 checksum.fixChecksums( algorithms );
883 private void initConfigVariables()
885 synchronized ( this.artifactPatterns )
887 this.artifactPatterns.clear();
889 this.artifactPatterns.addAll( filetypes.getFileTypePatterns( FileTypes.ARTIFACTS ) );
892 synchronized ( proxies )
894 this.proxies.clear();
896 List<ProxyConnectorConfiguration> proxyConfigs = configuration.getConfiguration().getProxyConnectors();
897 for ( ProxyConnectorConfiguration proxyConfig : proxyConfigs )
899 String key = proxyConfig.getSourceRepoId();
901 Set<String> remoteRepoIds = this.proxies.get( key );
903 if ( remoteRepoIds == null )
905 remoteRepoIds = new HashSet<String>();
908 remoteRepoIds.add( proxyConfig.getTargetRepoId() );
910 this.proxies.put( key, remoteRepoIds );
916 * Get the first Artifact found in the provided VersionedReference location.
918 * @param managedRepository the repository to search within.
919 * @param reference the reference to the versioned reference to search within
920 * @return the ArtifactReference to the first artifact located within the versioned reference. or null if
921 * no artifact was found within the versioned reference.
922 * @throws IOException if the versioned reference is invalid (example: doesn't exist, or isn't a directory)
923 * @throws LayoutException
925 public ArtifactReference getFirstArtifact( ManagedRepositoryContent managedRepository,
926 VersionedReference reference )
927 throws LayoutException, IOException
929 String path = toPath( reference );
931 int idx = path.lastIndexOf( '/' );
934 path = path.substring( 0, idx );
937 File repoDir = new File( managedRepository.getRepoRoot(), path );
939 if ( !repoDir.exists() )
941 throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
942 + repoDir.getAbsolutePath() );
945 if ( !repoDir.isDirectory() )
947 throw new IOException(
948 "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.getAbsolutePath() );
951 File repoFiles[] = repoDir.listFiles();
952 for ( int i = 0; i < repoFiles.length; i++ )
954 if ( repoFiles[i].isDirectory() )
956 // Skip it. it's a directory.
960 String relativePath = PathUtil.getRelative( managedRepository.getRepoRoot(), repoFiles[i] );
962 if ( filetypes.matchesArtifactPattern( relativePath ) )
964 ArtifactReference artifact = managedRepository.toArtifactReference( relativePath );
970 // No artifact was found.
974 public ArchivaConfiguration getConfiguration()
976 return configuration;
979 public void setConfiguration( ArchivaConfiguration configuration )
981 this.configuration = configuration;
984 public FileTypes getFiletypes()
989 public void setFiletypes( FileTypes filetypes )
991 this.filetypes = filetypes;