001 /*
002 * Copyright (c) 2009 The JOMC Project
003 * Copyright (c) 2005 Christian Schulte <schulte2005@users.sourceforge.net>
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions
008 * are met:
009 *
010 * o Redistributions of source code must retain the above copyright
011 * notice, this list of conditions and the following disclaimer.
012 *
013 * o Redistributions in binary form must reproduce the above copyright
014 * notice, this list of conditions and the following disclaimer in
015 * the documentation and/or other materials provided with the
016 * distribution.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR
022 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
027 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
028 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 *
030 * $Id: ResourceFileProcessor.java 1560 2010-03-07 00:31:49Z schulte2005 $
031 *
032 */
033 package org.jomc.tools;
034
035 import java.io.File;
036 import java.io.FileOutputStream;
037 import java.io.IOException;
038 import java.io.OutputStream;
039 import java.text.MessageFormat;
040 import java.util.HashMap;
041 import java.util.Locale;
042 import java.util.Map;
043 import java.util.Properties;
044 import java.util.ResourceBundle;
045 import java.util.logging.Level;
046 import org.jomc.model.Implementation;
047 import org.jomc.model.Message;
048 import org.jomc.model.Messages;
049 import org.jomc.model.Module;
050 import org.jomc.model.Specification;
051 import org.jomc.model.Text;
052
053 /**
054 * Processes resource files.
055 *
056 * <p><b>Use cases</b><br/><ul>
057 * <li>{@link #writeResourceBundleResourceFiles(File) }</li>
058 * <li>{@link #writeResourceBundleResourceFiles(Module, File) }</li>
059 * <li>{@link #writeResourceBundleResourceFiles(Specification, File) }</li>
060 * <li>{@link #writeResourceBundleResourceFiles(Implementation, File) }</li>
061 * </ul></p>
062 *
063 * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
064 * @version $Id: ResourceFileProcessor.java 1560 2010-03-07 00:31:49Z schulte2005 $
065 *
066 * @see #getModules()
067 */
068 public class ResourceFileProcessor extends JomcTool
069 {
070
071 /** Name of the generator. */
072 private static final String GENERATOR_NAME = ResourceFileProcessor.class.getName();
073
074 /** Constant for the version of the generator. */
075 private static final String GENERATOR_VERSION = "1.0";
076
077 /** The language of the default language properties file of generated resource bundle resources. */
078 private Locale resourceBundleDefaultLocale;
079
080 /** Creates a new {@code ResourceFileProcessor} instance. */
081 public ResourceFileProcessor()
082 {
083 super();
084 }
085
086 /**
087 * Creates a new {@code ResourceFileProcessor} instance taking a {@code ResourceFileProcessor} instance to
088 * initialize the instance with.
089 *
090 * @param tool The instance to initialize the new instance with.
091 *
092 * @throws NullPointerException if {@code tool} is {@code null}.
093 * @throws IOException if copying {@code tool} fails.
094 */
095 public ResourceFileProcessor( final ResourceFileProcessor tool ) throws IOException
096 {
097 super( tool );
098 this.setResourceBundleDefaultLocale( tool.getResourceBundleDefaultLocale() );
099 }
100
101 /**
102 * Gets the language of the default language properties file of generated resource bundle resource files.
103 *
104 * @return The language of the default language properties file of generated resource bundle resource files.
105 *
106 * @see #setResourceBundleDefaultLocale(java.util.Locale)
107 */
108 public Locale getResourceBundleDefaultLocale()
109 {
110 if ( this.resourceBundleDefaultLocale == null )
111 {
112 this.resourceBundleDefaultLocale = Locale.getDefault();
113
114 if ( this.isLoggable( Level.CONFIG ) )
115 {
116 this.log( Level.CONFIG, getMessage( "resourceBundleDefaultLocale", this.resourceBundleDefaultLocale ),
117 null );
118
119 }
120 }
121
122 return this.resourceBundleDefaultLocale;
123 }
124
125 /**
126 * Sets the language of the default language properties file of generated resource bundle resource files.
127 *
128 * @param value The language of the default language properties file of generated resource bundle resource files.
129 *
130 * @see #getResourceBundleDefaultLocale()
131 */
132 public void setResourceBundleDefaultLocale( final Locale value )
133 {
134 this.resourceBundleDefaultLocale = value;
135 }
136
137 /**
138 * Writes resource bundle resource files of the modules of the instance to a given directory.
139 *
140 * @param resourcesDirectory The directory to write resource bundle resource files to.
141 *
142 * @throws NullPointerException if {@code resourcesDirectory} is {@code null}.
143 * @throws IOException if writing resource bundle resource files fails.
144 *
145 * @see #writeResourceBundleResourceFiles(org.jomc.model.Module, java.io.File)
146 */
147 public void writeResourceBundleResourceFiles( final File resourcesDirectory ) throws IOException
148 {
149 if ( resourcesDirectory == null )
150 {
151 throw new NullPointerException( "resourcesDirectory" );
152 }
153
154 for ( Module m : this.getModules().getModule() )
155 {
156 this.writeResourceBundleResourceFiles( m, resourcesDirectory );
157 }
158 }
159
160 /**
161 * Writes resource bundle resource files of a given module from the modules of the instance to a given directory.
162 *
163 * @param module The module to process.
164 * @param resourcesDirectory The directory to write resource bundle resource files to.
165 *
166 * @throws NullPointerException if {@code module} or {@code resourcesDirectory} is {@code null}.
167 * @throws IOException if writing resource bundle resource files fails.
168 *
169 * @see #writeResourceBundleResourceFiles(org.jomc.model.Specification, java.io.File)
170 * @see #writeResourceBundleResourceFiles(org.jomc.model.Implementation, java.io.File)
171 */
172 public void writeResourceBundleResourceFiles( final Module module, final File resourcesDirectory )
173 throws IOException
174 {
175 if ( module == null )
176 {
177 throw new NullPointerException( "module" );
178 }
179 if ( resourcesDirectory == null )
180 {
181 throw new NullPointerException( "resourcesDirectory" );
182 }
183
184 if ( module.getSpecifications() != null )
185 {
186 for ( Specification s : module.getSpecifications().getSpecification() )
187 {
188 this.writeResourceBundleResourceFiles( s, resourcesDirectory );
189 }
190 }
191
192 if ( module.getImplementations() != null )
193 {
194 for ( Implementation i : module.getImplementations().getImplementation() )
195 {
196 this.writeResourceBundleResourceFiles( i, resourcesDirectory );
197 }
198 }
199 }
200
201 /**
202 * Writes resource bundle resource files of a given specification from the modules of the instance to a directory.
203 *
204 * @param specification The specification to process.
205 * @param resourcesDirectory The directory to write resource bundle resource files to.
206 *
207 * @throws NullPointerException if {@code specification} or {@code resourcesDirectory} is {@code null}.
208 * @throws IOException if writing resource bundle resource files fails.
209 *
210 * @see #getResourceBundleResources(org.jomc.model.Specification)
211 */
212 public void writeResourceBundleResourceFiles( final Specification specification, final File resourcesDirectory )
213 throws IOException
214 {
215 if ( specification == null )
216 {
217 throw new NullPointerException( "implementation" );
218 }
219 if ( resourcesDirectory == null )
220 {
221 throw new NullPointerException( "resourcesDirectory" );
222 }
223
224 if ( specification.isClassDeclaration() )
225 {
226 this.assertValidTemplates( specification );
227
228 final String bundlePath =
229 this.getJavaTypeName( specification, true ).replace( '.', File.separatorChar );
230
231 this.writeResourceBundleResourceFiles(
232 this.getResourceBundleResources( specification ), resourcesDirectory, bundlePath );
233
234 }
235 }
236
237 /**
238 * Writes resource bundle resource files of a given implementation from the modules of the instance to a directory.
239 *
240 * @param implementation The implementation to process.
241 * @param resourcesDirectory The directory to write resource bundle resource files to.
242 *
243 * @throws NullPointerException if {@code implementation} or {@code resourcesDirectory} is {@code null}.
244 * @throws IOException if writing resource bundle resource files fails.
245 *
246 * @see #getResourceBundleResources(org.jomc.model.Implementation)
247 */
248 public void writeResourceBundleResourceFiles( final Implementation implementation, final File resourcesDirectory )
249 throws IOException
250 {
251 if ( implementation == null )
252 {
253 throw new NullPointerException( "implementation" );
254 }
255 if ( resourcesDirectory == null )
256 {
257 throw new NullPointerException( "resourcesDirectory" );
258 }
259
260 if ( implementation.isClassDeclaration() )
261 {
262 this.assertValidTemplates( implementation );
263
264 final String bundlePath =
265 this.getJavaTypeName( implementation, true ).replace( '.', File.separatorChar );
266
267 this.writeResourceBundleResourceFiles(
268 this.getResourceBundleResources( implementation ), resourcesDirectory, bundlePath );
269
270 }
271 }
272
273 /**
274 * Gets resource bundle properties resources of a given specification.
275 *
276 * @param specification The specification to get resource bundle properties resources of.
277 *
278 * @return Resource bundle properties resources of {@code specification}.
279 *
280 * @throws NullPointerException if {@code specification} is {@code null}.
281 * @throws IOException if getting the resource bundle properties resources fails.
282 */
283 public Map<Locale, Properties> getResourceBundleResources( final Specification specification )
284 throws IOException
285 {
286 if ( specification == null )
287 {
288 throw new NullPointerException( "specification" );
289 }
290
291 return new HashMap<Locale, java.util.Properties>();
292 }
293
294 /**
295 * Gets resource bundle properties resources of a given implementation.
296 *
297 * @param implementation The implementation to get resource bundle properties resources of.
298 *
299 * @return Resource bundle properties resources of {@code implementation}.
300 *
301 * @throws NullPointerException if {@code implementation} is {@code null}.
302 * @throws IOException if getting the resource bundle properties resources fails.
303 */
304 public Map<Locale, Properties> getResourceBundleResources( final Implementation implementation )
305 throws IOException
306 {
307 if ( implementation == null )
308 {
309 throw new NullPointerException( "implementation" );
310 }
311
312 final Map<Locale, java.util.Properties> properties = new HashMap<Locale, java.util.Properties>( 10 );
313 final Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
314
315 if ( messages != null )
316 {
317 for ( Message message : messages.getMessage() )
318 {
319 if ( message.getTemplate() != null )
320 {
321 for ( Text text : message.getTemplate().getText() )
322 {
323 final Locale locale = new Locale( text.getLanguage().toLowerCase() );
324 Properties bundleProperties = properties.get( locale );
325
326 if ( bundleProperties == null )
327 {
328 bundleProperties = new Properties();
329 properties.put( locale, bundleProperties );
330 }
331
332 bundleProperties.setProperty( message.getName(), text.getValue() );
333 }
334 }
335 }
336 }
337
338 return properties;
339 }
340
341 private void writeResourceBundleResourceFiles( final Map<Locale, Properties> resources,
342 final File resourcesDirectory, final String bundlePath )
343 throws IOException
344 {
345 if ( resources == null )
346 {
347 throw new NullPointerException( "resources" );
348 }
349 if ( resourcesDirectory == null )
350 {
351 throw new NullPointerException( "resourcesDirectory" );
352 }
353 if ( bundlePath == null )
354 {
355 throw new NullPointerException( "bundlePath" );
356 }
357
358 Properties defProperties = null;
359 Properties fallbackProperties = null;
360
361 for ( Map.Entry<Locale, Properties> e : resources.entrySet() )
362 {
363 final String language = e.getKey().getLanguage().toLowerCase();
364 final Properties p = e.getValue();
365 final File file = new File( resourcesDirectory, bundlePath + "_" + language + ".properties" );
366
367 if ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() )
368 {
369 throw new IOException( getMessage( "failedCreatingDirectory",
370 file.getParentFile().getAbsolutePath() ) );
371
372 }
373
374 if ( this.isLoggable( Level.INFO ) )
375 {
376 this.log( Level.INFO, getMessage( "writing", file.getCanonicalPath() ), null );
377 }
378
379 OutputStream out = null;
380 try
381 {
382 out = new FileOutputStream( file );
383 p.store( out, GENERATOR_NAME + ' ' + GENERATOR_VERSION );
384 }
385 finally
386 {
387 if ( out != null )
388 {
389 out.close();
390 }
391 }
392
393 if ( this.getResourceBundleDefaultLocale().getLanguage().equalsIgnoreCase( language ) )
394 {
395 defProperties = p;
396 }
397
398 fallbackProperties = p;
399 }
400
401 if ( defProperties == null )
402 {
403 defProperties = fallbackProperties;
404 }
405
406 if ( defProperties != null )
407 {
408 final File file = new File( resourcesDirectory, bundlePath + ".properties" );
409 if ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() )
410 {
411 throw new IOException( getMessage( "failedCreatingDirectory",
412 file.getParentFile().getAbsolutePath() ) );
413
414 }
415
416 if ( this.isLoggable( Level.INFO ) )
417 {
418 this.log( Level.INFO, getMessage( "writing", file.getCanonicalPath() ), null );
419 }
420
421 OutputStream out = null;
422 try
423 {
424 out = new FileOutputStream( file );
425 defProperties.store( out, GENERATOR_NAME + ' ' + GENERATOR_VERSION );
426 }
427 finally
428 {
429 if ( out != null )
430 {
431 out.close();
432 }
433 }
434 }
435 }
436
437 private void assertValidTemplates( final Specification specification )
438 {
439 if ( specification == null )
440 {
441 throw new NullPointerException( "specification" );
442 }
443 }
444
445 private void assertValidTemplates( final Implementation implementation )
446 {
447 if ( implementation == null )
448 {
449 throw new NullPointerException( "implementation" );
450 }
451
452 final Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
453
454 if ( messages != null )
455 {
456 for ( Message m : messages.getMessage() )
457 {
458 if ( m.getTemplate() != null )
459 {
460 for ( Text t : m.getTemplate().getText() )
461 {
462 new MessageFormat( t.getValue() );
463 }
464 }
465 }
466 }
467 }
468
469 private static String getMessage( final String key, final Object... arguments )
470 {
471 if ( key == null )
472 {
473 throw new NullPointerException( "key" );
474 }
475
476 return MessageFormat.format( ResourceBundle.getBundle(
477 ResourceFileProcessor.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
478
479 }
480
481 }