f8db73fed1d22543f01a9906ace4c9e59722fd48
[odlparent.git] / karaf-plugin / src / main / java / org / opendaylight / odlparent / PopulateLocalRepoMojo.java
1 /*
2  * Copyright 2001-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.opendaylight.odlparent;
18
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.net.URL;
26 import java.util.Enumeration;
27 import java.util.HashMap;
28 import java.util.LinkedHashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Properties;
32 import java.util.Set;
33 import org.apache.karaf.features.internal.model.Features;
34 import org.apache.maven.plugin.AbstractMojo;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugin.MojoFailureException;
37 import org.apache.maven.project.MavenProject;
38 import org.eclipse.aether.RepositorySystem;
39 import org.eclipse.aether.RepositorySystemSession;
40 import org.eclipse.aether.artifact.Artifact;
41 import org.eclipse.aether.repository.RemoteRepository;
42 import org.opendaylight.odlparent.karafutil.CustomBundleUrlStreamHandlerFactory;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 // TODO: Use org.apache.maven.plugin.annotations.* to allow more flexibility for non-ODL consumers.
47
48 /**
49  * Mojo populating the local repository by delegating to Aether.
50  *
51  * @goal populate-local-repo
52  * @phase prepare-package
53  */
54 // URL.setURLStreamHandlerFactory throws an Error directly, so we can’t do any better than this...
55 @SuppressWarnings("checkstyle:IllegalCatch")
56 public class PopulateLocalRepoMojo
57     extends AbstractMojo {
58     private static final Logger LOG = LoggerFactory.getLogger(PopulateLocalRepoMojo.class);
59
60     static {
61         // Static initialization, as we may be invoked multiple times
62         // karaf-maven-plugin defines its own URLStreamHandlerFactory for install-kars, so we may find a factory
63         // already defined (but it handles "mvn:" and "wrap:mvn:" so we should be OK)
64         try {
65             URL.setURLStreamHandlerFactory(new CustomBundleUrlStreamHandlerFactory());
66         } catch (Error e) {
67             LOG.warn("populate-local-repo: URL factory is already defined");
68         }
69     }
70
71     /**
72      * The Maven project being built.
73      *
74      * @component
75      * @required
76      * @readonly
77      */
78     private MavenProject project;
79
80     /**
81      * The entry point to Aether, i.e. the component doing all the work.
82      *
83      * @component
84      */
85     private RepositorySystem repoSystem;
86
87     /**
88      * The current repository/network configuration of Maven.
89      *
90      * @parameter default-value="${repositorySystemSession}"
91      * @readonly
92      */
93     private RepositorySystemSession repoSession;
94
95     /**
96      * The project's remote repositories to use for the resolution of plugins and their dependencies.
97      *
98      * @parameter default-value="${project.remoteProjectRepositories}"
99      * @readonly
100      */
101     private List<RemoteRepository> remoteRepos;
102
103     /**
104      * The local repository to use for the resolution of plugins and their dependencies.
105      *
106      * @parameter
107      */
108     private File localRepo;
109
110     private AetherUtil aetherUtil;
111
112     @Override
113     public void execute() throws MojoExecutionException, MojoFailureException {
114
115         aetherUtil = new AetherUtil(repoSystem, repoSession, remoteRepos, localRepo);
116         try {
117             Set<Artifact> startupArtifacts = readStartupProperties();
118             aetherUtil.installArtifacts(startupArtifacts);
119             Set<Artifact> featureArtifacts = new LinkedHashSet<>();
120             Set<Features> features = new LinkedHashSet<>();
121             readFeatureCfg(featureArtifacts, features);
122             featureArtifacts.addAll(
123                 aetherUtil.resolveDependencies(MvnToAetherMapper.toAether(project.getDependencies()),
124                     new KarafFeaturesDependencyFilter()));
125             features.addAll(FeatureUtil.readFeatures(featureArtifacts));
126             // Do not provide FeatureUtil.featuresRepositoryToCoords(features)) as existingCoords
127             // to findAllFeaturesRecursively, as those coords are not resolved yet, and it would lead to Bug 6187.
128             features.addAll(FeatureUtil.findAllFeaturesRecursively(aetherUtil, features));
129             for (Features feature : features) {
130                 LOG.info("Feature repository discovered recursively: {}", feature.getName());
131             }
132             Set<Artifact> artifacts = aetherUtil.resolveArtifacts(FeatureUtil.featuresToCoords(features));
133             artifacts.addAll(featureArtifacts);
134
135             Map<Gace, String> gaceVersions = new HashMap<>();
136             for (Artifact artifact : artifacts) {
137                 LOG.debug("Artifact to be installed: {}", artifact.toString());
138                 Gace gace = new Gace(artifact);
139                 String duplicate = gaceVersions.putIfAbsent(gace, artifact.getVersion());
140                 if (duplicate != null && !duplicate.equals(artifact.getVersion())) {
141                     LOG.warn("Duplicate versions for {}, {} and {}", gace, duplicate, artifact.getVersion());
142                 }
143             }
144             if (localRepo != null) {
145                 aetherUtil.installArtifacts(artifacts);
146             }
147         } catch (Exception e) {
148             throw new MojoExecutionException("Failed to execute", e);
149         }
150     }
151
152     private void readFeatureCfg(Set<Artifact> artifacts, Set<Features> features) {
153         String karafHome = localRepo.getParent();
154         File file = new File(karafHome + "/etc/org.apache.karaf.features.cfg");
155         Properties prop = new Properties();
156         try {
157             prop.load(new FileInputStream(file));
158             String featuresRepositories = prop.getProperty("featuresRepositories");
159             for (String mvnUrl : featuresRepositories.split(",")) {
160                 String fixedUrl = mvnUrl.replace("${karaf.home}", karafHome);
161                 if (fixedUrl.startsWith("file:")) {
162                     try {
163                         // Local feature file
164                         features.add(FeatureUtil.readFeature(new File(new URI(fixedUrl))));
165                     } catch (URISyntaxException e) {
166                         LOG.info("Could not resolve URI: {}", fixedUrl, e);
167                     }
168                 } else {
169                     artifacts.add(aetherUtil.resolveArtifact(FeatureUtil.toCoord(new URL(fixedUrl))));
170                 }
171             }
172         } catch (FileNotFoundException e) {
173             LOG.info("Could not find properties file: {}", file.getAbsolutePath(), e);
174         } catch (IOException e) {
175             LOG.info("Could not read properties file: {}", file.getAbsolutePath(), e);
176         }
177     }
178
179     private Set<Artifact> readStartupProperties() {
180         Set<Artifact> artifacts = new LinkedHashSet<>();
181         File file = new File(localRepo.getParentFile().toString() + "/etc/startup.properties");
182         Properties prop = new Properties();
183         try {
184             prop.load(new FileInputStream(file));
185             Enumeration<Object> mvnUrls = prop.keys();
186             while (mvnUrls.hasMoreElements()) {
187                 String mvnUrl = (String) mvnUrls.nextElement();
188                 Artifact artifact = aetherUtil.resolveArtifact(FeatureUtil.toCoord(new URL(mvnUrl)));
189                 artifacts.add(artifact);
190             }
191         } catch (FileNotFoundException e) {
192             LOG.info("Could not find properties file: {}", file.getAbsolutePath(), e);
193         } catch (IOException e) {
194             LOG.info("Could not read properties file: {}", file.getAbsolutePath(), e);
195         }
196
197         return artifacts;
198     }
199 }