View Javadoc

1   /*
2    *  jDTAUS Core Resource Mojo
3    *  Copyright (C) 2005 Christian Schulte
4    *  <cs@schulte.it>
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19   *
20   */
21  package org.jdtaus.mojo.resource;
22  
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.FileOutputStream;
26  import java.io.FileWriter;
27  import java.io.InputStream;
28  import java.io.OutputStream;
29  import java.io.OutputStreamWriter;
30  import java.io.Writer;
31  import java.text.DateFormat;
32  import java.text.MessageFormat;
33  import java.util.Date;
34  import java.util.Iterator;
35  import java.util.Map;
36  import java.util.Properties;
37  import java.util.ResourceBundle;
38  import org.apache.maven.model.Resource;
39  import org.apache.maven.plugin.AbstractMojo;
40  import org.apache.maven.plugin.MojoExecutionException;
41  import org.apache.maven.plugin.MojoFailureException;
42  import org.apache.maven.project.MavenProject;
43  import org.jdtaus.mojo.resource.model.Implementation;
44  import org.jdtaus.mojo.resource.model.Message;
45  import org.jdtaus.mojo.resource.model.ModelManager;
46  import org.jdtaus.mojo.resource.model.Module;
47  import org.jdtaus.mojo.resource.model.Text;
48  import org.jdtaus.mojo.resource.util.BundleGenerator;
49  
50  /**
51   * Mojo to generate java resource accessor classes backed by java
52   * <code>ResourceBundle</code>s from a project's module descriptor.
53   *
54   * @goal java-resources
55   * @phase generate-sources
56   * @requiresDependencyResolution compile
57   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
58   * @version $JDTAUS: JavaResourcesMojo.java 8743 2012-10-07 03:06:20Z schulte $
59   */
60  public class JavaResourcesMojo extends AbstractMojo
61  {
62      //--JavaResourcesMojo-------------------------------------------------------
63  
64      /**
65       * Currently executed <code>MavenProject</code>.
66       *
67       * @parameter expression="${project}"
68       * @required
69       */
70      private MavenProject project;
71  
72      /**
73       * The directory to generate sources to.
74       *
75       * @parameter expression="${project.build.directory}/generated-sources/java-resources"
76       */
77      private File sourceDirectory;
78  
79      /**
80       * The directory to generate resources to.
81       *
82       * @parameter expression="${project.build.directory}/generated-resources/java-resources"
83       */
84      private File resourceDirectory;
85  
86      /**
87       * The directory to use for storing hashes for already generated files.
88       *
89       * @parameter expression="${project.build.directory}/java-resources"
90       */
91      private File buildDirectory;
92  
93      /**
94       * Project module descriptor to control the mojo.
95       * @parameter expression="${javaResources.moduleDescriptor}"
96       *            default-value="src/main/resources/META-INF/jdtaus/module.xml"
97       */
98      private File moduleDescriptor;
99  
100     /**
101      * The encoding to use for writing sources.
102      * @parameter expression="${project.build.sourceEncoding}"
103      */
104     private String encoding;
105 
106     /**
107      * The default language for generated bundles.
108      * @parameter expression="${javaResources.defaultLanguage}"
109      *            default-value="en"
110      */
111     private String defaultLanguage;
112 
113     /** @component */
114     private BundleGenerator generator;
115 
116     /** @component */
117     private ModelManager modelManager;
118 
119     /** Creates a new {@code JavaResourcesMojo} instance. */
120     public JavaResourcesMojo()
121     {
122         super();
123     }
124 
125     private MavenProject getProject()
126     {
127         return this.project;
128     }
129 
130     private File getSourceDirectory()
131     {
132         return this.sourceDirectory;
133     }
134 
135     private File getResourceDirectory()
136     {
137         return this.resourceDirectory;
138     }
139 
140     private File getBuildDirectory()
141     {
142         return this.buildDirectory;
143     }
144 
145     private BundleGenerator getBundleGenerator()
146     {
147         return this.generator;
148     }
149 
150     private ModelManager getModelManager()
151     {
152         return this.modelManager;
153     }
154 
155     private File getModuleDescriptor()
156     {
157         return this.moduleDescriptor;
158     }
159 
160     private String getEncoding()
161     {
162         return this.encoding;
163     }
164 
165     private String getDefaultLanguage()
166     {
167         return this.defaultLanguage;
168     }
169 
170     public void execute() throws MojoExecutionException, MojoFailureException
171     {
172         if ( !this.getModuleDescriptor().exists() )
173         {
174             throw new MojoExecutionException(
175                 this.getMessage( "fileNotFound" ).
176                 format( new Object[]
177                 {
178                     this.getModuleDescriptor().getAbsolutePath()
179                 } ) );
180 
181         }
182 
183         try
184         {
185             this.assertDirectoryExistence( this.getSourceDirectory() );
186             this.assertDirectoryExistence( this.getResourceDirectory() );
187             this.assertDirectoryExistence( this.getBuildDirectory() );
188 
189             this.getProject().addCompileSourceRoot(
190                 this.getSourceDirectory().getAbsolutePath() );
191 
192             final Resource resource = new Resource();
193             resource.setDirectory( this.getResourceDirectory().
194                 getAbsolutePath() );
195 
196             resource.setFiltering( false );
197 
198             this.getProject().addResource( resource );
199 
200             final Module module = this.getModelManager().
201                 getModule( this.getModuleDescriptor() );
202 
203             if ( module != null )
204             {
205                 this.assertValidTemplates( module );
206                 if ( module.getImplementations() != null )
207                 {
208                     this.generateBundles( module );
209                 }
210             }
211         }
212         catch ( final Exception e )
213         {
214             throw new MojoExecutionException( e.getMessage(), e );
215         }
216     }
217 
218     private MessageFormat getMessage( final String key )
219     {
220         if ( key == null )
221         {
222             throw new NullPointerException( "key" );
223         }
224 
225         return new MessageFormat(
226             ResourceBundle.getBundle( JavaResourcesMojo.class.getName() ).
227             getString( key ) );
228 
229     }
230 
231     private void assertDirectoryExistence( final File directory )
232         throws MojoExecutionException
233     {
234         if ( !directory.exists() && !directory.mkdirs() )
235         {
236             throw new MojoExecutionException(
237                 this.getMessage( "cannotCreateDirectory" ).
238                 format( new Object[]
239                 {
240                     directory.getAbsolutePath()
241                 } ) );
242 
243 
244         }
245     }
246 
247     private void generateBundles( final Module module )
248         throws Exception
249     {
250         InputStream in = null;
251         OutputStream out = null;
252         Writer writer = null;
253 
254         try
255         {
256             final Properties bundleHashcodes = new Properties();
257             final File propertiesFile =
258                 new File( this.getBuildDirectory(), "bundles.properties" );
259 
260             if ( !propertiesFile.exists() && !propertiesFile.createNewFile() )
261             {
262                 final MessageFormat fmt =
263                     this.getMessage( "cannotCreateFile" );
264 
265                 throw new MojoExecutionException( fmt.format( new Object[]
266                     {
267                         propertiesFile.getAbsolutePath()
268                     } ) );
269 
270             }
271 
272             in = new FileInputStream( propertiesFile );
273             bundleHashcodes.load( in );
274             in.close();
275             in = null;
276 
277             for ( final Iterator it = module.getImplementations().
278                 getImplementation().iterator(); it.hasNext(); )
279             {
280                 final Implementation impl = (Implementation) it.next();
281                 if ( impl.getMessages() == null )
282                 {
283                     continue;
284                 }
285 
286                 final int bundleHash =
287                     this.getModelManager().getHashCode( module, impl );
288 
289                 final String propertyHash =
290                     bundleHashcodes.getProperty( impl.getIdentifier() );
291 
292                 if ( propertyHash == null || Integer.valueOf( propertyHash ).
293                     intValue() != bundleHash )
294                 {
295                     bundleHashcodes.setProperty(
296                         impl.getIdentifier(), Integer.toString( bundleHash ) );
297 
298                     final String bundlePath =
299                         ( this.getModelManager().getJavaPackageName( impl )
300                           + '.' + this.getModelManager().getJavaTypeName( impl ) ).
301                         replace( '.', File.separatorChar );
302 
303                     final File bundleFile = new File( this.getSourceDirectory(),
304                                                       bundlePath + ".java" );
305 
306                     this.assertDirectoryExistence( bundleFile.getParentFile() );
307 
308                     writer =
309                         this.getEncoding() == null
310                         ? new FileWriter( bundleFile )
311                         : new OutputStreamWriter( new FileOutputStream(
312                         bundleFile ), this.getEncoding() );
313 
314                     this.getLog().info( this.getMessage( "writingBundle" ).
315                         format( new Object[]
316                         {
317                             bundleFile.getName()
318                         } ) );
319 
320                     this.getBundleGenerator().
321                         generateJava( module, impl, writer );
322 
323                     writer.close();
324                     writer = null;
325 
326                     final Map bundleProperties =
327                         this.getModelManager().
328                         getBundleProperties( module, impl );
329 
330                     for ( final Iterator it2 = bundleProperties.entrySet().
331                         iterator(); it2.hasNext(); )
332                     {
333                         final Map.Entry entry = (Map.Entry) it2.next();
334                         final String language = (String) entry.getKey();
335                         final Properties p = (Properties) entry.getValue();
336                         final File file = new File( this.getResourceDirectory(),
337                                                     bundlePath + "_" + language
338                                                     + ".properties" );
339 
340                         this.getLog().info( this.getMessage( "writingBundle" ).
341                             format( new Object[]
342                             {
343                                 file.getName()
344                             } ) );
345 
346                         this.assertDirectoryExistence( file.getParentFile() );
347 
348                         out = new FileOutputStream( file );
349                         p.store( out, this.getProject().getName() );
350                         out.close();
351                         out = null;
352 
353                         if ( this.getDefaultLanguage().
354                             equalsIgnoreCase( language ) )
355                         {
356                             final File defaultFile =
357                                 new File( this.getResourceDirectory(),
358                                           bundlePath + ".properties" );
359 
360                             this.assertDirectoryExistence(
361                                 defaultFile.getParentFile() );
362 
363                             this.getLog().info( this.
364                                 getMessage( "writingBundle" ).
365                                 format( new Object[]
366                                 {
367                                     defaultFile.getName()
368                                 } ) );
369 
370                             out = new FileOutputStream( defaultFile );
371                             p.store( out, this.getProject().getName() );
372                             out.close();
373                             out = null;
374                         }
375                     }
376                 }
377             }
378 
379             out = new FileOutputStream( propertiesFile );
380             bundleHashcodes.store( out, this.getClass().getName() + ": "
381                                         + DateFormat.getDateTimeInstance().
382                 format( new Date() ) );
383 
384             out.close();
385             out = null;
386         }
387         finally
388         {
389             try
390             {
391                 if ( in != null )
392                 {
393                     in.close();
394                 }
395             }
396             finally
397             {
398                 try
399                 {
400                     if ( out != null )
401                     {
402                         out.close();
403                     }
404                 }
405                 finally
406                 {
407                     if ( writer != null )
408                     {
409                         writer.close();
410                     }
411                 }
412             }
413         }
414     }
415 
416     private void assertValidTemplates( final Module module )
417         throws MojoExecutionException
418     {
419         if ( module.getImplementations() != null )
420         {
421             for ( final Iterator it = module.getImplementations().
422                 getImplementation().iterator(); it.hasNext(); )
423             {
424                 final Implementation impl = (Implementation) it.next();
425                 if ( impl.getMessages() == null )
426                 {
427                     continue;
428                 }
429 
430                 for ( final Iterator m = impl.getMessages().getMessage().
431                     iterator(); m.hasNext(); )
432                 {
433                     this.assertValidMessage( (Message) m.next() );
434                 }
435             }
436         }
437 
438         if ( module.getMessages() != null )
439         {
440             for ( final Iterator it = module.getMessages().getMessage().
441                 iterator(); it.hasNext(); )
442             {
443                 this.assertValidMessage( (Message) it.next() );
444             }
445         }
446     }
447 
448     private void assertValidMessage( final Message message )
449         throws MojoExecutionException
450     {
451         if ( message.getTemplate() != null )
452         {
453             for ( final Iterator it = message.getTemplate().getText().
454                 iterator(); it.hasNext(); )
455             {
456                 final Text text = (Text) it.next();
457                 try
458                 {
459                     new MessageFormat( text.getValue() );
460                 }
461                 catch ( final IllegalArgumentException e )
462                 {
463                     final MessageFormat fmt =
464                         this.getMessage( "illegalTemplate" );
465 
466                     throw new MojoExecutionException( fmt.format( new Object[]
467                         {
468                             text.getValue(),
469                             message.getName(),
470                             e.getMessage()
471                         } ), e );
472 
473                 }
474             }
475         }
476     }
477 
478     //-------------------------------------------------------JavaResourcesMojo--
479 }