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.guice.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 Camel using the
034     * <code>jndi.properties</code> file on the classpath to
035     * way to <a href="http://camel.apache.org/guice.html">bootstrap via Guice</a>
036     *
037     * @goal embedded
038     * @requiresDependencyResolution runtime
039     * @execute phase="test-compile"
040     */
041    public class EmbeddedMojo extends AbstractExecMojo {
042    
043        /**
044         * The duration to run the application for which by default is in milliseconds.
045         * A value <= 0 will run forever.
046         * Adding a s indicates seconds - eg "5s" means 5 seconds.
047         *
048         * @parameter expression="-1"
049         * @readonly
050         */
051        protected String duration;
052    
053        /**
054         * The DOT File name used to generate the DOT diagram of the route definitions
055         *
056         * @parameter expression="${project.build.directory}/site/cameldoc/routes.dot"
057         * @readonly
058         */
059        protected String outputDirectory;
060    
061        /**
062         * Allows the DOT file generation to be disabled
063         *
064         * @parameter expression="true"
065         * @readonly
066         */
067        protected boolean dotEnabled;
068    
069        /**
070         * Allows the routes from multiple contexts to be aggregated into one DOT file (in addition to the individual files)
071         *
072         * @parameter expression="false"
073         * @readonly
074         */
075        protected boolean dotAggregationEnabled;
076    
077        /**
078         * Project classpath.
079         *
080         * @parameter expression="${project.testClasspathElements}"
081         * @required
082         * @readonly
083         */
084        private List classpathElements;
085    
086        /**
087         * The main class to execute.
088         *
089         * @parameter expression="${camel.mainClass}"
090         *            default-value="org.apache.camel.guice.Main"
091         * @required
092         */
093        private String mainClass;
094    
095        /**
096         * This method will run the mojo
097         */
098        public void execute() throws MojoExecutionException {
099            try {
100                executeWithoutWrapping();
101            } catch (Exception e) {
102                throw new MojoExecutionException("Failed: " + e, e);
103            }
104        }
105    
106        public void executeWithoutWrapping() throws MalformedURLException, ClassNotFoundException,
107            NoSuchMethodException, IllegalAccessException, MojoExecutionException {
108            ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
109            try {
110                ClassLoader newLoader = createClassLoader(null);
111                Thread.currentThread().setContextClassLoader(newLoader);
112                runCamel(newLoader);
113            } finally {
114                Thread.currentThread().setContextClassLoader(oldClassLoader);
115            }
116        }
117    
118        // Properties
119        //-------------------------------------------------------------------------
120    
121        /**
122         * Getter for property output directory.
123         *
124         * @return The value of output directory.
125         */
126        public String getOutputDirectory() {
127            return outputDirectory;
128        }
129    
130        /**
131         * Setter for the output directory.
132         *
133         * @param inOutputDirectory The value of output directory.
134         */
135        public void setOutputDirectory(String inOutputDirectory) {
136            this.outputDirectory = inOutputDirectory;
137        }
138    
139        public List getClasspathElements() {
140            return classpathElements;
141        }
142    
143        public void setClasspathElements(List classpathElements) {
144            this.classpathElements = classpathElements;
145        }
146    
147        public boolean isDotEnabled() {
148            return dotEnabled;
149        }
150    
151        public void setDotEnabled(boolean dotEnabled) {
152            this.dotEnabled = dotEnabled;
153        }
154    
155        public String getDuration() {
156            return duration;
157        }
158    
159        public void setDuration(String duration) {
160            this.duration = duration;
161        }
162    
163        public boolean isDotAggregationEnabled() {
164            return dotAggregationEnabled;
165        }
166    
167        public void setDotAggregationEnabled(boolean dotAggregationEnabled) {
168            this.dotAggregationEnabled = dotAggregationEnabled;
169        }
170    
171        public String getMainClass() {
172            return mainClass;
173        }
174    
175        public void setMainClass(String mainClass) {
176            this.mainClass = mainClass;
177        }
178    
179        // Implementation methods
180        //-------------------------------------------------------------------------
181    
182        protected void runCamel(ClassLoader newLoader) throws ClassNotFoundException, NoSuchMethodException,
183            IllegalAccessException, MojoExecutionException {
184    
185            getLog().debug("Running Camel in: " + newLoader);
186            Class<?> type = newLoader.loadClass(mainClass);
187            Method method = type.getMethod("main", String[].class);
188            String[] arguments = createArguments();
189            getLog().debug("Starting the Camel Main with arguments: " + Arrays.asList(arguments));
190    
191            try {
192                method.invoke(null, new Object[] {arguments});
193            } catch (InvocationTargetException e) {
194                Throwable t = e.getTargetException();
195                throw new MojoExecutionException("Failed: " + t, t);
196            }
197        }
198    
199        protected String[] createArguments() {
200    
201            ArrayList<String> args = new ArrayList<String>(5);
202            if (isDotEnabled()) {
203                args.add("-outdir");
204                args.add(getOutputDirectory());
205            }
206    
207            if (isDotAggregationEnabled()) {
208                args.add("-aggregate-dot");
209                args.add("true");
210            }
211    
212            args.add("-duration");
213            args.add(getDuration());
214    
215            return args.toArray(new String[0]);
216        }
217    
218        public ClassLoader createClassLoader(ClassLoader parent) throws MalformedURLException {
219            getLog().debug("Using classpath: " + classpathElements);
220    
221            int size = classpathElements.size();
222            URL[] urls = new URL[size];
223            for (int i = 0; i < size; i++) {
224                String name = (String) classpathElements.get(i);
225                File file = new File(name);
226                urls[i] = file.toURL();
227                getLog().debug("URL: " + urls[i]);
228            }
229            URLClassLoader loader = new URLClassLoader(urls, parent);
230            return loader;
231        }
232    }