This project has retired. For details please refer to its Attic page.
DefaultFileUploadService xref
View Javadoc
1   package org.apache.archiva.web.api;
2   /*
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   */
20  
21  import com.google.common.base.Predicate;
22  import com.google.common.collect.Iterables;
23  import org.apache.archiva.admin.model.RepositoryAdminException;
24  import org.apache.archiva.admin.model.admin.ArchivaAdministration;
25  import org.apache.archiva.admin.model.beans.ManagedRepository;
26  import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
27  import org.apache.archiva.metadata.model.facets.AuditEvent;
28  import org.apache.archiva.checksum.ChecksumAlgorithm;
29  import org.apache.archiva.checksum.ChecksummedFile;
30  import org.apache.archiva.common.utils.VersionComparator;
31  import org.apache.archiva.common.utils.VersionUtil;
32  import org.apache.archiva.maven2.metadata.MavenMetadataReader;
33  import org.apache.archiva.model.ArchivaRepositoryMetadata;
34  import org.apache.archiva.model.ArtifactReference;
35  import org.apache.archiva.model.SnapshotVersion;
36  import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
37  import org.apache.archiva.repository.ManagedRepositoryContent;
38  import org.apache.archiva.repository.RepositoryContentFactory;
39  import org.apache.archiva.repository.RepositoryException;
40  import org.apache.archiva.repository.RepositoryNotFoundException;
41  import org.apache.archiva.repository.metadata.MetadataTools;
42  import org.apache.archiva.repository.metadata.RepositoryMetadataException;
43  import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
44  import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
45  import org.apache.archiva.rest.services.AbstractRestService;
46  import org.apache.archiva.scheduler.ArchivaTaskScheduler;
47  import org.apache.archiva.scheduler.repository.model.RepositoryTask;
48  import org.apache.archiva.web.model.FileMetadata;
49  import org.apache.archiva.xml.XMLException;
50  import org.apache.commons.io.FilenameUtils;
51  import org.apache.commons.io.IOUtils;
52  import org.apache.commons.lang.BooleanUtils;
53  import org.apache.commons.lang.StringUtils;
54  import org.apache.commons.lang.SystemUtils;
55  import org.apache.cxf.jaxrs.ext.multipart.Attachment;
56  import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
57  import org.apache.maven.model.Model;
58  import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
59  import org.slf4j.Logger;
60  import org.slf4j.LoggerFactory;
61  import org.springframework.stereotype.Service;
62  
63  import javax.inject.Inject;
64  import javax.inject.Named;
65  import javax.servlet.http.HttpServletRequest;
66  import javax.ws.rs.core.Context;
67  import javax.ws.rs.core.Response;
68  import java.io.File;
69  import java.io.FileOutputStream;
70  import java.io.FileWriter;
71  import java.io.IOException;
72  import java.net.URLDecoder;
73  import java.nio.file.*;
74  import java.text.DateFormat;
75  import java.text.SimpleDateFormat;
76  import java.util.ArrayList;
77  import java.util.Calendar;
78  import java.util.Collections;
79  import java.util.Date;
80  import java.util.Iterator;
81  import java.util.List;
82  import java.util.TimeZone;
83  import java.util.concurrent.CopyOnWriteArrayList;
84  
85  /**
86   * @author Olivier Lamy
87   */
88  @Service("fileUploadService#rest")
89  public class DefaultFileUploadService
90      extends AbstractRestService
91      implements FileUploadService
92  {
93      private Logger log = LoggerFactory.getLogger( getClass() );
94  
95      @Context
96      private HttpServletRequest httpServletRequest;
97  
98      @Inject
99      private ManagedRepositoryAdmin managedRepositoryAdmin;
100 
101     @Inject
102     private RepositoryContentFactory repositoryFactory;
103 
104     @Inject
105     private ArchivaAdministration archivaAdministration;
106 
107     private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
108 
109     private final String FS = FileSystems.getDefault().getSeparator();
110 
111     @Inject
112     @Named(value = "archivaTaskScheduler#repository")
113     private ArchivaTaskScheduler scheduler;
114 
115     private String getStringValue( MultipartBody multipartBody, String attachmentId )
116         throws IOException
117     {
118         Attachment attachment = multipartBody.getAttachment( attachmentId );
119         return attachment == null ? "" :
120             StringUtils.trim(URLDecoder.decode(IOUtils.toString( attachment.getDataHandler().getInputStream() ), "UTF-8"));
121     }
122 
123     @Override
124     public FileMetadata post( MultipartBody multipartBody )
125         throws ArchivaRestServiceException
126     {
127 
128         try
129         {
130 
131             String classifier = getStringValue( multipartBody, "classifier" );
132             String packaging = getStringValue( multipartBody, "packaging" );
133 
134             checkParamChars( "classifier", classifier );
135             checkParamChars( "packaging", packaging);
136 
137             // skygo: http header form pomFile was once sending 1 for true and void for false
138             // leading to permanent false value for pomFile if using toBoolean(); use , "1", ""
139 
140             boolean pomFile = false;
141             try
142             {
143                 pomFile = BooleanUtils.toBoolean( getStringValue( multipartBody, "pomFile" ) );
144             }
145             catch ( IllegalArgumentException ex )
146             {
147                 ArchivaRestServiceException e = new ArchivaRestServiceException("Bad value for boolean pomFile field.", null);
148                 e.setHttpErrorCode(422);
149                 e.setFieldName( "pomFile" );
150                 e.setErrorKey("fileupload.malformed.pomFile");
151                 throw e;
152             }
153 
154             Attachment file = multipartBody.getAttachment( "files[]" );
155 
156             //Content-Disposition: form-data; name="files[]"; filename="org.apache.karaf.features.command-2.2.2.jar"
157             String fileName = file.getContentDisposition().getParameter( "filename" );
158             Path fileNamePath = Paths.get(fileName);
159             if (!fileName.equals(fileNamePath.getFileName().toString())) {
160                 ArchivaRestServiceException e = new ArchivaRestServiceException("Bad filename in upload content: " + fileName + " - File traversal chars (..|/) are not allowed"
161                         , null);
162                 e.setHttpErrorCode(422);
163                 e.setErrorKey("fileupload.malformed.filename");
164                 throw e;
165             }
166 
167             File tmpFile = File.createTempFile( "upload-artifact", ".tmp" );
168             tmpFile.deleteOnExit();
169             IOUtils.copy( file.getDataHandler().getInputStream(), new FileOutputStream( tmpFile ) );
170             FileMetadata fileMetadata = new FileMetadata( fileName, tmpFile.length(), "theurl" );
171             fileMetadata.setServerFileName( tmpFile.getPath() );
172             fileMetadata.setClassifier( classifier );
173             fileMetadata.setDeleteUrl( tmpFile.getName() );
174             fileMetadata.setPomFile( pomFile );
175             fileMetadata.setPackaging( packaging );
176 
177             log.info( "uploading file: {}", fileMetadata );
178 
179             List<FileMetadata> fileMetadatas = getSessionFilesList();
180 
181             fileMetadatas.add( fileMetadata );
182 
183             return fileMetadata;
184         }
185         catch ( IOException e )
186         {
187             throw new ArchivaRestServiceException( e.getMessage(),
188                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
189         }
190 
191     }
192 
193     /**
194      * FIXME must be per session synchronized not globally
195      *
196      * @return
197      */
198     protected synchronized List<FileMetadata> getSessionFilesList()
199     {
200         List<FileMetadata> fileMetadatas =
201             (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY );
202         if ( fileMetadatas == null )
203         {
204             fileMetadatas = new CopyOnWriteArrayList<>();
205             httpServletRequest.getSession().setAttribute( FILES_SESSION_KEY, fileMetadatas );
206         }
207         return fileMetadatas;
208     }
209 
210     @Override
211     public Boolean deleteFile( String fileName )
212         throws ArchivaRestServiceException
213     {
214         // we make sure, that there are no other path components in the filename:
215         String checkedFileName = Paths.get(fileName).getFileName().toString();
216         File file = new File( SystemUtils.getJavaIoTmpDir(), checkedFileName );
217         log.debug( "delete file:{},exists:{}", file.getPath(), file.exists() );
218         boolean removed = getSessionFileMetadatas().remove( new FileMetadata( fileName ) );
219         // try with full name as ui only know the file name
220         if ( !removed )
221         {
222             removed = getSessionFileMetadatas().remove( new FileMetadata( file.getPath() ) );
223         }
224         if (removed && file.exists() )
225         {
226             return file.delete();
227         }
228         return Boolean.FALSE;
229     }
230 
231     @Override
232     public Boolean clearUploadedFiles()
233         throws ArchivaRestServiceException
234     {
235         List<FileMetadata> fileMetadatas = new ArrayList( getSessionFileMetadatas() );
236         for ( FileMetadata fileMetadata : fileMetadatas )
237         {
238             deleteFile( new File( fileMetadata.getServerFileName() ).getPath() );
239         }
240         getSessionFileMetadatas().clear();
241         return Boolean.TRUE;
242     }
243 
244     @Override
245     public List<FileMetadata> getSessionFileMetadatas()
246         throws ArchivaRestServiceException
247     {
248         List<FileMetadata> fileMetadatas =
249             (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY );
250 
251         return fileMetadatas == null ? Collections.<FileMetadata>emptyList() : fileMetadatas;
252     }
253 
254     private boolean hasValidChars(String checkString) {
255         if (checkString.contains(FS)) {
256             return false;
257         }
258         if (checkString.contains("../")) {
259             return false;
260         }
261         if (checkString.contains("/..")) {
262             return false;
263         }
264         return true;
265     }
266 
267     private void checkParamChars(String param, String value) throws ArchivaRestServiceException {
268         if (!hasValidChars(value)) {
269             ArchivaRestServiceException e = new ArchivaRestServiceException("Bad characters in " + param, null);
270             e.setHttpErrorCode(422);
271             e.setErrorKey("fileupload.malformed.param");
272             e.setFieldName(param);
273             throw e;
274         }
275     }
276 
277     @Override
278     public Boolean save( String repositoryId, String groupId, String artifactId, String version, String packaging,
279                          boolean generatePom )
280         throws ArchivaRestServiceException
281     {
282         repositoryId = StringUtils.trim( repositoryId );
283         groupId = StringUtils.trim( groupId );
284         artifactId = StringUtils.trim( artifactId );
285         version = StringUtils.trim( version );
286         packaging = StringUtils.trim( packaging );
287 
288         checkParamChars("repositoryId", repositoryId);
289         checkParamChars("groupId", groupId);
290         checkParamChars("artifactId", artifactId);
291         checkParamChars( "version", version);
292         checkParamChars("packaging", packaging);
293 
294 
295         List<FileMetadata> fileMetadatas = getSessionFilesList();
296         if ( fileMetadatas == null || fileMetadatas.isEmpty() )
297         {
298             return Boolean.FALSE;
299         }
300 
301         try
302         {
303             ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repositoryId );
304 
305             if ( managedRepository == null )
306             {
307                 // TODO i18n ?
308                 throw new ArchivaRestServiceException( "Cannot find managed repository with id " + repositoryId,
309                                                        Response.Status.BAD_REQUEST.getStatusCode(), null );
310             }
311 
312             if ( VersionUtil.isSnapshot( version ) && !managedRepository.isSnapshots() )
313             {
314                 // TODO i18n ?
315                 throw new ArchivaRestServiceException(
316                     "Managed repository with id " + repositoryId + " do not accept snapshots",
317                     Response.Status.BAD_REQUEST.getStatusCode(), null );
318             }
319         }
320         catch ( RepositoryAdminException e )
321         {
322             throw new ArchivaRestServiceException( e.getMessage(),
323                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
324         }
325 
326         // get from the session file with groupId/artifactId
327 
328         Iterable<FileMetadata> filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>()
329         {
330             public boolean apply( FileMetadata fileMetadata )
331             {
332                 return fileMetadata != null && !fileMetadata.isPomFile();
333             }
334         } );
335         Iterator<FileMetadata> iterator = filesToAdd.iterator();
336         boolean pomGenerated = false;
337         while ( iterator.hasNext() )
338         {
339             FileMetadata fileMetadata = iterator.next();
340             log.debug( "fileToAdd: {}", fileMetadata );
341             saveFile( repositoryId, fileMetadata, generatePom && !pomGenerated, groupId, artifactId, version,
342                       packaging );
343             pomGenerated = true;
344             deleteFile( fileMetadata.getServerFileName() );
345         }
346 
347         filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>()
348         {
349             @Override
350             public boolean apply( FileMetadata fileMetadata )
351             {
352                 return fileMetadata != null && fileMetadata.isPomFile();
353             }
354         } );
355 
356         iterator = filesToAdd.iterator();
357         while ( iterator.hasNext() )
358         {
359             FileMetadata fileMetadata = iterator.next();
360             log.debug( "fileToAdd: {}", fileMetadata );
361             savePomFile( repositoryId, fileMetadata, groupId, artifactId, version, packaging );
362             deleteFile( fileMetadata.getServerFileName() );
363         }
364 
365         return Boolean.TRUE;
366     }
367 
368     protected void savePomFile( String repositoryId, FileMetadata fileMetadata, String groupId, String artifactId,
369                                 String version, String packaging )
370         throws ArchivaRestServiceException
371     {
372 
373         try
374         {
375             boolean fixChecksums =
376                 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
377 
378             ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId );
379 
380             ArtifactReference artifactReference = new ArtifactReference();
381             artifactReference.setArtifactId( artifactId );
382             artifactReference.setGroupId( groupId );
383             artifactReference.setVersion( version );
384             artifactReference.setClassifier( fileMetadata.getClassifier() );
385             artifactReference.setType( packaging );
386 
387             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
388 
389             String artifactPath = repository.toPath( artifactReference );
390 
391             int lastIndex = artifactPath.lastIndexOf( '/' );
392 
393             String path = artifactPath.substring( 0, lastIndex );
394             File targetPath = new File( repoConfig.getLocation(), path );
395 
396             String pomFilename = artifactPath.substring( lastIndex + 1 );
397             if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) )
398             {
399                 pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() );
400             }
401             pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
402 
403             copyFile( new File( fileMetadata.getServerFileName() ), targetPath, pomFilename, fixChecksums );
404             triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
405             queueRepositoryTask( repoConfig.getId(), new File( targetPath, pomFilename ) );
406         }
407         catch ( IOException ie )
408         {
409             throw new ArchivaRestServiceException( "Error encountered while uploading pom file: " + ie.getMessage(),
410                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
411         }
412         catch ( RepositoryException rep )
413         {
414             throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(),
415                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep );
416         }
417         catch ( RepositoryAdminException e )
418         {
419             throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(),
420                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
421         }
422     }
423 
424     protected void saveFile( String repositoryId, FileMetadata fileMetadata, boolean generatePom, String groupId,
425                              String artifactId, String version, String packaging )
426         throws ArchivaRestServiceException
427     {
428         try
429         {
430 
431             ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId );
432 
433             ArtifactReference artifactReference = new ArtifactReference();
434             artifactReference.setArtifactId( artifactId );
435             artifactReference.setGroupId( groupId );
436             artifactReference.setVersion( version );
437             artifactReference.setClassifier( fileMetadata.getClassifier() );
438             artifactReference.setType(
439                 StringUtils.isEmpty( fileMetadata.getPackaging() ) ? packaging : fileMetadata.getPackaging() );
440 
441             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
442 
443             String artifactPath = repository.toPath( artifactReference );
444 
445             int lastIndex = artifactPath.lastIndexOf( '/' );
446 
447             String path = artifactPath.substring( 0, lastIndex );
448             File targetPath = new File( repoConfig.getLocation(), path );
449 
450             log.debug( "artifactPath: {} found targetPath: {}", artifactPath, targetPath );
451 
452             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
453             int newBuildNumber = -1;
454             String timestamp = null;
455 
456             File versionMetadataFile = new File( targetPath, MetadataTools.MAVEN_METADATA );
457             ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetadataFile );
458 
459             if ( VersionUtil.isSnapshot( version ) )
460             {
461                 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
462                 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
463                 fmt.setTimeZone( timezone );
464                 timestamp = fmt.format( lastUpdatedTimestamp );
465                 if ( versionMetadata.getSnapshotVersion() != null )
466                 {
467                     newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1;
468                 }
469                 else
470                 {
471                     newBuildNumber = 1;
472                 }
473             }
474 
475             if ( !targetPath.exists() )
476             {
477                 targetPath.mkdirs();
478             }
479 
480             String filename = artifactPath.substring( lastIndex + 1 );
481             if ( VersionUtil.isSnapshot( version ) )
482             {
483                 filename = filename.replaceAll( VersionUtil.SNAPSHOT, timestamp + "-" + newBuildNumber );
484             }
485 
486             boolean fixChecksums =
487                 !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
488 
489             try
490             {
491                 File targetFile = new File( targetPath, filename );
492                 if ( targetFile.exists() && !VersionUtil.isSnapshot( version ) && repoConfig.isBlockRedeployments() )
493                 {
494                     throw new ArchivaRestServiceException(
495                         "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
496                         Response.Status.BAD_REQUEST.getStatusCode(), null );
497                 }
498                 else
499                 {
500                     copyFile( new File( fileMetadata.getServerFileName() ), targetPath, filename, fixChecksums );
501                     triggerAuditEvent( repository.getId(), path + "/" + filename, AuditEvent.UPLOAD_FILE );
502                     queueRepositoryTask( repository.getId(), targetFile );
503                 }
504             }
505             catch ( IOException ie )
506             {
507                 log.error( "IOException copying file: {}", ie.getMessage(), ie );
508                 throw new ArchivaRestServiceException(
509                     "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
510                     Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
511             }
512 
513             if ( generatePom )
514             {
515                 String pomFilename = filename;
516                 if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) )
517                 {
518                     pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() );
519                 }
520                 pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
521 
522                 try
523                 {
524                     File generatedPomFile =
525                         createPom( targetPath, pomFilename, fileMetadata, groupId, artifactId, version, packaging );
526                     triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
527                     if ( fixChecksums )
528                     {
529                         fixChecksums( generatedPomFile );
530                     }
531                     queueRepositoryTask( repoConfig.getId(), generatedPomFile );
532                 }
533                 catch ( IOException ie )
534                 {
535                     throw new ArchivaRestServiceException(
536                         "Error encountered while writing pom file: " + ie.getMessage(),
537                         Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
538                 }
539             }
540 
541             // explicitly update only if metadata-updater consumer is not enabled!
542             if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) )
543             {
544                 updateProjectMetadata( targetPath.getAbsolutePath(), lastUpdatedTimestamp, timestamp, newBuildNumber,
545                                        fixChecksums, fileMetadata, groupId, artifactId, version, packaging );
546 
547                 if ( VersionUtil.isSnapshot( version ) )
548                 {
549                     updateVersionMetadata( versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
550                                            newBuildNumber, fixChecksums, fileMetadata, groupId, artifactId, version,
551                                            packaging );
552                 }
553             }
554         }
555         catch ( RepositoryNotFoundException re )
556         {
557             throw new ArchivaRestServiceException( "Target repository cannot be found: " + re.getMessage(),
558                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), re );
559         }
560         catch ( RepositoryException rep )
561         {
562             throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(),
563                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep );
564         }
565         catch ( RepositoryAdminException e )
566         {
567             throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(),
568                                                    Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
569         }
570     }
571 
572     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
573         throws RepositoryMetadataException
574     {
575         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
576         if ( metadataFile.exists() )
577         {
578             try
579             {
580                 metadata = MavenMetadataReader.read( metadataFile );
581             }
582             catch ( XMLException e )
583             {
584                 throw new RepositoryMetadataException( e.getMessage(), e );
585             }
586         }
587         return metadata;
588     }
589 
590     private File createPom( File targetPath, String filename, FileMetadata fileMetadata, String groupId,
591                             String artifactId, String version, String packaging )
592         throws IOException
593     {
594         Model projectModel = new Model();
595         projectModel.setModelVersion( "4.0.0" );
596         projectModel.setGroupId( groupId );
597         projectModel.setArtifactId( artifactId );
598         projectModel.setVersion( version );
599         projectModel.setPackaging( packaging );
600 
601         File pomFile = new File( targetPath, filename );
602         MavenXpp3Writer writer = new MavenXpp3Writer();
603 
604         try (FileWriter w = new FileWriter( pomFile ))
605         {
606             writer.write( w, projectModel );
607         }
608 
609         return pomFile;
610     }
611 
612     private void fixChecksums( File file )
613     {
614         ChecksummedFile checksum = new ChecksummedFile( file );
615         checksum.fixChecksums( algorithms );
616     }
617 
618     private void queueRepositoryTask( String repositoryId, File localFile )
619     {
620         RepositoryTask task = new RepositoryTask();
621         task.setRepositoryId( repositoryId );
622         task.setResourceFile( localFile );
623         task.setUpdateRelatedArtifacts( true );
624         task.setScanAll( false );
625 
626         try
627         {
628             scheduler.queueTask( task );
629         }
630         catch ( TaskQueueException e )
631         {
632             log.error( "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName()
633                            + "']." );
634         }
635     }
636 
637     private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums )
638         throws IOException
639     {
640 
641         Files.copy( sourceFile.toPath(), new File( targetPath, targetFilename ).toPath(), StandardCopyOption.REPLACE_EXISTING,
642                     StandardCopyOption.COPY_ATTRIBUTES );
643 
644         if ( fixChecksums )
645         {
646             fixChecksums( new File( targetPath, targetFilename ) );
647         }
648     }
649 
650     /**
651      * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
652      */
653     private void updateProjectMetadata( String targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
654                                         boolean fixChecksums, FileMetadata fileMetadata, String groupId,
655                                         String artifactId, String version, String packaging )
656         throws RepositoryMetadataException
657     {
658         List<String> availableVersions = new ArrayList<>();
659         String latestVersion = version;
660 
661         File projectDir = new File( targetPath ).getParentFile();
662         File projectMetadataFile = new File( projectDir, MetadataTools.MAVEN_METADATA );
663 
664         ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile );
665 
666         if ( projectMetadataFile.exists() )
667         {
668             availableVersions = projectMetadata.getAvailableVersions();
669 
670             Collections.sort( availableVersions, VersionComparator.getInstance() );
671 
672             if ( !availableVersions.contains( version ) )
673             {
674                 availableVersions.add( version );
675             }
676 
677             latestVersion = availableVersions.get( availableVersions.size() - 1 );
678         }
679         else
680         {
681             availableVersions.add( version );
682 
683             projectMetadata.setGroupId( groupId );
684             projectMetadata.setArtifactId( artifactId );
685         }
686 
687         if ( projectMetadata.getGroupId() == null )
688         {
689             projectMetadata.setGroupId( groupId );
690         }
691 
692         if ( projectMetadata.getArtifactId() == null )
693         {
694             projectMetadata.setArtifactId( artifactId );
695         }
696 
697         projectMetadata.setLatestVersion( latestVersion );
698         projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
699         projectMetadata.setAvailableVersions( availableVersions );
700 
701         if ( !VersionUtil.isSnapshot( version ) )
702         {
703             projectMetadata.setReleasedVersion( latestVersion );
704         }
705 
706         RepositoryMetadataWriter.write( projectMetadata, projectMetadataFile );
707 
708         if ( fixChecksums )
709         {
710             fixChecksums( projectMetadataFile );
711         }
712     }
713 
714     /**
715      * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
716      * if necessary.
717      */
718     private void updateVersionMetadata( ArchivaRepositoryMetadata metadata, File metadataFile,
719                                         Date lastUpdatedTimestamp, String timestamp, int buildNumber,
720                                         boolean fixChecksums, FileMetadata fileMetadata, String groupId,
721                                         String artifactId, String version, String packaging )
722         throws RepositoryMetadataException
723     {
724         if ( !metadataFile.exists() )
725         {
726             metadata.setGroupId( groupId );
727             metadata.setArtifactId( artifactId );
728             metadata.setVersion( version );
729         }
730 
731         if ( metadata.getSnapshotVersion() == null )
732         {
733             metadata.setSnapshotVersion( new SnapshotVersion() );
734         }
735 
736         metadata.getSnapshotVersion().setBuildNumber( buildNumber );
737         metadata.getSnapshotVersion().setTimestamp( timestamp );
738         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
739 
740         RepositoryMetadataWriter.write( metadata, metadataFile );
741 
742         if ( fixChecksums )
743         {
744             fixChecksums( metadataFile );
745         }
746     }
747 
748 
749 }