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