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