View Javadoc
1   package org.codehaus.mojo.gwt.eclipse;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.Writer;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.HashMap;
28  import java.util.LinkedList;
29  import java.util.List;
30  import java.util.Map;
31  
32  import org.apache.commons.io.FileUtils;
33  import org.apache.maven.artifact.Artifact;
34  import org.apache.maven.model.Resource;
35  import org.apache.maven.plugin.MojoExecutionException;
36  import org.apache.maven.plugin.MojoFailureException;
37  import org.apache.maven.plugins.annotations.Component;
38  import org.apache.maven.plugins.annotations.Execute;
39  import org.apache.maven.plugins.annotations.LifecyclePhase;
40  import org.apache.maven.plugins.annotations.Mojo;
41  import org.apache.maven.plugins.annotations.Parameter;
42  import org.apache.maven.plugins.annotations.ResolutionScope;
43  import org.apache.maven.project.MavenProject;
44  import org.codehaus.mojo.gwt.AbstractGwtModuleMojo;
45  import org.codehaus.mojo.gwt.utils.GwtModuleReaderException;
46  import org.codehaus.plexus.util.StringUtils;
47  import org.codehaus.plexus.util.WriterFactory;
48  
49  import freemarker.template.Configuration;
50  import freemarker.template.Template;
51  import freemarker.template.TemplateException;
52  
53  /**
54   * Goal which creates Eclipse lauch configurations for GWT modules.
55   *
56   * @version $Id$
57   * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
58   */
59  @Mojo(name = "eclipse", requiresDependencyResolution = ResolutionScope.COMPILE)
60  @Execute(phase = LifecyclePhase.GENERATE_RESOURCES)
61  public class EclipseMojo
62      extends AbstractGwtModuleMojo
63  {
64      @Component
65      private EclipseUtil eclipseUtil;
66  
67      /**
68       * Extra JVM arguments that are passed to the GWT-Maven generated scripts (for compiler, shell, etc - typically use
69       * -Xmx512m here, or -XstartOnFirstThread, etc).
70       * <p>
71       * Can be set from command line using '-Dgwt.extraJvmArgs=...', defaults to setting max Heap size to be large enough
72       * for most GWT use cases.
73       */
74      @Parameter(property = "gwt.extraJvmArgs", defaultValue = "-Xmx512m")
75      private String extraJvmArgs;
76  
77      /**
78       * The currently executed project (phase=generate-resources).
79       */
80      @Parameter(defaultValue = "${executedProject}", readonly = true)
81      private MavenProject executedProject;
82  
83      /**
84       * Location of the compiled classes.
85       */
86      @Parameter(defaultValue = "${project.build.outputDirectory}", required = true, readonly = true)
87      private File buildOutputDirectory;
88  
89      /**
90       * Location of the hosted-mode web application structure.
91       */
92      @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}")
93      private File hostedWebapp;
94  
95      /**
96       * Additional parameters to append to the module URL. For example, gwt-log users will set "log_level=DEBUG"
97       */
98      @Parameter
99      private String additionalPageParameters;
100 
101     /**
102      * Run without hosted mode server
103      */
104     @Parameter(defaultValue = "false", property = "gwt.noserver")
105     private boolean noserver;
106 
107     /**
108      * Port of the HTTP server used when noserver is set
109      */
110     @Parameter(defaultValue = "8080", property = "gwt.port")
111     private int port;
112 
113     /**
114      * Set GWT shell protocol/host whitelist.
115      * <p>
116      * Can be set from command line using '-Dgwt.whitelist=...'
117      */
118     @Parameter(property = "gwt.whitelist")
119     private String whitelist;
120 
121     /**
122      * Set GWT shell protocol/host blacklist.
123      * <p>
124      * Can be set from command line using '-Dgwt.blacklist=...'
125      */
126     @Parameter(property = "gwt.blacklist")
127     private String blacklist;
128 
129     /**
130      * Set GWT shell bindAddress.
131      * <p>
132      * Can be set from command line using '-Dgwt.bindAddress=...'
133      */
134     @Parameter(property = "gwt.bindAddress")
135     private String bindAddress;
136 
137     /**
138      * Setup a launch configuration for using the Google Eclipse Plugin. This is the recommended setup, as the home-made
139      * launch configuration has many limitations. This parameter is only for backward compatibility, the standard lauch
140      * configuration template will be removed in a future release.
141      */
142     @Parameter(defaultValue = "true", property = "use.google.eclipse.plugin")
143     private boolean useGoogleEclipsePlugin;
144 
145     /**
146      * @param parameters additional parameter for module URL
147      */
148     public void setAdditionalPageParameters( String parameters )
149     {
150         // escape the '&' char used for multiple parameters as the result must be XML compliant
151         this.additionalPageParameters = StringUtils.replace( parameters, "&", "&amp;" );
152     }
153 
154     /**
155      * {@inheritDoc}
156      *
157      * @see org.apache.maven.plugin.Mojo#execute()
158      */
159     public void execute()
160         throws MojoExecutionException, MojoFailureException
161     {
162         if ( !noserver )
163         {
164             // Jetty requires an exploded webapp
165             setupExplodedWar();
166         }
167         else
168         {
169             getLog().info( "noServer is set! Skipping exploding war file..." );
170         }
171 
172         for ( String module : getModules() )
173         {
174             createLaunchConfigurationForHostedModeBrowser( module );
175         }
176     }
177 
178     protected void setupExplodedWar()
179         throws MojoExecutionException
180     {
181         try
182         {
183             File classes = new File( hostedWebapp, "WEB-INF/classes" );
184             if ( !buildOutputDirectory.getAbsolutePath().equals( classes.getAbsolutePath() ) )
185             {
186                 getLog().warn( "Your POM <build><outputdirectory> must match your "
187                     + "hosted webapp WEB-INF/classes folder for GWT Hosted browser to see your classes." );
188             }
189 
190             File lib = new File( hostedWebapp, "WEB-INF/lib" );
191             getLog().info( "create exploded Jetty webapp in " + hostedWebapp );
192             lib.mkdirs();
193 
194             Collection<Artifact> artifacts = getProject().getRuntimeArtifacts();
195             for ( Artifact artifact : artifacts )
196             {
197                 if ( !artifact.getFile().isDirectory() )
198                 {
199                     FileUtils.copyFileToDirectory( artifact.getFile(), lib );
200                 }
201                 else
202                 {
203                     // TODO automatically add this one to GWT warnings exlusions
204                 }
205             }
206         }
207         catch ( IOException ioe )
208         {
209             throw new MojoExecutionException( "Failed to create Jetty exploded webapp", ioe );
210         }
211     }
212 
213     /**
214      * create an Eclipse launch configuration file to Eclipse to run the module in hosted browser
215      *
216      * @param module the GWT module
217      * @throws MojoExecutionException some error occured
218      */
219     private void createLaunchConfigurationForHostedModeBrowser( String module )
220         throws MojoExecutionException
221     {
222         try
223         {
224             File launchFile = new File( getProject().getBasedir(), readModule( module ).getPath() + ".launch" );
225             if ( launchFile.exists() )
226             {
227                 getLog().info( "launch file exists " + launchFile.getName() + " skip generation " );
228                 return;
229             }
230 
231             Configuration cfg = new Configuration();
232             cfg.setClassForTemplateLoading( EclipseMojo.class, "" );
233 
234             Map<String, Object> context = new HashMap<String, Object>();
235             // Read compileSourceRoots from executedProject to retrieve generated source directories
236             Collection<String> sources = new LinkedList<String>( executedProject.getCompileSourceRoots() );
237             List<Resource> resources = executedProject.getResources();
238             for ( Resource resource : resources )
239             {
240                 sources.add( resource.getDirectory() );
241             }
242             context.put( "sources", sources );
243             context.put( "module", module );
244             context.put( "localRepository", localRepository.getBasedir() );
245             int idx = module.lastIndexOf( '.' );
246             String page = module.substring( idx + 1 ) + ".html";
247             if ( additionalPageParameters != null )
248             {
249                 page += "?" + additionalPageParameters;
250             }
251 
252             context.put( "modulePath", readModule( module ).getPath() );
253             context.put( "page", page );
254             int basedir = getProject().getBasedir().getAbsolutePath().length();
255             context.put( "out", getOutputDirectory().getAbsolutePath().substring( basedir + 1 ) );
256             context.put( "war", hostedWebapp.getAbsolutePath().substring( basedir + 1 ) );
257             String args = noserver ? "-noserver -port " + port : "";
258             if ( blacklist != null )
259             {
260                 args += " -blacklist " + blacklist;
261             }
262             if ( whitelist != null )
263             {
264                 args += " -whitelist " + whitelist;
265             }
266             if ( bindAddress != null )
267             {
268                 args += " -bindAddress " + bindAddress;
269             }
270             context.put( "additionalArguments", args );
271             context.put( "extraJvmArgs", extraJvmArgs );
272             context.put( "project", eclipseUtil.getProjectName( getProject() ) );
273 
274             Collection<String> gwtDevJarPath = new ArrayList<String>();
275             for (File f : getJarFiles(GWT_DEV, false))
276             {
277                 gwtDevJarPath.add( f.getAbsolutePath().replace( '\\', '/' ) );
278             }
279             context.put( "gwtDevJarPath", gwtDevJarPath );
280 
281             Writer configWriter = WriterFactory.newXmlWriter( launchFile );
282             String templateName = useGoogleEclipsePlugin ? "google.fm" : "launch.fm";
283             Template template = cfg.getTemplate( templateName, "UTF-8" );
284             template.process( context, configWriter );
285             configWriter.flush();
286             configWriter.close();
287             getLog().info( "Write launch configuration for GWT module : " + launchFile.getAbsolutePath() );
288         }
289         catch ( IOException ioe )
290         {
291             throw new MojoExecutionException( "Unable to write launch configuration", ioe );
292         }
293         catch ( TemplateException te )
294         {
295             throw new MojoExecutionException( "Unable to merge freemarker template", te );
296         }
297         catch ( GwtModuleReaderException e )
298         {
299             throw new MojoExecutionException( e.getMessage(), e );
300         }
301         
302     }
303 
304 }