1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package org.jomc.tools;
32
33 import java.io.ByteArrayOutputStream;
34 import java.io.Closeable;
35 import java.io.File;
36 import java.io.IOException;
37 import java.io.RandomAccessFile;
38 import java.nio.ByteBuffer;
39 import java.nio.channels.FileChannel;
40 import java.nio.channels.FileLock;
41 import java.text.MessageFormat;
42 import java.util.HashMap;
43 import java.util.Locale;
44 import java.util.Map;
45 import java.util.Properties;
46 import java.util.ResourceBundle;
47 import java.util.logging.Level;
48 import org.apache.velocity.VelocityContext;
49 import org.jomc.model.Implementation;
50 import org.jomc.model.Message;
51 import org.jomc.model.Messages;
52 import org.jomc.model.Module;
53 import org.jomc.model.Specification;
54 import org.jomc.model.Text;
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public class ResourceFileProcessor extends JomcTool
72 {
73
74
75 private Locale resourceBundleDefaultLocale;
76
77
78 public ResourceFileProcessor()
79 {
80 super();
81 }
82
83
84
85
86
87
88
89
90
91
92 public ResourceFileProcessor( final ResourceFileProcessor tool ) throws IOException
93 {
94 super( tool );
95 this.resourceBundleDefaultLocale = tool.resourceBundleDefaultLocale;
96 }
97
98
99
100
101
102
103
104
105 public final Locale getResourceBundleDefaultLocale()
106 {
107 if ( this.resourceBundleDefaultLocale == null )
108 {
109 this.resourceBundleDefaultLocale = Locale.ENGLISH;
110
111 if ( this.isLoggable( Level.CONFIG ) )
112 {
113 this.log( Level.CONFIG, getMessage( "defaultResourceBundleDefaultLocale",
114 this.resourceBundleDefaultLocale ), null );
115
116 }
117 }
118
119 return this.resourceBundleDefaultLocale;
120 }
121
122
123
124
125
126
127
128
129 public final void setResourceBundleDefaultLocale( final Locale value )
130 {
131 this.resourceBundleDefaultLocale = value;
132 }
133
134
135
136
137
138
139
140
141
142
143
144 public void writeResourceBundleResourceFiles( final File resourcesDirectory ) throws IOException
145 {
146 if ( resourcesDirectory == null )
147 {
148 throw new NullPointerException( "resourcesDirectory" );
149 }
150
151 if ( this.getModules() != null )
152 {
153 for ( int i = 0, s0 = this.getModules().getModule().size(); i < s0; i++ )
154 {
155 this.writeResourceBundleResourceFiles( this.getModules().getModule().get( i ), resourcesDirectory );
156 }
157 }
158 else if ( this.isLoggable( Level.WARNING ) )
159 {
160 this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
161 }
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176 public void writeResourceBundleResourceFiles( final Module module, final File resourcesDirectory )
177 throws IOException
178 {
179 if ( module == null )
180 {
181 throw new NullPointerException( "module" );
182 }
183 if ( resourcesDirectory == null )
184 {
185 throw new NullPointerException( "resourcesDirectory" );
186 }
187
188 if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
189 {
190 if ( module.getSpecifications() != null )
191 {
192 for ( int i = 0, s0 = module.getSpecifications().getSpecification().size(); i < s0; i++ )
193 {
194 this.writeResourceBundleResourceFiles( module.getSpecifications().getSpecification().get( i ),
195 resourcesDirectory );
196
197 }
198 }
199
200 if ( module.getImplementations() != null )
201 {
202 for ( int i = 0, s0 = module.getImplementations().getImplementation().size(); i < s0; i++ )
203 {
204 this.writeResourceBundleResourceFiles( module.getImplementations().getImplementation().get( i ),
205 resourcesDirectory );
206
207 }
208 }
209 }
210 else if ( this.isLoggable( Level.WARNING ) )
211 {
212 this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
213 }
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227 public void writeResourceBundleResourceFiles( final Specification specification, final File resourcesDirectory )
228 throws IOException
229 {
230 if ( specification == null )
231 {
232 throw new NullPointerException( "implementation" );
233 }
234 if ( resourcesDirectory == null )
235 {
236 throw new NullPointerException( "resourcesDirectory" );
237 }
238
239 if ( this.getModules() != null
240 && this.getModules().getSpecification( specification.getIdentifier() ) != null )
241 {
242 if ( specification.isClassDeclaration() )
243 {
244 if ( !resourcesDirectory.isDirectory() )
245 {
246 throw new IOException( getMessage( "directoryNotFound", resourcesDirectory.getAbsolutePath() ) );
247 }
248
249 this.assertValidTemplates( specification );
250
251 final String bundlePath =
252 this.getJavaTypeName( specification, true ).replace( '.', File.separatorChar );
253
254 this.writeResourceBundleResourceFiles(
255 this.getResourceBundleResources( specification ), resourcesDirectory, bundlePath );
256
257 }
258 }
259 else if ( this.isLoggable( Level.WARNING ) )
260 {
261 this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
262 }
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276 public void writeResourceBundleResourceFiles( final Implementation implementation, final File resourcesDirectory )
277 throws IOException
278 {
279 if ( implementation == null )
280 {
281 throw new NullPointerException( "implementation" );
282 }
283 if ( resourcesDirectory == null )
284 {
285 throw new NullPointerException( "resourcesDirectory" );
286 }
287
288 if ( this.getModules() != null
289 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
290 {
291 if ( implementation.isClassDeclaration() )
292 {
293 if ( !resourcesDirectory.isDirectory() )
294 {
295 throw new IOException( getMessage( "directoryNotFound", resourcesDirectory.getAbsolutePath() ) );
296 }
297
298 this.assertValidTemplates( implementation );
299
300 final String bundlePath =
301 this.getJavaTypeName( implementation, true ).replace( '.', File.separatorChar );
302
303 this.writeResourceBundleResourceFiles(
304 this.getResourceBundleResources( implementation ), resourcesDirectory, bundlePath );
305
306 }
307 }
308 else if ( this.isLoggable( Level.WARNING ) )
309 {
310 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
311 }
312 }
313
314
315
316
317
318
319
320
321
322
323
324
325 public Map<Locale, Properties> getResourceBundleResources( final Specification specification )
326 throws IOException
327 {
328 if ( specification == null )
329 {
330 throw new NullPointerException( "specification" );
331 }
332
333 Map<Locale, Properties> properties = null;
334
335 if ( this.getModules() != null
336 && this.getModules().getSpecification( specification.getIdentifier() ) != null )
337 {
338 properties = new HashMap<Locale, Properties>();
339 }
340 else if ( this.isLoggable( Level.WARNING ) )
341 {
342 this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
343 }
344
345 return properties;
346 }
347
348
349
350
351
352
353
354
355
356
357
358
359 public Map<Locale, Properties> getResourceBundleResources( final Implementation implementation )
360 throws IOException
361 {
362 if ( implementation == null )
363 {
364 throw new NullPointerException( "implementation" );
365 }
366
367 Map<Locale, Properties> properties = null;
368
369 if ( this.getModules() != null
370 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
371 {
372 properties = new HashMap<Locale, java.util.Properties>( 10 );
373 final Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
374
375 if ( messages != null )
376 {
377 for ( int i = 0, s0 = messages.getMessage().size(); i < s0; i++ )
378 {
379 final Message message = messages.getMessage().get( i );
380
381 if ( message.getTemplate() != null )
382 {
383 for ( int j = 0, s1 = message.getTemplate().getText().size(); j < s1; j++ )
384 {
385 final Text text = message.getTemplate().getText().get( j );
386 final Locale locale = new Locale( text.getLanguage().toLowerCase() );
387 Properties bundleProperties = properties.get( locale );
388
389 if ( bundleProperties == null )
390 {
391 bundleProperties = new Properties();
392 properties.put( locale, bundleProperties );
393 }
394
395 bundleProperties.setProperty( message.getName(), text.getValue() );
396 }
397 }
398 }
399 }
400 }
401 else if ( this.isLoggable( Level.WARNING ) )
402 {
403 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
404 }
405
406 return properties;
407 }
408
409 private void writeResourceBundleResourceFiles( final Map<Locale, Properties> resources,
410 final File resourcesDirectory, final String bundlePath )
411 throws IOException
412 {
413 if ( resources == null )
414 {
415 throw new NullPointerException( "resources" );
416 }
417 if ( resourcesDirectory == null )
418 {
419 throw new NullPointerException( "resourcesDirectory" );
420 }
421 if ( bundlePath == null )
422 {
423 throw new NullPointerException( "bundlePath" );
424 }
425
426 Properties defProperties = null;
427 Properties fallbackProperties = null;
428
429 final VelocityContext ctx = this.getVelocityContext();
430 final String toolName = ctx.get( "toolName" ).toString();
431 final String toolVersion = ctx.get( "toolVersion" ).toString();
432 final String toolUrl = ctx.get( "toolUrl" ).toString();
433
434 for ( Map.Entry<Locale, Properties> e : resources.entrySet() )
435 {
436 final String language = e.getKey().getLanguage().toLowerCase();
437 final Properties p = e.getValue();
438 final File file = new File( resourcesDirectory, bundlePath + "_" + language + ".properties" );
439
440 if ( this.getResourceBundleDefaultLocale().getLanguage().equalsIgnoreCase( language ) )
441 {
442 defProperties = p;
443 }
444
445 fallbackProperties = p;
446
447 if ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() )
448 {
449 throw new IOException( getMessage( "failedCreatingDirectory",
450 file.getParentFile().getAbsolutePath() ) );
451
452 }
453
454 if ( this.isLoggable( Level.INFO ) )
455 {
456 this.log( Level.INFO, getMessage( "writing", file.getCanonicalPath() ), null );
457 }
458
459 this.writePropertiesFile( p, toolName + ' ' + toolVersion + " - See " + toolUrl, file );
460 }
461
462 if ( defProperties == null )
463 {
464 defProperties = fallbackProperties;
465 }
466
467 if ( defProperties != null )
468 {
469 final File file = new File( resourcesDirectory, bundlePath + ".properties" );
470
471 if ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() )
472 {
473 throw new IOException( getMessage( "failedCreatingDirectory",
474 file.getParentFile().getAbsolutePath() ) );
475
476 }
477
478 if ( this.isLoggable( Level.INFO ) )
479 {
480 this.log( Level.INFO, getMessage( "writing", file.getCanonicalPath() ), null );
481 }
482
483 this.writePropertiesFile( defProperties, toolName + ' ' + toolVersion + " - See " + toolUrl, file );
484 }
485 }
486
487 private void assertValidTemplates( final Specification specification )
488 {
489 if ( specification == null )
490 {
491 throw new NullPointerException( "specification" );
492 }
493 }
494
495 private void assertValidTemplates( final Implementation implementation )
496 {
497 if ( implementation == null )
498 {
499 throw new NullPointerException( "implementation" );
500 }
501
502 final Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
503
504 if ( messages != null )
505 {
506 for ( int i = messages.getMessage().size() - 1; i >= 0; i-- )
507 {
508 final Message m = messages.getMessage().get( i );
509
510 if ( m.getTemplate() != null )
511 {
512 for ( int j = m.getTemplate().getText().size() - 1; j >= 0; j-- )
513 {
514 new MessageFormat( m.getTemplate().getText().get( j ).getValue() );
515 }
516 }
517 }
518 }
519 }
520
521 private void writePropertiesFile( final Properties properties, final String comments, final File propertiesFile )
522 throws IOException
523 {
524 RandomAccessFile randomAccessFile = null;
525 FileChannel fileChannel = null;
526 FileLock fileLock = null;
527 boolean suppressExceptionOnClose = true;
528
529 final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
530 properties.store( byteStream, comments );
531 byteStream.close();
532
533 final byte[] bytes = byteStream.toByteArray();
534
535 try
536 {
537 randomAccessFile = new RandomAccessFile( propertiesFile, "rw" );
538 fileChannel = randomAccessFile.getChannel();
539 fileLock = fileChannel.lock();
540 fileChannel.truncate( bytes.length );
541 fileChannel.position( 0L );
542 fileChannel.write( ByteBuffer.wrap( bytes ) );
543 fileChannel.force( true );
544 suppressExceptionOnClose = false;
545 }
546 finally
547 {
548 this.releaseAndClose( fileLock, fileChannel, randomAccessFile, suppressExceptionOnClose );
549 }
550 }
551
552 private void releaseAndClose( final FileLock fileLock, final FileChannel fileChannel,
553 final Closeable closeable, final boolean suppressExceptions )
554 throws IOException
555 {
556 try
557 {
558 if ( fileLock != null )
559 {
560 fileLock.release();
561 }
562 }
563 catch ( final IOException e )
564 {
565 if ( suppressExceptions )
566 {
567 this.log( Level.SEVERE, null, e );
568 }
569 else
570 {
571 throw e;
572 }
573 }
574 finally
575 {
576 try
577 {
578 if ( fileChannel != null )
579 {
580 fileChannel.close();
581 }
582 }
583 catch ( final IOException e )
584 {
585 if ( suppressExceptions )
586 {
587 this.log( Level.SEVERE, null, e );
588 }
589 else
590 {
591 throw e;
592 }
593 }
594 finally
595 {
596 try
597 {
598 if ( closeable != null )
599 {
600 closeable.close();
601 }
602 }
603 catch ( final IOException e )
604 {
605 if ( suppressExceptions )
606 {
607 this.log( Level.SEVERE, null, e );
608 }
609 else
610 {
611 throw e;
612 }
613 }
614 }
615 }
616 }
617
618 private static String getMessage( final String key, final Object... arguments )
619 {
620 if ( key == null )
621 {
622 throw new NullPointerException( "key" );
623 }
624
625 return MessageFormat.format( ResourceBundle.getBundle(
626 ResourceFileProcessor.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
627
628 }
629
630 private static String getMessage( final Throwable t )
631 {
632 return t != null ? t.getMessage() != null ? t.getMessage() : getMessage( t.getCause() ) : null;
633 }
634
635 }