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 */
017 package org.apache.camel.maven;
018
019 import java.io.File;
020 import java.lang.reflect.InvocationTargetException;
021 import java.lang.reflect.Method;
022 import java.net.MalformedURLException;
023 import java.net.URL;
024 import java.net.URLClassLoader;
025 import java.util.ArrayList;
026 import java.util.Arrays;
027 import java.util.List;
028
029 import org.apache.maven.plugin.MojoExecutionException;
030 import org.codehaus.mojo.exec.AbstractExecMojo;
031
032 /**
033 * Runs a CamelContext using any Spring XML configuration files found in
034 * <code>META-INF/spring/*.xml</code> and <code>camel-*.xml</code>
035 * and starting up the context; then generating
036 * the DOT file before closing the context down.
037 *
038 * @goal embedded
039 * @requiresDependencyResolution runtime
040 * @execute phase="test-compile"
041 */
042 public class EmbeddedMojo extends AbstractExecMojo {
043
044 /**
045 * The duration to run the application for which by default is in milliseconds.
046 * A value <= 0 will run forever.
047 * Adding a s indicates seconds - eg "5s" means 5 seconds.
048 *
049 * @parameter expression="-1"
050 * @readonly
051 */
052 protected String duration;
053
054 /**
055 * The DOT File name used to generate the DOT diagram of the route definitions
056 *
057 * @parameter expression="${project.build.directory}/site/cameldoc/routes.dot"
058 * @readonly
059 */
060 protected String outputDirectory;
061
062 /**
063 * Allows the DOT file generation to be disabled
064 *
065 * @parameter expression="true"
066 * @readonly
067 */
068 protected boolean dotEnabled;
069
070 /**
071 * Allows the routes from multiple contexts to be aggregated into one DOT file (in addition to the individual files)
072 *
073 * @parameter expression="false"
074 * @readonly
075 */
076 protected boolean dotAggregationEnabled;
077
078 /**
079 * The classpath based application context uri that spring wants to get.
080 *
081 * @parameter expression="${camel.applicationContextUri}"
082 */
083 protected String applicationContextUri;
084
085 /**
086 * The filesystem based application context uri that spring wants to get.
087 *
088 * @parameter expression="${camel.fileApplicationContextUri}"
089 */
090 protected String fileApplicationContextUri;
091
092 /**
093 * Project classpath.
094 *
095 * @parameter expression="${project.testClasspathElements}"
096 * @required
097 * @readonly
098 */
099 private List classpathElements;
100
101 /**
102 * The main class to execute.
103 *
104 * @parameter expression="${camel.mainClass}"
105 * default-value="org.apache.camel.spring.Main"
106 * @required
107 */
108 private String mainClass;
109
110 /**
111 * This method will run the mojo
112 */
113 public void execute() throws MojoExecutionException {
114 try {
115 executeWithoutWrapping();
116 } catch (Exception e) {
117 throw new MojoExecutionException("Failed: " + e, e);
118 }
119 }
120
121 public void executeWithoutWrapping() throws MalformedURLException, ClassNotFoundException,
122 NoSuchMethodException, IllegalAccessException, MojoExecutionException {
123 ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
124 try {
125 ClassLoader newLoader = createClassLoader(null);
126 Thread.currentThread().setContextClassLoader(newLoader);
127 runCamel(newLoader);
128 } finally {
129 Thread.currentThread().setContextClassLoader(oldClassLoader);
130 }
131 }
132
133 // Properties
134 //-------------------------------------------------------------------------
135
136 /**
137 * Getter for property output directory.
138 *
139 * @return The value of output directory.
140 */
141 public String getOutputDirectory() {
142 return outputDirectory;
143 }
144
145 /**
146 * Setter for the output directory.
147 *
148 * @param inOutputDirectory The value of output directory.
149 */
150 public void setOutputDirectory(String inOutputDirectory) {
151 this.outputDirectory = inOutputDirectory;
152 }
153
154 public List getClasspathElements() {
155 return classpathElements;
156 }
157
158 public void setClasspathElements(List classpathElements) {
159 this.classpathElements = classpathElements;
160 }
161
162 public boolean isDotEnabled() {
163 return dotEnabled;
164 }
165
166 public void setDotEnabled(boolean dotEnabled) {
167 this.dotEnabled = dotEnabled;
168 }
169
170 public String getDuration() {
171 return duration;
172 }
173
174 public void setDuration(String duration) {
175 this.duration = duration;
176 }
177
178 public boolean isDotAggregationEnabled() {
179 return dotAggregationEnabled;
180 }
181
182 public void setDotAggregationEnabled(boolean dotAggregationEnabled) {
183 this.dotAggregationEnabled = dotAggregationEnabled;
184 }
185
186 public String getApplicationContextUri() {
187 return applicationContextUri;
188 }
189
190 public void setApplicationContextUri(String applicationContextUri) {
191 this.applicationContextUri = applicationContextUri;
192 }
193
194 public String getFileApplicationContextUri() {
195 return fileApplicationContextUri;
196 }
197
198 public void setFileApplicationContextUri(String fileApplicationContextUri) {
199 this.fileApplicationContextUri = fileApplicationContextUri;
200 }
201
202 public String getMainClass() {
203 return mainClass;
204 }
205
206 public void setMainClass(String mainClass) {
207 this.mainClass = mainClass;
208 }
209
210 // Implementation methods
211 //-------------------------------------------------------------------------
212
213 protected void runCamel(ClassLoader newLoader) throws ClassNotFoundException, NoSuchMethodException,
214 IllegalAccessException, MojoExecutionException {
215
216 getLog().debug("Running Camel in: " + newLoader);
217 Class<?> type = newLoader.loadClass(mainClass);
218 Method method = type.getMethod("main", String[].class);
219 String[] arguments = createArguments();
220 getLog().debug("Starting the Camel Main with arguments: " + Arrays.asList(arguments));
221
222 try {
223 method.invoke(null, new Object[] {arguments});
224 } catch (InvocationTargetException e) {
225 Throwable t = e.getTargetException();
226 throw new MojoExecutionException("Failed: " + t, t);
227 }
228 }
229
230 protected String[] createArguments() {
231
232 ArrayList<String> args = new ArrayList<String>(5);
233 if (isDotEnabled()) {
234 args.add("-outdir");
235 args.add(getOutputDirectory());
236 }
237
238 if (isDotAggregationEnabled()) {
239 args.add("-aggregate-dot");
240 args.add("true");
241 }
242
243 if (applicationContextUri != null) {
244 args.add("-applicationContext");
245 args.add(applicationContextUri);
246 } else if (fileApplicationContextUri != null) {
247 args.add("-fileApplicationContext");
248 args.add(fileApplicationContextUri);
249 }
250
251 args.add("-duration");
252 args.add(getDuration());
253
254 return (String[]) args.toArray(new String[0]);
255 }
256
257 public ClassLoader createClassLoader(ClassLoader parent) throws MalformedURLException {
258 getLog().debug("Using classpath: " + classpathElements);
259
260 int size = classpathElements.size();
261 URL[] urls = new URL[size];
262 for (int i = 0; i < size; i++) {
263 String name = (String) classpathElements.get(i);
264 File file = new File(name);
265 urls[i] = file.toURL();
266 getLog().debug("URL: " + urls[i]);
267 }
268 URLClassLoader loader = new URLClassLoader(urls, parent);
269 return loader;
270 }
271 }