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.lifecycle.internal.concurrent;
20  
21  import java.util.Collection;
22  import java.util.HashSet;
23  import java.util.LinkedHashMap;
24  import java.util.Map;
25  import java.util.Objects;
26  import java.util.Set;
27  import java.util.TreeMap;
28  import java.util.concurrent.atomic.AtomicBoolean;
29  import java.util.concurrent.atomic.AtomicInteger;
30  import java.util.stream.Stream;
31  
32  import org.apache.maven.api.Lifecycle;
33  import org.apache.maven.plugin.MojoExecution;
34  import org.apache.maven.project.MavenProject;
35  
36  public class BuildStep {
37      public static final int CREATED = 0;
38      public static final int PLANNING = 1;
39      public static final int SCHEDULED = 2;
40      public static final int EXECUTED = 3;
41      public static final int FAILED = 4;
42  
43      public static final String PLAN = "$plan$";
44      public static final String SETUP = "$setup$";
45      public static final String TEARDOWN = "$teardown$";
46  
47      final MavenProject project;
48      final String name;
49      final Lifecycle.Phase phase;
50      final Map<Integer, Map<String, MojoExecution>> mojos = new TreeMap<>();
51      final Collection<BuildStep> predecessors = new HashSet<>();
52      final Collection<BuildStep> successors = new HashSet<>();
53      final AtomicInteger status = new AtomicInteger();
54      final AtomicBoolean skip = new AtomicBoolean();
55  
56      public BuildStep(String name, MavenProject project, Lifecycle.Phase phase) {
57          this.name = name;
58          this.project = project;
59          this.phase = phase;
60      }
61  
62      public Stream<BuildStep> allPredecessors() {
63          return preds(new HashSet<>()).stream();
64      }
65  
66      private Set<BuildStep> preds(Set<BuildStep> preds) {
67          if (preds.add(this)) {
68              this.predecessors.forEach(n -> n.preds(preds));
69          }
70          return preds;
71      }
72  
73      public boolean isSuccessorOf(BuildStep step) {
74          return isSuccessorOf(new HashSet<>(), step);
75      }
76  
77      private boolean isSuccessorOf(Set<BuildStep> visited, BuildStep step) {
78          if (this == step) {
79              return true;
80          } else if (visited.add(this)) {
81              return this.predecessors.stream().anyMatch(n -> n.isSuccessorOf(visited, step));
82          } else {
83              return false;
84          }
85      }
86  
87      public void skip() {
88          skip.set(true);
89          mojos.clear();
90      }
91  
92      public void addMojo(MojoExecution mojo, int priority) {
93          if (!skip.get()) {
94              mojos.computeIfAbsent(priority, k -> new LinkedHashMap<>())
95                      .put(mojo.getGoal() + ":" + mojo.getExecutionId(), mojo);
96          }
97      }
98  
99      public void executeAfter(BuildStep stepToExecuteBefore) {
100         if (!isSuccessorOf(stepToExecuteBefore)) {
101             predecessors.add(stepToExecuteBefore);
102             stepToExecuteBefore.successors.add(this);
103         }
104     }
105 
106     public Stream<MojoExecution> executions() {
107         return mojos.values().stream().flatMap(m -> m.values().stream());
108     }
109 
110     @Override
111     public boolean equals(Object o) {
112         if (this == o) {
113             return true;
114         }
115         if (o == null || getClass() != o.getClass()) {
116             return false;
117         }
118         BuildStep that = (BuildStep) o;
119         return Objects.equals(project, that.project) && Objects.equals(name, that.name);
120     }
121 
122     @Override
123     public int hashCode() {
124         return Objects.hash(project, name);
125     }
126 
127     @Override
128     public String toString() {
129         return "BuildStep[" + "project="
130                 + project.getGroupId() + ":" + project.getArtifactId() + ", phase="
131                 + name + ']';
132     }
133 }