001/* 002 * Copyright (C) 2005 Christian Schulte <cs@schulte.it> 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without 006 * modification, are permitted provided that the following conditions 007 * are met: 008 * 009 * o Redistributions of source code must retain the above copyright 010 * notice, this list of conditions and the following disclaimer. 011 * 012 * o Redistributions in binary form must reproduce the above copyright 013 * notice, this list of conditions and the following disclaimer in 014 * the documentation and/or other materials provided with the 015 * distribution. 016 * 017 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 018 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 019 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 020 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, 021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 022 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 023 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 024 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 027 * 028 * $JOMC: ResourceFileProcessor.java 5307 2016-08-30 22:09:18Z schulte $ 029 * 030 */ 031package org.jomc.tools; 032 033import java.io.Closeable; 034import java.io.File; 035import java.io.FileOutputStream; 036import java.io.IOException; 037import java.lang.reflect.UndeclaredThrowableException; 038import java.nio.channels.FileLock; 039import java.text.MessageFormat; 040import java.util.HashMap; 041import java.util.LinkedList; 042import java.util.List; 043import java.util.Locale; 044import java.util.Map; 045import java.util.Properties; 046import java.util.ResourceBundle; 047import java.util.concurrent.Callable; 048import java.util.concurrent.CancellationException; 049import java.util.concurrent.ExecutionException; 050import java.util.concurrent.Future; 051import java.util.logging.Level; 052import org.apache.velocity.VelocityContext; 053import org.jomc.model.Implementation; 054import org.jomc.model.Implementations; 055import org.jomc.model.JavaTypeName; 056import org.jomc.model.Message; 057import org.jomc.model.Messages; 058import org.jomc.model.ModelObjectException; 059import org.jomc.model.Module; 060import org.jomc.model.Specification; 061import org.jomc.model.Specifications; 062import org.jomc.model.Text; 063 064/** 065 * Processes resource files. 066 * 067 * <p> 068 * <b>Use Cases:</b><br/><ul> 069 * <li>{@link #writeResourceBundleResourceFiles(File) }</li> 070 * <li>{@link #writeResourceBundleResourceFiles(Module, File) }</li> 071 * <li>{@link #writeResourceBundleResourceFiles(Specification, File) }</li> 072 * <li>{@link #writeResourceBundleResourceFiles(Implementation, File) }</li> 073 * </ul></p> 074 * 075 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 076 * @version $JOMC: ResourceFileProcessor.java 5307 2016-08-30 22:09:18Z schulte $ 077 * 078 * @see #getModules() 079 */ 080public class ResourceFileProcessor extends JomcTool 081{ 082 083 /** 084 * The language of the default language properties file of generated resource bundle resources. 085 */ 086 private volatile Locale resourceBundleDefaultLocale; 087 088 /** 089 * Creates a new {@code ResourceFileProcessor} instance. 090 */ 091 public ResourceFileProcessor() 092 { 093 super(); 094 } 095 096 /** 097 * Creates a new {@code ResourceFileProcessor} instance taking a {@code ResourceFileProcessor} instance to 098 * initialize the instance with. 099 * 100 * @param tool The instance to initialize the new instance with. 101 * 102 * @throws NullPointerException if {@code tool} is {@code null}. 103 * @throws IOException if copying {@code tool} fails. 104 */ 105 public ResourceFileProcessor( final ResourceFileProcessor tool ) throws IOException 106 { 107 super( tool ); 108 this.resourceBundleDefaultLocale = tool.resourceBundleDefaultLocale; 109 } 110 111 /** 112 * Gets the language of the default language properties file of generated resource bundle resource files. 113 * 114 * @return The language of the default language properties file of generated resource bundle resource files. 115 * 116 * @see #setResourceBundleDefaultLocale(java.util.Locale) 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 * Sets the language of the default language properties file of generated resource bundle resource files. 137 * 138 * @param value The language of the default language properties file of generated resource bundle resource files. 139 * 140 * @see #getResourceBundleDefaultLocale() 141 */ 142 public final void setResourceBundleDefaultLocale( final Locale value ) 143 { 144 this.resourceBundleDefaultLocale = value; 145 } 146 147 /** 148 * Writes resource bundle resource files of the modules of the instance to a given directory. 149 * 150 * @param resourcesDirectory The directory to write resource bundle resource files to. 151 * 152 * @throws NullPointerException if {@code resourcesDirectory} is {@code null}. 153 * @throws IOException if writing resource bundle resource files fails. 154 * @throws ModelObjectException if compiling the name of a referenced type fails. 155 * 156 * @see #writeResourceBundleResourceFiles(org.jomc.model.Module, java.io.File) 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 * Writes resource bundle resource files of a given module from the modules of the instance to a given directory. 181 * 182 * @param module The module to process. 183 * @param resourcesDirectory The directory to write resource bundle resource files to. 184 * 185 * @throws NullPointerException if {@code module} or {@code resourcesDirectory} is {@code null}. 186 * @throws IOException if writing resource bundle resource files fails. 187 * @throws ModelObjectException if compiling the name of a referenced type fails. 188 * 189 * @see #writeResourceBundleResourceFiles(org.jomc.model.Specification, java.io.File) 190 * @see #writeResourceBundleResourceFiles(org.jomc.model.Implementation, java.io.File) 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 * Writes resource bundle resource files of a given specification from the modules of the instance to a directory. 218 * 219 * @param specification The specification to process. 220 * @param resourcesDirectory The directory to write resource bundle resource files to. 221 * 222 * @throws NullPointerException if {@code specification} or {@code resourcesDirectory} is {@code null}. 223 * @throws IOException if writing resource bundle resource files fails. 224 * @throws ModelObjectException if compiling the name of the type referenced by the specification fails. 225 * 226 * @see #getResourceBundleResources(org.jomc.model.Specification) 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 * Writes resource bundle resource files of a given implementation from the modules of the instance to a directory. 271 * 272 * @param implementation The implementation to process. 273 * @param resourcesDirectory The directory to write resource bundle resource files to. 274 * 275 * @throws NullPointerException if {@code implementation} or {@code resourcesDirectory} is {@code null}. 276 * @throws IOException if writing resource bundle resource files fails. 277 * @throws ModelObjectException if compiling the name of the type referenced by the implementation fails. 278 * 279 * @see #getResourceBundleResources(org.jomc.model.Implementation) 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 * Gets resource bundle properties resources of a given specification. 324 * 325 * @param specification The specification to get resource bundle properties resources of. 326 * 327 * @return Resource bundle properties resources of {@code specification} or {@code null}, if no model objects are 328 * found. 329 * 330 * @throws NullPointerException if {@code specification} is {@code null}. 331 * @throws IOException if getting the resource bundle properties resources fails. 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 * Gets resource bundle properties resources of a given implementation. 358 * 359 * @param implementation The implementation to get resource bundle properties resources of. 360 * 361 * @return Resource bundle properties resources of {@code implementation} or {@code null}, if no model objects are 362 * found. 363 * 364 * @throws NullPointerException if {@code implementation} is {@code null}. 365 * @throws IOException if getting the resource bundle properties resources fails. 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 // JDK: As of JDK6 new IOException( getMessage( e.getCause() ), e.getCause() ) 539 throw (IOException) new IOException( getMessage( e.getCause() ) ).initCause( e.getCause() ); 540 } 541 catch ( final InterruptedException e ) 542 { 543 // JDK: As of JDK6 new IOException( getMessage( e.getCause() ), e.getCause() ) 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 // The fork-join framework breaks the exception handling contract of Callable by re-throwing any 559 // exception caught using a runtime exception. 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 // Checked exception not declared to be thrown by the Callable's 'call' method. 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 // Checked exception not declared to be thrown by the Callable's 'call' method. 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}