View Javadoc
1   package org.apache.maven.api.services;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.List;
26  import java.util.Optional;
27  
28  import org.apache.maven.api.Artifact;
29  import org.apache.maven.api.DependencyCoordinate;
30  import org.apache.maven.api.Project;
31  import org.apache.maven.api.Session;
32  import org.apache.maven.api.annotations.Experimental;
33  import org.apache.maven.api.annotations.Immutable;
34  import org.apache.maven.api.annotations.Nonnull;
35  import org.apache.maven.api.annotations.NotThreadSafe;
36  import org.apache.maven.api.annotations.Nullable;
37  
38  import static org.apache.maven.api.services.BaseRequest.nonNull;
39  
40  /**
41   * A request to collect the transitive dependencies and to build a dependency graph from them. There are three ways to
42   * create a dependency graph. First, only the root dependency can be given. Second, a root dependency and direct
43   * dependencies can be specified in which case the specified direct dependencies are merged with the direct dependencies
44   * retrieved from the artifact descriptor of the root dependency. And last, only direct dependencies can be specified in
45   * which case the root node of the resulting graph has no associated dependency.
46   *
47   * @since 4.0
48   * @see DependencyCollector#collect(DependencyCollectorRequest)
49   */
50  @Experimental
51  @Immutable
52  public interface DependencyCollectorRequest
53  {
54  
55      @Nonnull
56      Session getSession();
57  
58      @Nonnull
59      Optional<Artifact> getRootArtifact();
60  
61      @Nonnull
62      Optional<DependencyCoordinate> getRoot();
63  
64      @Nonnull
65      Collection<DependencyCoordinate> getDependencies();
66  
67      @Nonnull
68      Collection<DependencyCoordinate> getManagedDependencies();
69  
70      boolean getVerbose();
71  
72      @Nonnull
73      static DependencyCollectorRequest build( @Nonnull Session session, Artifact root )
74      {
75          return builder()
76                  .session( nonNull( session, "session cannot be null" ) )
77                  .rootArtifact( nonNull( root, "root cannot be null" ) )
78                  .build();
79      }
80  
81      @Nonnull
82      static DependencyCollectorRequest build( @Nonnull Session session, @Nonnull DependencyCoordinate root )
83      {
84          return builder()
85                  .session( nonNull( session, "session cannot be null" ) )
86                  .root( nonNull( root, "root cannot be null" ) )
87                  .build();
88      }
89  
90      @Nonnull
91      static DependencyCollectorRequest build( @Nonnull Session session, @Nonnull Project project )
92      {
93          return builder()
94                  .session( nonNull( session, "session cannot be null" ) )
95                  .rootArtifact( nonNull( project, "project cannot be null" ).getArtifact() )
96                  .dependencies( project.getDependencies() )
97                  .managedDependencies( project.getManagedDependencies() )
98                  .build();
99      }
100 
101     @Nonnull
102     static DependencyCollectorRequestBuilder builder()
103     {
104         return new DependencyCollectorRequestBuilder();
105     }
106 
107     @NotThreadSafe
108     class DependencyCollectorRequestBuilder
109     {
110 
111         Session session;
112         Artifact rootArtifact;
113         DependencyCoordinate root;
114         List<DependencyCoordinate> dependencies = Collections.emptyList();
115         List<DependencyCoordinate> managedDependencies = Collections.emptyList();
116         boolean verbose;
117 
118         DependencyCollectorRequestBuilder()
119         {
120         }
121 
122         @Nonnull
123         public DependencyCollectorRequestBuilder session( @Nonnull Session session )
124         {
125             this.session = session;
126             return this;
127         }
128 
129         /**
130          * Sets the root artifact for the dependency graph.
131          * This must not be confused with {@link #root(DependencyCoordinate)}: The root <em>dependency</em>, like any
132          * other specified dependency, will be subject to dependency collection/resolution, i.e. should have an artifact
133          * descriptor and a corresponding artifact file. The root <em>artifact</em> on the other hand is only used
134          * as a label for the root node of the graph in case no root dependency was specified. As such, the configured
135          * root artifact is ignored if {@link #root(DependencyCoordinate)} has been set.
136          *
137          * @param rootArtifact The root artifact for the dependency graph, may be {@code null}.
138          * @return This request for chaining, never {@code null}.
139          */
140         @Nonnull
141         public DependencyCollectorRequestBuilder rootArtifact( @Nullable Artifact rootArtifact )
142         {
143             this.rootArtifact = rootArtifact;
144             return this;
145         }
146 
147         /**
148          * @param root The root dependency
149          * @return This request for chaining, never {@code null}.
150          */
151         @Nonnull
152         public DependencyCollectorRequestBuilder root( @Nonnull DependencyCoordinate root )
153         {
154             this.root = root;
155             return this;
156         }
157 
158         /**
159          * Sets the direct dependencies. If both a root dependency and direct dependencies are given in the request, the
160          * direct dependencies from the request will be merged with the direct dependencies from the root dependency's
161          * artifact descriptor, giving higher priority to the dependencies from the request.
162          *
163          * @param dependencies The direct dependencies, may be {@code null}.
164          * @return This request for chaining, never {@code null}.
165          */
166         @Nonnull
167         public DependencyCollectorRequestBuilder dependencies( @Nullable List<DependencyCoordinate> dependencies )
168         {
169             this.dependencies = ( dependencies != null ) ? dependencies : Collections.emptyList();
170             return this;
171         }
172 
173         /**
174          * Adds the specified direct dependency.
175          *
176          * @param dependency The dependency to add, may be {@code null}.
177          * @return This request for chaining, never {@code null}.
178          */
179         @Nonnull
180         public DependencyCollectorRequestBuilder dependency( @Nullable DependencyCoordinate dependency )
181         {
182             if ( dependency != null )
183             {
184                 if ( this.dependencies.isEmpty() )
185                 {
186                     this.dependencies = new ArrayList<>();
187                 }
188                 this.dependencies.add( dependency );
189             }
190             return this;
191         }
192 
193 
194         /**
195          * Sets the dependency management to apply to transitive dependencies. To clarify, this management does not
196          * apply to
197          * the direct dependencies of the root node.
198          *
199          * @param managedDependencies The dependency management, may be {@code null}.
200          * @return This request for chaining, never {@code null}.
201          */
202         @Nonnull
203         public DependencyCollectorRequestBuilder managedDependencies(
204                         @Nullable List<DependencyCoordinate> managedDependencies )
205         {
206             this.managedDependencies = ( managedDependencies != null ) ? managedDependencies : Collections.emptyList();
207             return this;
208         }
209 
210         /**
211          * Adds the specified managed dependency.
212          *
213          * @param managedDependency The managed dependency to add, may be {@code null} in which case the call
214          *                          will have no effect.
215          * @return This request for chaining, never {@code null}.
216          */
217         @Nonnull
218         public DependencyCollectorRequestBuilder managedDependency( @Nullable DependencyCoordinate managedDependency )
219         {
220             if ( managedDependency != null )
221             {
222                 if ( this.managedDependencies.isEmpty() )
223                 {
224                     this.managedDependencies = new ArrayList<>();
225                 }
226                 this.managedDependencies.add( managedDependency );
227             }
228             return this;
229         }
230 
231         /**
232          * Specifies that the collection should be verbose.
233          *
234          * @param verbose whether the collection should be verbose or not.
235          * @return This request for chaining, never {@code null}.
236          */
237         @Nonnull
238         public DependencyCollectorRequestBuilder verbose( boolean verbose )
239         {
240             this.verbose = verbose;
241             return this;
242         }
243 
244         @Nonnull
245         public DependencyCollectorRequest build()
246         {
247             return new DefaultDependencyCollectorRequest(
248                     session,
249                     rootArtifact,
250                     root,
251                     dependencies,
252                     managedDependencies,
253                     verbose );
254         }
255 
256         static class DefaultDependencyCollectorRequest extends BaseRequest
257                 implements DependencyCollectorRequest
258         {
259             private final Artifact rootArtifact;
260             private final DependencyCoordinate root;
261             private final Collection<DependencyCoordinate> dependencies;
262             private final Collection<DependencyCoordinate> managedDependencies;
263             private final boolean verbose;
264 
265 
266             /**
267              * Creates a request with the specified properties.
268              *
269              * @param session      {@link Session}
270              * @param rootArtifact The root dependency whose transitive dependencies should be collected, may be {@code
271              *                     null}.
272              */
273             DefaultDependencyCollectorRequest(
274                     @Nonnull Session session,
275                     @Nullable Artifact rootArtifact,
276                     @Nullable DependencyCoordinate root,
277                     @Nonnull Collection<DependencyCoordinate> dependencies,
278                     @Nonnull Collection<DependencyCoordinate> managedDependencies,
279                     boolean verbose )
280             {
281                 super( session );
282                 this.rootArtifact = rootArtifact;
283                 this.root = root;
284                 this.dependencies = unmodifiable( nonNull( dependencies, "dependencies cannot be null" ) );
285                 this.managedDependencies = unmodifiable( nonNull( managedDependencies,
286                                                          "managedDependencies cannot be null" ) );
287                 this.verbose = verbose;
288             }
289 
290             @Nonnull
291             @Override
292             public Optional<Artifact> getRootArtifact()
293             {
294                 return Optional.ofNullable( rootArtifact );
295             }
296 
297             @Nonnull
298             @Override
299             public Optional<DependencyCoordinate> getRoot()
300             {
301                 return Optional.ofNullable( root );
302             }
303 
304             @Nonnull
305             @Override
306             public Collection<DependencyCoordinate> getDependencies()
307             {
308                 return dependencies;
309             }
310 
311             @Nonnull
312             @Override
313             public Collection<DependencyCoordinate> getManagedDependencies()
314             {
315                 return managedDependencies;
316             }
317 
318             @Override
319             public boolean getVerbose()
320             {
321                 return verbose;
322             }
323 
324             @Nonnull
325             @Override
326             public String toString()
327             {
328                 return getRoot() + " -> " + getDependencies();
329             }
330 
331         }
332     }
333 
334 }