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