2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.odlparent;
12 import java.io.FileInputStream;
13 import java.io.FileNotFoundException;
14 import java.net.MalformedURLException;
16 import java.util.ArrayList;
17 import java.util.LinkedHashSet;
18 import java.util.List;
20 import java.util.regex.Pattern;
21 import javax.annotation.RegEx;
22 import org.apache.karaf.features.internal.model.Bundle;
23 import org.apache.karaf.features.internal.model.ConfigFile;
24 import org.apache.karaf.features.internal.model.Feature;
25 import org.apache.karaf.features.internal.model.Features;
26 import org.apache.karaf.features.internal.model.JaxbUtil;
27 import org.eclipse.aether.artifact.Artifact;
28 import org.eclipse.aether.resolution.ArtifactResolutionException;
29 import org.ops4j.pax.url.mvn.internal.Parser;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
33 public final class FeatureUtil {
34 private static final Logger LOG = LoggerFactory.getLogger(FeatureUtil.class);
36 private static final Pattern MVN_PATTERN = Pattern.compile("mvn:", Pattern.LITERAL);
37 private static final Pattern WRAP_PATTERN = Pattern.compile("wrap:", Pattern.LITERAL);
40 private static final String VERSION_STRIP_PATTERN_STR = "\\$.*$";
41 private static final Pattern VERSION_STRIP_PATTERN = Pattern.compile(VERSION_STRIP_PATTERN_STR);
43 private FeatureUtil() {
44 throw new UnsupportedOperationException();
48 * Converts the given list of URLs to artifact coordinates.
50 * @param urls The URLs.
51 * @return The corresponding artifact coordinates.
52 * @throws MalformedURLException if a URL is malformed.
54 public static List<String> toCoord(final List<URL> urls) throws MalformedURLException {
55 List<String> result = new ArrayList<>();
56 for (URL url : urls) {
57 result.add(toCoord(url));
59 LOG.trace("toCoord({}) returns {}", urls, result);
64 * Converts the given URL to artifact coordinates.
67 * @return The corresponding artifact coordinates.
68 * @throws MalformedURLException if the URL is malformed.
70 public static String toCoord(final URL url) throws MalformedURLException {
71 String repository = url.toString();
72 String unwrappedRepo = WRAP_PATTERN.matcher(repository).replaceFirst("");
74 // FIXME: this is a hack to deal with broken upstream repo and should be removed once karaf moves
75 // to hibernate-validator-osgi-features-5.4.2+
76 if ("mvn:com.thoughtworks.paranamer:paranamer:2.8".equals(unwrappedRepo)) {
77 LOG.info("Working around broken hibernate-validator-osgi-karaf-features...");
78 unwrappedRepo = "mvn:com.thoughtworks.paranamer/paranamer/2.8";
81 Parser parser = new Parser(unwrappedRepo);
82 String coord = MVN_PATTERN.matcher(parser.getGroup()).replaceFirst("") + ":" + parser.getArtifact();
83 if (parser.getType() != null) {
84 coord = coord + ":" + parser.getType();
86 if (parser.getClassifier() != null) {
87 coord = coord + ":" + parser.getClassifier();
89 coord = coord + ":" + VERSION_STRIP_PATTERN.matcher(parser.getVersion()).replaceAll("");
90 LOG.trace("toCoord({}) returns {}", url, coord);
95 * Parses the given repository as URLs and converts them to artifact coordinates.
97 * @param repository The repository (list of URLs).
98 * @return The corresponding artifact coordinates.
99 * @throws MalformedURLException if a URL is malformed.
101 public static Set<String> mvnUrlsToCoord(final List<String> repository) throws MalformedURLException {
102 Set<String> result = new LinkedHashSet<>();
103 for (String url : repository) {
104 result.add(toCoord(new URL(url)));
106 LOG.trace("mvnUrlsToCoord({}) returns {}", repository, result);
111 * Converts the given features' repository to artifact coordinates.
113 * @param features The features.
114 * @return The corresponding artifact coordinates.
115 * @throws MalformedURLException if a URL is malformed.
117 public static Set<String> featuresRepositoryToCoords(final Features features) throws MalformedURLException {
118 return mvnUrlsToCoord(features.getRepository());
122 * Converts all the given features' repositories to artifact coordinates.
124 * @param features The features.
125 * @return The corresponding artifact coordinates.
126 * @throws MalformedURLException if a URL is malformed.
128 public static Set<String> featuresRepositoryToCoords(final Set<Features> features) throws MalformedURLException {
129 Set<String> result = new LinkedHashSet<>();
130 for (Features feature : features) {
131 result.addAll(featuresRepositoryToCoords(feature));
133 LOG.trace("featuresRepositoryToCoords({}) returns {}", features, result);
138 * Lists the artifact coordinates of the given feature's bundles and configuration files.
140 * @param feature The feature.
141 * @return The corresponding coordinates.
142 * @throws MalformedURLException if a URL is malformed.
144 public static Set<String> featureToCoords(final Feature feature) throws MalformedURLException {
145 Set<String> result = new LinkedHashSet<>();
146 if (feature.getBundle() != null) {
147 result.addAll(bundlesToCoords(feature.getBundle()));
149 if (feature.getConfigfile() != null) {
150 result.addAll(configFilesToCoords(feature.getConfigfile()));
152 LOG.trace("featureToCoords({}) returns {}", feature.getName(), result);
157 * Lists the artifact coordinates of the given configuration files.
159 * @param configfiles The configuration files.
160 * @return The corresponding coordinates.
161 * @throws MalformedURLException if a URL is malformed.
163 public static Set<String> configFilesToCoords(final List<ConfigFile> configfiles) throws MalformedURLException {
164 Set<String> result = new LinkedHashSet<>();
165 for (ConfigFile configFile : configfiles) {
166 result.add(toCoord(new URL(configFile.getLocation())));
168 LOG.trace("configFilesToCoords({}) returns {}", configfiles, result);
173 * Lists the artifact coordinates of the given bundles.
175 * @param bundles The bundles.
176 * @return The corresponding coordinates.
177 * @throws MalformedURLException if a URL is malformed.
179 public static Set<String> bundlesToCoords(final List<Bundle> bundles) throws MalformedURLException {
180 Set<String> result = new LinkedHashSet<>();
181 for (Bundle bundle : bundles) {
182 result.add(toCoord(new URL(bundle.getLocation())));
184 LOG.trace("bundlesToCoords({}) returns {}", bundles, result);
189 * Extracts all the artifact coordinates for the given features (repositories, bundles, configuration files).
191 * @param features The feature.
192 * @return The artifact coordinates.
193 * @throws MalformedURLException if a URL is malformed.
195 public static Set<String> featuresToCoords(final Features features) throws MalformedURLException {
196 Set<String> result = new LinkedHashSet<>();
197 if (features.getRepository() != null) {
198 result.addAll(featuresRepositoryToCoords(features));
200 if (features.getFeature() != null) {
201 for (Feature feature : features.getFeature()) {
202 result.addAll(featureToCoords(feature));
205 LOG.trace("featuresToCoords({}) returns {}", features.getName(), result);
210 * Extracts all the artifact coordinates for the given set of features (repositories, bundles, configuration
213 * @param features The features.
214 * @return The artifact coordinates.
215 * @throws MalformedURLException if a URL is malformed.
217 public static Set<String> featuresToCoords(final Set<Features> features) throws MalformedURLException {
218 Set<String> result = new LinkedHashSet<>();
219 for (Features feature : features) {
220 result.addAll(featuresToCoords(feature));
222 LOG.trace("featuresToCoords({}) returns {}", features, result);
227 * Unmarshal all the features in the given artifacts.
229 * @param featureArtifacts The artifacts.
230 * @return The features.
231 * @throws FileNotFoundException if a file is missing.
233 public static Set<Features> readFeatures(final Set<Artifact> featureArtifacts) throws FileNotFoundException {
234 Set<Features> result = new LinkedHashSet<>();
235 for (Artifact artifact : featureArtifacts) {
236 result.add(readFeature(artifact));
238 LOG.trace("readFeatures({}) returns {}", featureArtifacts, result);
243 * Unmarshal the features in the given artifact.
245 * @param artifact The artifact.
246 * @return The features.
247 * @throws FileNotFoundException if a file is missing.
249 public static Features readFeature(final Artifact artifact) throws FileNotFoundException {
250 return readFeature(artifact.getFile());
254 * Unmarshal the features in the given file.
256 * @param file The file.
257 * @return The features.
258 * @throws FileNotFoundException if a file is missing.
260 public static Features readFeature(final File file) throws FileNotFoundException {
261 FileInputStream stream = new FileInputStream(file);
262 Features result = JaxbUtil.unmarshal(file.toURI().toString(), stream, false);
263 LOG.trace("readFeature({}) returns {} without resolving first", file, result.getName());
268 * Unmarshal the features matching the given artifact coordinates.
270 * @param aetherUtil The Aether resolver.
271 * @param coords The artifact coordinates.
272 * @return The features.
273 * @throws ArtifactResolutionException if the coordinates can't be resolved.
274 * @throws FileNotFoundException if a file is missing.
276 public static Features readFeature(final AetherUtil aetherUtil, final String coords)
277 throws ArtifactResolutionException, FileNotFoundException {
278 Artifact artifact = aetherUtil.resolveArtifact(coords);
279 Features result = readFeature(artifact);
280 LOG.trace("readFeature({}) returns {} after resolving first", coords, result.getName());
285 * Unmarshals all the features starting from the given feature.
287 * @param aetherUtil The Aether resolver.
288 * @param features The starting features.
289 * @param existingCoords The artifact coordinates which have already been unmarshalled.
290 * @return The features.
291 * @throws MalformedURLException if a URL is malformed.
292 * @throws FileNotFoundException if a file is missing.
293 * @throws ArtifactResolutionException if artifact coordinates can't be resolved.
295 public static Set<Features> findAllFeaturesRecursively(
296 final AetherUtil aetherUtil, final Features features, final Set<String> existingCoords)
297 throws MalformedURLException, FileNotFoundException, ArtifactResolutionException {
298 LOG.debug("findAllFeaturesRecursively({}) starts", features.getName());
299 LOG.trace("findAllFeaturesRecursively knows about these coords: {}", existingCoords);
300 Set<Features> result = new LinkedHashSet<>();
301 Set<String> coords = FeatureUtil.featuresRepositoryToCoords(features);
302 for (String coord : coords) {
303 if (!existingCoords.contains(coord)) {
304 LOG.trace("findAllFeaturesRecursively() going to add {}", coord);
305 existingCoords.add(coord);
306 Features feature = FeatureUtil.readFeature(aetherUtil, coord);
308 LOG.debug("findAllFeaturesRecursively() added {}", coord);
309 result.addAll(findAllFeaturesRecursively(aetherUtil, FeatureUtil.readFeature(aetherUtil, coord),
312 LOG.trace("findAllFeaturesRecursively() skips known {}", coord);
319 * Unmarshals all the features starting from the given features.
321 * @param aetherUtil The Aether resolver.
322 * @param features The starting features.
323 * @param existingCoords The artifact coordinates which have already been unmarshalled.
324 * @return The features.
325 * @throws MalformedURLException if a URL is malformed.
326 * @throws FileNotFoundException if a file is missing.
327 * @throws ArtifactResolutionException if artifact coordinates can't be resolved.
329 public static Set<Features> findAllFeaturesRecursively(
330 final AetherUtil aetherUtil, final Set<Features> features, final Set<String> existingCoords)
331 throws MalformedURLException, FileNotFoundException, ArtifactResolutionException {
332 Set<Features> result = new LinkedHashSet<>();
333 for (Features feature : features) {
334 result.addAll(findAllFeaturesRecursively(aetherUtil, feature, existingCoords));
340 * Unmarshals all the features (including known ones) starting from the given features.
342 * @param aetherUtil The Aether resolver.
343 * @param features The starting features.
344 * @return The features.
345 * @throws MalformedURLException if a URL is malformed.
346 * @throws FileNotFoundException if a file is missing.
347 * @throws ArtifactResolutionException if artifact coordinates can't be resolved.
349 public static Set<Features> findAllFeaturesRecursively(final AetherUtil aetherUtil, final Set<Features> features)
350 throws MalformedURLException, FileNotFoundException, ArtifactResolutionException {
351 return findAllFeaturesRecursively(aetherUtil, features, new LinkedHashSet<String>());