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