EMMA Coverage Report (generated Thu Jan 03 04:54:40 CET 2013)
[all classes][org.jomc.tools]

COVERAGE SUMMARY FOR SOURCE FILE [SourceFileProcessor.java]

nameclass, %method, %block, %line, %
SourceFileProcessor.java100% (2/2)77%  (36/47)70%  (1527/2194)76%  (305.2/402)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SourceFileProcessor$SourceFileEditor100% (1/1)59%  (16/27)62%  (931/1500)70%  (187.6/269)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor): void 0%   (0/1)0%   (0/8)0%   (0/2)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, Implementation): void 0%   (0/1)0%   (0/7)0%   (0/2)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, Implementation, Li... 0%   (0/1)0%   (0/7)0%   (0/2)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, Implementation, Li... 0%   (0/1)0%   (0/37)0%   (0/6)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, Implementation, St... 0%   (0/1)0%   (0/7)0%   (0/2)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, LineEditor): void 0%   (0/1)0%   (0/6)0%   (0/2)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, Specification): void 0%   (0/1)0%   (0/7)0%   (0/2)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, Specification, Lin... 0%   (0/1)0%   (0/7)0%   (0/2)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, Specification, Lin... 0%   (0/1)0%   (0/37)0%   (0/6)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, Specification, Str... 0%   (0/1)0%   (0/7)0%   (0/2)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, String): void 0%   (0/1)0%   (0/7)0%   (0/2)
releaseAndClose (FileLock, FileChannel, RandomAccessFile, boolean): void 100% (1/1)6%   (15/238)18%  (4.4/24)
getVelocityContext (): VelocityContext 100% (1/1)20%  (6/30)25%  (2/8)
getSourceFileType (): SourceFileType 100% (1/1)25%  (6/24)33%  (2/6)
edit (Implementation, SourceFileType, File): void 100% (1/1)72%  (73/101)80%  (16/20)
edit (Specification, SourceFileType, File): void 100% (1/1)72%  (73/101)80%  (16/20)
<static initializer> 100% (1/1)75%  (6/8)75%  (0.8/1)
writeSourceFile (File, String): void 100% (1/1)77%  (63/82)89%  (17.9/20)
createSection (String, String, SourceSectionType): Section 100% (1/1)80%  (60/75)77%  (10/13)
editSourceFile (File): void 100% (1/1)80%  (185/230)89%  (35.5/40)
readSourceFile (File): String 100% (1/1)87%  (95/109)94%  (20.6/22)
editSection (Section): void 100% (1/1)93%  (216/232)93%  (35.5/38)
SourceFileProcessor$SourceFileEditor (SourceFileProcessor, LineEditor, String... 100% (1/1)100% (8/8)100% (3/3)
createSections (SourceFileType, SourceSectionsType, Section): void 100% (1/1)100% (82/82)100% (12/12)
getAddedSections (): List 100% (1/1)100% (11/11)100% (3/3)
getOutput (Section): String 100% (1/1)100% (21/21)100% (6/6)
getUnknownSections (): List 100% (1/1)100% (11/11)100% (3/3)
     
class SourceFileProcessor100% (1/1)100% (20/20)86%  (596/694)88%  (117.7/133)
getMessage (Throwable): String 100% (1/1)64%  (9/14)64%  (0.6/1)
getSourceFileType (Implementation): SourceFileType 100% (1/1)67%  (34/51)80%  (8/10)
getSourceFileType (Specification): SourceFileType 100% (1/1)67%  (34/51)80%  (8/10)
getSourceFileEditor (Implementation): SourceFileProcessor$SourceFileEditor 100% (1/1)70%  (7/10)67%  (2/3)
getSourceFileEditor (Specification): SourceFileProcessor$SourceFileEditor 100% (1/1)70%  (7/10)67%  (2/3)
getSourceFilesType (Implementation): SourceFilesType 100% (1/1)70%  (59/84)83%  (12.4/15)
getMessage (String, Object []): String 100% (1/1)72%  (13/18)67%  (2/3)
<static initializer> 100% (1/1)75%  (6/8)75%  (0.8/1)
SourceFileProcessor (SourceFileProcessor): void 100% (1/1)78%  (14/18)94%  (3.8/4)
getSourceFilesType (Specification): SourceFilesType 100% (1/1)83%  (49/59)85%  (11/13)
manageSourceFiles (Specification, File): void 100% (1/1)94%  (108/115)88%  (21/24)
SourceFileProcessor (): void 100% (1/1)100% (3/3)100% (2/2)
access$000 (String, Object []): String 100% (1/1)100% (4/4)100% (1/1)
access$100 (Throwable): String 100% (1/1)100% (3/3)100% (1/1)
getSourceFileEditor (): SourceFileProcessor$SourceFileEditor 100% (1/1)100% (19/19)100% (3/3)
getSourceFilesType (): SourceFilesType 100% (1/1)100% (11/11)100% (3/3)
manageSourceFiles (File): void 100% (1/1)100% (50/50)100% (8/8)
manageSourceFiles (Implementation, File): void 100% (1/1)100% (72/72)100% (14/14)
manageSourceFiles (Module, File): void 100% (1/1)100% (90/90)100% (14/14)
setSourceFileEditor (SourceFileProcessor$SourceFileEditor): void 100% (1/1)100% (4/4)100% (2/2)

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

[all classes][org.jomc.tools]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov