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 }