View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.repository.legacy.resolver.transform;
20  
21  import java.text.DateFormat;
22  import java.text.SimpleDateFormat;
23  import java.util.Date;
24  import java.util.GregorianCalendar;
25  import java.util.TimeZone;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
29  import org.apache.maven.artifact.repository.ArtifactRepository;
30  import org.apache.maven.artifact.repository.RepositoryRequest;
31  import org.apache.maven.artifact.repository.metadata.Metadata;
32  import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
33  import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
34  import org.apache.maven.artifact.repository.metadata.Snapshot;
35  import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
36  import org.apache.maven.artifact.repository.metadata.Versioning;
37  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
38  import org.codehaus.plexus.component.annotations.Component;
39  import org.codehaus.plexus.util.StringUtils;
40  
41  /**
42   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
43   * @author <a href="mailto:mmaczka@interia.pl">Michal Maczka</a>
44   */
45  @Component(role = ArtifactTransformation.class, hint = "snapshot")
46  public class SnapshotTransformation extends AbstractVersionTransformation {
47      private static final String DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT = "yyyyMMdd.HHmmss";
48  
49      private static final TimeZone DEFAULT_SNAPSHOT_TIME_ZONE = TimeZone.getTimeZone("Etc/UTC");
50  
51      private String deploymentTimestamp;
52  
53      public void transformForResolve(Artifact artifact, RepositoryRequest request) throws ArtifactResolutionException {
54          // Only select snapshots that are unresolved (eg 1.0-SNAPSHOT, not 1.0-20050607.123456)
55          if (artifact.isSnapshot() && artifact.getBaseVersion().equals(artifact.getVersion())) {
56              try {
57                  String version = resolveVersion(artifact, request);
58                  artifact.updateVersion(version, request.getLocalRepository());
59              } catch (RepositoryMetadataResolutionException e) {
60                  throw new ArtifactResolutionException(e.getMessage(), artifact, e);
61              }
62          }
63      }
64  
65      public void transformForInstall(Artifact artifact, ArtifactRepository localRepository) {
66          if (artifact.isSnapshot()) {
67              Snapshot snapshot = new Snapshot();
68              snapshot.setLocalCopy(true);
69              RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata(artifact, snapshot);
70  
71              artifact.addMetadata(metadata);
72          }
73      }
74  
75      public void transformForDeployment(
76              Artifact artifact, ArtifactRepository remoteRepository, ArtifactRepository localRepository)
77              throws ArtifactDeploymentException {
78          if (artifact.isSnapshot()) {
79              Snapshot snapshot = new Snapshot();
80  
81              // TODO Should this be changed for MNG-6754 too?
82              snapshot.setTimestamp(getDeploymentTimestamp());
83  
84              // we update the build number anyway so that it doesn't get lost. It requires the timestamp to take effect
85              try {
86                  int buildNumber = resolveLatestSnapshotBuildNumber(artifact, localRepository, remoteRepository);
87  
88                  snapshot.setBuildNumber(buildNumber + 1);
89              } catch (RepositoryMetadataResolutionException e) {
90                  throw new ArtifactDeploymentException(
91                          "Error retrieving previous build number for artifact '" + artifact.getDependencyConflictId()
92                                  + "': " + e.getMessage(),
93                          e);
94              }
95  
96              RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata(artifact, snapshot);
97  
98              artifact.setResolvedVersion(
99                      constructVersion(metadata.getMetadata().getVersioning(), artifact.getBaseVersion()));
100 
101             artifact.addMetadata(metadata);
102         }
103     }
104 
105     public String getDeploymentTimestamp() {
106         if (deploymentTimestamp == null) {
107             deploymentTimestamp = getUtcDateFormatter().format(new Date());
108         }
109         return deploymentTimestamp;
110     }
111 
112     protected String constructVersion(Versioning versioning, String baseVersion) {
113         String version = null;
114         Snapshot snapshot = versioning.getSnapshot();
115         if (snapshot != null) {
116             if (snapshot.getTimestamp() != null && snapshot.getBuildNumber() > 0) {
117                 String newVersion = snapshot.getTimestamp() + "-" + snapshot.getBuildNumber();
118                 version = StringUtils.replace(baseVersion, Artifact.SNAPSHOT_VERSION, newVersion);
119             } else {
120                 version = baseVersion;
121             }
122         }
123         return version;
124     }
125 
126     private int resolveLatestSnapshotBuildNumber(
127             Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
128             throws RepositoryMetadataResolutionException {
129         RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata(artifact);
130 
131         getLogger().info("Retrieving previous build number from " + remoteRepository.getId());
132         repositoryMetadataManager.resolveAlways(metadata, localRepository, remoteRepository);
133 
134         int buildNumber = 0;
135         Metadata repoMetadata = metadata.getMetadata();
136         if ((repoMetadata != null)
137                 && (repoMetadata.getVersioning() != null
138                         && repoMetadata.getVersioning().getSnapshot() != null)) {
139             buildNumber = repoMetadata.getVersioning().getSnapshot().getBuildNumber();
140         }
141         return buildNumber;
142     }
143 
144     public static DateFormat getUtcDateFormatter() {
145         DateFormat utcDateFormatter = new SimpleDateFormat(DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT);
146         utcDateFormatter.setCalendar(new GregorianCalendar());
147         utcDateFormatter.setTimeZone(DEFAULT_SNAPSHOT_TIME_ZONE);
148         return utcDateFormatter;
149     }
150 }