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    }