Add .tox/ to .gitignore
[odlparent.git] / karaf / karaf-maven-plugin / src / main / java / org / apache / karaf / tooling / RunMojo.java
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.karaf.tooling;
20
21 import org.apache.commons.compress.archivers.ArchiveEntry;
22 import org.apache.commons.compress.archivers.ArchiveInputStream;
23 import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
24 import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
25 import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
26 import org.apache.commons.compress.utils.IOUtils;
27 import org.apache.commons.io.FileUtils;
28 import org.apache.karaf.features.BootFinished;
29 import org.apache.karaf.features.Feature;
30 import org.apache.karaf.features.FeaturesListener;
31 import org.apache.karaf.features.FeaturesService;
32 import org.apache.karaf.main.Main;
33 import org.apache.karaf.tooling.utils.MojoSupport;
34 import org.apache.maven.artifact.Artifact;
35 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
36 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
37 import org.apache.maven.plugin.MojoExecutionException;
38 import org.apache.maven.plugin.MojoFailureException;
39 import org.apache.maven.plugins.annotations.LifecyclePhase;
40 import org.apache.maven.plugins.annotations.Mojo;
41 import org.apache.maven.plugins.annotations.Parameter;
42 import org.apache.maven.plugins.annotations.ResolutionScope;
43 import org.osgi.framework.Bundle;
44 import org.osgi.framework.BundleContext;
45 import org.osgi.framework.ServiceReference;
46 import org.osgi.util.tracker.ServiceTracker;
47
48 import java.io.*;
49 import java.util.regex.Matcher;
50 import java.util.regex.Pattern;
51
52 /**
53  * Run a Karaf instance
54  */
55 @Mojo(name = "run", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = false)
56 public class RunMojo extends MojoSupport {
57
58     /**
59      * Directory containing Karaf container base directory.
60      */
61     @Parameter(defaultValue = "${project.build.directory}/karaf")
62     private File karafDirectory = null;
63
64     /**
65      * Location where to download the Karaf distribution
66      */
67     @Parameter(defaultValue = "mvn:org.apache.karaf/apache-karaf/LATEST/zip")
68     private String karafDistribution = null;
69
70     /**
71      * Define if the project artifact should be deployed in the started container or not
72      */
73     @Parameter(defaultValue = "true")
74     private boolean deployProjectArtifact = true;
75
76     /**
77      * Define if the Karaf container keep running or stop just after the goal execution
78      */
79     @Parameter(defaultValue = "true")
80     private boolean keepRunning = true;
81
82     /**
83      * Define if the Karaf embedded sshd should be started or not
84      */
85     @Parameter(defaultValue = "false")
86     private String startSsh = "false";
87
88     private static final Pattern mvnPattern = Pattern.compile("mvn:([^/ ]+)/([^/ ]+)/([^/ ]*)(/([^/ ]+)(/([^/ ]+))?)?");
89
90     public void execute() throws MojoExecutionException, MojoFailureException {
91         if (karafDirectory.exists()) {
92             getLog().info("Using Karaf container located " + karafDirectory.getAbsolutePath());
93         } else {
94             getLog().info("Extracting Karaf container");
95             try {
96                 File karafArchiveFile = resolveFile(karafDistribution);
97                 extract(karafArchiveFile, karafDirectory);
98             } catch (Exception e) {
99                 throw new MojoFailureException("Can't extract Karaf container", e);
100             }
101         }
102
103         getLog().info("Starting Karaf container");
104         System.setProperty("karaf.home", karafDirectory.getAbsolutePath());
105         System.setProperty("karaf.base", karafDirectory.getAbsolutePath());
106         System.setProperty("karaf.data", karafDirectory.getAbsolutePath() + "/data");
107         System.setProperty("karaf.etc", karafDirectory.getAbsolutePath() + "/etc");
108         System.setProperty("karaf.instances", karafDirectory.getAbsolutePath() + "/instances");
109         System.setProperty("karaf.startLocalConsole", "false");
110         System.setProperty("karaf.startRemoteShell", startSsh);
111         System.setProperty("karaf.lock", "false");
112         Main main = new Main(new String[0]);
113         try {
114             main.launch();
115             while (main.getFramework().getState() != Bundle.ACTIVE) {
116                 Thread.sleep(1000);
117             }
118             BundleContext bundleContext = main.getFramework().getBundleContext();
119             Object bootFinished = null;
120             while (bootFinished == null) {
121                 Thread.sleep(1000);
122                 ServiceReference ref = bundleContext.getServiceReference(BootFinished.class);
123                 if (ref != null) {
124                     bootFinished = bundleContext.getService(ref);
125                 }
126             }
127             deploy(bundleContext);
128             if (keepRunning)
129                 main.awaitShutdown();
130             main.destroy();
131         } catch (Throwable e) {
132             throw new MojoExecutionException("Can't start container", e);
133         } finally {
134             System.gc();
135         }
136     }
137
138     private void deploy(BundleContext bundleContext) throws MojoExecutionException {
139         if (deployProjectArtifact) {
140             File artifact = project.getArtifact().getFile();
141             if (artifact != null && artifact.exists()) {
142                 if (project.getPackaging().equals("bundle")) {
143                     try {
144                         Bundle bundle = bundleContext.installBundle(artifact.toURI().toURL().toString());
145                         bundle.start();
146                     } catch (Exception e) {
147                         throw new MojoExecutionException("Can't deploy project artifact in container", e);
148                     }
149                 } else {
150                     throw new MojoExecutionException("Packaging " + project.getPackaging() + " is not supported");
151                 }
152             } else {
153                 throw new MojoExecutionException("Project artifact doesn't exist");
154             }
155         }
156     }
157
158     public static void extract(File sourceFile, File targetFolder) throws IOException {
159         if (sourceFile.getAbsolutePath().indexOf(".zip") > 0) {
160             extractZipDistribution(sourceFile, targetFolder);
161         } else if (sourceFile.getAbsolutePath().indexOf(".tar.gz") > 0) {
162             extractTarGzDistribution(sourceFile, targetFolder);
163         } else {
164             throw new IllegalStateException("Unknown packaging of distribution; only zip or tar.gz could be handled.");
165         }
166         return;
167     }
168
169     private static void extractTarGzDistribution(File sourceDistribution, File _targetFolder)
170             throws IOException {
171         File uncompressedFile = File.createTempFile("uncompressedTarGz-", ".tar");
172         extractGzArchive(new FileInputStream(sourceDistribution), uncompressedFile);
173         extract(new TarArchiveInputStream(new FileInputStream(uncompressedFile)), _targetFolder);
174         FileUtils.forceDelete(uncompressedFile);
175     }
176
177     private static void extractZipDistribution(File sourceDistribution, File _targetFolder)
178             throws IOException {
179         extract(new ZipArchiveInputStream(new FileInputStream(sourceDistribution)), _targetFolder);
180     }
181
182     private static void extractGzArchive(InputStream tarGz, File tar) throws IOException {
183         BufferedInputStream in = new BufferedInputStream(tarGz);
184         FileOutputStream out = new FileOutputStream(tar);
185         GzipCompressorInputStream gzIn = new GzipCompressorInputStream(in);
186         final byte[] buffer = new byte[1000];
187         int n = 0;
188         while (-1 != (n = gzIn.read(buffer))) {
189             out.write(buffer, 0, n);
190         }
191         out.close();
192         gzIn.close();
193     }
194
195     private static void extract(ArchiveInputStream is, File targetDir) throws IOException {
196         try {
197             if (targetDir.exists()) {
198                 FileUtils.forceDelete(targetDir);
199             }
200             targetDir.mkdirs();
201             ArchiveEntry entry = is.getNextEntry();
202             while (entry != null) {
203                 String name = entry.getName();
204                 name = name.substring(name.indexOf("/") + 1);
205                 File file = new File(targetDir, name);
206                 if (entry.isDirectory()) {
207                     file.mkdirs();
208                 }
209                 else {
210                     file.getParentFile().mkdirs();
211                     OutputStream os = new FileOutputStream(file);
212                     try {
213                         IOUtils.copy(is, os);
214                     }
215                     finally {
216                         IOUtils.closeQuietly(os);
217                     }
218                 }
219                 entry = is.getNextEntry();
220             }
221         }
222         finally {
223             is.close();
224         }
225     }
226
227     protected static boolean isMavenUrl(String name) {
228         Matcher m = mvnPattern.matcher(name);
229         return m.matches();
230     }
231
232     private File resolveFile(String file) {
233         File fileResolved = null;
234
235         if (isMavenUrl(file)) {
236             fileResolved = new File(fromMaven(file));
237             try {
238                 Artifact artifactTemp = resourceToArtifact(file, false);
239                 if (!fileResolved.exists()) {
240                     try {
241                         artifactResolver.resolve(artifactTemp, remoteRepos, localRepo);
242                         fileResolved = artifactTemp.getFile();
243                     } catch (ArtifactResolutionException e) {
244                         getLog().error("Artifact was not resolved", e);
245                     } catch (ArtifactNotFoundException e) {
246                         getLog().error("Artifact was not found", e);
247                     }
248                 }
249             } catch (MojoExecutionException e) {
250                 getLog().error(e);
251             }
252         } else {
253             fileResolved = new File(file);
254         }
255
256         return fileResolved;
257     }
258
259     /**
260      * Return a path for an artifact:
261      * - if the input is already a path (doesn't contain ':'), the same path is returned.
262      * - if the input is a Maven URL, the input is converted to a default repository location path, type and classifier
263      *   are optional.
264      *
265      * @param name artifact data
266      * @return path as supplied or a default Maven repository path
267      */
268     private static String fromMaven(String name) {
269         Matcher m = mvnPattern.matcher(name);
270         if (!m.matches()) {
271             return name;
272         }
273
274         StringBuilder b = new StringBuilder();
275         b.append(m.group(1));
276         for (int i = 0; i < b.length(); i++) {
277             if (b.charAt(i) == '.') {
278                 b.setCharAt(i, '/');
279             }
280         }
281         b.append("/"); // groupId
282         String artifactId = m.group(2);
283         String version = m.group(3);
284         String extension = m.group(5);
285         String classifier = m.group(7);
286         b.append(artifactId).append("/"); // artifactId
287         b.append(version).append("/"); // version
288         b.append(artifactId).append("-").append(version);
289         if (present(classifier)) {
290             b.append("-").append(classifier);
291         }
292         if (present(classifier)) {
293             b.append(".").append(extension);
294         } else {
295             b.append(".jar");
296         }
297         return b.toString();
298     }
299
300     private static boolean present(String part) {
301         return part != null && !part.isEmpty();
302     }
303
304 }