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