View Javadoc

1   /*
2    *   Copyright (C) Christian Schulte, 2005-206
3    *   All rights reserved.
4    *
5    *   Redistribution and use in source and binary forms, with or without
6    *   modification, are permitted provided that the following conditions
7    *   are met:
8    *
9    *     o Redistributions of source code must retain the above copyright
10   *       notice, this list of conditions and the following disclaimer.
11   *
12   *     o Redistributions in binary form must reproduce the above copyright
13   *       notice, this list of conditions and the following disclaimer in
14   *       the documentation and/or other materials provided with the
15   *       distribution.
16   *
17   *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18   *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19   *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20   *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
21   *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22   *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23   *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24   *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25   *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26   *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27   *
28   *   $JOMC: SourceFileProcessor.java 4925 2014-03-23 17:24:27Z schulte $
29   *
30   */
31  package org.jomc.tools;
32  
33  import java.io.File;
34  import java.io.IOException;
35  import java.io.RandomAccessFile;
36  import java.io.StringWriter;
37  import java.nio.ByteBuffer;
38  import java.nio.channels.FileChannel;
39  import java.nio.channels.FileLock;
40  import java.text.MessageFormat;
41  import java.util.LinkedList;
42  import java.util.List;
43  import java.util.ResourceBundle;
44  import java.util.logging.Level;
45  import org.apache.commons.lang.StringUtils;
46  import org.apache.velocity.Template;
47  import org.apache.velocity.VelocityContext;
48  import org.apache.velocity.exception.VelocityException;
49  import org.jomc.model.Implementation;
50  import org.jomc.model.Implementations;
51  import org.jomc.model.Instance;
52  import org.jomc.model.Module;
53  import org.jomc.model.Specification;
54  import org.jomc.tools.model.SourceFileType;
55  import org.jomc.tools.model.SourceFilesType;
56  import org.jomc.tools.model.SourceSectionType;
57  import org.jomc.tools.model.SourceSectionsType;
58  import org.jomc.util.LineEditor;
59  import org.jomc.util.Section;
60  import org.jomc.util.SectionEditor;
61  import org.jomc.util.TrailingWhitespaceEditor;
62  
63  /**
64   * Processes source code files.
65   *
66   * <p><b>Use Cases:</b><br/><ul>
67   * <li>{@link #manageSourceFiles(File) }</li>
68   * <li>{@link #manageSourceFiles(Module, File) }</li>
69   * <li>{@link #manageSourceFiles(Specification, File) }</li>
70   * <li>{@link #manageSourceFiles(Implementation, File) }</li>
71   * </ul></p>
72   *
73   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
74   * @version $JOMC: SourceFileProcessor.java 4925 2014-03-23 17:24:27Z schulte $
75   */
76  public class SourceFileProcessor extends JomcTool
77  {
78  
79      /** The source file editor of the instance. */
80      private SourceFileProcessor.SourceFileEditor sourceFileEditor;
81  
82      /** Source files model. */
83      @Deprecated
84      private SourceFilesType sourceFilesType;
85  
86      /** Creates a new {@code SourceFileProcessor} instance. */
87      public SourceFileProcessor()
88      {
89          super();
90      }
91  
92      /**
93       * Creates a new {@code SourceFileProcessor} instance taking a {@code SourceFileProcessor} instance to initialize
94       * the instance with.
95       *
96       * @param tool The instance to initialize the new instance with,
97       *
98       * @throws NullPointerException if {@code tool} is {@code null}.
99       * @throws IOException if copying {@code tool} fails.
100      */
101     public SourceFileProcessor( final SourceFileProcessor tool ) throws IOException
102     {
103         super( tool );
104         this.sourceFilesType = tool.sourceFilesType != null ? tool.sourceFilesType.clone() : null;
105         this.sourceFileEditor = tool.sourceFileEditor;
106     }
107 
108     /**
109      * Gets the source files model of the instance.
110      * <p>This accessor method returns a reference to the live object, not a snapshot. Therefore any modification you
111      * make to the returned object will be present inside the object. This is why there is no {@code set} method.</p>
112      *
113      * @return The source files model of the instance.
114      *
115      * @see #getSourceFileType(org.jomc.model.Specification)
116      * @see #getSourceFileType(org.jomc.model.Implementation)
117      *
118      * @deprecated As of JOMC 1.2, please add source file models to {@code Specification}s and {@code Implementation}s
119      * directly. This method will be removed in version 2.0.
120      */
121     @Deprecated
122     public SourceFilesType getSourceFilesType()
123     {
124         if ( this.sourceFilesType == null )
125         {
126             this.sourceFilesType = new SourceFilesType();
127         }
128 
129         return this.sourceFilesType;
130     }
131 
132     /**
133      * Gets the model of a specification source file of the modules of the instance.
134      *
135      * @param specification The specification to get a source file model for.
136      *
137      * @return The source file model for {@code specification}. As of JOMC 1.2, this method returns {@code null} if no
138      * source file model is found.
139      *
140      * @throws NullPointerException if {@code specification} is {@code null}.
141      *
142      * @deprecated As of JOMC 1.2, please use method {@link #getSourceFilesType(org.jomc.model.Specification)}. This
143      * method will be removed in version 2.0.
144      */
145     @Deprecated
146     public SourceFileType getSourceFileType( final Specification specification )
147     {
148         if ( specification == null )
149         {
150             throw new NullPointerException( "specification" );
151         }
152 
153         SourceFileType sourceFileType = null;
154 
155         if ( this.getModules() != null
156              && this.getModules().getSpecification( specification.getIdentifier() ) != null )
157         {
158             sourceFileType = this.getSourceFilesType().getSourceFile( specification.getIdentifier() );
159 
160             if ( sourceFileType == null )
161             {
162                 sourceFileType = specification.getAnyObject( SourceFileType.class );
163             }
164         }
165         else if ( this.isLoggable( Level.WARNING ) )
166         {
167             this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
168         }
169 
170         return sourceFileType;
171     }
172 
173     /**
174      * Gets the source files model of a specification of the modules of the instance.
175      *
176      * @param specification The specification to get a source files model for.
177      *
178      * @return The source files model for {@code specification} or {@code null}, if no source files model is found.
179      *
180      * @throws NullPointerException if {@code specification} is {@code null}.
181      *
182      * @since 1.2
183      */
184     public SourceFilesType getSourceFilesType( final Specification specification )
185     {
186         if ( specification == null )
187         {
188             throw new NullPointerException( "specification" );
189         }
190 
191         SourceFilesType model = null;
192 
193         if ( this.getModules() != null
194                  && this.getModules().getSpecification( specification.getIdentifier() ) != null )
195         {
196             final SourceFileType sourceFileType = this.getSourceFileType( specification );
197 
198             if ( sourceFileType != null )
199             {
200                 model = new SourceFilesType();
201                 model.getSourceFile().add( sourceFileType );
202             }
203             else
204             {
205                 model = specification.getAnyObject( SourceFilesType.class );
206             }
207         }
208         else if ( this.isLoggable( Level.WARNING ) )
209         {
210             this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
211         }
212 
213         return model;
214     }
215 
216     /**
217      * Gets the model of an implementation source file of the modules of the instance.
218      *
219      * @param implementation The implementation to get a source file model for.
220      *
221      * @return The source file model for {@code implementation}. As of JOMC 1.2, this method returns {@code null} if no
222      * source file model is found.
223      *
224      * @throws NullPointerException if {@code implementation} is {@code null}.
225      *
226      * @deprecated As of JOMC 1.2, please use method {@link #getSourceFilesType(org.jomc.model.Implementation)}. This
227      * method will be removed in version 2.0.
228      */
229     @Deprecated
230     public SourceFileType getSourceFileType( final Implementation implementation )
231     {
232         if ( implementation == null )
233         {
234             throw new NullPointerException( "implementation" );
235         }
236 
237         SourceFileType sourceFileType = null;
238 
239         if ( this.getModules() != null
240              && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
241         {
242             sourceFileType = this.getSourceFilesType().getSourceFile( implementation.getIdentifier() );
243 
244             if ( sourceFileType == null )
245             {
246                 sourceFileType = implementation.getAnyObject( SourceFileType.class );
247             }
248         }
249         else if ( this.isLoggable( Level.WARNING ) )
250         {
251             this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
252         }
253 
254         return sourceFileType;
255     }
256 
257     /**
258      * Gets the source files model of an implementation of the modules of the instance.
259      *
260      * @param implementation The implementation to get a source files model for.
261      *
262      * @return The source files model for {@code implementation} or {@code null}, if no source files model is found.
263      *
264      * @throws NullPointerException if {@code implementation} is {@code null}.
265      *
266      * @since 1.2
267      */
268     public SourceFilesType getSourceFilesType( final Implementation implementation )
269     {
270         if ( implementation == null )
271         {
272             throw new NullPointerException( "implementation" );
273         }
274 
275         SourceFilesType model = null;
276 
277         if ( this.getModules() != null
278                  && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
279         {
280             final SourceFileType sourceFileType = this.getSourceFileType( implementation );
281 
282             if ( sourceFileType != null )
283             {
284                 model = new SourceFilesType();
285                 model.getSourceFile().add( sourceFileType );
286             }
287             else
288             {
289                 final Instance instance = this.getModules().getInstance( implementation.getIdentifier() );
290                 assert instance != null : "Instance '" + implementation.getIdentifier() + "' not found.";
291                 model = instance.getAnyObject( SourceFilesType.class );
292             }
293         }
294         else if ( this.isLoggable( Level.WARNING ) )
295         {
296             this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
297         }
298 
299         return model;
300     }
301 
302     /**
303      * Gets the source file editor of the instance.
304      *
305      * @return The source file editor of the instance.
306      *
307      * @since 1.2
308      *
309      * @see #setSourceFileEditor(org.jomc.tools.SourceFileProcessor.SourceFileEditor)
310      */
311     public final SourceFileProcessor.SourceFileEditor getSourceFileEditor()
312     {
313         if ( this.sourceFileEditor == null )
314         {
315             this.sourceFileEditor =
316                 new SourceFileProcessor.SourceFileEditor( new TrailingWhitespaceEditor( this.getLineSeparator() ),
317                                                           this.getLineSeparator() );
318 
319         }
320 
321         return this.sourceFileEditor;
322     }
323 
324     /**
325      * Sets the source file editor of the instance.
326      *
327      * @param value The new source file editor of the instance or {@code null}.
328      *
329      * @since 1.2
330      *
331      * @see #getSourceFileEditor()
332      */
333     public final void setSourceFileEditor( final SourceFileProcessor.SourceFileEditor value )
334     {
335         this.sourceFileEditor = value;
336     }
337 
338     /**
339      * Gets a new editor for editing the source file of a given specification of the modules of the instance.
340      *
341      * @param specification The specification whose source file to edit.
342      *
343      * @return A new editor for editing the source file of {@code specification}.
344      *
345      * @throws NullPointerException if {@code specification} is {@code null}.
346      *
347      * @deprecated As of JOMC 1.2, please use method {@link #getSourceFileEditor()}. This method will be removed in
348      * version 2.0.
349      *
350      * @see SourceFileEditor#edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)
351      */
352     @Deprecated
353     public SourceFileProcessor.SourceFileEditor getSourceFileEditor( final Specification specification )
354     {
355         if ( specification == null )
356         {
357             throw new NullPointerException( "specification" );
358         }
359 
360         return this.getSourceFileEditor();
361     }
362 
363     /**
364      * Gets a new editor for editing the source file of a given implementation of the modules of the instance.
365      *
366      * @param implementation The implementation whose source file to edit.
367      *
368      * @return A new editor for editing the source file of {@code implementation}.
369      *
370      * @throws NullPointerException if {@code implementation} is {@code null}.
371      *
372      * @deprecated As of JOMC 1.2, please use method {@link #getSourceFileEditor()}. This method will be removed in
373      * version 2.0.
374      *
375      * @see SourceFileEditor#edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)
376      */
377     @Deprecated
378     public SourceFileProcessor.SourceFileEditor getSourceFileEditor( final Implementation implementation )
379     {
380         if ( implementation == null )
381         {
382             throw new NullPointerException( "implementation" );
383         }
384 
385         return this.getSourceFileEditor();
386     }
387 
388     /**
389      * Manages the source files of the modules of the instance.
390      *
391      * @param sourcesDirectory The directory holding the source files to manage.
392      *
393      * @throws NullPointerException if {@code sourcesDirectory} is {@code null}.
394      * @throws IOException if managing source files fails.
395      *
396      * @see #manageSourceFiles(org.jomc.model.Module, java.io.File)
397      */
398     public void manageSourceFiles( final File sourcesDirectory ) throws IOException
399     {
400         if ( sourcesDirectory == null )
401         {
402             throw new NullPointerException( "sourcesDirectory" );
403         }
404 
405         if ( this.getModules() != null )
406         {
407             for ( int i = this.getModules().getModule().size() - 1; i >= 0; i-- )
408             {
409                 this.manageSourceFiles( this.getModules().getModule().get( i ), sourcesDirectory );
410             }
411         }
412         else if ( this.isLoggable( Level.WARNING ) )
413         {
414             this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
415         }
416     }
417 
418     /**
419      * Manages the source files of a given module of the modules of the instance.
420      *
421      * @param module The module to process.
422      * @param sourcesDirectory The directory holding the source files to manage.
423      *
424      * @throws NullPointerException if {@code module} or {@code sourcesDirectory} is {@code null}.
425      * @throws IOException if managing source files fails.
426      *
427      * @see #manageSourceFiles(org.jomc.model.Specification, java.io.File)
428      * @see #manageSourceFiles(org.jomc.model.Implementation, java.io.File)
429      */
430     public void manageSourceFiles( final Module module, final File sourcesDirectory ) throws IOException
431     {
432         if ( module == null )
433         {
434             throw new NullPointerException( "module" );
435         }
436         if ( sourcesDirectory == null )
437         {
438             throw new NullPointerException( "sourcesDirectory" );
439         }
440 
441         if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
442         {
443             if ( module.getSpecifications() != null )
444             {
445                 for ( int i = 0, s0 = module.getSpecifications().getSpecification().size(); i < s0; i++ )
446                 {
447                     this.manageSourceFiles( module.getSpecifications().getSpecification().get( i ), sourcesDirectory );
448                 }
449             }
450             if ( module.getImplementations() != null )
451             {
452                 for ( int i = 0, s0 = module.getImplementations().getImplementation().size(); i < s0; i++ )
453                 {
454                     this.manageSourceFiles( module.getImplementations().getImplementation().get( i ), sourcesDirectory );
455                 }
456             }
457         }
458         else if ( this.isLoggable( Level.WARNING ) )
459         {
460             this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
461         }
462     }
463 
464     /**
465      * Manages the source files of a given specification of the modules of the instance.
466      *
467      * @param specification The specification to process.
468      * @param sourcesDirectory The directory holding the source files to manage.
469      *
470      * @throws NullPointerException if {@code specification} or {@code sourcesDirectory} is {@code null}.
471      * @throws IOException if managing source files fails.
472      *
473      * @see #getSourceFileEditor()
474      * @see #getSourceFilesType(org.jomc.model.Specification)
475      */
476     public void manageSourceFiles( final Specification specification, final File sourcesDirectory ) throws IOException
477     {
478         if ( specification == null )
479         {
480             throw new NullPointerException( "specification" );
481         }
482         if ( sourcesDirectory == null )
483         {
484             throw new NullPointerException( "sourcesDirectory" );
485         }
486 
487         if ( this.getModules() != null
488                  && this.getModules().getSpecification( specification.getIdentifier() ) != null )
489         {
490             if ( specification.isClassDeclaration() )
491             {
492                 boolean manage = true;
493                 final Implementations implementations = this.getModules().getImplementations();
494 
495                 if ( implementations != null )
496                 {
497                     for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
498                     {
499                         final Implementation impl = implementations.getImplementation().get( i );
500 
501                         if ( impl.isClassDeclaration() && specification.getClazz().equals( impl.getClazz() ) )
502                         {
503                             this.manageSourceFiles( impl, sourcesDirectory );
504                             manage = false;
505                             break;
506                         }
507                     }
508                 }
509 
510                 if ( manage )
511                 {
512                     final SourceFilesType model = this.getSourceFilesType( specification );
513 
514                     if ( model != null )
515                     {
516                         for ( int i = 0, s0 = model.getSourceFile().size(); i < s0; i++ )
517                         {
518                             this.getSourceFileEditor().edit(
519                                 specification, model.getSourceFile().get( i ), sourcesDirectory );
520 
521                         }
522                     }
523                 }
524             }
525         }
526         else if ( this.isLoggable( Level.WARNING ) )
527         {
528             this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
529         }
530     }
531 
532     /**
533      * Manages the source files of a given implementation of the modules of the instance.
534      *
535      * @param implementation The implementation to process.
536      * @param sourcesDirectory The directory holding the source files to manage.
537      *
538      * @throws NullPointerException if {@code implementation} or {@code sourcesDirectory} is {@code null}.
539      * @throws IOException if managing source files fails.
540      *
541      * @see #getSourceFileEditor()
542      * @see #getSourceFilesType(org.jomc.model.Implementation)
543      */
544     public void manageSourceFiles( final Implementation implementation, final File sourcesDirectory )
545         throws IOException
546     {
547         if ( implementation == null )
548         {
549             throw new NullPointerException( "implementation" );
550         }
551         if ( sourcesDirectory == null )
552         {
553             throw new NullPointerException( "sourcesDirectory" );
554         }
555 
556         if ( this.getModules() != null
557                  && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
558         {
559             if ( implementation.isClassDeclaration() )
560             {
561                 final SourceFilesType model = this.getSourceFilesType( implementation );
562 
563                 if ( model != null )
564                 {
565                     for ( int i = 0, s0 = model.getSourceFile().size(); i < s0; i++ )
566                     {
567                         this.getSourceFileEditor().edit(
568                             implementation, model.getSourceFile().get( i ), sourcesDirectory );
569 
570                     }
571                 }
572             }
573         }
574         else if ( this.isLoggable( Level.WARNING ) )
575         {
576             this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
577         }
578     }
579 
580     private static String getMessage( final String key, final Object... arguments )
581     {
582         if ( key == null )
583         {
584             throw new NullPointerException( "key" );
585         }
586 
587         return MessageFormat.format( ResourceBundle.getBundle(
588             SourceFileProcessor.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
589 
590     }
591 
592     private static String getMessage( final Throwable t )
593     {
594         return t != null
595                    ? t.getMessage() != null && t.getMessage().trim().length() > 0
596                          ? t.getMessage()
597                          : getMessage( t.getCause() )
598                    : null;
599 
600     }
601 
602     /**
603      * Extension to {@code SectionEditor} adding support for editing source code files.
604      *
605      * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
606      * @version $JOMC: SourceFileProcessor.java 4925 2014-03-23 17:24:27Z schulte $
607      *
608      * @see #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)
609      * @see #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)
610      */
611     public class SourceFileEditor extends SectionEditor
612     {
613 
614         /** {@code Specification} of the instance or {@code null}. */
615         private Specification specification;
616 
617         /** {@code Implementation} of the instance or {@code null}. */
618         private Implementation implementation;
619 
620         /** The source code file to edit. */
621         private SourceFileType sourceFileType;
622 
623         /** The {@code VelocityContext} of the instance. */
624         private VelocityContext velocityContext;
625 
626         /** List of sections added to the input. */
627         @Deprecated
628         private List<Section> addedSections;
629 
630         /** List of sections without corresponding model entry. */
631         @Deprecated
632         private List<Section> unknownSections;
633 
634         /**
635          * Creates a new {@code SourceFileEditor} instance.
636          *
637          * @since 1.2
638          */
639         public SourceFileEditor()
640         {
641             this( (LineEditor) null, (String) null );
642         }
643 
644         /**
645          * Creates a new {@code SourceFileEditor} instance taking a string to use for separating lines.
646          *
647          * @param lineSeparator String to use for separating lines.
648          *
649          * @since 1.2
650          */
651         public SourceFileEditor( final String lineSeparator )
652         {
653             this( (LineEditor) null, lineSeparator );
654         }
655 
656         /**
657          * Creates a new {@code SourceFileEditor} instance taking an editor to chain.
658          *
659          * @param editor The editor to chain.
660          *
661          * @since 1.2
662          */
663         public SourceFileEditor( final LineEditor editor )
664         {
665             this( editor, null );
666         }
667 
668         /**
669          * Creates a new {@code SourceFileEditor} instance taking an editor to chain and a string to use for separating
670          * lines.
671          *
672          * @param editor The editor to chain.
673          * @param lineSeparator String to use for separating lines.
674          *
675          * @since 1.2
676          */
677         public SourceFileEditor( final LineEditor editor, final String lineSeparator )
678         {
679             super( editor, lineSeparator );
680         }
681 
682         /**
683          * Creates a new {@code SourceFileEditor} taking a {@code Specification} to edit source code of.
684          *
685          * @param specification The specification to edit source code of.
686          *
687          * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)}.
688          * This constructor will be removed in version 2.0.
689          */
690         @Deprecated
691         public SourceFileEditor( final Specification specification )
692         {
693             this( specification, null, null );
694         }
695 
696         /**
697          * Creates a new {@code SourceFileEditor} taking a {@code Specification} to edit source code of and a line
698          * separator.
699          *
700          * @param specification The specification to edit source code of.
701          * @param lineSeparator The line separator of the editor.
702          *
703          * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)}.
704          * This constructor will be removed in version 2.0.
705          */
706         @Deprecated
707         public SourceFileEditor( final Specification specification, final String lineSeparator )
708         {
709             this( specification, null, lineSeparator );
710         }
711 
712         /**
713          * Creates a new {@code SourceFileEditor} taking a {@code Specification} to edit source code of and an editor to
714          * chain.
715          *
716          * @param specification The specification backing the editor.
717          * @param lineEditor The editor to chain.
718          *
719          * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)}.
720          * This constructor will be removed in version 2.0.
721          */
722         @Deprecated
723         public SourceFileEditor( final Specification specification, final LineEditor lineEditor )
724         {
725             this( specification, lineEditor, null );
726         }
727 
728         /**
729          * Creates a new {@code SourceFileEditor} taking a {@code Specification} to edit source code of, an editor to
730          * chain and a line separator.
731          *
732          * @param specification The specification backing the editor.
733          * @param lineEditor The editor to chain.
734          * @param lineSeparator The line separator of the editor.
735          *
736          * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)}.
737          * This constructor will be removed in version 2.0.
738          */
739         @Deprecated
740         public SourceFileEditor( final Specification specification, final LineEditor lineEditor,
741                                  final String lineSeparator )
742         {
743             super( lineEditor, lineSeparator );
744             this.specification = specification;
745             this.implementation = null;
746 
747             assert getModules().getSpecification( specification.getIdentifier() ) != null :
748                 "Specification '" + specification.getIdentifier() + "' not found.";
749 
750         }
751 
752         /**
753          * Creates a new {@code SourceFileEditor} taking an {@code Implementation} to edit source code of.
754          *
755          * @param implementation The implementation to edit source code of.
756          *
757          * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)}.
758          * This constructor will be removed in version 2.0.
759          */
760         @Deprecated
761         public SourceFileEditor( final Implementation implementation )
762         {
763             this( implementation, null, null );
764         }
765 
766         /**
767          * Creates a new {@code SourceFileEditor} taking an {@code Implementation} to edit source code of and a line
768          * separator.
769          *
770          * @param implementation The implementation to edit source code of.
771          * @param lineSeparator The line separator of the editor.
772          *
773          * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)}.
774          * This constructor will be removed in version 2.0.
775          */
776         @Deprecated
777         public SourceFileEditor( final Implementation implementation, final String lineSeparator )
778         {
779             this( implementation, null, lineSeparator );
780         }
781 
782         /**
783          * Creates a new {@code SourceFileEditor} taking an {@code Implementation} to edit source code of and an editor
784          * to chain.
785          *
786          * @param implementation The implementation to edit source code of.
787          * @param lineEditor The editor to chain.
788          *
789          * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)}.
790          * This constructor will be removed in version 2.0.
791          */
792         @Deprecated
793         public SourceFileEditor( final Implementation implementation, final LineEditor lineEditor )
794         {
795             this( implementation, lineEditor, null );
796         }
797 
798         /**
799          * Creates a new {@code SourceFileEditor} taking an {@code Implementation} to edit source code of, an editor
800          * to chain and a line separator.
801          *
802          * @param implementation The implementation to edit source code of.
803          * @param lineEditor The editor to chain.
804          * @param lineSeparator The line separator of the editor.
805          *
806          * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)}.
807          * This constructor will be removed in version 2.0.
808          */
809         @Deprecated
810         public SourceFileEditor( final Implementation implementation, final LineEditor lineEditor,
811                                  final String lineSeparator )
812         {
813             super( lineEditor, lineSeparator );
814             this.implementation = implementation;
815             this.specification = null;
816 
817             assert getModules().getImplementation( implementation.getIdentifier() ) != null :
818                 "Implementation '" + implementation.getIdentifier() + "' not found.";
819 
820         }
821 
822         /**
823          * Edits a source file of a given specification.
824          *
825          * @param specification The specification to edit a source file of.
826          * @param sourceFileType The model of the source file to edit.
827          * @param sourcesDirectory The directory holding the source file to edit.
828          *
829          * @throws NullPointerException if {@code specification}, {@code sourceFileType} or {@code sourcesDirectory} is
830          * {@code null}.
831          * @throws IOException if editing fails.
832          *
833          * @since 1.2
834          */
835         public final void edit( final Specification specification, final SourceFileType sourceFileType,
836                                 final File sourcesDirectory ) throws IOException
837         {
838             if ( specification == null )
839             {
840                 throw new NullPointerException( "specification" );
841             }
842             if ( sourceFileType == null )
843             {
844                 throw new NullPointerException( "sourceFileType" );
845             }
846             if ( sourcesDirectory == null )
847             {
848                 throw new NullPointerException( "sourcesDirectory" );
849             }
850 
851             try
852             {
853                 if ( getModules() != null
854                          && getModules().getSpecification( specification.getIdentifier() ) != null )
855                 {
856                     this.specification = specification;
857                     this.sourceFileType = sourceFileType;
858                     this.velocityContext = SourceFileProcessor.this.getVelocityContext();
859                     this.velocityContext.put( "specification", specification );
860                     this.velocityContext.put( "smodel", sourceFileType );
861 
862                     this.editSourceFile( sourcesDirectory );
863                 }
864                 else
865                 {
866                     throw new IOException( getMessage( "specificationNotFound", specification.getIdentifier() ) );
867                 }
868             }
869             finally
870             {
871                 this.specification = null;
872                 this.implementation = null;
873                 this.sourceFileType = null;
874                 this.velocityContext = null;
875             }
876         }
877 
878         /**
879          * Edits a source file of a given implementation.
880          *
881          * @param implementation The implementation to edit a source file of.
882          * @param sourceFileType The model of the source file to edit.
883          * @param sourcesDirectory The directory holding the source file to edit.
884          *
885          * @throws NullPointerException if {@code implementation}, {@code sourceFileType} or {@code sourcesDirectory} is
886          * {@code null}.
887          * @throws IOException if editing fails.
888          *
889          * @since 1.2
890          */
891         public final void edit( final Implementation implementation, final SourceFileType sourceFileType,
892                                 final File sourcesDirectory ) throws IOException
893         {
894             if ( implementation == null )
895             {
896                 throw new NullPointerException( "implementation" );
897             }
898             if ( sourceFileType == null )
899             {
900                 throw new NullPointerException( "sourceFileType" );
901             }
902             if ( sourcesDirectory == null )
903             {
904                 throw new NullPointerException( "sourcesDirectory" );
905             }
906 
907             try
908             {
909                 if ( getModules() != null
910                          && getModules().getImplementation( implementation.getIdentifier() ) != null )
911                 {
912                     this.implementation = implementation;
913                     this.sourceFileType = sourceFileType;
914                     this.velocityContext = SourceFileProcessor.this.getVelocityContext();
915                     this.velocityContext.put( "implementation", implementation );
916                     this.velocityContext.put( "smodel", sourceFileType );
917 
918                     this.editSourceFile( sourcesDirectory );
919                 }
920                 else
921                 {
922                     throw new IOException( getMessage( "implementationNotFound", implementation.getIdentifier() ) );
923                 }
924             }
925             finally
926             {
927                 this.specification = null;
928                 this.implementation = null;
929                 this.sourceFileType = null;
930                 this.velocityContext = null;
931             }
932         }
933 
934         /**
935          * Gets a list of sections added to the input.
936          * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you
937          * make to the returned list will be present inside the object. This is why there is no {@code set} method
938          * for the added sections property.</p>
939          *
940          * @return A list of sections added to the input.
941          *
942          * @deprecated As of JOMC 1.2, deprecated without replacement. This method will be removed in version 2.0.
943          */
944         @Deprecated
945         public List<Section> getAddedSections()
946         {
947             if ( this.addedSections == null )
948             {
949                 this.addedSections = new LinkedList<Section>();
950             }
951 
952             return this.addedSections;
953         }
954 
955         /**
956          * Gets a list of sections without corresponding model entry.
957          * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you
958          * make to the returned list will be present inside the object. This is why there is no {@code set} method
959          * for the unknown sections property.</p>
960          *
961          * @return A list of sections without corresponding model entry.
962          *
963          * @deprecated As of JOMC 1.2, deprecated without replacement. This method will be removed in version 2.0.
964          */
965         @Deprecated
966         public List<Section> getUnknownSections()
967         {
968             if ( this.unknownSections == null )
969             {
970                 this.unknownSections = new LinkedList<Section>();
971             }
972 
973             return this.unknownSections;
974         }
975 
976         /**
977          * Gets the currently edited source code file.
978          *
979          * @return The currently edited source code file.
980          *
981          * @deprecated As of JOMC 1.2, deprecated without replacement. This method will be removed in version 2.0.
982          */
983         @Deprecated
984         protected SourceFileType getSourceFileType()
985         {
986             if ( this.sourceFileType == null )
987             {
988                 if ( this.specification != null )
989                 {
990                     return SourceFileProcessor.this.getSourceFileType( this.specification );
991                 }
992 
993                 if ( this.implementation != null )
994                 {
995                     return SourceFileProcessor.this.getSourceFileType( this.implementation );
996                 }
997             }
998 
999             return this.sourceFileType;
1000         }
1001 
1002         /**
1003          * Gets a new velocity context used for merging templates.
1004          *
1005          * @return A new velocity context used for merging templates.
1006          *
1007          * @throws IOException if creating a new context instance fails.
1008          * 
1009          * @deprecated As of JOMC 1.2, deprecated without replacement. This method will be removed in version 2.0.
1010          */
1011         @Deprecated
1012         protected VelocityContext getVelocityContext() throws IOException
1013         {
1014             if ( this.velocityContext == null )
1015             {
1016                 final VelocityContext ctx = SourceFileProcessor.this.getVelocityContext();
1017 
1018                 if ( this.specification != null )
1019                 {
1020                     ctx.put( "specification", this.specification );
1021                 }
1022 
1023                 if ( this.implementation != null )
1024                 {
1025                     ctx.put( "implementation", this.implementation );
1026                 }
1027 
1028                 return ctx;
1029             }
1030 
1031             return this.velocityContext;
1032         }
1033 
1034         /**
1035          * {@inheritDoc}
1036          * <p>This method creates any sections declared in the model of the source file as returned by method
1037          * {@code getSourceFileType} prior to rendering the output of the editor.</p>
1038          *
1039          * @param section The section to start rendering the editor's output with.
1040          *
1041          * @see #createSection(java.lang.String, java.lang.String, org.jomc.tools.model.SourceSectionType)
1042          */
1043         @Override
1044         protected String getOutput( final Section section ) throws IOException
1045         {
1046             this.getAddedSections().clear();
1047             this.getUnknownSections().clear();
1048 
1049             final SourceFileType model = this.getSourceFileType();
1050 
1051             if ( model != null )
1052             {
1053                 this.createSections( model, model.getSourceSections(), section );
1054             }
1055 
1056             return super.getOutput( section );
1057         }
1058 
1059         /**
1060          * {@inheritDoc}
1061          * <p>This method searches the model of the source file for a section matching {@code s} and updates properties
1062          * {@code headContent} and {@code tailContent} of {@code s} according to the templates declared in the model
1063          * as returned by method {@code getSourceFileType}.</p>
1064          *
1065          * @param s The section to edit.
1066          */
1067         @Override
1068         protected void editSection( final Section s ) throws IOException
1069         {
1070             try
1071             {
1072                 super.editSection( s );
1073 
1074                 final SourceFileType model = this.getSourceFileType();
1075 
1076                 if ( s.getName() != null && model != null && model.getSourceSections() != null )
1077                 {
1078                     final SourceSectionType sourceSectionType =
1079                         model.getSourceSections().getSourceSection( s.getName() );
1080 
1081                     if ( sourceSectionType != null )
1082                     {
1083                         if ( s.getStartingLine() != null )
1084                         {
1085                             s.setStartingLine( getIndentation( sourceSectionType.getIndentationLevel() )
1086                                                    + s.getStartingLine().trim() );
1087 
1088                         }
1089                         if ( s.getEndingLine() != null )
1090                         {
1091                             s.setEndingLine( getIndentation( sourceSectionType.getIndentationLevel() )
1092                                                  + s.getEndingLine().trim() );
1093 
1094                         }
1095 
1096                         if ( sourceSectionType.getHeadTemplate() != null
1097                                  && ( !sourceSectionType.isEditable()
1098                                       || s.getHeadContent().toString().trim().length() == 0 ) )
1099                         {
1100                             final StringWriter writer = new StringWriter();
1101                             final Template template = getVelocityTemplate( sourceSectionType.getHeadTemplate() );
1102                             final VelocityContext ctx = getVelocityContext();
1103                             ctx.put( "template", template );
1104                             ctx.put( "ssection", sourceSectionType );
1105                             template.merge( ctx, writer );
1106                             writer.close();
1107                             s.getHeadContent().setLength( 0 );
1108                             s.getHeadContent().append( writer.toString() );
1109                             ctx.remove( "template" );
1110                             ctx.remove( "ssection" );
1111                         }
1112 
1113                         if ( sourceSectionType.getTailTemplate() != null
1114                                  && ( !sourceSectionType.isEditable()
1115                                       || s.getTailContent().toString().trim().length() == 0 ) )
1116                         {
1117                             final StringWriter writer = new StringWriter();
1118                             final Template template = getVelocityTemplate( sourceSectionType.getTailTemplate() );
1119                             final VelocityContext ctx = getVelocityContext();
1120                             ctx.put( "template", template );
1121                             ctx.put( "ssection", sourceSectionType );
1122                             template.merge( ctx, writer );
1123                             writer.close();
1124                             s.getTailContent().setLength( 0 );
1125                             s.getTailContent().append( writer.toString() );
1126                             ctx.remove( "template" );
1127                             ctx.remove( "ssection" );
1128                         }
1129                     }
1130                     else
1131                     {
1132                         if ( isLoggable( Level.WARNING ) )
1133                         {
1134                             if ( this.implementation != null )
1135                             {
1136                                 final Module m =
1137                                     getModules().getModuleOfImplementation( this.implementation.getIdentifier() );
1138 
1139                                 log( Level.WARNING, getMessage(
1140                                      "unknownImplementationSection", m.getName(), this.implementation.getIdentifier(),
1141                                      model.getIdentifier(), s.getName() ), null );
1142 
1143                             }
1144                             else if ( this.specification != null )
1145                             {
1146                                 final Module m =
1147                                     getModules().getModuleOfSpecification( this.specification.getIdentifier() );
1148 
1149                                 log( Level.WARNING, getMessage(
1150                                      "unknownSpecificationSection", m.getName(), this.specification.getIdentifier(),
1151                                      model.getIdentifier(), s.getName() ), null );
1152 
1153                             }
1154                         }
1155 
1156                         this.getUnknownSections().add( s );
1157                     }
1158                 }
1159             }
1160             catch ( final VelocityException e )
1161             {
1162                 // JDK: As of JDK 6, "new IOException( message, cause )".
1163                 throw (IOException) new IOException( getMessage( e ) ).initCause( e );
1164             }
1165         }
1166 
1167         private void createSections( final SourceFileType sourceFileType, final SourceSectionsType sourceSectionsType,
1168                                      final Section section ) throws IOException
1169         {
1170             if ( sourceSectionsType != null && section != null )
1171             {
1172                 for ( int i = 0, s0 = sourceSectionsType.getSourceSection().size(); i < s0; i++ )
1173                 {
1174                     final SourceSectionType sourceSectionType = sourceSectionsType.getSourceSection().get( i );
1175                     Section childSection = section.getSection( sourceSectionType.getName() );
1176 
1177                     if ( childSection == null && !sourceSectionType.isOptional() )
1178                     {
1179                         childSection = this.createSection( StringUtils.defaultString( sourceFileType.getHeadComment() ),
1180                                                            StringUtils.defaultString( sourceFileType.getTailComment() ),
1181                                                            sourceSectionType );
1182 
1183                         section.getSections().add( childSection );
1184 
1185                         if ( isLoggable( Level.FINE ) )
1186                         {
1187                             log( Level.FINE, getMessage(
1188                                  "addedSection", sourceFileType.getIdentifier(), childSection.getName() ), null );
1189 
1190                         }
1191 
1192                         this.getAddedSections().add( childSection );
1193                     }
1194 
1195                     this.createSections( sourceFileType, sourceSectionType.getSourceSections(), childSection );
1196                 }
1197             }
1198         }
1199 
1200         /**
1201          * Creates a new {@code Section} instance for a given {@code SourceSectionType}.
1202          *
1203          * @param headComment Characters to use to start a comment in the source file.
1204          * @param tailComment Characters to use to end a comment in the source file.
1205          * @param sourceSectionType The {@code SourceSectionType} to create a new {@code Section} instance for.
1206          *
1207          * @return A new {@code Section} instance for {@code sourceSectionType}.
1208          *
1209          * @throws NullPointerException if {@code headComment}, {@code tailComment} or {@code sourceSectionType} is
1210          * {@code null}.
1211          * @throws IOException if creating a new {@code Section} instance fails.
1212          *
1213          * @since 1.2
1214          */
1215         private Section createSection( final String headComment, final String tailComment,
1216                                        final SourceSectionType sourceSectionType ) throws IOException
1217         {
1218             if ( headComment == null )
1219             {
1220                 throw new NullPointerException( "headComment" );
1221             }
1222             if ( tailComment == null )
1223             {
1224                 throw new NullPointerException( "tailComment" );
1225             }
1226             if ( sourceSectionType == null )
1227             {
1228                 throw new NullPointerException( "sourceSectionType" );
1229             }
1230 
1231             final Section s = new Section();
1232             s.setName( sourceSectionType.getName() );
1233 
1234             final StringBuilder head = new StringBuilder( 255 );
1235             head.append( getIndentation( sourceSectionType.getIndentationLevel() ) ).append( headComment );
1236 
1237             s.setStartingLine( head + " SECTION-START[" + sourceSectionType.getName() + ']' + tailComment );
1238             s.setEndingLine( head + " SECTION-END" + tailComment );
1239 
1240             return s;
1241         }
1242 
1243         private void editSourceFile( final File sourcesDirectory ) throws IOException
1244         {
1245             if ( sourcesDirectory == null )
1246             {
1247                 throw new NullPointerException( "sourcesDirectory" );
1248             }
1249             if ( !sourcesDirectory.isDirectory() )
1250             {
1251                 throw new IOException( getMessage( "directoryNotFound", sourcesDirectory.getAbsolutePath() ) );
1252             }
1253 
1254             final SourceFileType model = this.getSourceFileType();
1255 
1256             if ( model != null && model.getLocation() != null )
1257             {
1258                 final File f = new File( sourcesDirectory, model.getLocation() );
1259 
1260                 try
1261                 {
1262                     String content = "";
1263                     String edited = null;
1264                     boolean creating = false;
1265 
1266                     if ( !f.exists() )
1267                     {
1268                         if ( model.getTemplate() != null )
1269                         {
1270                             final StringWriter writer = new StringWriter();
1271                             final Template template = getVelocityTemplate( model.getTemplate() );
1272                             final VelocityContext ctx = this.getVelocityContext();
1273                             ctx.put( "template", template );
1274                             template.merge( ctx, writer );
1275                             writer.close();
1276                             content = writer.toString();
1277                             ctx.remove( "template" );
1278                             creating = true;
1279                         }
1280                     }
1281                     else
1282                     {
1283                         if ( isLoggable( Level.FINER ) )
1284                         {
1285                             log( Level.FINER, getMessage( "reading", f.getAbsolutePath() ), null );
1286                         }
1287 
1288                         content = this.readSourceFile( f );
1289                     }
1290 
1291                     try
1292                     {
1293                         edited = super.edit( content );
1294                     }
1295                     catch ( final IOException e )
1296                     {
1297                         // JDK: As of JDK 6, "new IOException( message, cause )".
1298                         throw (IOException) new IOException( getMessage(
1299                             "failedEditing", f.getAbsolutePath(), getMessage( e ) ) ).initCause( e );
1300 
1301                     }
1302 
1303                     if ( !edited.equals( content ) || edited.length() == 0 )
1304                     {
1305                         if ( !f.getParentFile().exists() && !f.getParentFile().mkdirs() )
1306                         {
1307                             throw new IOException( getMessage(
1308                                 "failedCreatingDirectory", f.getParentFile().getAbsolutePath() ) );
1309 
1310                         }
1311 
1312                         if ( isLoggable( Level.INFO ) )
1313                         {
1314                             log( Level.INFO, getMessage(
1315                                  creating ? "creating" : "editing", f.getAbsolutePath() ), null );
1316 
1317                         }
1318 
1319                         this.writeSourceFile( f, edited );
1320                     }
1321                     else if ( isLoggable( Level.FINER ) )
1322                     {
1323                         log( Level.FINER, getMessage( "unchanged", f.getAbsolutePath() ), null );
1324                     }
1325                 }
1326                 catch ( final VelocityException e )
1327                 {
1328                     // JDK: As of JDK 6, "new IOException( message, cause )".
1329                     throw (IOException) new IOException( getMessage(
1330                         "failedEditing", f.getAbsolutePath(), getMessage( e ) ) ).initCause( e );
1331 
1332                 }
1333             }
1334         }
1335 
1336         private String readSourceFile( final File file ) throws IOException
1337         {
1338             if ( file == null )
1339             {
1340                 throw new NullPointerException( "file" );
1341             }
1342 
1343             RandomAccessFile randomAccessFile = null;
1344             FileChannel fileChannel = null;
1345             FileLock fileLock = null;
1346             boolean suppressExceptionOnClose = true;
1347 
1348             //final Charset charset = Charset.forName( getInputEncoding() );
1349             final int length = file.length() > 0L ? Long.valueOf( file.length() ).intValue() : 1;
1350             final ByteBuffer buf = ByteBuffer.allocate( length );
1351             final StringBuilder appendable = new StringBuilder( length );
1352 
1353             try
1354             {
1355                 randomAccessFile = new RandomAccessFile( file, "r" );
1356                 fileChannel = randomAccessFile.getChannel();
1357                 fileLock = fileChannel.lock( 0L, file.length(), true );
1358                 fileChannel.position( 0L );
1359 
1360                 buf.clear();
1361                 int read = fileChannel.read( buf );
1362 
1363                 while ( read != -1 )
1364                 {
1365                     // JDK: As of JDK 6, new String( byte[], int, int, Charset )
1366                     appendable.append( new String( buf.array(), buf.arrayOffset(), read, getInputEncoding() ) );
1367                     buf.clear();
1368                     read = fileChannel.read( buf );
1369                 }
1370 
1371                 suppressExceptionOnClose = false;
1372                 return appendable.toString();
1373             }
1374             finally
1375             {
1376                 this.releaseAndClose( fileLock, fileChannel, randomAccessFile, suppressExceptionOnClose );
1377             }
1378         }
1379 
1380         private void writeSourceFile( final File file, final String content ) throws IOException
1381         {
1382             if ( file == null )
1383             {
1384                 throw new NullPointerException( "file" );
1385             }
1386             if ( content == null )
1387             {
1388                 throw new NullPointerException( "content" );
1389             }
1390 
1391             RandomAccessFile randomAccessFile = null;
1392             FileChannel fileChannel = null;
1393             FileLock fileLock = null;
1394             boolean suppressExceptionOnClose = true;
1395             final byte[] bytes = content.getBytes( getOutputEncoding() );
1396 
1397             try
1398             {
1399                 randomAccessFile = new RandomAccessFile( file, "rw" );
1400                 fileChannel = randomAccessFile.getChannel();
1401                 fileLock = fileChannel.lock( 0L, bytes.length, false );
1402                 fileChannel.truncate( bytes.length );
1403                 fileChannel.position( 0L );
1404                 fileChannel.write( ByteBuffer.wrap( bytes ) );
1405                 fileChannel.force( true );
1406                 suppressExceptionOnClose = false;
1407             }
1408             finally
1409             {
1410                 this.releaseAndClose( fileLock, fileChannel, randomAccessFile, suppressExceptionOnClose );
1411             }
1412         }
1413 
1414         private void releaseAndClose( final FileLock fileLock, final FileChannel fileChannel,
1415                                       final RandomAccessFile randomAccessFile, final boolean suppressExceptions )
1416             throws IOException
1417         {
1418             try
1419             {
1420                 if ( fileLock != null )
1421                 {
1422                     fileLock.release();
1423                 }
1424             }
1425             catch ( final IOException e )
1426             {
1427                 if ( suppressExceptions )
1428                 {
1429                     log( Level.SEVERE, null, e );
1430                 }
1431                 else
1432                 {
1433                     throw e;
1434                 }
1435             }
1436             finally
1437             {
1438                 try
1439                 {
1440                     if ( fileChannel != null )
1441                     {
1442                         fileChannel.close();
1443                     }
1444                 }
1445                 catch ( final IOException e )
1446                 {
1447                     if ( suppressExceptions )
1448                     {
1449                         log( Level.SEVERE, null, e );
1450                     }
1451                     else
1452                     {
1453                         throw e;
1454                     }
1455                 }
1456                 finally
1457                 {
1458                     try
1459                     {
1460                         if ( randomAccessFile != null )
1461                         {
1462                             randomAccessFile.close();
1463                         }
1464                     }
1465                     catch ( final IOException e )
1466                     {
1467                         if ( suppressExceptions )
1468                         {
1469                             log( Level.SEVERE, null, e );
1470                         }
1471                         else
1472                         {
1473                             throw e;
1474                         }
1475                     }
1476                 }
1477             }
1478         }
1479 
1480     }
1481 
1482 }