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