This project has retired. For details please refer to its
Attic page.
LegacyToDefaultConverter xref
1 package org.apache.archiva.converter.artifact;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.archiva.common.plexusbridge.DigesterUtils;
23 import org.apache.archiva.common.plexusbridge.PlexusSisuBridge;
24 import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException;
25 import org.apache.archiva.transaction.FileTransaction;
26 import org.apache.archiva.transaction.TransactionException;
27 import org.apache.commons.io.FileUtils;
28 import org.apache.maven.artifact.Artifact;
29 import org.apache.maven.artifact.factory.ArtifactFactory;
30 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
31 import org.apache.maven.artifact.repository.ArtifactRepository;
32 import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
33 import org.apache.maven.artifact.repository.metadata.Metadata;
34 import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
35 import org.apache.maven.artifact.repository.metadata.Snapshot;
36 import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
37 import org.apache.maven.artifact.repository.metadata.Versioning;
38 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
39 import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
40 import org.apache.maven.model.DistributionManagement;
41 import org.apache.maven.model.Model;
42 import org.apache.maven.model.Relocation;
43 import org.apache.maven.model.converter.ModelConverter;
44 import org.apache.maven.model.converter.PomTranslationException;
45 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
46 import org.codehaus.plexus.digest.Digester;
47 import org.codehaus.plexus.digest.DigesterException;
48 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
49 import org.springframework.stereotype.Service;
50
51 import javax.annotation.PostConstruct;
52 import javax.inject.Inject;
53 import java.io.File;
54 import java.io.IOException;
55 import java.io.Reader;
56 import java.io.StringReader;
57 import java.io.StringWriter;
58 import java.nio.charset.Charset;
59 import java.nio.file.Files;
60 import java.util.ArrayList;
61 import java.util.HashMap;
62 import java.util.List;
63 import java.util.Map;
64 import java.util.Properties;
65 import java.util.regex.Matcher;
66
67
68
69
70 @Service("artifactConverter#legacy-to-default")
71 public class LegacyToDefaultConverter
72 implements ArtifactConverter
73 {
74
75
76
77 private List<? extends Digester> digesters;
78
79 @Inject
80 private PlexusSisuBridge plexusSisuBridge;
81
82 @Inject
83 private DigesterUtils digesterUtils;
84
85 private ModelConverter translator;
86
87 private ArtifactFactory artifactFactory;
88
89 private ArtifactHandlerManager artifactHandlerManager;
90
91 private boolean force;
92
93 private boolean dryrun;
94
95 private Map<Artifact, List<String>> warnings = new HashMap<>();
96
97 @PostConstruct
98 public void initialize()
99 throws PlexusSisuBridgeException
100 {
101 this.digesters = digesterUtils.getAllDigesters();
102 translator = plexusSisuBridge.lookup( ModelConverter.class );
103 artifactFactory = plexusSisuBridge.lookup( ArtifactFactory.class );
104 artifactHandlerManager = plexusSisuBridge.lookup( ArtifactHandlerManager.class );
105 }
106
107 @Override
108 public void convert( Artifact artifact, ArtifactRepository targetRepository )
109 throws ArtifactConversionException
110 {
111 if ( artifact.getRepository().getUrl().equals( targetRepository.getUrl() ) )
112 {
113 throw new ArtifactConversionException( Messages.getString( "exception.repositories.match" ) );
114 }
115
116 if ( !validateMetadata( artifact ) )
117 {
118 addWarning( artifact, Messages.getString( "unable.to.validate.metadata" ) );
119 return;
120 }
121
122 FileTransaction transaction = new FileTransaction();
123
124 if ( !copyPom( artifact, targetRepository, transaction ) )
125 {
126 addWarning( artifact, Messages.getString( "unable.to.copy.pom" ) );
127 return;
128 }
129
130 if ( !copyArtifact( artifact, targetRepository, transaction ) )
131 {
132 addWarning( artifact, Messages.getString( "unable.to.copy.artifact" ) );
133 return;
134 }
135
136 Metadata metadata = createBaseMetadata( artifact );
137 Versioning versioning = new Versioning();
138 versioning.addVersion( artifact.getBaseVersion() );
139 metadata.setVersioning( versioning );
140 updateMetadata( new ArtifactRepositoryMetadata( artifact ), targetRepository, metadata, transaction );
141
142 metadata = createBaseMetadata( artifact );
143 metadata.setVersion( artifact.getBaseVersion() );
144 versioning = new Versioning();
145
146 Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
147 if ( matcher.matches() )
148 {
149 Snapshot snapshot = new Snapshot();
150 snapshot.setBuildNumber( Integer.parseInt( matcher.group( 3 ) ) );
151 snapshot.setTimestamp( matcher.group( 2 ) );
152 versioning.setSnapshot( snapshot );
153 }
154
155
156 metadata.setVersioning( versioning );
157 updateMetadata( new SnapshotArtifactRepositoryMetadata( artifact ), targetRepository, metadata, transaction );
158
159 if ( !dryrun )
160 {
161 try
162 {
163 transaction.commit();
164 }
165 catch ( TransactionException e )
166 {
167 throw new ArtifactConversionException( Messages.getString( "transaction.failure", e.getMessage() ),
168 e );
169 }
170 }
171 }
172
173 @SuppressWarnings("unchecked")
174 private boolean copyPom( Artifact artifact, ArtifactRepository targetRepository, FileTransaction transaction )
175 throws ArtifactConversionException
176 {
177 Artifact pom = artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
178 artifact.getVersion() );
179 pom.setBaseVersion( artifact.getBaseVersion() );
180 ArtifactRepository repository = artifact.getRepository();
181 File file = new File( repository.getBasedir(), repository.pathOf( pom ) );
182
183 boolean result = true;
184 if ( file.exists() )
185 {
186 File targetFile = new File( targetRepository.getBasedir(), targetRepository.pathOf( pom ) );
187
188 String contents = null;
189 boolean checksumsValid = false;
190 try
191 {
192 if ( testChecksums( artifact, file ) )
193 {
194 checksumsValid = true;
195 }
196
197
198 contents = FileUtils.readFileToString( file, Charset.defaultCharset() );
199 }
200 catch ( IOException e )
201 {
202 throw new ArtifactConversionException(
203 Messages.getString( "unable.to.read.source.pom", e.getMessage() ), e );
204 }
205
206 if ( checksumsValid && contents.indexOf( "modelVersion" ) >= 0 )
207 {
208
209 try
210 {
211 boolean matching = false;
212 if ( !force && targetFile.exists() )
213 {
214 String targetContents = FileUtils.readFileToString( targetFile, Charset.defaultCharset() );
215 matching = targetContents.equals( contents );
216 }
217 if ( force || !matching )
218 {
219 transaction.createFile( contents, targetFile, digesters );
220 }
221 }
222 catch ( IOException e )
223 {
224 throw new ArtifactConversionException(
225 Messages.getString( "unable.to.write.target.pom", e.getMessage() ), e );
226 }
227 }
228 else
229 {
230
231 try (StringReader stringReader = new StringReader( contents ))
232 {
233
234 try (StringWriter writer = new StringWriter())
235 {
236 org.apache.maven.model.v3_0_0.io.xpp3.MavenXpp3Reader v3Reader =
237 new org.apache.maven.model.v3_0_0.io.xpp3.MavenXpp3Reader();
238 org.apache.maven.model.v3_0_0.Model v3Model = v3Reader.read( stringReader );
239
240 if ( doRelocation( artifact, v3Model, targetRepository, transaction ) )
241 {
242 Artifact relocatedPom =
243 artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
244 artifact.getVersion() );
245 targetFile =
246 new File( targetRepository.getBasedir(), targetRepository.pathOf( relocatedPom ) );
247 }
248
249 Model v4Model = translator.translate( v3Model );
250
251 translator.validateV4Basics( v4Model, v3Model.getGroupId(), v3Model.getArtifactId(),
252 v3Model.getVersion(), v3Model.getPackage() );
253
254 MavenXpp3Writer xpp3Writer = new MavenXpp3Writer();
255 xpp3Writer.write( writer, v4Model );
256
257 transaction.createFile( writer.toString(), targetFile, digesters );
258
259 List<String> warnings = translator.getWarnings();
260
261 for ( String message : warnings )
262 {
263 addWarning( artifact, message );
264 }
265 }
266 catch ( XmlPullParserException e )
267 {
268 addWarning( artifact,
269 Messages.getString( "invalid.source.pom", e.getMessage() ) );
270 result = false;
271 }
272 catch ( IOException e )
273 {
274 throw new ArtifactConversionException( Messages.getString( "unable.to.write.converted.pom" ),
275 e );
276 }
277 catch ( PomTranslationException e )
278 {
279 addWarning( artifact,
280 Messages.getString( "invalid.source.pom", e.getMessage() ) );
281 result = false;
282 }
283 }
284 }
285 }
286 else
287 {
288 addWarning( artifact, Messages.getString( "warning.missing.pom" ) );
289 }
290 return result;
291 }
292
293 private boolean testChecksums( Artifact artifact, File file )
294 throws IOException
295 {
296 boolean result = true;
297 for ( Digester digester : digesters )
298 {
299 result &= verifyChecksum( file, file.getName() + "." + getDigesterFileExtension( digester ), digester,
300
301 artifact,
302 "failure.incorrect." + getDigesterFileExtension( digester ) );
303 }
304 return result;
305 }
306
307 private boolean verifyChecksum( File file, String fileName, Digester digester, Artifact artifact, String key )
308 throws IOException
309 {
310 boolean result = true;
311
312 File checksumFile = new File( file.getParentFile(), fileName );
313 if ( checksumFile.exists() )
314 {
315 String checksum = FileUtils.readFileToString( checksumFile, Charset.defaultCharset() );
316 try
317 {
318 digester.verify( file, checksum );
319 }
320 catch ( DigesterException e )
321 {
322 addWarning( artifact, Messages.getString( key ) );
323 result = false;
324 }
325 }
326 return result;
327 }
328
329
330
331
332
333 private String getDigesterFileExtension( Digester digester )
334 {
335 return digester.getAlgorithm().toLowerCase().replaceAll( "-", "" );
336 }
337
338 private boolean copyArtifact( Artifact artifact, ArtifactRepository targetRepository, FileTransaction transaction )
339 throws ArtifactConversionException
340 {
341 File sourceFile = artifact.getFile();
342
343 if ( sourceFile.getAbsolutePath().indexOf( "/plugins/" ) > -1 )
344 {
345 artifact.setArtifactHandler( artifactHandlerManager.getArtifactHandler( "maven-plugin" ) );
346 }
347
348 File targetFile = new File( targetRepository.getBasedir(), targetRepository.pathOf( artifact ) );
349
350 boolean result = true;
351 try
352 {
353 boolean matching = false;
354 if ( !force && targetFile.exists() )
355 {
356 matching = FileUtils.contentEquals( sourceFile, targetFile );
357 if ( !matching )
358 {
359 addWarning( artifact, Messages.getString( "failure.target.already.exists" ) );
360 result = false;
361 }
362 }
363 if ( result )
364 {
365 if ( force || !matching )
366 {
367 if ( testChecksums( artifact, sourceFile ) )
368 {
369 transaction.copyFile( sourceFile, targetFile, digesters );
370 }
371 else
372 {
373 result = false;
374 }
375 }
376 }
377 }
378 catch ( IOException e )
379 {
380 throw new ArtifactConversionException( Messages.getString( "error.copying.artifact" ), e );
381 }
382 return result;
383 }
384
385 private Metadata createBaseMetadata( Artifact artifact )
386 {
387 Metadata metadata = new Metadata();
388 metadata.setArtifactId( artifact.getArtifactId() );
389 metadata.setGroupId( artifact.getGroupId() );
390 return metadata;
391 }
392
393 private Metadata readMetadata( File file )
394 throws ArtifactConversionException
395 {
396 MetadataXpp3Reader reader = new MetadataXpp3Reader();
397
398 try (Reader fileReader = Files.newBufferedReader( file.toPath(), Charset.defaultCharset() ))
399 {
400 return reader.read( fileReader );
401 }
402 catch ( IOException | XmlPullParserException e )
403 {
404 throw new ArtifactConversionException( Messages.getString( "error.reading.target.metadata" ),
405 e );
406 }
407 }
408
409 private boolean validateMetadata( Artifact artifact )
410 throws ArtifactConversionException
411 {
412 ArtifactRepository repository = artifact.getRepository();
413
414 boolean result = true;
415
416 RepositoryMetadata repositoryMetadata = new ArtifactRepositoryMetadata( artifact );
417 File file =
418 new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( repositoryMetadata ) );
419 if ( file.exists() )
420 {
421 Metadata metadata = readMetadata( file );
422 result = validateMetadata( metadata, repositoryMetadata, artifact );
423 }
424
425 repositoryMetadata = new SnapshotArtifactRepositoryMetadata( artifact );
426 file = new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( repositoryMetadata ) );
427 if ( file.exists() )
428 {
429 Metadata metadata = readMetadata( file );
430 result = result && validateMetadata( metadata, repositoryMetadata, artifact );
431 }
432
433 return result;
434 }
435
436 @SuppressWarnings("unchecked")
437 private boolean validateMetadata( Metadata metadata, RepositoryMetadata repositoryMetadata, Artifact artifact )
438 {
439 String groupIdKey;
440 String artifactIdKey = null;
441 String snapshotKey = null;
442 String versionKey = null;
443 String versionsKey = null;
444
445 if ( repositoryMetadata.storedInGroupDirectory() )
446 {
447 groupIdKey = "failure.incorrect.groupMetadata.groupId";
448 }
449 else if ( repositoryMetadata.storedInArtifactVersionDirectory() )
450 {
451 groupIdKey = "failure.incorrect.snapshotMetadata.groupId";
452 artifactIdKey = "failure.incorrect.snapshotMetadata.artifactId";
453 versionKey = "failure.incorrect.snapshotMetadata.version";
454 snapshotKey = "failure.incorrect.snapshotMetadata.snapshot";
455 }
456 else
457 {
458 groupIdKey = "failure.incorrect.artifactMetadata.groupId";
459 artifactIdKey = "failure.incorrect.artifactMetadata.artifactId";
460 versionsKey = "failure.incorrect.artifactMetadata.versions";
461 }
462
463 boolean result = true;
464
465 if ( metadata.getGroupId() == null || !metadata.getGroupId().equals( artifact.getGroupId() ) )
466 {
467 addWarning( artifact, Messages.getString( groupIdKey ) );
468 result = false;
469 }
470 if ( !repositoryMetadata.storedInGroupDirectory() )
471 {
472 if ( metadata.getGroupId() == null || !metadata.getArtifactId().equals( artifact.getArtifactId() ) )
473 {
474 addWarning( artifact, Messages.getString( artifactIdKey ) );
475 result = false;
476 }
477 if ( !repositoryMetadata.storedInArtifactVersionDirectory() )
478 {
479
480
481 boolean foundVersion = false;
482 if ( metadata.getVersioning() != null )
483 {
484 for ( String version : (List<String>) metadata.getVersioning().getVersions() )
485 {
486 if ( version.equals( artifact.getBaseVersion() ) )
487 {
488 foundVersion = true;
489 break;
490 }
491 }
492 }
493
494 if ( !foundVersion )
495 {
496 addWarning( artifact, Messages.getString( versionsKey ) );
497 result = false;
498 }
499 }
500 else
501 {
502
503 if ( !artifact.getBaseVersion().equals( metadata.getVersion() ) )
504 {
505 addWarning( artifact, Messages.getString( versionKey ) );
506 result = false;
507 }
508
509 if ( artifact.isSnapshot() )
510 {
511 Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
512 if ( matcher.matches() )
513 {
514 boolean correct = false;
515 if ( metadata.getVersioning() != null && metadata.getVersioning().getSnapshot() != null )
516 {
517 Snapshot snapshot = metadata.getVersioning().getSnapshot();
518 int build = Integer.parseInt( matcher.group( 3 ) );
519 String ts = matcher.group( 2 );
520 if ( build == snapshot.getBuildNumber() && ts.equals( snapshot.getTimestamp() ) )
521 {
522 correct = true;
523 }
524 }
525
526 if ( !correct )
527 {
528 addWarning( artifact, Messages.getString( snapshotKey ) );
529 result = false;
530 }
531 }
532 }
533 }
534 }
535 return result;
536 }
537
538 private void updateMetadata( RepositoryMetadata artifactMetadata, ArtifactRepository targetRepository,
539 Metadata newMetadata, FileTransaction transaction )
540 throws ArtifactConversionException
541 {
542 File file = new File( targetRepository.getBasedir(),
543 targetRepository.pathOfRemoteRepositoryMetadata( artifactMetadata ) );
544
545 Metadata metadata;
546 boolean changed;
547
548 if ( file.exists() )
549 {
550 metadata = readMetadata( file );
551 changed = metadata.merge( newMetadata );
552 }
553 else
554 {
555 changed = true;
556 metadata = newMetadata;
557 }
558
559 if ( changed )
560 {
561
562 try (StringWriter writer = new StringWriter())
563 {
564 MetadataXpp3Writer mappingWriter = new MetadataXpp3Writer();
565
566 mappingWriter.write( writer, metadata );
567
568 transaction.createFile( writer.toString(), file, digesters );
569 }
570 catch ( IOException e )
571 {
572 throw new ArtifactConversionException( Messages.getString( "error.writing.target.metadata" ),
573 e );
574 }
575 }
576 }
577
578 private boolean doRelocation( Artifact artifact, org.apache.maven.model.v3_0_0.Model v3Model,
579 ArtifactRepository repository, FileTransaction transaction )
580 throws IOException
581 {
582 Properties properties = v3Model.getProperties();
583 if ( properties.containsKey( "relocated.groupId" ) || properties.containsKey( "relocated.artifactId" )
584
585 || properties.containsKey( "relocated.version" ) )
586 {
587 String newGroupId = properties.getProperty( "relocated.groupId", v3Model.getGroupId() );
588 properties.remove( "relocated.groupId" );
589
590 String newArtifactId =
591 properties.getProperty( "relocated.artifactId", v3Model.getArtifactId() );
592 properties.remove( "relocated.artifactId" );
593
594 String newVersion = properties.getProperty( "relocated.version", v3Model.getVersion() );
595 properties.remove( "relocated.version" );
596
597 String message = properties.getProperty( "relocated.message", "" );
598 properties.remove( "relocated.message" );
599
600 if ( properties.isEmpty() )
601 {
602 v3Model.setProperties( null );
603 }
604
605 writeRelocationPom( v3Model.getGroupId(), v3Model.getArtifactId(), v3Model.getVersion(), newGroupId,
606 newArtifactId, newVersion, message, repository, transaction );
607
608 v3Model.setGroupId( newGroupId );
609 v3Model.setArtifactId( newArtifactId );
610 v3Model.setVersion( newVersion );
611
612 artifact.setGroupId( newGroupId );
613 artifact.setArtifactId( newArtifactId );
614 artifact.setVersion( newVersion );
615
616 return true;
617 }
618 else
619 {
620 return false;
621 }
622 }
623
624 private void writeRelocationPom( String groupId, String artifactId, String version, String newGroupId,
625 String newArtifactId, String newVersion, String message,
626 ArtifactRepository repository, FileTransaction transaction )
627 throws IOException
628 {
629 Model pom = new Model();
630 pom.setGroupId( groupId );
631 pom.setArtifactId( artifactId );
632 pom.setVersion( version );
633
634 DistributionManagement dMngt = new DistributionManagement();
635
636 Relocation relocation = new Relocation();
637 relocation.setGroupId( newGroupId );
638 relocation.setArtifactId( newArtifactId );
639 relocation.setVersion( newVersion );
640 if ( message != null && message.length() > 0 )
641 {
642 relocation.setMessage( message );
643 }
644
645 dMngt.setRelocation( relocation );
646
647 pom.setDistributionManagement( dMngt );
648
649 Artifact artifact = artifactFactory.createBuildArtifact( groupId, artifactId, version, "pom" );
650 File pomFile = new File( repository.getBasedir(), repository.pathOf( artifact ) );
651
652 StringWriter strWriter = new StringWriter();
653 MavenXpp3Writer pomWriter = new MavenXpp3Writer();
654 pomWriter.write( strWriter, pom );
655
656 transaction.createFile( strWriter.toString(), pomFile, digesters );
657 }
658
659 private void addWarning( Artifact artifact, String message )
660 {
661 List<String> messages = warnings.get( artifact );
662 if ( messages == null )
663 {
664 messages = new ArrayList<>( 1 );
665 }
666 messages.add( message );
667 warnings.put( artifact, messages );
668 }
669
670 @Override
671 public void clearWarnings()
672 {
673 warnings.clear();
674 }
675
676 @Override
677 public Map<Artifact, List<String>> getWarnings()
678 {
679 return warnings;
680 }
681
682
683 public List<? extends Digester> getDigesters()
684 {
685 return digesters;
686 }
687
688 public void setDigesters( List<Digester> digesters )
689 {
690 this.digesters = digesters;
691 }
692
693 public ModelConverter getTranslator()
694 {
695 return translator;
696 }
697
698 public void setTranslator( ModelConverter translator )
699 {
700 this.translator = translator;
701 }
702
703 public ArtifactFactory getArtifactFactory()
704 {
705 return artifactFactory;
706 }
707
708 public void setArtifactFactory( ArtifactFactory artifactFactory )
709 {
710 this.artifactFactory = artifactFactory;
711 }
712
713 public ArtifactHandlerManager getArtifactHandlerManager()
714 {
715 return artifactHandlerManager;
716 }
717
718 public void setArtifactHandlerManager( ArtifactHandlerManager artifactHandlerManager )
719 {
720 this.artifactHandlerManager = artifactHandlerManager;
721 }
722
723 public boolean isForce()
724 {
725 return force;
726 }
727
728 public void setForce( boolean force )
729 {
730 this.force = force;
731 }
732
733 public boolean isDryrun()
734 {
735 return dryrun;
736 }
737
738 public void setDryrun( boolean dryrun )
739 {
740 this.dryrun = dryrun;
741 }
742 }