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.servicemix.maven.plugin.xfire;
018    
019    import java.io.File;
020    import java.net.MalformedURLException;
021    import java.net.URL;
022    import java.net.URLClassLoader;
023    import java.util.ArrayList;
024    import java.util.Collection;
025    import java.util.Iterator;
026    import java.util.List;
027    
028    import org.apache.maven.artifact.Artifact;
029    import org.apache.maven.model.Resource;
030    import org.apache.maven.plugin.AbstractMojo;
031    import org.apache.maven.plugin.MojoExecutionException;
032    import org.apache.maven.project.MavenProject;
033    import org.apache.tools.ant.AntClassLoader;
034    import org.apache.tools.ant.BuildEvent;
035    import org.apache.tools.ant.BuildException;
036    import org.apache.tools.ant.BuildListener;
037    import org.apache.tools.ant.Project;
038    import org.codehaus.xfire.gen.WsdlGenTask;
039    import org.codehaus.xfire.spring.XFireConfigLoader;
040    
041    /**
042     * WsdlGen mojo.
043     * <p/>
044     * Implemented as a wrapper around the XFire WsdlGen Ant task.
045     *
046     * @author <a href="jerome@coffeebreaks.org">Jerome Lacoste</a>
047     * @version $Id$
048     * @goal wsdlgen
049     * @requiresProject
050     * @requiresDependencyResolution
051     */
052    public class WsdlgenMojo extends AbstractMojo {
053        
054        /**
055         * Project.
056         *
057         * @parameter expression="${project}"
058         * @required
059         * @readonly
060         */
061        private MavenProject project;
062    
063        /**
064         * xfire service.xml config files
065         * If not specified, the list will contain a single value 'src/main/resources/META-INF/xfire/services.xml'
066         *
067         * @parameter
068         */
069        private List configs;
070    
071        /**
072         * The directory will be added as Project's Resource.
073         * @parameter expression="${outputDirectory}" default-value="${project.build.directory}/generated-sources/xfire/wsdlgen"
074         * @required
075         */
076        private File outputDirectory;
077    
078        /**
079         * The basedir of the project.
080         *
081         * @parameter expression="${basedir}"
082         * @required
083         * @readonly
084         */
085        private File basedir;
086    
087        /*
088         private PrintStream systemErr;
089         private PrintStream systemOut;
090         private final PrintStream mySystemErr = new PrintStream(new WsdlgenMojo.MyErrorStream());
091         private final PrintStream mySystemOut = new PrintStream(new WsdlgenMojo.MyOutputStream());
092    
093         public void execute()
094         throws MojoExecutionException
095         {
096    
097         systemErr = System.err;
098         systemOut = System.out;
099         System.setErr(mySystemErr);
100         // System.setOut(mySystemOut); // causes java.lang.OutOfMemoryError: Java heap space  on my box
101    
102         try {
103         exec();
104         } finally {
105         System.setErr( systemErr );
106         // System.setOut( systemOut );
107         }
108         }
109    
110         class MyErrorStream extends OutputStream {
111         private StringBuffer buffer = new StringBuffer();
112    
113         public void write( final int b ) throws IOException {
114         final char c = (char) b;
115         // shouldn't we handle '\r' as well ??
116         if (c == '\n') {
117         getLog().error( buffer );
118         buffer = new StringBuffer();
119         } else {
120         buffer.append( c );
121         }
122         }
123         }
124    
125         class MyOutputStream extends OutputStream {
126         private StringBuffer buffer = new StringBuffer();
127    
128         public void write( final int b ) throws IOException {
129         final char c = (char) b;
130         // shouldn't we handle '\r' as well ??
131         if (c == '\n') {
132         getLog().info( buffer );
133         buffer = new StringBuffer();
134         } else {
135         buffer.append( c );
136         }
137         }
138         }
139         */
140    
141        public void execute() throws MojoExecutionException {
142    
143            if (configs == null) {
144                configs = new ArrayList();
145            }
146    
147            if (configs.size() == 0) {
148                configs
149                        .add(new File(basedir,
150                                "src/main/resources/META-INF/xfire/services.xml")
151                                .getPath());
152            }
153    
154            if (!outputDirectory.exists() && !outputDirectory.mkdirs()) {
155                getLog()
156                        .warn(
157                                "the output directory "
158                                        + outputDirectory
159                                        + " doesn't exist and couldn't be created. The goal with probably fail.");
160            }
161    
162            final Project antProject = new Project();
163    
164            antProject.addBuildListener(new WsdlgenMojo.DebugAntBuildListener());
165    
166            // add current pom dependencies to WsdlGenTask class loader
167            ClassLoader parent = WsdlGenTask.class.getClassLoader();
168    
169            URL[] urls;
170            try {
171                Collection l = project.getArtifacts();
172                List theurls = new ArrayList();
173                theurls.add(new File(project.getBuild().getOutputDirectory())
174                        .toURL());
175                for (Iterator iterator = l.iterator(); iterator.hasNext();) {
176                    Artifact dep = (Artifact) iterator.next();
177                    theurls.add(dep.getFile().toURL());
178                }
179                urls = (URL[]) theurls.toArray(new URL[theurls.size()]);
180    
181                getLog().debug("classloader classpath: " + theurls);
182    
183            } catch (MalformedURLException e) {
184                throw new IllegalStateException(e);
185            }
186    
187            URLClassLoader cl = new URLClassLoader(urls, parent);
188            ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
189            Thread.currentThread().setContextClassLoader(cl);
190    
191            // displayClasspath(cl, "using classpath");
192            // load("javax.servlet.ServletException", cl);
193            // load("org.codehaus.xfire.transport.http.XFireServletController", cl);
194    
195            final WsdlGenTask task = new WsdlGenTask();
196    
197            task.setProject(antProject);
198    
199            task.setOutputDirectory(outputDirectory.getAbsolutePath());
200    
201            for (Iterator iterator = configs.iterator(); iterator.hasNext();) {
202                String configUrl = (String) iterator.next();
203    
204                // required for multi-modules projects
205                if (!new File(configUrl).exists()) {
206                    getLog().warn("configUrl not found. Task will perhaps fail");
207                }
208    
209                task.setConfigUrl(configUrl);
210    
211                getLog().info(
212                        "Executing XFire WsdlGen task for configUrl: " + configUrl);
213    
214                try {
215                    task.execute();
216                } catch (BuildException e) {
217                    throw new MojoExecutionException("command execution failed", e);
218                }
219    
220                getLog().debug("generated " + task.getGeneratedFile());
221            }
222            Thread.currentThread().setContextClassLoader(oldCl);
223    
224            getLog().debug("Adding outputDirectory as Project's resource.");
225            Resource resource = new Resource();
226            resource.setDirectory(outputDirectory.getAbsolutePath());
227            project.addResource(resource);
228        }
229    
230        /*
231         void displayClasspath(URLClassLoader cl, String message)
232         {
233         URL[] urls = cl.getURLs();
234         for (int i = 0; i < urls.length; i++) {
235         URL urL = urls[i];
236         getLog().info("URL " + i + ":" +  urL);
237         }
238         }
239         */
240        private void displayClasspath(ClassLoader classLoader, String message) {
241            getLog().info("------ " + message + ":" + classLoader);
242            if (classLoader == null) {
243                return;
244            }
245            if (classLoader instanceof URLClassLoader) {
246                URLClassLoader cl = (URLClassLoader) classLoader;
247                URL[] urls = cl.getURLs();
248                for (int i = 0; i < urls.length; i++) {
249                    URL urL = urls[i];
250                    getLog().info("URL " + i + ":" + urL);
251                }
252            } else if (classLoader instanceof AntClassLoader) {
253                AntClassLoader cl = (AntClassLoader) XFireConfigLoader.class
254                        .getClassLoader();
255                String[] urls = cl.getClasspath().split(File.pathSeparator);
256                for (int i = 0; i < urls.length; i++) {
257                    String url = urls[i];
258                    getLog().info("URL " + i + ":" + url);
259                }
260            } else {
261                // not handled
262            }
263            displayClasspath(classLoader.getParent(), "parent->" + message);
264        }
265    
266        void load(String className, ClassLoader cl) {
267            try {
268                Class c = Class.forName(className, true, cl);
269                getLog().debug(c.toString());
270            } catch (Exception e) {
271                displayClasspath(cl, "using classpath");
272                getLog().error(e);
273            }
274        }
275    
276        private class DebugAntBuildListener implements BuildListener {
277            public void buildStarted(final BuildEvent buildEvent) {
278                getLog().debug(buildEvent.getMessage());
279            }
280    
281            public void buildFinished(final BuildEvent buildEvent) {
282                getLog().debug(buildEvent.getMessage());
283            }
284    
285            public void targetStarted(final BuildEvent buildEvent) {
286                getLog().debug(buildEvent.getMessage());
287            }
288    
289            public void targetFinished(final BuildEvent buildEvent) {
290                getLog().debug(buildEvent.getMessage());
291            }
292    
293            public void taskStarted(final BuildEvent buildEvent) {
294                getLog().debug(buildEvent.getMessage());
295            }
296    
297            public void taskFinished(final BuildEvent buildEvent) {
298                getLog().debug(buildEvent.getMessage());
299            }
300    
301            public void messageLogged(final BuildEvent buildEvent) {
302                getLog().debug(buildEvent.getMessage());
303            }
304        }
305    }