3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org.apache.karaf.tooling.utils;
21 import java.io.FileInputStream;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.net.MalformedURLException;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
32 import org.apache.karaf.util.StreamUtils;
33 import org.apache.maven.artifact.Artifact;
34 import org.apache.maven.artifact.factory.ArtifactFactory;
35 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
36 import org.apache.maven.artifact.repository.ArtifactRepository;
37 import org.apache.maven.artifact.repository.DefaultArtifactRepository;
38 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
39 import org.apache.maven.artifact.resolver.ArtifactResolver;
40 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
41 import org.apache.maven.artifact.versioning.VersionRange;
42 import org.apache.maven.execution.MavenSession;
43 import org.apache.maven.model.Dependency;
44 import org.apache.maven.model.DependencyManagement;
45 import org.apache.maven.plugin.AbstractMojo;
46 import org.apache.maven.plugin.MojoExecutionException;
47 import org.apache.maven.plugins.annotations.Component;
48 import org.apache.maven.plugins.annotations.Parameter;
49 import org.apache.maven.project.MavenProject;
50 import org.apache.maven.project.MavenProjectBuilder;
51 import org.apache.maven.project.MavenProjectHelper;
52 import org.apache.maven.project.ProjectBuildingException;
53 import org.apache.maven.settings.Proxy;
54 import org.codehaus.plexus.PlexusContainer;
56 @SuppressWarnings({"deprecation", "rawtypes", "unchecked"})
57 public abstract class MojoSupport extends AbstractMojo {
63 protected MavenProjectHelper projectHelper;
68 @Parameter(defaultValue = "${project}", readonly = true)
69 protected MavenProject project;
72 * Directory that resources are copied to during the build.
74 @Parameter(defaultValue = "${project.build.directory}/${project.artifactId}-${project.version}-installer")
75 protected File workDirectory;
78 protected MavenProjectBuilder projectBuilder;
80 @Parameter(defaultValue = "${localRepository}")
81 protected ArtifactRepository localRepo;
83 @Parameter(defaultValue = "${project.remoteArtifactRepositories}")
84 protected List<ArtifactRepository> remoteRepos;
87 protected ArtifactMetadataSource artifactMetadataSource;
90 protected ArtifactResolver artifactResolver;
93 protected ArtifactFactory factory;
96 * The artifact type of a feature.
98 @Parameter(defaultValue = "xml")
99 private String featureArtifactType = "xml";
104 @Parameter(defaultValue = "${session}", readonly = true)
105 protected MavenSession mavenSession;
108 * <p>We can't autowire strongly typed RepositorySystem from Aether because it may be Sonatype (Maven 3.0.x)
109 * or Eclipse (Maven 3.1.x/3.2.x) version, so we switch to service locator by autowiring entire {@link PlexusContainer}</p>
111 * <p>It's a bit of a hack but we have not choice when we want to be usable both in Maven 3.0.x and 3.1.x/3.2.x</p>
114 protected PlexusContainer container;
116 protected MavenProject getProject() {
120 protected File getWorkDirectory() {
121 return workDirectory;
124 public MavenProjectHelper getProjectHelper() {
125 return projectHelper;
128 // called by Plexus when injecting the mojo's session
129 public void setMavenSession(MavenSession mavenSession) {
130 this.mavenSession = mavenSession;
132 if (mavenSession != null) {
133 // check for custom settings.xml and pass it onto pax-url-aether
134 File settingsFile = mavenSession.getRequest().getUserSettingsFile();
135 if (settingsFile != null && settingsFile.isFile()) {
136 System.setProperty("org.ops4j.pax.url.mvn.settings", settingsFile.getPath());
141 protected Map createManagedVersionMap(String projectId,
142 DependencyManagement dependencyManagement) throws ProjectBuildingException {
144 if (dependencyManagement != null
145 && dependencyManagement.getDependencies() != null) {
147 for (Iterator i = dependencyManagement.getDependencies().iterator(); i
149 Dependency d = (Dependency) i.next();
152 VersionRange versionRange = VersionRange
153 .createFromVersionSpec(d.getVersion());
154 Artifact artifact = factory.createDependencyArtifact(d
155 .getGroupId(), d.getArtifactId(), versionRange, d
156 .getType(), d.getClassifier(), d.getScope());
157 map.put(d.getManagementKey(), artifact);
158 } catch (InvalidVersionSpecificationException e) {
159 throw new ProjectBuildingException(projectId,
160 "Unable to parse version '" + d.getVersion()
161 + "' for dependency '"
162 + d.getManagementKey() + "': "
163 + e.getMessage(), e);
167 map = Collections.EMPTY_MAP;
172 protected String translateFromMaven(String uri) {
173 if (uri.startsWith("mvn:")) {
174 String[] parts = uri.substring("mvn:".length()).split("/");
175 String groupId = parts[0];
176 String artifactId = parts[1];
177 String version = null;
178 String classifier = null;
180 if (parts.length > 2) {
182 if (parts.length > 3) {
184 if (parts.length > 4) {
185 classifier = parts[4];
189 String dir = groupId.replace('.', '/') + "/" + artifactId + "/" + version + "/";
190 String name = artifactId + "-" + version + (classifier != null ? "-" + classifier : "") + "." + type;
192 return getLocalRepoUrl() + "/" + dir + name;
194 if (System.getProperty("os.name").startsWith("Windows") && uri.startsWith("file:")) {
195 String baseDir = uri.substring(5).replace('\\', '/').replaceAll(" ", "%20");
196 String result = baseDir;
197 if (baseDir.indexOf(":") > 0) {
198 result = "file:///" + baseDir;
205 protected String getLocalRepoUrl() {
206 if (System.getProperty("os.name").startsWith("Windows")) {
207 String baseDir = localRepo.getBasedir().replace('\\', '/').replaceAll(" ", "%20");
208 return extractProtocolFromLocalMavenRepo() + ":///" + baseDir;
210 return localRepo.getUrl();
215 * Required because Maven 3 returns null in {@link ArtifactRepository#getProtocol()} (see KARAF-244)
217 private String extractProtocolFromLocalMavenRepo() {
219 return new URL(localRepo.getUrl()).getProtocol();
220 } catch (MalformedURLException e) {
221 // Basically this should not happen; if it does though cancel the process
222 throw new RuntimeException("Repository URL is not valid", e);
226 private Dependency findDependency(List<Dependency> dependencies, String artifactId, String groupId) {
227 for(Dependency dep : dependencies) {
228 if (artifactId.equals(dep.getArtifactId()) && groupId.equals(dep.getGroupId()) &&
229 featureArtifactType.equals(dep.getType())) {
230 if (dep.getVersion() != null)
238 * Convert a feature resourceLocation (bundle or configuration file) into an artifact.
240 * @param resourceLocation the feature resource location (bundle or configuration file).
241 * @param skipNonMavenProtocols flag to skip protocol different than mvn:
242 * @return the artifact corresponding to the resource.
243 * @throws MojoExecutionException
245 protected Artifact resourceToArtifact(String resourceLocation, boolean skipNonMavenProtocols) throws MojoExecutionException {
246 resourceLocation = resourceLocation.replace("\r\n", "").replace("\n", "").replace(" ", "").replace("\t", "");
247 final int index = resourceLocation.indexOf("mvn:");
249 if (skipNonMavenProtocols) {
252 throw new MojoExecutionException("Resource URL is not a Maven URL: " + resourceLocation);
254 resourceLocation = resourceLocation.substring(index + "mvn:".length());
256 // Truncate the URL when a '#', a '?' or a '$' is encountered
257 final int index1 = resourceLocation.indexOf('?');
258 final int index2 = resourceLocation.indexOf('#');
262 endIndex = Math.min(index1, index2);
266 } else if (index2 > 0) {
270 resourceLocation = resourceLocation.substring(0, endIndex);
272 final int index3 = resourceLocation.indexOf('$');
274 resourceLocation = resourceLocation.substring(0, index3);
277 //check if the resourceLocation descriptor contains also remote repository information.
278 ArtifactRepository repo = null;
279 if (resourceLocation.startsWith("http://")) {
280 final int repoDelimIntex = resourceLocation.indexOf('!');
281 String repoUrl = resourceLocation.substring(0, repoDelimIntex);
283 repo = new DefaultArtifactRepository(
286 new DefaultRepositoryLayout());
287 org.apache.maven.repository.Proxy mavenProxy = configureProxyToInlineRepo();
288 if (mavenProxy != null) {
289 repo.setProxy(mavenProxy);
291 resourceLocation = resourceLocation.substring(repoDelimIntex + 1);
294 String[] parts = resourceLocation.split("/");
295 String groupId = parts[0];
296 String artifactId = parts[1];
297 String version = null;
298 String classifier = null;
300 if (parts.length > 2) {
302 if (parts.length > 3) {
304 if (parts.length > 4) {
305 classifier = parts[4];
309 Dependency dep = findDependency(project.getDependencies(), artifactId, groupId);
310 if (dep == null && project.getDependencyManagement() != null) {
311 dep = findDependency(project.getDependencyManagement().getDependencies(), artifactId, groupId);
314 version = dep.getVersion();
315 classifier = dep.getClassifier();
316 type = dep.getType();
319 if (version == null || version.isEmpty()) {
320 throw new MojoExecutionException("Cannot find version for: " + resourceLocation);
322 Artifact artifact = factory.createArtifactWithClassifier(groupId, artifactId, version, type, classifier);
323 artifact.setRepository(repo);
327 private org.apache.maven.repository.Proxy configureProxyToInlineRepo() {
328 if (mavenSession != null && mavenSession.getSettings() != null) {
329 Proxy proxy = mavenSession.getSettings().getActiveProxy();
330 org.apache.maven.repository.Proxy mavenProxy = new org.apache.maven.repository.Proxy();
332 mavenProxy.setProtocol(proxy.getProtocol());
333 mavenProxy.setHost(proxy.getHost());
334 mavenProxy.setPort(proxy.getPort());
335 mavenProxy.setNonProxyHosts(proxy.getNonProxyHosts());
336 mavenProxy.setUserName(proxy.getUsername());
337 mavenProxy.setPassword(proxy.getPassword());
348 protected void copy(File sourceFile, File destFile) {
349 File targetDir = destFile.getParentFile();
350 ensureDirExists(targetDir);
354 FileInputStream is = new FileInputStream(sourceFile);
355 FileOutputStream bos = new FileOutputStream(destFile)
357 StreamUtils.copy(is, bos);
359 } catch (IOException e) {
360 throw new RuntimeException(e.getMessage(), e);
366 * Make sure the target directory exists and
367 * that is actually a directory
369 * @throws IOException
371 private static void ensureDirExists(File targetDir) {
372 if (!targetDir.exists()) {
373 if (!targetDir.mkdirs()) {
374 throw new RuntimeException("Unable to create target directory: " + targetDir);
376 } else if (!targetDir.isDirectory()) {
377 throw new RuntimeException("Target is not a directory: " + targetDir);