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 8641 2012-09-27 06:45:17Z 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     private MavenProject getProject()
120     {
121         return this.project;
122     }
123 
124     private File getSourceDirectory()
125     {
126         return this.sourceDirectory;
127     }
128 
129     private File getResourceDirectory()
130     {
131         return this.resourceDirectory;
132     }
133 
134     private File getBuildDirectory()
135     {
136         return this.buildDirectory;
137     }
138 
139     private BundleGenerator getBundleGenerator()
140     {
141         return this.generator;
142     }
143 
144     private ModelManager getModelManager()
145     {
146         return this.modelManager;
147     }
148 
149     private File getModuleDescriptor()
150     {
151         return this.moduleDescriptor;
152     }
153 
154     private String getEncoding()
155     {
156         return this.encoding;
157     }
158 
159     private String getDefaultLanguage()
160     {
161         return this.defaultLanguage;
162     }
163 
164     public void execute() throws MojoExecutionException, MojoFailureException
165     {
166         if ( !this.getModuleDescriptor().exists() )
167         {
168             throw new MojoExecutionException(
169                 this.getMessage( "fileNotFound" ).
170                 format( new Object[]
171                 {
172                     this.getModuleDescriptor().getAbsolutePath()
173                 } ) );
174 
175         }
176 
177         try
178         {
179             this.assertDirectoryExistence( this.getSourceDirectory() );
180             this.assertDirectoryExistence( this.getResourceDirectory() );
181             this.assertDirectoryExistence( this.getBuildDirectory() );
182 
183             this.getProject().addCompileSourceRoot(
184                 this.getSourceDirectory().getAbsolutePath() );
185 
186             final Resource resource = new Resource();
187             resource.setDirectory( this.getResourceDirectory().
188                 getAbsolutePath() );
189 
190             resource.setFiltering( false );
191 
192             this.getProject().addResource( resource );
193 
194             final Module module = this.getModelManager().
195                 getModule( this.getModuleDescriptor() );
196 
197             if ( module != null )
198             {
199                 this.assertValidTemplates( module );
200                 if ( module.getImplementations() != null )
201                 {
202                     this.generateBundles( module );
203                 }
204             }
205         }
206         catch ( Exception e )
207         {
208             throw new MojoExecutionException( e.getMessage(), e );
209         }
210     }
211 
212     private MessageFormat getMessage( final String key )
213     {
214         if ( key == null )
215         {
216             throw new NullPointerException( "key" );
217         }
218 
219         return new MessageFormat(
220             ResourceBundle.getBundle( JavaResourcesMojo.class.getName() ).
221             getString( key ) );
222 
223     }
224 
225     private void assertDirectoryExistence( final File directory )
226         throws MojoExecutionException
227     {
228         if ( !directory.exists() && !directory.mkdirs() )
229         {
230             throw new MojoExecutionException(
231                 this.getMessage( "cannotCreateDirectory" ).
232                 format( new Object[]
233                 {
234                     directory.getAbsolutePath()
235                 } ) );
236 
237 
238         }
239     }
240 
241     private void generateBundles( final Module module )
242         throws Exception
243     {
244         final Properties bundleHashcodes = new Properties();
245         final File propertiesFile =
246             new File( this.getBuildDirectory(), "bundles.properties" );
247 
248         if ( !propertiesFile.exists() )
249         {
250             propertiesFile.createNewFile();
251         }
252 
253         final InputStream in = new FileInputStream( propertiesFile );
254         bundleHashcodes.load( in );
255         in.close();
256 
257         for ( Iterator it = module.getImplementations().getImplementation().
258             iterator(); it.hasNext(); )
259         {
260             final Implementation impl = (Implementation) it.next();
261             if ( impl.getMessages() == null )
262             {
263                 continue;
264             }
265 
266             final int bundleHash = this.getModelManager().
267                 getHashCode( module, impl );
268 
269             final String propertyHash =
270                 bundleHashcodes.getProperty( impl.getIdentifier() );
271 
272             if ( propertyHash == null ||
273                 Integer.valueOf( propertyHash ).intValue() != bundleHash )
274             {
275                 bundleHashcodes.setProperty( impl.getIdentifier(),
276                     Integer.toString( bundleHash ) );
277 
278                 final String bundlePath =
279                     ( this.getModelManager().getJavaPackageName( impl ) +
280                     '.' + this.getModelManager().getJavaTypeName( impl ) ).
281                     replace( '.', File.separatorChar );
282 
283                 final File bundleFile = new File( this.getSourceDirectory(),
284                     bundlePath + ".java" );
285 
286                 this.assertDirectoryExistence( bundleFile.getParentFile() );
287 
288                 final Writer writer =
289                     this.getEncoding() == null
290                     ? new FileWriter( bundleFile )
291                     : new OutputStreamWriter( new FileOutputStream(
292                     bundleFile ),
293                     this.getEncoding() );
294 
295                 this.getLog().info( this.getMessage( "writingBundle" ).
296                     format( new Object[]
297                     {
298                         bundleFile.getName()
299                     } ) );
300 
301                 this.getBundleGenerator().generateJava( module, impl, writer );
302 
303                 writer.close();
304 
305                 final Map bundleProperties = this.getModelManager().
306                     getBundleProperties( module, impl );
307 
308                 for ( Iterator properties = bundleProperties.entrySet().
309                     iterator(); properties.hasNext(); )
310                 {
311                     final Map.Entry entry = (Map.Entry) properties.next();
312                     final String language = (String) entry.getKey();
313                     final Properties p = (Properties) entry.getValue();
314                     final File file = new File( this.getResourceDirectory(),
315                         bundlePath + "_" + language +
316                         ".properties" );
317 
318                     this.getLog().info( this.getMessage( "writingBundle" ).
319                         format( new Object[]
320                         {
321                             file.getName()
322                         } ) );
323 
324                     this.assertDirectoryExistence( file.getParentFile() );
325 
326                     final OutputStream out = new FileOutputStream( file );
327                     p.store( out, this.getProject().getName() );
328                     out.close();
329 
330                     if ( this.getDefaultLanguage().
331                         equalsIgnoreCase( language ) )
332                     {
333                         final File defaultFile =
334                             new File( this.getResourceDirectory(),
335                             bundlePath + ".properties" );
336 
337                         this.assertDirectoryExistence(
338                             defaultFile.getParentFile() );
339 
340                         this.getLog().info( this.getMessage( "writingBundle" ).
341                             format( new Object[]
342                             {
343                                 defaultFile.getName()
344                             } ) );
345 
346                         final OutputStream defaultOut =
347                             new FileOutputStream( defaultFile );
348 
349                         p.store( defaultOut, this.getProject().getName() );
350                         defaultOut.close();
351                     }
352                 }
353             }
354         }
355 
356         final OutputStream out = new FileOutputStream( propertiesFile );
357         bundleHashcodes.store( out, this.getClass().getName() + ": " +
358             DateFormat.getDateTimeInstance().
359             format( new Date() ) );
360 
361         out.close();
362     }
363 
364     private void assertValidTemplates( final Module module )
365         throws MojoExecutionException
366     {
367         if ( module.getImplementations() != null )
368         {
369             for ( Iterator it = module.getImplementations().getImplementation().
370                 iterator(); it.hasNext(); )
371             {
372                 final Implementation impl = (Implementation) it.next();
373                 if ( impl.getMessages() == null )
374                 {
375                     continue;
376                 }
377 
378                 for ( Iterator m = impl.getMessages().getMessage().iterator();
379                     m.hasNext(); )
380                 {
381                     this.assertValidMessage( (Message) m.next() );
382                 }
383             }
384         }
385 
386         if ( module.getMessages() != null )
387         {
388             for ( Iterator it = module.getMessages().getMessage().iterator();
389                 it.hasNext(); )
390             {
391                 this.assertValidMessage( (Message) it.next() );
392             }
393         }
394     }
395 
396     private void assertValidMessage( final Message message )
397         throws MojoExecutionException
398     {
399         if ( message.getTemplate() != null )
400         {
401             for ( Iterator it = message.getTemplate().getText().iterator();
402                 it.hasNext(); )
403             {
404                 final Text text = (Text) it.next();
405                 try
406                 {
407                     new MessageFormat( text.getValue() );
408                 }
409                 catch ( IllegalArgumentException e )
410                 {
411                     final MessageFormat fmt =
412                         this.getMessage( "illegalTemplate" );
413 
414                     throw new MojoExecutionException( fmt.format( new Object[]
415                         {
416                             text.getValue(),
417                             message.getName(),
418                             e.getMessage()
419                         } ), e );
420 
421                 }
422             }
423         }
424     }
425 
426     //-------------------------------------------------------JavaResourcesMojo--
427 }