]> source.dussan.org Git - archiva.git/blob
b0cf465a205ac963111527dad9beb0f409b36541
[archiva.git] /
1 package org.apache.archiva.stagerepository.merge;
2
3 /*
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
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
22 import org.apache.archiva.common.utils.VersionComparator;
23 import org.apache.archiva.common.utils.VersionUtil;
24 import org.apache.archiva.configuration.ArchivaConfiguration;
25 import org.apache.archiva.configuration.Configuration;
26 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
27 import org.apache.archiva.maven2.metadata.MavenMetadataReader;
28 import org.apache.archiva.metadata.model.ArtifactMetadata;
29 import org.apache.archiva.metadata.repository.MetadataRepository;
30 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
31 import org.apache.archiva.metadata.repository.filter.Filter;
32 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
33 import org.apache.archiva.model.ArchivaRepositoryMetadata;
34 import org.apache.archiva.repository.RepositoryException;
35 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
36 import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
37 import org.apache.archiva.xml.XMLException;
38 import org.apache.commons.io.FileUtils;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.stereotype.Service;
42
43 import javax.inject.Inject;
44 import javax.inject.Named;
45 import java.io.IOException;
46 import java.nio.file.Files;
47 import java.nio.file.Path;
48 import java.nio.file.Paths;
49 import java.text.DateFormat;
50 import java.text.SimpleDateFormat;
51 import java.util.ArrayList;
52 import java.util.Calendar;
53 import java.util.Collections;
54 import java.util.Date;
55 import java.util.List;
56 import java.util.TimeZone;
57 import java.util.regex.Pattern;
58
59 /**
60  *
61  */
62 @Service ("repositoryMerger#maven2")
63 public class Maven2RepositoryMerger
64     implements RepositoryMerger
65 {
66
67     private Logger log = LoggerFactory.getLogger( getClass() );
68
69     /**
70      *
71      */
72     private ArchivaConfiguration configuration;
73
74     /**
75      *
76      */
77     private RepositoryPathTranslator pathTranslator;
78
79     private static final String METADATA_FILENAME = "maven-metadata.xml";
80
81     @Inject
82     public Maven2RepositoryMerger(
83         @Named (value = "archivaConfiguration#default") ArchivaConfiguration archivaConfiguration,
84         @Named (value = "repositoryPathTranslator#maven2") RepositoryPathTranslator repositoryPathTranslator )
85     {
86         this.configuration = archivaConfiguration;
87         this.pathTranslator = repositoryPathTranslator;
88     }
89
90     public void setConfiguration( ArchivaConfiguration configuration )
91     {
92         this.configuration = configuration;
93     }
94
95     @Override
96     public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId )
97         throws RepositoryMergerException
98     {
99
100         try
101         {
102             List<ArtifactMetadata> artifactsInSourceRepo = metadataRepository.getArtifacts( sourceRepoId );
103             for ( ArtifactMetadata artifactMetadata : artifactsInSourceRepo )
104             {
105                 artifactMetadata.setRepositoryId( targetRepoId );
106                 createFolderStructure( sourceRepoId, targetRepoId, artifactMetadata );
107             }
108         }
109         catch ( MetadataRepositoryException e )
110         {
111             throw new RepositoryMergerException( e.getMessage(), e );
112         }
113         catch ( IOException e )
114         {
115             throw new RepositoryMergerException( e.getMessage(), e );
116         }
117         catch ( RepositoryException e )
118         {
119             throw new RepositoryMergerException( e.getMessage(), e );
120         }
121     }
122
123     // TODO when UI needs a subset to merge
124     @Override
125     public void merge( MetadataRepository metadataRepository, String sourceRepoId, String targetRepoId,
126                        Filter<ArtifactMetadata> filter )
127         throws RepositoryMergerException
128     {
129         try
130         {
131             List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( sourceRepoId );
132             for ( ArtifactMetadata metadata : sourceArtifacts )
133             {
134                 if ( filter.accept( metadata ) )
135                 {
136                     createFolderStructure( sourceRepoId, targetRepoId, metadata );
137                 }
138             }
139         }
140         catch ( MetadataRepositoryException e )
141         {
142             throw new RepositoryMergerException( e.getMessage(), e );
143         }
144         catch ( IOException e )
145         {
146             throw new RepositoryMergerException( e.getMessage(), e );
147         }
148         catch ( RepositoryException e )
149         {
150             throw new RepositoryMergerException( e.getMessage(), e );
151         }
152     }
153
154     private void createFolderStructure( String sourceRepoId, String targetRepoId, ArtifactMetadata artifactMetadata )
155         throws IOException, RepositoryException
156     {
157         Configuration config = configuration.getConfiguration();
158
159         ManagedRepositoryConfiguration targetRepoConfig = config.findManagedRepositoryById( targetRepoId );
160
161         ManagedRepositoryConfiguration sourceRepoConfig = config.findManagedRepositoryById( sourceRepoId );
162
163         Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
164
165         TimeZone timezone = TimeZone.getTimeZone( "UTC" );
166
167         DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
168
169         fmt.setTimeZone( timezone );
170
171         String timestamp = fmt.format( lastUpdatedTimestamp );
172
173         String targetRepoPath = targetRepoConfig.getLocation();
174
175         String sourceRepoPath = sourceRepoConfig.getLocation();
176
177         String artifactPath = pathTranslator.toPath( artifactMetadata.getNamespace(), artifactMetadata.getProject(),
178                                                      artifactMetadata.getProjectVersion(), artifactMetadata.getId() );
179
180         Path sourceArtifactFile = Paths.get( sourceRepoPath, artifactPath );
181
182         Path targetArtifactFile = Paths.get( targetRepoPath, artifactPath );
183
184         log.debug( "artifactPath {}", artifactPath );
185
186         int lastIndex = artifactPath.lastIndexOf( RepositoryPathTranslator.PATH_SEPARATOR );
187
188         Path targetFile = Paths.get( targetRepoPath, artifactPath.substring( 0, lastIndex ) );
189
190         if ( !Files.exists(targetFile) )
191         {
192             // create the folder structure when it does not exist
193             Files.createDirectories(targetFile);
194         }
195         // artifact copying
196         copyFile( sourceArtifactFile, targetArtifactFile );
197
198         // pom file copying
199         // TODO need to use path translator to get the pom file path
200 //        String fileName = artifactMetadata.getProject() + "-" + artifactMetadata.getVersion() + ".pom";
201 //
202 //        File sourcePomFile =
203 //            pathTranslator.toFile( new File( sourceRepoPath ), artifactMetadata.getId(), artifactMetadata.getProject(),
204 //                                   artifactMetadata.getVersion(), fileName );
205 //
206 //        String relativePathToPomFile = sourcePomFile.getAbsolutePath().split( sourceRepoPath )[1];
207 //        File targetPomFile = new File( targetRepoPath, relativePathToPomFile );
208
209         //pom file copying  (file path is taken with out using path translator)
210
211         String index = artifactPath.substring( lastIndex + 1 );
212         int last = index.lastIndexOf( '.' );
213         Path sourcePomFile = Paths.get( sourceRepoPath,
214                                        artifactPath.substring( 0, lastIndex ) + "/" + artifactPath.substring(
215                                            lastIndex + 1 ).substring( 0, last ) + ".pom" );
216         Path targetPomFile = Paths.get( targetRepoPath,
217                                        artifactPath.substring( 0, lastIndex ) + "/" + artifactPath.substring(
218                                            lastIndex + 1 ).substring( 0, last ) + ".pom" );
219
220         if ( !Files.exists(targetPomFile) && Files.exists(sourcePomFile) )
221         {
222             copyFile( sourcePomFile, targetPomFile );
223         }
224
225         // explicitly update only if metadata-updater consumer is not enabled!
226         if ( !config.getRepositoryScanning().getKnownContentConsumers().contains( "metadata-updater" ) )
227         {
228
229             // updating version metadata files
230             Path versionMetaDataFileInSourceRepo =
231                 pathTranslator.toFile( Paths.get( sourceRepoPath ), artifactMetadata.getNamespace(),
232                                        artifactMetadata.getProject(), artifactMetadata.getVersion(),
233                                        METADATA_FILENAME );
234
235             if ( Files.exists(versionMetaDataFileInSourceRepo) )
236             {//Pattern quote for windows path
237                 String relativePathToVersionMetadataFile =
238                     versionMetaDataFileInSourceRepo.toAbsolutePath().toString().split( Pattern.quote( sourceRepoPath ) )[1];
239                 Path versionMetaDataFileInTargetRepo = Paths.get( targetRepoPath, relativePathToVersionMetadataFile );
240
241                 if ( !Files.exists(versionMetaDataFileInTargetRepo) )
242                 {
243                     copyFile( versionMetaDataFileInSourceRepo, versionMetaDataFileInTargetRepo );
244                 }
245                 else
246                 {
247                     updateVersionMetadata( versionMetaDataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp );
248
249                 }
250             }
251
252             // updating project meta data file
253             Path projectDirectoryInSourceRepo = versionMetaDataFileInSourceRepo.getParent().getParent();
254             Path projectMetadataFileInSourceRepo = projectDirectoryInSourceRepo.resolve(METADATA_FILENAME );
255
256             if ( Files.exists(projectMetadataFileInSourceRepo) )
257             {
258                 String relativePathToProjectMetadataFile =
259                     projectMetadataFileInSourceRepo.toAbsolutePath().toString().split( Pattern.quote( sourceRepoPath ) )[1];
260                 Path projectMetadataFileInTargetRepo = Paths.get( targetRepoPath, relativePathToProjectMetadataFile );
261
262                 if ( !Files.exists(projectMetadataFileInTargetRepo) )
263                 {
264
265                     copyFile( projectMetadataFileInSourceRepo, projectMetadataFileInTargetRepo );
266                 }
267                 else
268                 {
269                     updateProjectMetadata( projectMetadataFileInTargetRepo, artifactMetadata, lastUpdatedTimestamp,
270                                            timestamp );
271                 }
272             }
273         }
274
275     }
276
277     private void copyFile( Path sourceFile, Path targetFile )
278         throws IOException
279     {
280
281         FileUtils.copyFile( sourceFile.toFile(), targetFile.toFile() );
282
283     }
284
285     private void updateProjectMetadata( Path projectMetaDataFileIntargetRepo, ArtifactMetadata artifactMetadata,
286                                         Date lastUpdatedTimestamp, String timestamp )
287         throws RepositoryMetadataException
288     {
289         ArrayList<String> availableVersions = new ArrayList<>();
290         String latestVersion = artifactMetadata.getProjectVersion();
291
292         ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetaDataFileIntargetRepo );
293
294         if ( Files.exists(projectMetaDataFileIntargetRepo) )
295         {
296             availableVersions = (ArrayList<String>) projectMetadata.getAvailableVersions();
297
298             Collections.sort( availableVersions, VersionComparator.getInstance() );
299
300             if ( !availableVersions.contains( artifactMetadata.getVersion() ) )
301             {
302                 availableVersions.add( artifactMetadata.getVersion() );
303             }
304
305             latestVersion = availableVersions.get( availableVersions.size() - 1 );
306         }
307         else
308         {
309             availableVersions.add( artifactMetadata.getProjectVersion() );
310             projectMetadata.setGroupId( artifactMetadata.getNamespace() );
311             projectMetadata.setArtifactId( artifactMetadata.getProject() );
312         }
313
314         if ( projectMetadata.getGroupId() == null )
315         {
316             projectMetadata.setGroupId( artifactMetadata.getNamespace() );
317         }
318
319         if ( projectMetadata.getArtifactId() == null )
320         {
321             projectMetadata.setArtifactId( artifactMetadata.getProject() );
322         }
323
324         projectMetadata.setLatestVersion( latestVersion );
325         projectMetadata.setAvailableVersions( availableVersions );
326         projectMetadata.setLastUpdated( timestamp );
327         projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
328
329         if ( !VersionUtil.isSnapshot( artifactMetadata.getVersion() ) )
330         {
331             projectMetadata.setReleasedVersion( latestVersion );
332         }
333
334         RepositoryMetadataWriter.write( projectMetadata, projectMetaDataFileIntargetRepo );
335
336     }
337
338     private void updateVersionMetadata( Path versionMetaDataFileInTargetRepo, ArtifactMetadata artifactMetadata,
339                                         Date lastUpdatedTimestamp )
340         throws RepositoryMetadataException
341     {
342         ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetaDataFileInTargetRepo );
343         if ( !Files.exists(versionMetaDataFileInTargetRepo) )
344         {
345             versionMetadata.setGroupId( artifactMetadata.getNamespace() );
346             versionMetadata.setArtifactId( artifactMetadata.getProject() );
347             versionMetadata.setVersion( artifactMetadata.getProjectVersion() );
348         }
349
350         versionMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
351         RepositoryMetadataWriter.write( versionMetadata, versionMetaDataFileInTargetRepo );
352     }
353
354     private ArchivaRepositoryMetadata getMetadata( Path metadataFile )
355         throws RepositoryMetadataException
356     {
357         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
358         if ( Files.exists(metadataFile) )
359         {
360             try
361             {
362                 metadata = MavenMetadataReader.read( metadataFile );
363             }
364             catch ( XMLException e )
365             {
366                 throw new RepositoryMetadataException( e.getMessage(), e );
367             }
368         }
369         return metadata;
370     }
371
372     @Override
373     public List<ArtifactMetadata> getConflictingArtifacts( MetadataRepository metadataRepository, String sourceRepo,
374                                                            String targetRepo )
375         throws RepositoryMergerException
376     {
377         try
378         {
379             List<ArtifactMetadata> targetArtifacts = metadataRepository.getArtifacts( targetRepo );
380             List<ArtifactMetadata> sourceArtifacts = metadataRepository.getArtifacts( sourceRepo );
381             List<ArtifactMetadata> conflictsArtifacts = new ArrayList<>();
382
383             for ( ArtifactMetadata targetArtifact : targetArtifacts )
384             {
385                 for ( ArtifactMetadata sourceArtifact : sourceArtifacts )
386                 {
387                     if ( isEquals( targetArtifact, sourceArtifact ) )
388                     {
389                         if ( !conflictsArtifacts.contains( sourceArtifact ) )
390                         {
391                             conflictsArtifacts.add( sourceArtifact );
392                         }
393                     }
394                 }
395             }
396
397             sourceArtifacts.removeAll( conflictsArtifacts );
398
399             return conflictsArtifacts;
400         }
401         catch ( MetadataRepositoryException e )
402         {
403             throw new RepositoryMergerException( e.getMessage(), e );
404         }
405     }
406
407     private boolean isEquals( ArtifactMetadata sourceArtifact, ArtifactMetadata targetArtifact )
408     {
409         boolean isSame = false;
410
411         if ( ( sourceArtifact.getNamespace().equals( targetArtifact.getNamespace() ) )
412             && ( sourceArtifact.getProject().equals( targetArtifact.getProject() ) ) && ( sourceArtifact.getId().equals(
413             targetArtifact.getId() ) ) && ( sourceArtifact.getProjectVersion().equals(
414             targetArtifact.getProjectVersion() ) ) )
415
416         {
417             isSame = true;
418
419         }
420
421         return isSame;
422     }
423 }