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.plugins.dependency.utils.filters;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.nio.file.Files;
24  import java.util.LinkedHashSet;
25  import java.util.Set;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.plugins.dependency.fromConfiguration.ArtifactItem;
29  import org.apache.maven.plugins.dependency.utils.DependencyUtil;
30  import org.apache.maven.shared.artifact.filter.collection.AbstractArtifactsFilter;
31  import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
32  
33  import static org.apache.maven.plugins.dependency.utils.StringUtils.isEmpty;
34  
35  /**
36   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
37   */
38  public class DestFileFilter extends AbstractArtifactsFilter implements ArtifactItemFilter {
39      private boolean overWriteReleases;
40  
41      private boolean overWriteSnapshots;
42  
43      private boolean overWriteIfNewer;
44  
45      private boolean useSubDirectoryPerArtifact;
46  
47      private boolean useSubDirectoryPerType;
48  
49      private final boolean useSubDirectoryPerScope;
50  
51      private boolean useRepositoryLayout;
52  
53      private boolean removeVersion;
54  
55      private boolean removeType;
56  
57      private boolean removeClassifier;
58  
59      private final boolean prependGroupId;
60  
61      private final boolean useBaseVersion;
62  
63      private File outputFileDirectory;
64  
65      /**
66       * @param outputFileDirectory the output directory.
67       */
68      public DestFileFilter(File outputFileDirectory) {
69          this(false, false, false, false, false, false, false, false, false, false, outputFileDirectory);
70      }
71  
72      /**
73       * @param overWriteReleases true/false.
74       * @param overWriteSnapshots true/false.
75       * @param overWriteIfNewer true/false.
76       * @param useSubDirectoryPerArtifact true/false.
77       * @param useSubDirectoryPerType true/false.
78       * @param useSubDirectoryPerScope true/false.
79       * @param useRepositoryLayout true/false.
80       * @param removeVersion true/false.
81       * @param prependGroupId true/false.
82       * @param useBaseVersion true/false.
83       * @param outputFileDirectory the output directory.
84       */
85      public DestFileFilter(
86              boolean overWriteReleases,
87              boolean overWriteSnapshots,
88              boolean overWriteIfNewer,
89              boolean useSubDirectoryPerArtifact,
90              boolean useSubDirectoryPerType,
91              boolean useSubDirectoryPerScope,
92              boolean useRepositoryLayout,
93              boolean removeVersion,
94              boolean prependGroupId,
95              boolean useBaseVersion,
96              File outputFileDirectory) {
97          this.overWriteReleases = overWriteReleases;
98          this.overWriteSnapshots = overWriteSnapshots;
99          this.overWriteIfNewer = overWriteIfNewer;
100         this.useSubDirectoryPerArtifact = useSubDirectoryPerArtifact;
101         this.useSubDirectoryPerType = useSubDirectoryPerType;
102         this.useSubDirectoryPerScope = useSubDirectoryPerScope;
103         this.useRepositoryLayout = useRepositoryLayout;
104         this.removeVersion = removeVersion;
105         this.prependGroupId = prependGroupId;
106         this.useBaseVersion = useBaseVersion;
107         this.outputFileDirectory = outputFileDirectory;
108     }
109 
110     /*
111      * (non-Javadoc)
112      * @see org.apache.mojo.dependency.utils.filters.ArtifactsFilter#filter(java.util.Set,
113      * org.apache.maven.plugin.logging.Log)
114      */
115     @Override
116     public Set<Artifact> filter(Set<Artifact> artifacts) throws ArtifactFilterException {
117         Set<Artifact> result = new LinkedHashSet<>();
118 
119         for (Artifact artifact : artifacts) {
120             if (isArtifactIncluded(new ArtifactItem(artifact))) {
121                 result.add(artifact);
122             }
123         }
124         return result;
125     }
126 
127     /**
128      * @return Returns the overWriteReleases.
129      */
130     public boolean isOverWriteReleases() {
131         return this.overWriteReleases;
132     }
133 
134     /**
135      * @param overWriteReleases The overWriteReleases to set.
136      */
137     public void setOverWriteReleases(boolean overWriteReleases) {
138         this.overWriteReleases = overWriteReleases;
139     }
140 
141     /**
142      * @return Returns the overWriteSnapshots.
143      */
144     public boolean isOverWriteSnapshots() {
145         return this.overWriteSnapshots;
146     }
147 
148     /**
149      * @param overWriteSnapshots The overWriteSnapshots to set.
150      */
151     public void setOverWriteSnapshots(boolean overWriteSnapshots) {
152         this.overWriteSnapshots = overWriteSnapshots;
153     }
154 
155     /**
156      * @return Returns the overWriteIfNewer.
157      */
158     public boolean isOverWriteIfNewer() {
159         return this.overWriteIfNewer;
160     }
161 
162     /**
163      * @param overWriteIfNewer The overWriteIfNewer to set.
164      */
165     public void setOverWriteIfNewer(boolean overWriteIfNewer) {
166         this.overWriteIfNewer = overWriteIfNewer;
167     }
168 
169     /**
170      * @return Returns the outputFileDirectory.
171      */
172     public File getOutputFileDirectory() {
173         return this.outputFileDirectory;
174     }
175 
176     /**
177      * @param outputFileDirectory The outputFileDirectory to set.
178      */
179     public void setOutputFileDirectory(File outputFileDirectory) {
180         this.outputFileDirectory = outputFileDirectory;
181     }
182 
183     /**
184      * @return Returns the removeVersion.
185      */
186     public boolean isRemoveVersion() {
187         return this.removeVersion;
188     }
189 
190     /**
191      * @param removeType The removeType to set.
192      */
193     public void setRemoveType(boolean removeType) {
194         this.removeType = removeType;
195     }
196 
197     /**
198      * @return Returns the removeType.
199      */
200     public boolean isRemoveType() {
201         return this.removeType;
202     }
203 
204     /**
205      * @param removeVersion The removeVersion to set.
206      */
207     public void setRemoveVersion(boolean removeVersion) {
208         this.removeVersion = removeVersion;
209     }
210 
211     /**
212      * @return Returns the removeClassifier.
213      */
214     public boolean isRemoveClassifier() {
215         return this.removeClassifier;
216     }
217 
218     /**
219      * @param removeClassifier The removeClassifier to set.
220      */
221     public void setRemoveClassifier(boolean removeClassifier) {
222         this.removeClassifier = removeClassifier;
223     }
224 
225     /**
226      * @return Returns the useSubDirectoryPerArtifact.
227      */
228     public boolean isUseSubDirectoryPerArtifact() {
229         return this.useSubDirectoryPerArtifact;
230     }
231 
232     /**
233      * @param useSubDirectoryPerArtifact The useSubDirectoryPerArtifact to set.
234      */
235     public void setUseSubDirectoryPerArtifact(boolean useSubDirectoryPerArtifact) {
236         this.useSubDirectoryPerArtifact = useSubDirectoryPerArtifact;
237     }
238 
239     /**
240      * @return Returns the useSubDirectoryPerType.
241      */
242     public boolean isUseSubDirectoryPerType() {
243         return this.useSubDirectoryPerType;
244     }
245 
246     /**
247      * @param useSubDirectoryPerType The useSubDirectoryPerType to set.
248      */
249     public void setUseSubDirectoryPerType(boolean useSubDirectoryPerType) {
250         this.useSubDirectoryPerType = useSubDirectoryPerType;
251     }
252 
253     /**
254      * @return Returns the useRepositoryLayout
255      */
256     public boolean isUseRepositoryLayout() {
257         return useRepositoryLayout;
258     }
259 
260     /**
261      * @param useRepositoryLayout the useRepositoryLayout to set
262      */
263     public void setUseRepositoryLayout(boolean useRepositoryLayout) {
264         this.useRepositoryLayout = useRepositoryLayout;
265     }
266 
267     @Override
268     public boolean isArtifactIncluded(ArtifactItem item) throws ArtifactFilterException {
269         Artifact artifact = item.getArtifact();
270 
271         boolean overWrite = (artifact.isSnapshot() && this.overWriteSnapshots)
272                 || (!artifact.isSnapshot() && this.overWriteReleases);
273 
274         File destFolder = item.getOutputDirectory();
275         if (destFolder == null) {
276             destFolder = DependencyUtil.getFormattedOutputDirectory(
277                     useSubDirectoryPerScope,
278                     useSubDirectoryPerType,
279                     useSubDirectoryPerArtifact,
280                     useRepositoryLayout,
281                     removeVersion,
282                     removeType,
283                     this.outputFileDirectory,
284                     artifact);
285         }
286 
287         File destFile;
288 
289         if (isEmpty(item.getDestFileName())) {
290             String formattedFileName = DependencyUtil.getFormattedFileName(
291                     artifact, removeVersion, prependGroupId, useBaseVersion, removeClassifier);
292             destFile = new File(destFolder, formattedFileName);
293         } else {
294             destFile = new File(destFolder, item.getDestFileName());
295         }
296 
297         return overWrite
298                 || !destFile.exists()
299                 || (overWriteIfNewer && getLastModified(artifact.getFile()) > getLastModified(destFile));
300     }
301 
302     /**
303      * Using simply {@code File.getLastModified} will return sometimes a wrong value see JDK bug for details.
304      * <p>
305      * https://bugs.openjdk.java.net/browse/JDK-8177809
306      *
307      * @param file {@link File}
308      * @return the last modification time in milliseconds.
309      * @throws ArtifactFilterException in case of a IO Exception.
310      */
311     private long getLastModified(File file) throws ArtifactFilterException {
312         try {
313             return Files.getLastModifiedTime(file.toPath()).toMillis();
314         } catch (IOException e) {
315             throw new ArtifactFilterException("IO Exception", e);
316         }
317     }
318 }