001    package 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    
021    import com.google.common.base.Predicate;
022    import com.google.common.collect.Iterables;
023    import org.apache.archiva.admin.model.RepositoryAdminException;
024    import org.apache.archiva.admin.model.admin.ArchivaAdministration;
025    import org.apache.archiva.admin.model.beans.ManagedRepository;
026    import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
027    import org.apache.archiva.audit.AuditEvent;
028    import org.apache.archiva.checksum.ChecksumAlgorithm;
029    import org.apache.archiva.checksum.ChecksummedFile;
030    import org.apache.archiva.common.utils.VersionComparator;
031    import org.apache.archiva.common.utils.VersionUtil;
032    import org.apache.archiva.maven2.metadata.MavenMetadataReader;
033    import org.apache.archiva.model.ArchivaRepositoryMetadata;
034    import org.apache.archiva.model.ArtifactReference;
035    import org.apache.archiva.model.SnapshotVersion;
036    import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
037    import org.apache.archiva.repository.ManagedRepositoryContent;
038    import org.apache.archiva.repository.RepositoryContentFactory;
039    import org.apache.archiva.repository.RepositoryException;
040    import org.apache.archiva.repository.RepositoryNotFoundException;
041    import org.apache.archiva.repository.metadata.MetadataTools;
042    import org.apache.archiva.repository.metadata.RepositoryMetadataException;
043    import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
044    import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
045    import org.apache.archiva.rest.services.AbstractRestService;
046    import org.apache.archiva.scheduler.ArchivaTaskScheduler;
047    import org.apache.archiva.scheduler.repository.model.RepositoryTask;
048    import org.apache.archiva.web.model.FileMetadata;
049    import org.apache.archiva.xml.XMLException;
050    import org.apache.commons.io.FilenameUtils;
051    import org.apache.commons.io.IOUtils;
052    import org.apache.commons.lang.BooleanUtils;
053    import org.apache.commons.lang.StringUtils;
054    import org.apache.commons.lang.SystemUtils;
055    import org.apache.cxf.jaxrs.ext.multipart.Attachment;
056    import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
057    import org.apache.maven.model.Model;
058    import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
059    import org.slf4j.Logger;
060    import org.slf4j.LoggerFactory;
061    import org.springframework.stereotype.Service;
062    
063    
064    import javax.inject.Inject;
065    import javax.inject.Named;
066    import javax.servlet.http.HttpServletRequest;
067    import javax.ws.rs.core.Context;
068    import javax.ws.rs.core.Response;
069    import java.io.File;
070    import java.io.FileInputStream;
071    import java.io.FileOutputStream;
072    import java.io.FileWriter;
073    import java.io.IOException;
074    import java.text.DateFormat;
075    import java.text.SimpleDateFormat;
076    import java.util.ArrayList;
077    import java.util.Calendar;
078    import java.util.Collections;
079    import java.util.Date;
080    import java.util.Iterator;
081    import java.util.List;
082    import java.util.TimeZone;
083    import java.util.concurrent.CopyOnWriteArrayList;
084    
085    /**
086     * @author Olivier Lamy
087     */
088    @Service( "fileUploadService#rest" )
089    public 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        @Inject
110        @Named( value = "archivaTaskScheduler#repository" )
111        private ArchivaTaskScheduler scheduler;
112    
113        private String getStringValue( MultipartBody multipartBody, String attachmentId )
114            throws IOException
115        {
116            Attachment attachment = multipartBody.getAttachment( attachmentId );
117            return attachment == null ? "" : IOUtils.toString( attachment.getDataHandler().getInputStream() );
118        }
119    
120        public FileMetadata post( MultipartBody multipartBody )
121            throws ArchivaRestServiceException
122        {
123    
124            try
125            {
126    
127                String classifier = getStringValue( multipartBody, "classifier" );
128                // skygo: http header form pomFile was once sending 1 for true and void for false
129                // leading to permanent false value for pomFile if using toBoolean(); use , "1", ""
130                boolean pomFile = BooleanUtils.toBoolean( getStringValue( multipartBody, "pomFile" ) );
131                
132                Attachment file = multipartBody.getAttachment( "files[]" );
133    
134                //Content-Disposition: form-data; name="files[]"; filename="org.apache.karaf.features.command-2.2.2.jar"
135                String fileName = file.getContentDisposition().getParameter( "filename" );
136    
137                File tmpFile = File.createTempFile( "upload-artifact", "tmp" );
138                tmpFile.deleteOnExit();
139                IOUtils.copy( file.getDataHandler().getInputStream(), new FileOutputStream( tmpFile ) );
140                FileMetadata fileMetadata = new FileMetadata( fileName, tmpFile.length(), "theurl" );
141                fileMetadata.setServerFileName( tmpFile.getPath() );
142                fileMetadata.setClassifier( classifier );
143                fileMetadata.setDeleteUrl( tmpFile.getName() );
144                fileMetadata.setPomFile( pomFile );
145    
146                log.info( "uploading file: {}", fileMetadata );
147    
148                List<FileMetadata> fileMetadatas = getSessionFilesList();
149    
150                fileMetadatas.add( fileMetadata );
151    
152                return fileMetadata;
153            }
154            catch ( IOException e )
155            {
156                throw new ArchivaRestServiceException( e.getMessage(),
157                                                       Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
158            }
159    
160        }
161    
162        /**
163         * FIXME must be per session synchronized not globally
164         *
165         * @return
166         */
167        protected synchronized List<FileMetadata> getSessionFilesList()
168        {
169            List<FileMetadata> fileMetadatas =
170                (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY );
171            if ( fileMetadatas == null )
172            {
173                fileMetadatas = new CopyOnWriteArrayList<FileMetadata>();
174                httpServletRequest.getSession().setAttribute( FILES_SESSION_KEY, fileMetadatas );
175            }
176            return fileMetadatas;
177        }
178    
179        public Boolean deleteFile( String fileName )
180            throws ArchivaRestServiceException
181        {
182            File file = new File( SystemUtils.getJavaIoTmpDir(), fileName );
183            log.debug( "delete file:{},exists:{}", file.getPath(), file.exists() );
184            boolean removed = getSessionFileMetadatas().remove(
185                new FileMetadata( SystemUtils.getJavaIoTmpDir().getPath() + "/" + fileName ) );
186            if ( file.exists() )
187            {
188                return file.delete();
189            }
190            return Boolean.FALSE;
191        }
192    
193        public Boolean clearUploadedFiles()
194            throws ArchivaRestServiceException
195        {
196            List<FileMetadata> fileMetadatas = new ArrayList( getSessionFileMetadatas() );
197            for ( FileMetadata fileMetadata : fileMetadatas )
198            {
199                deleteFile( new File( fileMetadata.getServerFileName() ).getName() );
200            }
201            return Boolean.TRUE;
202        }
203    
204        public List<FileMetadata> getSessionFileMetadatas()
205            throws ArchivaRestServiceException
206        {
207            List<FileMetadata> fileMetadatas =
208                (List<FileMetadata>) httpServletRequest.getSession().getAttribute( FILES_SESSION_KEY );
209    
210            return fileMetadatas == null ? Collections.<FileMetadata>emptyList() : fileMetadatas;
211        }
212    
213        public Boolean save( String repositoryId, final String groupId, final String artifactId, String version,
214                             String packaging, final boolean generatePom )
215            throws ArchivaRestServiceException
216        {
217            List<FileMetadata> fileMetadatas = getSessionFilesList();
218            if ( fileMetadatas == null || fileMetadatas.isEmpty() )
219            {
220                return Boolean.FALSE;
221            }
222            // get from the session file with groupId/artifactId
223    
224            Iterable<FileMetadata> filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>()
225            {
226                public boolean apply( FileMetadata fileMetadata )
227                {
228                    return fileMetadata != null && !fileMetadata.isPomFile();
229                }
230            } );
231            Iterator<FileMetadata> iterator = filesToAdd.iterator();
232            boolean pomGenerated = false;
233            while ( iterator.hasNext() )
234            {
235                FileMetadata fileMetadata = iterator.next();
236                log.debug( "fileToAdd: {}", fileMetadata );
237                saveFile( repositoryId, fileMetadata, generatePom && !pomGenerated, groupId, artifactId, version,
238                          packaging );
239                pomGenerated = true;
240                deleteFile( fileMetadata.getServerFileName() );
241            }
242    
243            filesToAdd = Iterables.filter( fileMetadatas, new Predicate<FileMetadata>()
244            {
245                public boolean apply( FileMetadata fileMetadata )
246                {
247                    return fileMetadata != null && fileMetadata.isPomFile();
248                }
249            } );
250    
251            iterator = filesToAdd.iterator();
252            while ( iterator.hasNext() )
253            {
254                FileMetadata fileMetadata = iterator.next();
255                log.debug( "fileToAdd: {}", fileMetadata );
256                savePomFile( repositoryId, fileMetadata, groupId, artifactId, version, packaging );
257                deleteFile( fileMetadata.getServerFileName() );
258            }
259    
260            return Boolean.TRUE;
261        }
262    
263        protected void savePomFile( String repositoryId, FileMetadata fileMetadata, String groupId, String artifactId,
264                                    String version, String packaging )
265            throws ArchivaRestServiceException
266        {
267    
268            try
269            {
270                boolean fixChecksums =
271                    !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
272    
273                ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId );
274    
275                ArtifactReference artifactReference = new ArtifactReference();
276                artifactReference.setArtifactId( artifactId );
277                artifactReference.setGroupId( groupId );
278                artifactReference.setVersion( version );
279                artifactReference.setClassifier( fileMetadata.getClassifier() );
280                artifactReference.setType( packaging );
281    
282                ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
283    
284                String artifactPath = repository.toPath( artifactReference );
285    
286                int lastIndex = artifactPath.lastIndexOf( '/' );
287    
288                String path = artifactPath.substring( 0, lastIndex );
289                File targetPath = new File( repoConfig.getLocation(), path );
290    
291                String pomFilename = artifactPath.substring( lastIndex + 1 );
292                if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) )
293                {
294                    pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() );
295                }
296                pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
297    
298                copyFile( new File( fileMetadata.getServerFileName() ), targetPath, pomFilename, fixChecksums );
299                triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
300                queueRepositoryTask( repoConfig.getId(), new File( targetPath, pomFilename ) );
301            }
302            catch ( IOException ie )
303            {
304                throw new ArchivaRestServiceException( "Error encountered while uploading pom file: " + ie.getMessage(),
305                                                       Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
306            }
307            catch ( RepositoryException rep )
308            {
309                throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(),
310                                                       Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep );
311            }
312            catch ( RepositoryAdminException e )
313            {
314                throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(),
315                                                       Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
316            }
317        }
318    
319        protected void saveFile( String repositoryId, FileMetadata fileMetadata, boolean generatePom, String groupId,
320                                 String artifactId, String version, String packaging )
321            throws ArchivaRestServiceException
322        {
323            try
324            {
325    
326                ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId );
327    
328                ArtifactReference artifactReference = new ArtifactReference();
329                artifactReference.setArtifactId( artifactId );
330                artifactReference.setGroupId( groupId );
331                artifactReference.setVersion( version );
332                artifactReference.setClassifier( fileMetadata.getClassifier() );
333                artifactReference.setType( packaging );
334    
335                ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
336    
337                String artifactPath = repository.toPath( artifactReference );
338    
339                int lastIndex = artifactPath.lastIndexOf( '/' );
340    
341                String path = artifactPath.substring( 0, lastIndex );
342                File targetPath = new File( repoConfig.getLocation(), path );
343    
344                log.debug( "artifactPath: {} found targetPath: {}", artifactPath, targetPath );
345    
346                Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
347                int newBuildNumber = -1;
348                String timestamp = null;
349    
350                File versionMetadataFile = new File( targetPath, MetadataTools.MAVEN_METADATA );
351                ArchivaRepositoryMetadata versionMetadata = getMetadata( versionMetadataFile );
352    
353                if ( VersionUtil.isSnapshot( version ) )
354                {
355                    TimeZone timezone = TimeZone.getTimeZone( "UTC" );
356                    DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
357                    fmt.setTimeZone( timezone );
358                    timestamp = fmt.format( lastUpdatedTimestamp );
359                    if ( versionMetadata.getSnapshotVersion() != null )
360                    {
361                        newBuildNumber = versionMetadata.getSnapshotVersion().getBuildNumber() + 1;
362                    }
363                    else
364                    {
365                        newBuildNumber = 1;
366                    }
367                }
368    
369                if ( !targetPath.exists() )
370                {
371                    targetPath.mkdirs();
372                }
373    
374                String filename = artifactPath.substring( lastIndex + 1 );
375                if ( VersionUtil.isSnapshot( version ) )
376                {
377                    filename = filename.replaceAll( VersionUtil.SNAPSHOT, timestamp + "-" + newBuildNumber );
378                }
379    
380                boolean fixChecksums =
381                    !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
382    
383                try
384                {
385                    File targetFile = new File( targetPath, filename );
386                    if ( targetFile.exists() && !VersionUtil.isSnapshot( version ) && repoConfig.isBlockRedeployments() )
387                    {
388                        throw new ArchivaRestServiceException(
389                            "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
390                            Response.Status.BAD_REQUEST.getStatusCode(), null );
391                    }
392                    else
393                    {
394                        copyFile( new File( fileMetadata.getServerFileName() ), targetPath, filename, fixChecksums );
395                        triggerAuditEvent( repository.getId(), path + "/" + filename, AuditEvent.UPLOAD_FILE );
396                        queueRepositoryTask( repository.getId(), targetFile );
397                    }
398                }
399                catch ( IOException ie )
400                {
401                    throw new ArchivaRestServiceException(
402                        "Overwriting released artifacts in repository '" + repoConfig.getId() + "' is not allowed.",
403                        Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
404                }
405    
406                if ( generatePom )
407                {
408                    String pomFilename = filename;
409                    if ( StringUtils.isNotEmpty( fileMetadata.getClassifier() ) )
410                    {
411                        pomFilename = StringUtils.remove( pomFilename, "-" + fileMetadata.getClassifier() );
412                    }
413                    pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
414    
415                    try
416                    {
417                        File generatedPomFile =
418                            createPom( targetPath, pomFilename, fileMetadata, groupId, artifactId, version, packaging );
419                        triggerAuditEvent( repoConfig.getId(), path + "/" + pomFilename, AuditEvent.UPLOAD_FILE );
420                        if ( fixChecksums )
421                        {
422                            fixChecksums( generatedPomFile );
423                        }
424                        queueRepositoryTask( repoConfig.getId(), generatedPomFile );
425                    }
426                    catch ( IOException ie )
427                    {
428                        throw new ArchivaRestServiceException(
429                            "Error encountered while writing pom file: " + ie.getMessage(),
430                            Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ie );
431                    }
432                }
433    
434                // explicitly update only if metadata-updater consumer is not enabled!
435                if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) )
436                {
437                    updateProjectMetadata( targetPath.getAbsolutePath(), lastUpdatedTimestamp, timestamp, newBuildNumber,
438                                           fixChecksums, fileMetadata, groupId, artifactId, version, packaging );
439    
440                    if ( VersionUtil.isSnapshot( version ) )
441                    {
442                        updateVersionMetadata( versionMetadata, versionMetadataFile, lastUpdatedTimestamp, timestamp,
443                                               newBuildNumber, fixChecksums, fileMetadata, groupId, artifactId, version,
444                                               packaging );
445                    }
446                }
447            }
448            catch ( RepositoryNotFoundException re )
449            {
450                throw new ArchivaRestServiceException( "Target repository cannot be found: " + re.getMessage(),
451                                                       Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), re );
452            }
453            catch ( RepositoryException rep )
454            {
455                throw new ArchivaRestServiceException( "Repository exception: " + rep.getMessage(),
456                                                       Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), rep );
457            }
458            catch ( RepositoryAdminException e )
459            {
460                throw new ArchivaRestServiceException( "RepositoryAdmin exception: " + e.getMessage(),
461                                                       Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
462            }
463        }
464    
465        private ArchivaRepositoryMetadata getMetadata( File metadataFile )
466            throws RepositoryMetadataException
467        {
468            ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
469            if ( metadataFile.exists() )
470            {
471                try
472                {
473                    metadata = MavenMetadataReader.read( metadataFile );
474                }
475                catch ( XMLException e )
476                {
477                    throw new RepositoryMetadataException( e.getMessage(), e );
478                }
479            }
480            return metadata;
481        }
482    
483        private File createPom( File targetPath, String filename, FileMetadata fileMetadata, String groupId,
484                                String artifactId, String version, String packaging )
485            throws IOException
486        {
487            Model projectModel = new Model();
488            projectModel.setModelVersion( "4.0.0" );
489            projectModel.setGroupId( groupId );
490            projectModel.setArtifactId( artifactId );
491            projectModel.setVersion( version );
492            projectModel.setPackaging( packaging );
493    
494            File pomFile = new File( targetPath, filename );
495            MavenXpp3Writer writer = new MavenXpp3Writer();
496            FileWriter w = new FileWriter( pomFile );
497            try
498            {
499                writer.write( w, projectModel );
500            }
501            finally
502            {
503                IOUtils.closeQuietly( w );
504            }
505    
506            return pomFile;
507        }
508    
509        private void fixChecksums( File file )
510        {
511            ChecksummedFile checksum = new ChecksummedFile( file );
512            checksum.fixChecksums( algorithms );
513        }
514    
515        private void queueRepositoryTask( String repositoryId, File localFile )
516        {
517            RepositoryTask task = new RepositoryTask();
518            task.setRepositoryId( repositoryId );
519            task.setResourceFile( localFile );
520            task.setUpdateRelatedArtifacts( true );
521            task.setScanAll( false );
522    
523            try
524            {
525                scheduler.queueTask( task );
526            }
527            catch ( TaskQueueException e )
528            {
529                log.error( "Unable to queue repository task to execute consumers on resource file ['" + localFile.getName()
530                               + "']." );
531            }
532        }
533    
534        private void copyFile( File sourceFile, File targetPath, String targetFilename, boolean fixChecksums )
535            throws IOException
536        {
537            FileOutputStream out = new FileOutputStream( new File( targetPath, targetFilename ) );
538            FileInputStream input = new FileInputStream( sourceFile );
539    
540            try
541            {
542                IOUtils.copy( input, out );
543            }
544            finally
545            {
546                out.close();
547                input.close();
548            }
549    
550            if ( fixChecksums )
551            {
552                fixChecksums( new File( targetPath, targetFilename ) );
553            }
554        }
555    
556        /**
557         * Update artifact level metadata. If it does not exist, create the metadata and fix checksums if necessary.
558         */
559        private void updateProjectMetadata( String targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
560                                            boolean fixChecksums, FileMetadata fileMetadata, String groupId,
561                                            String artifactId, String version, String packaging )
562            throws RepositoryMetadataException
563        {
564            List<String> availableVersions = new ArrayList<String>();
565            String latestVersion = version;
566    
567            File projectDir = new File( targetPath ).getParentFile();
568            File projectMetadataFile = new File( projectDir, MetadataTools.MAVEN_METADATA );
569    
570            ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile );
571    
572            if ( projectMetadataFile.exists() )
573            {
574                availableVersions = projectMetadata.getAvailableVersions();
575    
576                Collections.sort( availableVersions, VersionComparator.getInstance() );
577    
578                if ( !availableVersions.contains( version ) )
579                {
580                    availableVersions.add( version );
581                }
582    
583                latestVersion = availableVersions.get( availableVersions.size() - 1 );
584            }
585            else
586            {
587                availableVersions.add( version );
588    
589                projectMetadata.setGroupId( groupId );
590                projectMetadata.setArtifactId( artifactId );
591            }
592    
593            if ( projectMetadata.getGroupId() == null )
594            {
595                projectMetadata.setGroupId( groupId );
596            }
597    
598            if ( projectMetadata.getArtifactId() == null )
599            {
600                projectMetadata.setArtifactId( artifactId );
601            }
602    
603            projectMetadata.setLatestVersion( latestVersion );
604            projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
605            projectMetadata.setAvailableVersions( availableVersions );
606    
607            if ( !VersionUtil.isSnapshot( version ) )
608            {
609                projectMetadata.setReleasedVersion( latestVersion );
610            }
611    
612            RepositoryMetadataWriter.write( projectMetadata, projectMetadataFile );
613    
614            if ( fixChecksums )
615            {
616                fixChecksums( projectMetadataFile );
617            }
618        }
619    
620        /**
621         * Update version level metadata for snapshot artifacts. If it does not exist, create the metadata and fix checksums
622         * if necessary.
623         */
624        private void updateVersionMetadata( ArchivaRepositoryMetadata metadata, File metadataFile,
625                                            Date lastUpdatedTimestamp, String timestamp, int buildNumber,
626                                            boolean fixChecksums, FileMetadata fileMetadata, String groupId,
627                                            String artifactId, String version, String packaging )
628            throws RepositoryMetadataException
629        {
630            if ( !metadataFile.exists() )
631            {
632                metadata.setGroupId( groupId );
633                metadata.setArtifactId( artifactId );
634                metadata.setVersion( version );
635            }
636    
637            if ( metadata.getSnapshotVersion() == null )
638            {
639                metadata.setSnapshotVersion( new SnapshotVersion() );
640            }
641    
642            metadata.getSnapshotVersion().setBuildNumber( buildNumber );
643            metadata.getSnapshotVersion().setTimestamp( timestamp );
644            metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
645    
646            RepositoryMetadataWriter.write( metadata, metadataFile );
647    
648            if ( fixChecksums )
649            {
650                fixChecksums( metadataFile );
651            }
652        }
653    
654    
655    }