001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.maven;
018
019import java.util.Properties;
020
021import org.apache.activemq.broker.TransportConnector;
022import org.apache.maven.plugin.AbstractMojo;
023import org.apache.maven.plugin.MojoExecutionException;
024import org.apache.maven.project.MavenProject;
025
026/**
027 * Goal which starts an activemq broker.
028 *
029 * @goal run
030 * @phase process-sources
031 */
032public class StartBrokerMojo extends AbstractMojo {
033    /**
034     * Default connector property name format.
035     */
036    public static final String  DEFAULT_CONNECTOR_PROPERTY_NAME_FORMAT = "org.apache.activemq.connector.%s.uri";
037
038    /**
039     * The maven project.
040     *
041     * @parameter property="project" default-value="${project}"
042     * @required
043     * @readonly
044     */
045    protected MavenProject project;
046
047    /**
048     * The broker configuration uri The list of currently supported URI syntaxes
049     * is described <a
050     * href="http://activemq.apache.org/how-do-i-embed-a-broker-inside-a-connection.html">here</a>
051     *
052     * @parameter property="configUri"
053     *            default-value="broker:(tcp://localhost:61616)?useJmx=false&persistent=false"
054     * @required
055     */
056    private String configUri;
057
058    /**
059     * Indicates whether to fork the broker, useful for integration tests.
060     *
061     * @parameter property="fork" default-value="false"
062     */
063    private boolean fork;
064
065    /**
066     * System properties to add
067     *
068     * @parameter property="systemProperties"
069     */
070    private Properties systemProperties;
071
072    /**
073     * Skip execution of the ActiveMQ Broker plugin if set to true
074     *
075     * @parameter property="skip"
076     */
077    private boolean skip;
078
079    /**
080     * Format of the connector URI property names.  The first argument for the format is the connector name.
081     *
082     * @parameter property="connectorPropertyNameFormat"
083     */
084    private String connectorPropertyNameFormat = DEFAULT_CONNECTOR_PROPERTY_NAME_FORMAT;
085
086    /**
087     * Broker manager used to start and stop the broker.
088     */
089    private MavenBrokerManager  brokerManager;
090
091    /**
092     * XBean File Resolver used to detect and transform xbean file URIs.
093     */
094    private XBeanFileResolver   xBeanFileResolver = new XBeanFileResolver();
095
096    /**
097     * Retrieve the Maven project for this mojo.
098     *
099     * @return the Maven project.
100     */
101    public MavenProject getProject() {
102        return project;
103    }
104
105    /**
106     * Set the Maven project for this mojo.
107     *
108     * @param project the Maven project.
109     */
110    public void setProject(MavenProject project) {
111        this.project = project;
112    }
113
114    /**
115     * Retrieve the URI used to configure the broker on startup.
116     *
117     * @return the configuration URI.
118     */
119    public String getConfigUri() {
120        return configUri;
121    }
122
123    /**
124     * Set the URI used to configure the broker on startup.
125     *
126     * @param configUri the URI used to configure the broker.
127     */
128    public void setConfigUri(String configUri) {
129        this.configUri = configUri;
130    }
131
132    /**
133     * Determine if the mojo is configured to fork a broker.
134     *
135     * @return true => the mojo will fork a broker (i.e. start it in the background); false => start the broker and
136     * wait synchronously for it to terminate.
137     */
138    public boolean isFork() {
139        return fork;
140    }
141
142    /**
143     * Configure the mojo to run the broker asynchronously (i.e. fork) or synchronously.
144     *
145     * @param fork true => start the broker asynchronously; true => start the broker synchronously.
146     */
147    public void setFork(boolean fork) {
148        this.fork = fork;
149    }
150
151    /**
152     * Determine if the mojo is configured to skip the broker startup.
153     *
154     * @return true => the mojo will skip the broker startup; false => the mojo will start the broker normally.
155     */
156    public boolean isSkip() {
157        return skip;
158    }
159
160    /**
161     * Configure the mojo to skip or normally execute the broker startup.
162     *
163     * @param skip true => the mojo will skip the broker startup; false => the mojo will start the broker normally.
164     */
165    public void setSkip(boolean skip) {
166        this.skip = skip;
167    }
168
169    /**
170     * Retrieve properties to add to the System properties on broker startup.
171     *
172     * @return properties to add to the System properties.
173     */
174    public Properties getSystemProperties() {
175        return systemProperties;
176    }
177
178    /**
179     * Set properties to add to the System properties on broker startup.
180     *
181     * @param systemProperties properties to add to the System properties.
182     */
183    public void setSystemProperties(Properties systemProperties) {
184        this.systemProperties = systemProperties;
185    }
186
187    /**
188     * Retrieve the format used to generate property names when registering connector URIs.
189     *
190     * @return the format used to generate property names.
191     */
192    public String getConnectorPropertyNameFormat() {
193        return connectorPropertyNameFormat;
194    }
195
196    /**
197     * Set the format used to generate property names when registering connector URIs.
198     *
199     * @param connectorPropertyNameFormat the new format to use when generating property names.
200     */
201    public void setConnectorPropertyNameFormat(String connectorPropertyNameFormat) {
202        this.connectorPropertyNameFormat = connectorPropertyNameFormat;
203    }
204
205    /**
206     * Retrieve the manager used to create and retain the started broker.
207     *
208     * @return the manager.
209     */
210    public MavenBrokerManager getBrokerManager() {
211        return brokerManager;
212    }
213
214    /**
215     * Set the manager used to create and retain the started broker.
216     *
217     * @param brokerManager the new manager to use.
218     */
219    public void setBrokerManager(MavenBrokerManager brokerManager) {
220        this.brokerManager = brokerManager;
221    }
222
223    /**
224     * Retrieve the XBeanFileResolver used to detect and transform XBean URIs.
225     *
226     * @return the XBeanFileResolver used.
227     */
228    public XBeanFileResolver getxBeanFileResolver() {
229        return xBeanFileResolver;
230    }
231
232    /**
233     * Set the XBeanFileResolver to use when detecting and transforming XBean URIs.
234     *
235     * @param xBeanFileResolver the XBeanFileResolver to use.
236     */
237    public void setxBeanFileResolver(XBeanFileResolver xBeanFileResolver) {
238        this.xBeanFileResolver = xBeanFileResolver;
239    }
240
241    /**
242     * Perform the mojo operation, which starts the ActiveMQ broker unless configured to skip it.  Also registers the
243     * connector URIs in the maven project properties on startup, which enables the use of variable substitution in
244     * the pom.xml file to determine the address of the connector using the standard ${...} syntax.
245     *
246     * @throws MojoExecutionException
247     */
248    @Override
249    public void execute() throws MojoExecutionException {
250        if (skip) {
251            getLog().info("Skipped execution of ActiveMQ Broker");
252            return;
253        }
254
255        addActiveMQSystemProperties();
256
257        getLog().info("Loading broker configUri: " + configUri);
258        if (this.xBeanFileResolver.isXBeanFile(configUri)) {
259            getLog().debug("configUri before transformation: " + configUri);
260            configUri = this.xBeanFileResolver.toUrlCompliantAbsolutePath(configUri);
261            getLog().debug("configUri after transformation: " + configUri);
262        }
263
264        this.useBrokerManager().start(fork, configUri);
265
266        //
267        // Register the transport connector URIs in the Maven project.
268        //
269        this.registerTransportConnectorUris();
270
271        getLog().info("Started the ActiveMQ Broker");
272    }
273
274    /**
275     * Set system properties
276     */
277    protected void addActiveMQSystemProperties() {
278        // Set the default properties
279        System.setProperty("activemq.base", project.getBuild().getDirectory() + "/");
280        System.setProperty("activemq.home", project.getBuild().getDirectory() + "/");
281        System.setProperty("org.apache.activemq.UseDedicatedTaskRunner", "true");
282        System.setProperty("org.apache.activemq.default.directory.prefix", project.getBuild().getDirectory() + "/");
283        System.setProperty("derby.system.home", project.getBuild().getDirectory() + "/");
284        System.setProperty("derby.storage.fileSyncTransactionLog", "true");
285
286        // Overwrite any custom properties
287        System.getProperties().putAll(systemProperties);
288    }
289
290    /**
291     * Register all of the broker's transport connector URIs in the Maven project as properties.  Property names are
292     * formed from the connectorPropertyNameFormat using String.format(), with the connector name as the one and only
293     * argument.  The value of each property is that returned by getPublishableConnectString().
294     */
295    protected void  registerTransportConnectorUris () {
296        Properties props = project.getProperties();
297
298        //
299        // Loop through all of the connectors, adding each.
300        //
301        for ( TransportConnector oneConnector : this.useBrokerManager().getBroker().getTransportConnectors() ) {
302            try {
303                //
304                // Format the name of the property and grab the value.
305                //
306                String propName = String.format(this.connectorPropertyNameFormat, oneConnector.getName());
307                String value    = oneConnector.getPublishableConnectString();
308
309                getLog().debug("setting transport connector URI property: propertyName=\"" + propName +
310                               "\"; value=\"" + value + "\"");
311
312                //
313                // Set the property.
314                //
315                props.setProperty(propName, value);
316            } catch (Exception exc) {
317                //
318                // Warn of the issue and continue.
319                //
320                getLog().warn("error on obtaining broker connector uri; connector=" + oneConnector, exc);
321            }
322        }
323    }
324
325    /**
326     * Use the configured broker manager, if defined; otherwise, use the default broker manager.
327     *
328     * @return the broker manager to use.
329     */
330    protected MavenBrokerManager    useBrokerManager () {
331        if ( this.brokerManager == null ) {
332            this.brokerManager = new MavenBrokerSingletonManager();
333        }
334
335        return  this.brokerManager;
336    }
337}