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.Closeable;
34 import java.io.File;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.lang.reflect.UndeclaredThrowableException;
38 import java.nio.channels.FileLock;
39 import java.text.MessageFormat;
40 import java.util.HashMap;
41 import java.util.LinkedList;
42 import java.util.List;
43 import java.util.Locale;
44 import java.util.Map;
45 import java.util.Properties;
46 import java.util.ResourceBundle;
47 import java.util.concurrent.Callable;
48 import java.util.concurrent.CancellationException;
49 import java.util.concurrent.ExecutionException;
50 import java.util.concurrent.Future;
51 import java.util.logging.Level;
52 import org.apache.velocity.VelocityContext;
53 import org.jomc.model.Implementation;
54 import org.jomc.model.Implementations;
55 import org.jomc.model.JavaTypeName;
56 import org.jomc.model.Message;
57 import org.jomc.model.Messages;
58 import org.jomc.model.ModelObjectException;
59 import org.jomc.model.Module;
60 import org.jomc.model.Specification;
61 import org.jomc.model.Specifications;
62 import org.jomc.model.Text;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public class ResourceFileProcessor extends JomcTool
81 {
82
83
84
85
86 private volatile Locale resourceBundleDefaultLocale;
87
88
89
90
91 public ResourceFileProcessor()
92 {
93 super();
94 }
95
96
97
98
99
100
101
102
103
104
105 public ResourceFileProcessor( final ResourceFileProcessor tool ) throws IOException
106 {
107 super( tool );
108 this.resourceBundleDefaultLocale = tool.resourceBundleDefaultLocale;
109 }
110
111
112
113
114
115
116
117
118 public final Locale getResourceBundleDefaultLocale()
119 {
120 if ( this.resourceBundleDefaultLocale == null )
121 {
122 this.resourceBundleDefaultLocale = Locale.ENGLISH;
123
124 if ( this.isLoggable( Level.CONFIG ) )
125 {
126 this.log( Level.CONFIG, getMessage( "defaultResourceBundleDefaultLocale",
127 this.resourceBundleDefaultLocale ), null );
128
129 }
130 }
131
132 return this.resourceBundleDefaultLocale;
133 }
134
135
136
137
138
139
140
141
142 public final void setResourceBundleDefaultLocale( final Locale value )
143 {
144 this.resourceBundleDefaultLocale = value;
145 }
146
147
148
149
150
151
152
153
154
155
156
157
158 public void writeResourceBundleResourceFiles( final File resourcesDirectory )
159 throws IOException, ModelObjectException
160 {
161 if ( resourcesDirectory == null )
162 {
163 throw new NullPointerException( "resourcesDirectory" );
164 }
165
166 if ( this.getModules() != null )
167 {
168 this.writeResourceBundleResourceFiles( this.getModules().getSpecifications(),
169 this.getModules().getImplementations(),
170 resourcesDirectory );
171
172 }
173 else if ( this.isLoggable( Level.WARNING ) )
174 {
175 this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
176 }
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 public void writeResourceBundleResourceFiles( final Module module, final File resourcesDirectory )
193 throws IOException, ModelObjectException
194 {
195 if ( module == null )
196 {
197 throw new NullPointerException( "module" );
198 }
199 if ( resourcesDirectory == null )
200 {
201 throw new NullPointerException( "resourcesDirectory" );
202 }
203
204 if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
205 {
206 this.writeResourceBundleResourceFiles( module.getSpecifications(), module.getImplementations(),
207 resourcesDirectory );
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
228 public void writeResourceBundleResourceFiles( final Specification specification, final File resourcesDirectory )
229 throws IOException, ModelObjectException
230 {
231 if ( specification == null )
232 {
233 throw new NullPointerException( "implementation" );
234 }
235 if ( resourcesDirectory == null )
236 {
237 throw new NullPointerException( "resourcesDirectory" );
238 }
239
240 if ( this.getModules() != null
241 && this.getModules().getSpecification( specification.getIdentifier() ) != null )
242 {
243 if ( specification.isClassDeclaration() )
244 {
245 if ( !resourcesDirectory.isDirectory() )
246 {
247 throw new IOException( getMessage( "directoryNotFound", resourcesDirectory.getAbsolutePath() ) );
248 }
249
250 this.assertValidTemplates( specification );
251
252 final JavaTypeName javaTypeName = specification.getJavaTypeName();
253
254 if ( javaTypeName != null )
255 {
256 final String bundlePath = javaTypeName.getQualifiedName().replace( '.', File.separatorChar );
257 this.writeResourceBundleResourceFiles(
258 this.getResourceBundleResources( specification ), resourcesDirectory, bundlePath );
259
260 }
261 }
262 }
263 else if ( this.isLoggable( Level.WARNING ) )
264 {
265 this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
266 }
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280
281 public void writeResourceBundleResourceFiles( final Implementation implementation, final File resourcesDirectory )
282 throws IOException, ModelObjectException
283 {
284 if ( implementation == null )
285 {
286 throw new NullPointerException( "implementation" );
287 }
288 if ( resourcesDirectory == null )
289 {
290 throw new NullPointerException( "resourcesDirectory" );
291 }
292
293 if ( this.getModules() != null
294 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
295 {
296 if ( implementation.isClassDeclaration() )
297 {
298 if ( !resourcesDirectory.isDirectory() )
299 {
300 throw new IOException( getMessage( "directoryNotFound", resourcesDirectory.getAbsolutePath() ) );
301 }
302
303 this.assertValidTemplates( implementation );
304
305 final JavaTypeName javaTypeName = implementation.getJavaTypeName();
306
307 if ( javaTypeName != null )
308 {
309 final String bundlePath = javaTypeName.getQualifiedName().replace( '.', File.separatorChar );
310 this.writeResourceBundleResourceFiles(
311 this.getResourceBundleResources( implementation ), resourcesDirectory, bundlePath );
312
313 }
314 }
315 }
316 else if ( this.isLoggable( Level.WARNING ) )
317 {
318 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
319 }
320 }
321
322
323
324
325
326
327
328
329
330
331
332
333 public Map<Locale, Properties> getResourceBundleResources( final Specification specification )
334 throws IOException
335 {
336 if ( specification == null )
337 {
338 throw new NullPointerException( "specification" );
339 }
340
341 Map<Locale, Properties> properties = null;
342
343 if ( this.getModules() != null
344 && this.getModules().getSpecification( specification.getIdentifier() ) != null )
345 {
346 properties = new HashMap<Locale, Properties>();
347 }
348 else if ( this.isLoggable( Level.WARNING ) )
349 {
350 this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
351 }
352
353 return properties;
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367 public Map<Locale, Properties> getResourceBundleResources( final Implementation implementation )
368 throws IOException
369 {
370 if ( implementation == null )
371 {
372 throw new NullPointerException( "implementation" );
373 }
374
375 Map<Locale, Properties> properties = null;
376
377 if ( this.getModules() != null
378 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
379 {
380 properties = new HashMap<Locale, java.util.Properties>( 10 );
381 final Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
382
383 if ( messages != null )
384 {
385 for ( int i = 0, s0 = messages.getMessage().size(); i < s0; i++ )
386 {
387 final Message message = messages.getMessage().get( i );
388
389 if ( message.getTemplate() != null )
390 {
391 for ( int j = 0, s1 = message.getTemplate().getText().size(); j < s1; j++ )
392 {
393 final Text text = message.getTemplate().getText().get( j );
394 final Locale locale = new Locale( text.getLanguage().toLowerCase() );
395 Properties bundleProperties = properties.get( locale );
396
397 if ( bundleProperties == null )
398 {
399 bundleProperties = new Properties();
400 properties.put( locale, bundleProperties );
401 }
402
403 bundleProperties.setProperty( message.getName(), text.getValue() );
404 }
405 }
406 }
407 }
408 }
409 else if ( this.isLoggable( Level.WARNING ) )
410 {
411 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
412 }
413
414 return properties;
415 }
416
417 private void writeResourceBundleResourceFiles( final Specifications specifications,
418 final Implementations implementations,
419 final File resourcesDirectory )
420 throws IOException, ModelObjectException
421 {
422 try
423 {
424 class WriteResourceBundleResourceFilesTask implements Callable<Void>
425 {
426
427 final Specification specification;
428
429 final Implementation implementation;
430
431 WriteResourceBundleResourceFilesTask( final Specification specification,
432 final Implementation implementation )
433 {
434 super();
435 this.specification = specification;
436 this.implementation = implementation;
437 }
438
439 @Override
440 public Void call() throws IOException, ModelObjectException
441 {
442 if ( this.specification != null )
443 {
444 writeResourceBundleResourceFiles( this.specification, resourcesDirectory );
445 }
446 if ( this.implementation != null )
447 {
448 writeResourceBundleResourceFiles( this.implementation, resourcesDirectory );
449 }
450
451 return null;
452 }
453
454 }
455
456 final List<WriteResourceBundleResourceFilesTask> tasks =
457 new LinkedList<WriteResourceBundleResourceFilesTask>();
458
459 if ( specifications != null )
460 {
461 for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ )
462 {
463 final Specification specification = specifications.getSpecification().get( i );
464 tasks.add( new WriteResourceBundleResourceFilesTask( specification, null ) );
465
466 if ( specification.isClassDeclaration() && specification.getJavaTypeName() != null )
467 {
468 if ( !resourcesDirectory.isDirectory() )
469 {
470 throw new IOException( getMessage( "directoryNotFound",
471 resourcesDirectory.getAbsolutePath() ) );
472
473 }
474
475 final String bundlePath =
476 specification.getJavaTypeName().getQualifiedName().replace( '.', File.separatorChar );
477
478 final File bundleDirectory = new File( resourcesDirectory, bundlePath ).getParentFile();
479
480 if ( !bundleDirectory.exists() && !bundleDirectory.mkdirs() )
481 {
482 throw new IOException( getMessage( "failedCreatingDirectory",
483 bundleDirectory.getAbsolutePath() ) );
484
485 }
486 }
487 }
488 }
489
490 if ( implementations != null )
491 {
492 for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
493 {
494 final Implementation implementation = implementations.getImplementation().get( i );
495 tasks.add( new WriteResourceBundleResourceFilesTask( null, implementation ) );
496
497 if ( implementation.isClassDeclaration() && implementation.getJavaTypeName() != null )
498 {
499 if ( !resourcesDirectory.isDirectory() )
500 {
501 throw new IOException( getMessage( "directoryNotFound",
502 resourcesDirectory.getAbsolutePath() ) );
503
504 }
505
506 final String bundlePath =
507 implementation.getJavaTypeName().getQualifiedName().replace( '.', File.separatorChar );
508
509 final File bundleDirectory = new File( resourcesDirectory, bundlePath ).getParentFile();
510
511 if ( !bundleDirectory.exists() && !bundleDirectory.mkdirs() )
512 {
513 throw new IOException( getMessage( "failedCreatingDirectory",
514 bundleDirectory.getAbsolutePath() ) );
515
516 }
517 }
518 }
519 }
520
521 if ( this.getExecutorService() != null && tasks.size() > 1 )
522 {
523 for ( final Future<Void> task : this.getExecutorService().invokeAll( tasks ) )
524 {
525 task.get();
526 }
527 }
528 else
529 {
530 for ( int i = 0, s0 = tasks.size(); i < s0; i++ )
531 {
532 tasks.get( i ).call();
533 }
534 }
535 }
536 catch ( final CancellationException e )
537 {
538
539 throw (IOException) new IOException( getMessage( e.getCause() ) ).initCause( e.getCause() );
540 }
541 catch ( final InterruptedException e )
542 {
543
544 throw (IOException) new IOException( getMessage( e.getCause() ) ).initCause( e.getCause() );
545 }
546 catch ( final ExecutionException e )
547 {
548 if ( e.getCause() instanceof ModelObjectException )
549 {
550 throw (ModelObjectException) e.getCause();
551 }
552 else if ( e.getCause() instanceof IOException )
553 {
554 throw (IOException) e.getCause();
555 }
556 else if ( e.getCause() instanceof RuntimeException )
557 {
558
559
560 if ( e.getCause().getCause() instanceof ModelObjectException )
561 {
562 throw (ModelObjectException) e.getCause().getCause();
563 }
564 else if ( e.getCause().getCause() instanceof IOException )
565 {
566 throw (IOException) e.getCause().getCause();
567 }
568 else if ( e.getCause().getCause() instanceof RuntimeException )
569 {
570 throw (RuntimeException) e.getCause().getCause();
571 }
572 else if ( e.getCause().getCause() instanceof Error )
573 {
574 throw (Error) e.getCause().getCause();
575 }
576 else if ( e.getCause().getCause() instanceof Exception )
577 {
578
579 throw new UndeclaredThrowableException( e.getCause().getCause() );
580 }
581 else
582 {
583 throw (RuntimeException) e.getCause();
584 }
585 }
586 else if ( e.getCause() instanceof Error )
587 {
588 throw (Error) e.getCause();
589 }
590 else
591 {
592
593 throw new UndeclaredThrowableException( e.getCause() );
594 }
595 }
596 }
597
598 private void writeResourceBundleResourceFiles( final Map<Locale, Properties> resources,
599 final File resourcesDirectory, final String bundlePath )
600 throws IOException
601 {
602 if ( resources == null )
603 {
604 throw new NullPointerException( "resources" );
605 }
606 if ( resourcesDirectory == null )
607 {
608 throw new NullPointerException( "resourcesDirectory" );
609 }
610 if ( bundlePath == null )
611 {
612 throw new NullPointerException( "bundlePath" );
613 }
614
615 Properties defProperties = null;
616 Properties fallbackProperties = null;
617
618 final VelocityContext ctx = this.getVelocityContext();
619 final String toolName = ctx.get( "toolName" ).toString();
620 final String toolVersion = ctx.get( "toolVersion" ).toString();
621 final String toolUrl = ctx.get( "toolUrl" ).toString();
622
623 for ( final Map.Entry<Locale, Properties> e : resources.entrySet() )
624 {
625 final String language = e.getKey().getLanguage().toLowerCase();
626 final Properties p = e.getValue();
627 final File file = new File( resourcesDirectory, bundlePath + "_" + language + ".properties" );
628
629 if ( this.getResourceBundleDefaultLocale().getLanguage().equalsIgnoreCase( language ) )
630 {
631 defProperties = p;
632 }
633
634 fallbackProperties = p;
635
636 if ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() )
637 {
638 throw new IOException( getMessage( "failedCreatingDirectory",
639 file.getParentFile().getAbsolutePath() ) );
640
641 }
642
643 if ( this.isLoggable( Level.INFO ) )
644 {
645 this.log( Level.INFO, getMessage( "writing", file.getCanonicalPath() ), null );
646 }
647
648 this.writePropertiesFile( p, toolName + ' ' + toolVersion + " - See " + toolUrl, file );
649 }
650
651 if ( defProperties == null )
652 {
653 defProperties = fallbackProperties;
654 }
655
656 if ( defProperties != null )
657 {
658 final File file = new File( resourcesDirectory, bundlePath + ".properties" );
659
660 if ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() )
661 {
662 throw new IOException( getMessage( "failedCreatingDirectory",
663 file.getParentFile().getAbsolutePath() ) );
664
665 }
666
667 if ( this.isLoggable( Level.INFO ) )
668 {
669 this.log( Level.INFO, getMessage( "writing", file.getCanonicalPath() ), null );
670 }
671
672 this.writePropertiesFile( defProperties, toolName + ' ' + toolVersion + " - See " + toolUrl, file );
673 }
674 }
675
676 private void assertValidTemplates( final Specification specification )
677 {
678 if ( specification == null )
679 {
680 throw new NullPointerException( "specification" );
681 }
682 }
683
684 private void assertValidTemplates( final Implementation implementation )
685 {
686 if ( implementation == null )
687 {
688 throw new NullPointerException( "implementation" );
689 }
690
691 final Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
692
693 if ( messages != null )
694 {
695 for ( int i = messages.getMessage().size() - 1; i >= 0; i-- )
696 {
697 final Message m = messages.getMessage().get( i );
698
699 if ( m.getTemplate() != null )
700 {
701 for ( int j = m.getTemplate().getText().size() - 1; j >= 0; j-- )
702 {
703 new MessageFormat( m.getTemplate().getText().get( j ).getValue() );
704 }
705 }
706 }
707 }
708 }
709
710 private void writePropertiesFile( final Properties properties, final String comments, final File propertiesFile )
711 throws IOException
712 {
713 FileOutputStream out = null;
714 FileLock fileLock = null;
715
716 try
717 {
718 out = new FileOutputStream( propertiesFile );
719 fileLock = out.getChannel().lock();
720
721 properties.store( out, comments );
722 out.getChannel().force( true );
723
724 fileLock.release();
725 fileLock = null;
726
727 out.close();
728 out = null;
729 }
730 finally
731 {
732 this.releaseAndClose( fileLock, out );
733 }
734 }
735
736 private void releaseAndClose( final FileLock fileLock, final Closeable closeable )
737 throws IOException
738 {
739 try
740 {
741 if ( fileLock != null )
742 {
743 fileLock.release();
744 }
745 }
746 catch ( final IOException e )
747 {
748 this.log( Level.SEVERE, getMessage( e ), e );
749 }
750 finally
751 {
752 try
753 {
754 if ( closeable != null )
755 {
756 closeable.close();
757 }
758 }
759 catch ( final IOException e )
760 {
761 this.log( Level.SEVERE, getMessage( e ), e );
762 }
763 }
764 }
765
766 void initDefaults()
767 {
768 super.initDefaults();
769 this.getResourceBundleDefaultLocale();
770 }
771
772 private static String getMessage( final Throwable t )
773 {
774 return t != null
775 ? t.getMessage() != null && t.getMessage().trim().length() > 0
776 ? t.getMessage()
777 : getMessage( t.getCause() )
778 : null;
779
780 }
781
782 private static String getMessage( final String key, final Object... arguments )
783 {
784 if ( key == null )
785 {
786 throw new NullPointerException( "key" );
787 }
788
789 return MessageFormat.format( ResourceBundle.getBundle(
790 ResourceFileProcessor.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
791
792 }
793
794 }