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