1 package org.apache.archiva.stagerepository.merge;
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.metadata.model.ArtifactMetadata;
23 import org.apache.archiva.metadata.repository.MetadataRepository;
24 import org.apache.archiva.metadata.repository.filter.Filter;
25 import org.apache.archiva.metadata.repository.filter.IncludesFilter;
26 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
27 import org.apache.commons.io.IOUtils;
28 import org.apache.maven.archiva.common.utils.VersionComparator;
29 import org.apache.maven.archiva.common.utils.VersionUtil;
30 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
31 import org.apache.maven.archiva.configuration.Configuration;
32 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
33 import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
34 import org.apache.maven.archiva.repository.RepositoryException;
35 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
36 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
37 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
38 import org.springframework.stereotype.Service;
41 import java.io.FileInputStream;
42 import java.io.FileOutputStream;
43 import java.io.IOException;
44 import java.text.DateFormat;
45 import java.text.SimpleDateFormat;
46 import java.util.ArrayList;
47 import java.util.Calendar;
48 import java.util.Collections;
49 import java.util.Date;
50 import java.util.List;
51 import java.util.TimeZone;
52 import javax.inject.Inject;
53 import javax.inject.Named;
58 @Service( "repositoryMerger#maven2" )
59 public class Maven2RepositoryMerger
60 implements RepositoryMerger
63 * plexus.requirement role-hint="default"
65 private ArchivaConfiguration configuration;
68 * plexus.requirement role-hint="maven2"
70 private RepositoryPathTranslator pathTranslator;
72 private static final String METADATA_FILENAME = "maven-metadata.xml";
75 public Maven2RepositoryMerger(
76 @Named( value = "archivaConfiguration#default" ) ArchivaConfiguration archivaConfiguration,
77 @Named( value = "repositoryPathTranslator#maven2") RepositoryPathTranslator repositoryPathTranslator )
79 this.configuration = archivaConfiguration;
80 this.pathTranslator = repositoryPathTranslator;
83 public void setConfiguration( ArchivaConfiguration configuration )
85 this.configuration = configuration;
88 public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId )
92 List<ArtifactMetadata> artifactsInSourceRepo = metadataRepository.getArtifacts( sourceRepoId );
93 for ( ArtifactMetadata artifactMetadata : artifactsInSourceRepo )
95 artifactMetadata.setRepositoryId( targetRepoId );
96 createFolderStructure( sourceRepoId, targetRepoId, artifactMetadata );
100 // TODO when UI needs a subset to merge
101 public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId,
102 Filter<ArtifactMetadata> filter )
105 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( sourceRepoId );
106 for ( ArtifactMetadata metadata : sourceArtifacts )
108 if ( filter.accept( metadata ) )
110 createFolderStructure( sourceRepoId, targetRepoId, metadata );
115 private void createFolderStructure( String sourceRepoId, String targetRepoId, ArtifactMetadata artifactMetadata )
116 throws IOException, RepositoryException
118 Configuration config = configuration.getConfiguration();
120 ManagedRepositoryConfiguration targetRepoConfig = config.findManagedRepositoryById( targetRepoId );
122 ManagedRepositoryConfiguration sourceRepoConfig = config.findManagedRepositoryById( sourceRepoId );
124 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
126 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
128 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
130 fmt.setTimeZone( timezone );
132 String timestamp = fmt.format( lastUpdatedTimestamp );
134 String targetRepoPath = targetRepoConfig.getLocation();
136 String sourceRepoPath = sourceRepoConfig.getLocation();
138 String artifactPath = pathTranslator.toPath( artifactMetadata.getNamespace(), artifactMetadata.getProject(),
139 artifactMetadata.getProjectVersion(), artifactMetadata.getId() );
141 File sourceArtifactFile = new File( sourceRepoPath, artifactPath );
143 File targetArtifactFile = new File( targetRepoPath, artifactPath );
145 int lastIndex = artifactPath.lastIndexOf( '/' );
147 File targetFile = new File( targetRepoPath, artifactPath.substring( 0, lastIndex ) );
149 if ( !targetFile.exists() )
151 // create the folder structure when it does not exist
155 copyFile( sourceArtifactFile, targetArtifactFile );
158 String fileName = artifactMetadata.getProject() + "-" + artifactMetadata.getVersion() + ".pom";
161 // TODO need to use path translator to get the pom file path
162 // String fileName = artifactMetadata.getProject() + "-" + artifactMetadata.getVersion() + ".pom";
164 // File sourcePomFile =
165 // pathTranslator.toFile( new File( sourceRepoPath ), artifactMetadata.getId(), artifactMetadata.getProject(),
166 // artifactMetadata.getVersion(), fileName );
168 // String relativePathToPomFile = sourcePomFile.getAbsolutePath().split( sourceRepoPath )[1];
169 // File targetPomFile = new File( targetRepoPath, relativePathToPomFile );
171 //pom file copying (file path is taken with out using path translator)
173 String index = artifactPath.substring( lastIndex + 1 );
174 int last = index.lastIndexOf( '.' );
175 File sourcePomFile = new File( sourceRepoPath, artifactPath.substring( 0, lastIndex ) + "/"
176 + artifactPath.substring( lastIndex + 1 ).substring( 0, last ) + ".pom" );
177 File targetPomFile = new File( targetRepoPath, artifactPath.substring( 0, lastIndex ) + "/"
178 + artifactPath.substring( lastIndex + 1 ).substring( 0, last ) + ".pom" );
180 if ( !targetPomFile.exists() && sourcePomFile.exists() )
182 copyFile( sourcePomFile, targetPomFile );
185 // explicitly update only if metadata-updater consumer is not enabled!
186 if ( !config.getRepositoryScanning().getKnownContentConsumers().contains( "metadata-updater" ) )
189 // updating version metadata files
190 File versionMetaDataFileInSourceRepo =
191 pathTranslator.toFile( new File( sourceRepoPath ), artifactMetadata.getNamespace(),
192 artifactMetadata.getProject(), artifactMetadata.getVersion(),
195 if ( versionMetaDataFileInSourceRepo.exists() )
197 String relativePathToVersionMetadataFile =
198 versionMetaDataFileInSourceRepo.getAbsolutePath().split( sourceRepoPath )[1];
199 File versionMetaDataFileInTargetRepo = new File( targetRepoPath, relativePathToVersionMetadataFile );
201 if ( !versionMetaDataFileInTargetRepo.exists() )
203 copyFile( versionMetaDataFileInSourceRepo, versionMetaDataFileInTargetRepo );
207 updateVersionMetadata( versionMetaDataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp );
212 // updating project meta data file
213 String projectDirectoryInSourceRepo = new File( versionMetaDataFileInSourceRepo.getParent() ).getParent();
214 File projectMetadataFileInSourceRepo = new File( projectDirectoryInSourceRepo, METADATA_FILENAME );
216 if ( projectMetadataFileInSourceRepo.exists() )
218 String relativePathToProjectMetadataFile =
219 projectMetadataFileInSourceRepo.getAbsolutePath().split( sourceRepoPath )[1];
220 File projectMetadataFileInTargetRepo = new File( targetRepoPath, relativePathToProjectMetadataFile );
222 if ( !projectMetadataFileInTargetRepo.exists() )
225 copyFile( projectMetadataFileInSourceRepo, projectMetadataFileInSourceRepo );
229 updateProjectMetadata( projectMetadataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp,
237 private void copyFile( File sourceFile, File targetFile )
240 FileOutputStream out = new FileOutputStream( targetFile );
241 FileInputStream input = new FileInputStream( sourceFile );
243 // IOUtils internally buffers the streams
246 IOUtils.copy( input, out );
250 IOUtils.closeQuietly( out );
251 IOUtils.closeQuietly( input );
255 private void updateProjectMetadata( File projectMetaDataFileIntargetRepo, ArtifactMetadata artifactMetadata,
256 Date lastUpdatedTimestamp, String timestamp )
257 throws RepositoryMetadataException
259 ArrayList<String> availableVersions = new ArrayList<String>();
260 String latestVersion = artifactMetadata.getProjectVersion();
262 ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetaDataFileIntargetRepo );
264 if ( projectMetaDataFileIntargetRepo.exists() )
266 availableVersions = (ArrayList<String>) projectMetadata.getAvailableVersions();
268 Collections.sort( availableVersions, VersionComparator.getInstance() );
270 if ( !availableVersions.contains( artifactMetadata.getVersion() ) )
272 availableVersions.add( artifactMetadata.getVersion() );
275 latestVersion = availableVersions.get( availableVersions.size() - 1 );
279 availableVersions.add( artifactMetadata.getProjectVersion() );
280 projectMetadata.setGroupId( artifactMetadata.getNamespace() );
281 projectMetadata.setArtifactId( artifactMetadata.getProject() );
284 if ( projectMetadata.getGroupId() == null )
286 projectMetadata.setGroupId( artifactMetadata.getNamespace() );
289 if ( projectMetadata.getArtifactId() == null )
291 projectMetadata.setArtifactId( artifactMetadata.getProject() );
294 projectMetadata.setLatestVersion( latestVersion );
295 projectMetadata.setAvailableVersions( availableVersions );
296 projectMetadata.setLastUpdated( timestamp );
297 projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
299 if ( !VersionUtil.isSnapshot( artifactMetadata.getVersion() ) )
301 projectMetadata.setReleasedVersion( latestVersion );
304 RepositoryMetadataWriter.write( projectMetadata, projectMetaDataFileIntargetRepo );
308 private void updateVersionMetadata( File versionMetaDataFileInTargetRepo, ArtifactMetadata artifactMetadata,
309 Date lastUpdatedTimestamp )
310 throws RepositoryMetadataException
312 ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetaDataFileInTargetRepo );
313 if ( !versionMetaDataFileInTargetRepo.exists() )
315 versionMetadata.setGroupId( artifactMetadata.getNamespace() );
316 versionMetadata.setArtifactId( artifactMetadata.getProject() );
317 versionMetadata.setVersion( artifactMetadata.getProjectVersion() );
320 versionMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
321 RepositoryMetadataWriter.write( versionMetadata, versionMetaDataFileInTargetRepo );
324 private ArchivaRepositoryMetadata getMetadata( File metadataFile )
325 throws RepositoryMetadataException
327 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
328 if ( metadataFile.exists() )
330 metadata = RepositoryMetadataReader.read( metadataFile );
335 public List<ArtifactMetadata> getConflictingArtifacts( MetadataRepository metadataRepository, String sourceRepo,
339 List<ArtifactMetadata> targetArtifacts = metadataRepository.getArtifacts( targetRepo );
340 List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( sourceRepo );
341 List<ArtifactMetadata> conflictsArtifacts = new ArrayList<ArtifactMetadata>();
343 for ( ArtifactMetadata targetArtifact : targetArtifacts )
345 for ( ArtifactMetadata sourceArtifact : sourceArtifacts )
347 if ( isEquals( targetArtifact, sourceArtifact ) )
349 if ( !conflictsArtifacts.contains( sourceArtifact ) )
351 conflictsArtifacts.add( sourceArtifact );
357 sourceArtifacts.removeAll( conflictsArtifacts );
358 Filter<ArtifactMetadata> artifactsWithOutConflicts = new IncludesFilter<ArtifactMetadata>( sourceArtifacts );
359 // merge( sourceRepo, targetRepo, artifactsWithOutConflicts );
360 return conflictsArtifacts;
363 private boolean isEquals( ArtifactMetadata sourceArtifact, ArtifactMetadata targetArtifact )
365 boolean isSame = false;
367 if ( ( sourceArtifact.getNamespace().equals( targetArtifact.getNamespace() ) )
368 && ( sourceArtifact.getProject().equals( targetArtifact.getProject() ) )
369 && ( sourceArtifact.getId().equals( targetArtifact.getId() ) )
370 && ( sourceArtifact.getProjectVersion().equals( targetArtifact.getProjectVersion() ) ) )