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