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