View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2014 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.maven.plugins.cq;
21  
22  import java.io.File;
23  
24  import javax.inject.Inject;
25  
26  import org.apache.commons.lang3.StringUtils;
27  import org.apache.commons.lang3.Strings;
28  import org.apache.maven.execution.MavenSession;
29  import org.apache.maven.model.Plugin;
30  import org.apache.maven.plugin.AbstractMojo;
31  import org.apache.maven.plugin.BuildPluginManager;
32  import org.apache.maven.plugin.MavenPluginManager;
33  import org.apache.maven.plugin.MojoExecution;
34  import org.apache.maven.plugin.MojoExecutionException;
35  import org.apache.maven.plugin.MojoFailureException;
36  import org.apache.maven.plugin.descriptor.MojoDescriptor;
37  import org.apache.maven.plugin.descriptor.PluginDescriptor;
38  import org.apache.maven.plugin.logging.Log;
39  import org.apache.maven.plugins.annotations.Execute;
40  import org.apache.maven.plugins.annotations.LifecyclePhase;
41  import org.apache.maven.plugins.annotations.Mojo;
42  import org.apache.maven.plugins.annotations.Parameter;
43  import org.apache.maven.plugins.annotations.ResolutionScope;
44  import org.apache.maven.project.MavenProject;
45  import org.apache.maven.settings.Settings;
46  import org.apache.maven.shared.invoker.DefaultInvocationRequest;
47  import org.apache.maven.shared.invoker.DefaultInvoker;
48  import org.apache.maven.shared.invoker.InvocationRequest;
49  import org.apache.maven.shared.invoker.InvocationResult;
50  import org.apache.maven.shared.invoker.Invoker;
51  import org.apache.maven.shared.invoker.MavenInvocationException;
52  import org.apache.maven.shared.utils.cli.CommandLineException;
53  import org.codehaus.plexus.configuration.PlexusConfiguration;
54  import org.codehaus.plexus.configuration.PlexusConfigurationException;
55  import org.codehaus.plexus.util.xml.Xpp3Dom;
56  
57  /**
58   * Executes install phase and installs an OSGi bundle jar to a running Sling instance
59   * (combines goals "install" and "sling:install").
60   */
61  @Mojo(name = "install",
62      requiresDependencyResolution = ResolutionScope.COMPILE,
63      requiresProject = true,
64      threadSafe = true)
65  @Execute(phase = LifecyclePhase.INSTALL)
66  public class InstallMojo extends AbstractMojo {
67  
68    /**
69     * Version of sling plugin
70     */
71    @Parameter(property = "sling.plugin.version", required = true, defaultValue = "2.4.2")
72    private String slingPluginVersion;
73  
74    /**
75     * The URL of osgi console
76     */
77    @Parameter(property = "sling.console.url", required = true, defaultValue = "http://localhost:8080/system/console")
78    private String slingConsoleUrl;
79  
80    /**
81     * The user name to authenticate at osgi console
82     */
83    @Parameter(property = "sling.console.user", required = true, defaultValue = "admin")
84    private String slingConsoleUser;
85  
86    /**
87     * The password to authenticate at osgi console
88     */
89    @Parameter(property = "sling.console.password", required = true, defaultValue = "admin")
90    private String slingConsolePassword;
91  
92  
93    @Parameter(defaultValue = "${project}", readonly = true)
94    private MavenProject project;
95    @Parameter(defaultValue = "${settings}", readonly = true)
96    private Settings settings;
97    @Parameter(defaultValue = "${session}", readonly = true)
98    private MavenSession session;
99  
100   @Inject
101   private MavenPluginManager pluginManager;
102   @Inject
103   private BuildPluginManager buildPluginManager;
104 
105   @Override
106   public void execute() throws MojoExecutionException, MojoFailureException {
107 
108     // detect goal to deploy current project based on packaging
109     if (isBundleProject()) {
110       executeSlingPluginDirectly();
111     }
112     else if (isContentPackageProject()) {
113       getLog().info("Install content package to instance...");
114       executeWithMavenInvoker("wcmio-content-package:install");
115     }
116     else {
117       // no supported packaging - skip processing
118       getLog().info("No bundle or content-package project, skip deployment.");
119     }
120   }
121 
122   private boolean isBundleProject() {
123     // check for "bundle" packaging as used by maven-bundle-plugin
124     String packaging = project.getPackaging();
125     if (Strings.CS.equals(packaging, "bundle")) {
126       return true;
127     }
128 
129     // check for active bnd-maven-plugin in current project
130     return project.getBuildPlugins().stream()
131       .anyMatch(this::isBndMavenPlugin);
132   }
133 
134   private boolean isBndMavenPlugin(Plugin plugin) {
135     return Strings.CS.equals(plugin.getGroupId(), "biz.aQute.bnd")
136         && Strings.CS.equals(plugin.getArtifactId(), "bnd-maven-plugin");
137   }
138 
139   private boolean isContentPackageProject() {
140     String packaging = project.getPackaging();
141     return Strings.CS.equals(packaging, "content-package");
142   }
143 
144   /**
145    * Executes the sling-maven-plugin directly from the current project.
146    */
147   @SuppressWarnings({
148       "java:S1181", "checkstyle:IllegalCatch"
149   }) // allow catch of throwable
150   private void executeSlingPluginDirectly() throws MojoExecutionException {
151 
152     Plugin plugin = new Plugin();
153     plugin.setGroupId("org.apache.sling");
154     plugin.setArtifactId("sling-maven-plugin");
155     plugin.setVersion(this.slingPluginVersion);
156 
157     try {
158       PluginDescriptor pluginDescriptor = pluginManager.getPluginDescriptor(plugin,
159           project.getRemotePluginRepositories(), session.getRepositorySession());
160       MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo("install-file");
161       MojoExecution mojoExecution = new MojoExecution(pluginDescriptor.getMojo("install-file"));
162 
163       Xpp3Dom config = convertConfiguration(mojoDescriptor.getMojoConfiguration());
164       config.getChild("slingUrl").setValue(this.slingConsoleUrl);
165       config.getChild("user").setValue(this.slingConsoleUser);
166       config.getChild("password").setValue(this.slingConsolePassword);
167       config.getChild("mountByFS").setValue("false");
168       mojoExecution.setConfiguration(config);
169 
170       buildPluginManager.executeMojo(session, mojoExecution);
171     }
172     catch (Throwable ex) {
173       throw new MojoExecutionException("Faild to execute plugin: " + plugin, ex);
174     }
175 
176   }
177 
178   private Xpp3Dom convertConfiguration(PlexusConfiguration plexusConfig) throws PlexusConfigurationException {
179     Xpp3Dom config = new Xpp3Dom(plexusConfig.getName());
180     config.setValue(plexusConfig.getValue());
181     for (String attribute : plexusConfig.getAttributeNames()) {
182       config.setAttribute(attribute, plexusConfig.getAttribute(attribute));
183     }
184     for (PlexusConfiguration child : plexusConfig.getChildren()) {
185       config.addChild(convertConfiguration(child));
186     }
187     return config;
188   }
189 
190   /**
191    * Invoke maven for the current project with all it's setting and the given goal.
192    * @param goal Goal
193    * @throws MojoExecutionException Mojo execution exception
194    */
195   private void executeWithMavenInvoker(String goal) throws MojoExecutionException {
196     InvocationRequest invocationRequest = new DefaultInvocationRequest();
197     invocationRequest.setPomFile(project.getFile());
198     invocationRequest.addArg(goal);
199     invocationRequest.setBatchMode(true);
200 
201     // take over all systems properties and profile settings from current maven execution
202     invocationRequest.setShellEnvironmentInherited(true);
203     invocationRequest.setLocalRepositoryDirectory(new File(settings.getLocalRepository()));
204     invocationRequest.setProperties(session.getUserProperties());
205     invocationRequest.setProfiles(settings.getActiveProfiles());
206 
207     setupInvokerLogger(invocationRequest);
208     Invoker invoker = new DefaultInvoker();
209 
210     try {
211       InvocationResult invocationResult = invoker.execute(invocationRequest);
212       if (invocationResult.getExitCode() != 0) {
213         String msg = "Execution of cq:install failed, see above.";
214         if (invocationResult.getExecutionException() != null) {
215           msg = invocationResult.getExecutionException().getMessage();
216         }
217         throw new CommandLineException(msg);
218       }
219     }
220     catch (MavenInvocationException | CommandLineException ex) {
221       throw new MojoExecutionException("Failed to execute goals", ex);
222     }
223   }
224 
225   /**
226    * Mirror maven execution log output to current maven logger.
227    * @param request Invocation request
228    */
229   private void setupInvokerLogger(InvocationRequest request) {
230     Log log = getLog();
231     request.setOutputHandler(line -> {
232       if (Strings.CS.startsWith(line, "[ERROR] ")) {
233         log.error(StringUtils.substringAfter(line, "[ERROR] "));
234       }
235       else if (Strings.CS.startsWith(line, "[WARNING] ")) {
236         log.warn(StringUtils.substringAfter(line, "[WARNING] "));
237       }
238       else if (Strings.CS.startsWith(line, "[INFO] ")) {
239         log.info(StringUtils.substringAfter(line, "[INFO] "));
240       }
241       else if (Strings.CS.startsWith(line, "[DEBUG] ")) {
242         log.debug(StringUtils.substringAfter(line, "[DEBUG] "));
243       }
244       else {
245         log.info(line);
246       }
247     });
248   }
249 
250 }