This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.web.api;
002/*
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 */
020
021import com.google.common.base.Predicate;
022import com.google.common.collect.Iterables;
023import org.apache.archiva.admin.model.RepositoryAdminException;
024import org.apache.archiva.admin.model.admin.ArchivaAdministration;
025import org.apache.archiva.admin.model.beans.ManagedRepository;
026import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
027import org.apache.archiva.metadata.model.facets.AuditEvent;
028import org.apache.archiva.checksum.ChecksumAlgorithm;
029import org.apache.archiva.checksum.ChecksummedFile;
030import org.apache.archiva.common.utils.VersionComparator;
031import org.apache.archiva.common.utils.VersionUtil;
032import org.apache.archiva.maven2.metadata.MavenMetadataReader;
033import org.apache.archiva.model.ArchivaRepositoryMetadata;
034import org.apache.archiva.model.ArtifactReference;
035import org.apache.archiva.model.SnapshotVersion;
036import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
037import org.apache.archiva.repository.ManagedRepositoryContent;
038import org.apache.archiva.repository.RepositoryContentFactory;
039import org.apache.archiva.repository.RepositoryException;
040import org.apache.archiva.repository.RepositoryNotFoundException;
041import org.apache.archiva.repository.metadata.MetadataTools;
042import org.apache.archiva.repository.metadata.RepositoryMetadataException;
043import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
044import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
045import org.apache.archiva.rest.services.AbstractRestService;
046import org.apache.archiva.scheduler.ArchivaTaskScheduler;
047import org.apache.archiva.scheduler.repository.model.RepositoryTask;
048import org.apache.archiva.web.model.FileMetadata;
049import org.apache.archiva.xml.XMLException;
050import org.apache.commons.io.FilenameUtils;
051import org.apache.commons.io.IOUtils;
052import org.apache.commons.lang.BooleanUtils;
053import org.apache.commons.lang.StringUtils;
054import org.apache.commons.lang.SystemUtils;
055import org.apache.cxf.jaxrs.ext.multipart.Attachment;
056import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
057import org.apache.maven.model.Model;
058import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
059import org.slf4j.Logger;
060import org.slf4j.LoggerFactory;
061import org.springframework.stereotype.Service;
062
063import javax.inject.Inject;
064import javax.inject.Named;
065import javax.servlet.http.HttpServletRequest;
066import javax.ws.rs.core.Context;
067import javax.ws.rs.core.Response;
068import java.io.File;
069import java.io.FileOutputStream;
070import java.io.FileWriter;
071import java.io.IOException;
072import java.net.URLDecoder;
073import java.nio.file.*;
074import java.text.DateFormat;
075import java.text.SimpleDateFormat;
076import java.util.ArrayList;
077import java.util.Calendar;
078import java.util.Collections;
079import java.util.Date;
080import java.util.Iterator;
081import java.util.List;
082import java.util.TimeZone;
083import java.util.concurrent.CopyOnWriteArrayList;
084
085/**
086 * @author Olivier Lamy
087 */
088@Service("fileUploadService#rest")
089public class DefaultFileUploadService
090    extends AbstractRestService
091    implements FileUploadService
092{
093    private Logger log = LoggerFactory.getLogger( getClass() );
094
095    @Context
096    private HttpServletRequest httpServletRequest;
097
098    @Inject
099    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}