Bug 6187: Force more maven resolution in karaf-plugin
[odlparent.git] / karaf-plugin / src / main / java / org / opendaylight / odlparent / FeatureUtil.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.odlparent;
10
11 import java.io.File;
12 import java.io.FileInputStream;
13 import java.io.FileNotFoundException;
14 import java.net.MalformedURLException;
15 import java.net.URL;
16 import java.util.ArrayList;
17 import java.util.LinkedHashSet;
18 import java.util.List;
19 import java.util.Set;
20 import org.apache.karaf.features.internal.model.Bundle;
21 import org.apache.karaf.features.internal.model.ConfigFile;
22 import org.apache.karaf.features.internal.model.Feature;
23 import org.apache.karaf.features.internal.model.Features;
24 import org.apache.karaf.features.internal.model.JaxbUtil;
25 import org.eclipse.aether.artifact.Artifact;
26 import org.eclipse.aether.resolution.ArtifactResolutionException;
27 import org.ops4j.pax.url.mvn.internal.Parser;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 public final class FeatureUtil {
32     private static final Logger LOG = LoggerFactory.getLogger(FeatureUtil.class);
33
34     private FeatureUtil() {
35         throw new UnsupportedOperationException();
36     }
37
38     /**
39      * Converts the given list of URLs to artifact coordinates.
40      *
41      * @param urls The URLs.
42      * @return The corresponding artifact coordinates.
43      * @throws MalformedURLException if a URL is malformed.
44      */
45     public static List<String> toCoord(List<URL> urls) throws MalformedURLException {
46         List<String> result = new ArrayList<>();
47         for (URL url : urls) {
48             result.add(toCoord(url));
49         }
50         LOG.trace("toCoord({}) returns {}", urls, result);
51         return result;
52     }
53
54     /**
55      * Converts the given URL to artifact coordinates.
56      *
57      * @param url The URL.
58      * @return The corresponding artifact coordinates.
59      * @throws MalformedURLException if the URL is malformed.
60      */
61     public static String toCoord(URL url) throws MalformedURLException {
62         String repository = url.toString();
63         String unwrappedRepo = repository.replaceFirst("wrap:", "");
64         Parser parser = new Parser(unwrappedRepo);
65         String coord = parser.getGroup().replace("mvn:", "") + ":" + parser.getArtifact();
66         if (parser.getType() != null) {
67             coord = coord + ":" + parser.getType();
68         }
69         if (parser.getClassifier() != null) {
70             coord = coord + ":" + parser.getClassifier();
71         }
72         coord = coord + ":" + parser.getVersion().replaceAll("\\$.*$", "");
73         LOG.trace("toCoord({}) returns {}", url, coord);
74         return coord;
75     }
76
77     /**
78      * Parses the given repository as URLs and converts them to artifact coordinates.
79      *
80      * @param repository The repository (list of URLs).
81      * @return The corresponding artifact coordinates.
82      * @throws MalformedURLException if a URL is malformed.
83      */
84     public static Set<String> mvnUrlsToCoord(List<String> repository) throws MalformedURLException {
85         Set<String> result = new LinkedHashSet<>();
86         for (String url : repository) {
87             result.add(toCoord(new URL(url)));
88         }
89         LOG.trace("mvnUrlsToCoord({}) returns {}", repository, result);
90         return result;
91     }
92
93     /**
94      * Converts the given features' repository to artifact coordinates.
95      *
96      * @param features The features.
97      * @return The corresponding artifact coordinates.
98      * @throws MalformedURLException if a URL is malformed.
99      */
100     public static Set<String> featuresRepositoryToCoords(Features features) throws MalformedURLException {
101         return mvnUrlsToCoord(features.getRepository());
102     }
103
104     /**
105      * Converts all the given features' repositories to artifact coordinates.
106      *
107      * @param features The features.
108      * @return The corresponding artifact coordinates.
109      * @throws MalformedURLException if a URL is malformed.
110      */
111     public static Set<String> featuresRepositoryToCoords(Set<Features> features) throws MalformedURLException {
112         Set<String> result = new LinkedHashSet<>();
113         for (Features feature : features) {
114             result.addAll(featuresRepositoryToCoords(feature));
115         }
116         LOG.trace("featuresRepositoryToCoords({}) returns {}", features, result);
117         return result;
118     }
119
120     /**
121      * Lists the artifact coordinates of the given feature's bundles and configuration files.
122      *
123      * @param feature The feature.
124      * @return The corresponding coordinates.
125      * @throws MalformedURLException if a URL is malformed.
126      */
127     public static Set<String> featureToCoords(Feature feature) throws MalformedURLException {
128         Set<String> result = new LinkedHashSet<>();
129         if (feature.getBundle() != null) {
130             result.addAll(bundlesToCoords(feature.getBundle()));
131         }
132         if (feature.getConfigfile() != null) {
133             result.addAll(configFilesToCoords(feature.getConfigfile()));
134         }
135         LOG.trace("featureToCoords({}) returns {}", feature.getName(), result);
136         return result;
137     }
138
139     /**
140      * Lists the artifact coordinates of the given configuration files.
141      *
142      * @param configfiles The configuration files.
143      * @return The corresponding coordinates.
144      * @throws MalformedURLException if a URL is malformed.
145      */
146     public static Set<String> configFilesToCoords(List<ConfigFile> configfiles) throws MalformedURLException {
147         Set<String> result = new LinkedHashSet<>();
148         for (ConfigFile configFile : configfiles) {
149             result.add(toCoord(new URL(configFile.getLocation())));
150         }
151         LOG.trace("configFilesToCoords({}) returns {}", configfiles, result);
152         return result;
153     }
154
155     /**
156      * Lists the artifact coordinates of the given bundles.
157      *
158      * @param bundles The bundles.
159      * @return The corresponding coordinates.
160      * @throws MalformedURLException if a URL is malformed.
161      */
162     public static Set<String> bundlesToCoords(List<Bundle> bundles) throws MalformedURLException {
163         Set<String> result = new LinkedHashSet<>();
164         for (Bundle bundle : bundles) {
165             result.add(toCoord(new URL(bundle.getLocation())));
166         }
167         LOG.trace("bundlesToCoords({}) returns {}", bundles, result);
168         return result;
169     }
170
171     /**
172      * Extracts all the artifact coordinates for the given features (repositories, bundles, configuration files).
173      *
174      * @param features The feature.
175      * @return The artifact coordinates.
176      * @throws MalformedURLException if a URL is malformed.
177      */
178     public static Set<String> featuresToCoords(Features features) throws MalformedURLException {
179         Set<String> result = new LinkedHashSet<>();
180         if (features.getRepository() != null) {
181             result.addAll(featuresRepositoryToCoords(features));
182         }
183         if (features.getFeature() != null) {
184             for (Feature feature : features.getFeature()) {
185                 result.addAll(featureToCoords(feature));
186             }
187         }
188         LOG.trace("featuresToCoords({}) returns {}", features.getName(), result);
189         return result;
190     }
191
192     /**
193      * Extracts all the artifact coordinates for the given set of features (repositories, bundles, configuration
194      * files).
195      *
196      * @param features The features.
197      * @return The artifact coordinates.
198      * @throws MalformedURLException if a URL is malformed.
199      */
200     public static Set<String> featuresToCoords(Set<Features> features) throws MalformedURLException {
201         Set<String> result = new LinkedHashSet<>();
202         for (Features feature : features) {
203             result.addAll(featuresToCoords(feature));
204         }
205         LOG.trace("featuresToCoords({}) returns {}", features, result);
206         return result;
207     }
208
209     /**
210      * Unmarshal all the features in the given artifacts.
211      *
212      * @param featureArtifacts The artifacts.
213      * @return The features.
214      * @throws FileNotFoundException if a file is missing.
215      */
216     public static Set<Features> readFeatures(Set<Artifact> featureArtifacts) throws FileNotFoundException {
217         Set<Features> result = new LinkedHashSet<>();
218         for (Artifact artifact : featureArtifacts) {
219             result.add(readFeature(artifact));
220         }
221         LOG.trace("readFeatures({}) returns {}", featureArtifacts, result);
222         return result;
223     }
224
225     /**
226      * Unmarshal the features in the given artifact.
227      *
228      * @param artifact The artifact.
229      * @return The features.
230      * @throws FileNotFoundException if a file is missing.
231      */
232     public static Features readFeature(Artifact artifact) throws FileNotFoundException {
233         File file = artifact.getFile();
234         FileInputStream stream = new FileInputStream(file);
235         Features result = JaxbUtil.unmarshal(stream, false);
236         LOG.trace("readFeature({}) returns {} without resolving first", artifact, result.getName());
237         return result;
238     }
239
240     /**
241      * Unmarshal the features matching the given artifact coordinates.
242      *
243      * @param aetherUtil The Aether resolver.
244      * @param coords The artifact coordinates.
245      * @return The features.
246      * @throws ArtifactResolutionException if the coordinates can't be resolved.
247      * @throws FileNotFoundException if a file is missing.
248      */
249     public static Features readFeature(AetherUtil aetherUtil, String coords)
250             throws ArtifactResolutionException, FileNotFoundException {
251         Artifact artifact = aetherUtil.resolveArtifact(coords);
252         Features result = readFeature(artifact);
253         LOG.trace("readFeature({}) returns {} after resolving first", coords, result.getName());
254         return result;
255     }
256
257     /**
258      * Unmarshals all the features starting from the given feature.
259      *
260      * @param aetherUtil The Aether resolver.
261      * @param features The starting features.
262      * @param existingCoords The artifact coordinates which have already been unmarshalled.
263      * @return The features.
264      * @throws MalformedURLException if a URL is malformed.
265      * @throws FileNotFoundException if a file is missing.
266      * @throws ArtifactResolutionException if artifact coordinates can't be resolved.
267      */
268     public static Set<Features> findAllFeaturesRecursively(
269             AetherUtil aetherUtil, Features features, Set<String> existingCoords)
270             throws MalformedURLException, FileNotFoundException, ArtifactResolutionException {
271         LOG.debug("findAllFeaturesRecursively({}) starts", features.getName());
272         LOG.trace("findAllFeaturesRecursively knows about these coords: {}", existingCoords);
273         Set<Features> result = new LinkedHashSet<>();
274         Set<String> coords = FeatureUtil.featuresRepositoryToCoords(features);
275         for (String coord : coords) {
276             if (!existingCoords.contains(coord)) {
277                 LOG.trace("findAllFeaturesRecursively() going to add {}", coord);
278                 existingCoords.add(coord);
279                 Features feature = FeatureUtil.readFeature(aetherUtil, coord);
280                 result.add(feature);
281                 LOG.debug("findAllFeaturesRecursively() added {}", coord);
282                 result.addAll(findAllFeaturesRecursively(aetherUtil, FeatureUtil.readFeature(aetherUtil, coord),
283                         existingCoords));
284             } else {
285                 LOG.trace("findAllFeaturesRecursively() skips known {}", coord);
286             }
287         }
288         return result;
289     }
290
291     /**
292      * Unmarshals all the features starting from the given features.
293      *
294      * @param aetherUtil The Aether resolver.
295      * @param features The starting features.
296      * @param existingCoords The artifact coordinates which have already been unmarshalled.
297      * @return The features.
298      * @throws MalformedURLException if a URL is malformed.
299      * @throws FileNotFoundException if a file is missing.
300      * @throws ArtifactResolutionException if artifact coordinates can't be resolved.
301      */
302     public static Set<Features> findAllFeaturesRecursively(
303             AetherUtil aetherUtil, Set<Features> features, Set<String> existingCoords)
304             throws MalformedURLException, FileNotFoundException, ArtifactResolutionException {
305         Set<Features> result = new LinkedHashSet<>();
306         for (Features feature : features) {
307             result.addAll(findAllFeaturesRecursively(aetherUtil, feature, existingCoords));
308         }
309         return result;
310     }
311
312     /**
313      * Unmarshals all the features (including known ones) starting from the given features.
314      *
315      * @param aetherUtil The Aether resolver.
316      * @param features The starting features.
317      * @return The features.
318      * @throws MalformedURLException if a URL is malformed.
319      * @throws FileNotFoundException if a file is missing.
320      * @throws ArtifactResolutionException if artifact coordinates can't be resolved.
321      */
322     public static Set<Features> findAllFeaturesRecursively(AetherUtil aetherUtil, Set<Features> features)
323             throws MalformedURLException, FileNotFoundException, ArtifactResolutionException {
324         return findAllFeaturesRecursively(aetherUtil, features, new LinkedHashSet<String>());
325     }
326
327 }