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.invoker;
20
21 /*
22 * Licensed to the Apache Software Foundation (ASF) under one
23 * or more contributor license agreements. See the NOTICE file
24 * distributed with this work for additional information
25 * regarding copyright ownership. The ASF licenses this file
26 * to you under the Apache License, Version 2.0 (the
27 * "License"); you may not use this file except in compliance
28 * with the License. You may obtain a copy of the License at
29 *
30 * http://www.apache.org/licenses/LICENSE-2.0
31 *
32 * Unless required by applicable law or agreed to in writing,
33 * software distributed under the License is distributed on an
34 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
35 * KIND, either express or implied. See the License for the
36 * specific language governing permissions and limitations
37 * under the License.
38 */
39
40 import java.util.LinkedHashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.concurrent.Callable;
44 import java.util.concurrent.ExecutorService;
45 import java.util.concurrent.Executors;
46 import java.util.stream.Collectors;
47
48 import org.apache.maven.plugins.invoker.model.BuildJob;
49
50 /**
51 * Execute build jobs with parallel.
52 *
53 * @author Slawomir Jaranowski
54 */
55 class JobExecutor {
56 interface ThrowableJobConsumer {
57 void accept(BuildJob t) throws Throwable;
58 }
59
60 private final List<BuildJob> jobs;
61 private final int threadsCount;
62
63 JobExecutor(List<BuildJob> jobs, int threadsCount) {
64 this.jobs = jobs;
65 this.threadsCount = threadsCount;
66 }
67
68 public void forEach(ThrowableJobConsumer jobConsumer) {
69 // group and sort jobs by ordinal
70 Map<Integer, List<BuildJob>> groupedJobs = jobs.stream()
71 .sorted((j1, j2) -> Integer.compare(j2.getOrdinal(), j1.getOrdinal()))
72 .collect(Collectors.groupingBy(BuildJob::getOrdinal, LinkedHashMap::new, Collectors.toList()));
73
74 ExecutorService executorService = Executors.newFixedThreadPool(threadsCount);
75
76 groupedJobs.forEach((key, value) -> {
77 // prepare list of callable tasks
78 List<Callable<Void>> callableJobs = value.stream()
79 .map(buildJob -> (Callable<Void>) () -> {
80 try {
81 jobConsumer.accept(buildJob);
82 } catch (Throwable e) {
83 buildJob.setResult(BuildJob.Result.ERROR);
84 buildJob.setFailureMessage(String.valueOf(e));
85 }
86 return null;
87 })
88 .collect(Collectors.toList());
89
90 try {
91 executorService.invokeAll(callableJobs);
92 } catch (InterruptedException e) {
93 Thread.currentThread().interrupt();
94 throw new RuntimeException(e);
95 }
96 });
97
98 // all task are finished here
99 executorService.shutdownNow();
100 }
101 }