EMMA Coverage Report (generated Mon Apr 22 06:35:53 CEST 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%  (1532/2199)76%  (305.3/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%  (601/699)89%  (117.8/133)
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)
getMessage (Throwable): String 100% (1/1)74%  (14/19)73%  (0.7/1)
<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 4760 2013-04-08 17:56:26Z 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 4760 2013-04-08 17:56:26Z 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
595               ? t.getMessage() != null && t.getMessage().trim().length() > 0
596                 ? t.getMessage()
597                 : getMessage( t.getCause() )
598               : null;
599 
600    }
601 
602    /**
603     * Extension to {@code SectionEditor} adding support for editing source code files.
604     *
605     * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
606     * @version $JOMC: SourceFileProcessor.java 4760 2013-04-08 17:56:26Z schulte $
607     *
608     * @see #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)
609     * @see #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)
610     */
611    public class SourceFileEditor extends SectionEditor
612    {
613 
614        /** {@code Specification} of the instance or {@code null}. */
615        private Specification specification;
616 
617        /** {@code Implementation} of the instance or {@code null}. */
618        private Implementation implementation;
619 
620        /** The source code file to edit. */
621        private SourceFileType sourceFileType;
622 
623        /** The {@code VelocityContext} of the instance. */
624        private VelocityContext velocityContext;
625 
626        /** List of sections added to the input. */
627        @Deprecated
628        private List<Section> addedSections;
629 
630        /** List of sections without corresponding model entry. */
631        @Deprecated
632        private List<Section> unknownSections;
633 
634        /**
635         * Creates a new {@code SourceFileEditor} instance.
636         *
637         * @since 1.2
638         */
639        public SourceFileEditor()
640        {
641            this( (LineEditor) null, (String) null );
642        }
643 
644        /**
645         * Creates a new {@code SourceFileEditor} instance taking a string to use for separating lines.
646         *
647         * @param lineSeparator String to use for separating lines.
648         *
649         * @since 1.2
650         */
651        public SourceFileEditor( final String lineSeparator )
652        {
653            this( (LineEditor) null, lineSeparator );
654        }
655 
656        /**
657         * Creates a new {@code SourceFileEditor} instance taking an editor to chain.
658         *
659         * @param editor The editor to chain.
660         *
661         * @since 1.2
662         */
663        public SourceFileEditor( final LineEditor editor )
664        {
665            this( editor, null );
666        }
667 
668        /**
669         * Creates a new {@code SourceFileEditor} instance taking an editor to chain and a string to use for separating
670         * lines.
671         *
672         * @param editor The editor to chain.
673         * @param lineSeparator String to use for separating lines.
674         *
675         * @since 1.2
676         */
677        public SourceFileEditor( final LineEditor editor, final String lineSeparator )
678        {
679            super( editor, lineSeparator );
680        }
681 
682        /**
683         * Creates a new {@code SourceFileEditor} taking a {@code Specification} to edit source code of.
684         *
685         * @param specification The specification to edit source code of.
686         *
687         * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)}.
688         * This constructor will be removed in version 2.0.
689         */
690        @Deprecated
691        public SourceFileEditor( final Specification specification )
692        {
693            this( specification, null, null );
694        }
695 
696        /**
697         * Creates a new {@code SourceFileEditor} taking a {@code Specification} to edit source code of and a line
698         * separator.
699         *
700         * @param specification The specification to edit source code of.
701         * @param lineSeparator The line separator of the editor.
702         *
703         * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)}.
704         * This constructor will be removed in version 2.0.
705         */
706        @Deprecated
707        public SourceFileEditor( final Specification specification, final String lineSeparator )
708        {
709            this( specification, null, lineSeparator );
710        }
711 
712        /**
713         * Creates a new {@code SourceFileEditor} taking a {@code Specification} to edit source code of and an editor to
714         * chain.
715         *
716         * @param specification The specification backing the editor.
717         * @param lineEditor The editor to chain.
718         *
719         * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)}.
720         * This constructor will be removed in version 2.0.
721         */
722        @Deprecated
723        public SourceFileEditor( final Specification specification, final LineEditor lineEditor )
724        {
725            this( specification, lineEditor, null );
726        }
727 
728        /**
729         * Creates a new {@code SourceFileEditor} taking a {@code Specification} to edit source code of, an editor to
730         * chain and a line separator.
731         *
732         * @param specification The specification backing the editor.
733         * @param lineEditor The editor to chain.
734         * @param lineSeparator The line separator of the editor.
735         *
736         * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Specification, org.jomc.tools.model.SourceFileType, java.io.File)}.
737         * This constructor will be removed in version 2.0.
738         */
739        @Deprecated
740        public SourceFileEditor( final Specification specification, final LineEditor lineEditor,
741                                 final String lineSeparator )
742        {
743            super( lineEditor, lineSeparator );
744            this.specification = specification;
745            this.implementation = null;
746 
747            assert getModules().getSpecification( specification.getIdentifier() ) != null :
748                "Specification '" + specification.getIdentifier() + "' not found.";
749 
750        }
751 
752        /**
753         * Creates a new {@code SourceFileEditor} taking an {@code Implementation} to edit source code of.
754         *
755         * @param implementation The implementation to edit source code of.
756         *
757         * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)}.
758         * This constructor will be removed in version 2.0.
759         */
760        @Deprecated
761        public SourceFileEditor( final Implementation implementation )
762        {
763            this( implementation, null, null );
764        }
765 
766        /**
767         * Creates a new {@code SourceFileEditor} taking an {@code Implementation} to edit source code of and a line
768         * separator.
769         *
770         * @param implementation The implementation to edit source code of.
771         * @param lineSeparator The line separator of the editor.
772         *
773         * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)}.
774         * This constructor will be removed in version 2.0.
775         */
776        @Deprecated
777        public SourceFileEditor( final Implementation implementation, final String lineSeparator )
778        {
779            this( implementation, null, lineSeparator );
780        }
781 
782        /**
783         * Creates a new {@code SourceFileEditor} taking an {@code Implementation} to edit source code of and an editor
784         * to chain.
785         *
786         * @param implementation The implementation to edit source code of.
787         * @param lineEditor The editor to chain.
788         *
789         * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)}.
790         * This constructor will be removed in version 2.0.
791         */
792        @Deprecated
793        public SourceFileEditor( final Implementation implementation, final LineEditor lineEditor )
794        {
795            this( implementation, lineEditor, null );
796        }
797 
798        /**
799         * Creates a new {@code SourceFileEditor} taking an {@code Implementation} to edit source code of, an editor
800         * to chain and a line separator.
801         *
802         * @param implementation The implementation to edit source code of.
803         * @param lineEditor The editor to chain.
804         * @param lineSeparator The line separator of the editor.
805         *
806         * @deprecated As of JOMC 1.2, please use method {@link #edit(org.jomc.model.Implementation, org.jomc.tools.model.SourceFileType, java.io.File)}.
807         * This constructor will be removed in version 2.0.
808         */
809        @Deprecated
810        public SourceFileEditor( final Implementation implementation, final LineEditor lineEditor,
811                                 final String lineSeparator )
812        {
813            super( lineEditor, lineSeparator );
814            this.implementation = implementation;
815            this.specification = null;
816 
817            assert getModules().getImplementation( implementation.getIdentifier() ) != null :
818                "Implementation '" + implementation.getIdentifier() + "' not found.";
819 
820        }
821 
822        /**
823         * Edits a source file of a given specification.
824         *
825         * @param specification The specification to edit a source file of.
826         * @param sourceFileType The model of the source file to edit.
827         * @param sourcesDirectory The directory holding the source file to edit.
828         *
829         * @throws NullPointerException if {@code specification}, {@code sourceFileType} or {@code sourcesDirectory} is
830         * {@code null}.
831         * @throws IOException if editing fails.
832         *
833         * @since 1.2
834         */
835        public final void edit( final Specification specification, final SourceFileType sourceFileType,
836                                final File sourcesDirectory ) throws IOException
837        {
838            if ( specification == null )
839            {
840                throw new NullPointerException( "specification" );
841            }
842            if ( sourceFileType == null )
843            {
844                throw new NullPointerException( "sourceFileType" );
845            }
846            if ( sourcesDirectory == null )
847            {
848                throw new NullPointerException( "sourcesDirectory" );
849            }
850 
851            try
852            {
853                if ( getModules() != null
854                     && getModules().getSpecification( specification.getIdentifier() ) != null )
855                {
856                    this.specification = specification;
857                    this.sourceFileType = sourceFileType;
858                    this.velocityContext = SourceFileProcessor.this.getVelocityContext();
859                    this.velocityContext.put( "specification", specification );
860                    this.velocityContext.put( "smodel", sourceFileType );
861 
862                    this.editSourceFile( sourcesDirectory );
863                }
864                else
865                {
866                    throw new IOException( getMessage( "specificationNotFound", specification.getIdentifier() ) );
867                }
868            }
869            finally
870            {
871                this.specification = null;
872                this.implementation = null;
873                this.sourceFileType = null;
874                this.velocityContext = null;
875            }
876        }
877 
878        /**
879         * Edits a source file of a given implementation.
880         *
881         * @param implementation The implementation to edit a source file of.
882         * @param sourceFileType The model of the source file to edit.
883         * @param sourcesDirectory The directory holding the source file to edit.
884         *
885         * @throws NullPointerException if {@code implementation}, {@code sourceFileType} or {@code sourcesDirectory} is
886         * {@code null}.
887         * @throws IOException if editing fails.
888         *
889         * @since 1.2
890         */
891        public final void edit( final Implementation implementation, final SourceFileType sourceFileType,
892                                final File sourcesDirectory ) throws IOException
893        {
894            if ( implementation == null )
895            {
896                throw new NullPointerException( "implementation" );
897            }
898            if ( sourceFileType == null )
899            {
900                throw new NullPointerException( "sourceFileType" );
901            }
902            if ( sourcesDirectory == null )
903            {
904                throw new NullPointerException( "sourcesDirectory" );
905            }
906 
907            try
908            {
909                if ( getModules() != null
910                     && getModules().getImplementation( implementation.getIdentifier() ) != null )
911                {
912                    this.implementation = implementation;
913                    this.sourceFileType = sourceFileType;
914                    this.velocityContext = SourceFileProcessor.this.getVelocityContext();
915                    this.velocityContext.put( "implementation", implementation );
916                    this.velocityContext.put( "smodel", sourceFileType );
917 
918                    this.editSourceFile( sourcesDirectory );
919                }
920                else
921                {
922                    throw new IOException( getMessage( "implementationNotFound", implementation.getIdentifier() ) );
923                }
924            }
925            finally
926            {
927                this.specification = null;
928                this.implementation = null;
929                this.sourceFileType = null;
930                this.velocityContext = null;
931            }
932        }
933 
934        /**
935         * Gets a list of sections added to the input.
936         * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you
937         * make to the returned list will be present inside the object. This is why there is no {@code set} method
938         * for the added sections property.</p>
939         *
940         * @return A list of sections added to the input.
941         *
942         * @deprecated As of JOMC 1.2, deprecated without replacement. This method will be removed in version 2.0.
943         */
944        @Deprecated
945        public List<Section> getAddedSections()
946        {
947            if ( this.addedSections == null )
948            {
949                this.addedSections = new LinkedList<Section>();
950            }
951 
952            return this.addedSections;
953        }
954 
955        /**
956         * Gets a list of sections without corresponding model entry.
957         * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you
958         * make to the returned list will be present inside the object. This is why there is no {@code set} method
959         * for the unknown sections property.</p>
960         *
961         * @return A list of sections without corresponding model entry.
962         *
963         * @deprecated As of JOMC 1.2, deprecated without replacement. This method will be removed in version 2.0.
964         */
965        @Deprecated
966        public List<Section> getUnknownSections()
967        {
968            if ( this.unknownSections == null )
969            {
970                this.unknownSections = new LinkedList<Section>();
971            }
972 
973            return this.unknownSections;
974        }
975 
976        /**
977         * Gets the currently edited source code file.
978         *
979         * @return The currently edited source code file.
980         *
981         * @deprecated As of JOMC 1.2, deprecated without replacement. This method will be removed in version 2.0.
982         */
983        @Deprecated
984        protected SourceFileType getSourceFileType()
985        {
986            if ( this.sourceFileType == null )
987            {
988                if ( this.specification != null )
989                {
990                    return SourceFileProcessor.this.getSourceFileType( this.specification );
991                }
992 
993                if ( this.implementation != null )
994                {
995                    return SourceFileProcessor.this.getSourceFileType( this.implementation );
996                }
997            }
998 
999            return this.sourceFileType;
1000        }
1001 
1002        /**
1003         * Gets a new velocity context used for merging templates.
1004         *
1005         * @return A new velocity context used for merging templates.
1006         *
1007         * @throws IOException if creating a new context instance fails.
1008         * 
1009         * @deprecated As of JOMC 1.2, deprecated without replacement. This method will be removed in version 2.0.
1010         */
1011        @Deprecated
1012        protected VelocityContext getVelocityContext() throws IOException
1013        {
1014            if ( this.velocityContext == null )
1015            {
1016                final VelocityContext ctx = SourceFileProcessor.this.getVelocityContext();
1017 
1018                if ( this.specification != null )
1019                {
1020                    ctx.put( "specification", this.specification );
1021                }
1022 
1023                if ( this.implementation != null )
1024                {
1025                    ctx.put( "implementation", this.implementation );
1026                }
1027 
1028                return ctx;
1029            }
1030 
1031            return this.velocityContext;
1032        }
1033 
1034        /**
1035         * {@inheritDoc}
1036         * <p>This method creates any sections declared in the model of the source file as returned by method
1037         * {@code getSourceFileType} prior to rendering the output of the editor.</p>
1038         *
1039         * @param section The section to start rendering the editor's output with.
1040         *
1041         * @see #createSection(java.lang.String, java.lang.String, org.jomc.tools.model.SourceSectionType)
1042         */
1043        @Override
1044        protected String getOutput( final Section section ) throws IOException
1045        {
1046            this.getAddedSections().clear();
1047            this.getUnknownSections().clear();
1048 
1049            final SourceFileType model = this.getSourceFileType();
1050 
1051            if ( model != null )
1052            {
1053                this.createSections( model, model.getSourceSections(), section );
1054            }
1055 
1056            return super.getOutput( section );
1057        }
1058 
1059        /**
1060         * {@inheritDoc}
1061         * <p>This method searches the model of the source file for a section matching {@code s} and updates properties
1062         * {@code headContent} and {@code tailContent} of {@code s} according to the templates declared in the model
1063         * as returned by method {@code getSourceFileType}.</p>
1064         *
1065         * @param s The section to edit.
1066         */
1067        @Override
1068        protected void editSection( final Section s ) throws IOException
1069        {
1070            try
1071            {
1072                super.editSection( s );
1073 
1074                final SourceFileType model = this.getSourceFileType();
1075 
1076                if ( s.getName() != null && model != null && model.getSourceSections() != null )
1077                {
1078                    final SourceSectionType sourceSectionType =
1079                        model.getSourceSections().getSourceSection( s.getName() );
1080 
1081                    if ( sourceSectionType != null )
1082                    {
1083                        if ( s.getStartingLine() != null )
1084                        {
1085                            s.setStartingLine( getIndentation( sourceSectionType.getIndentationLevel() )
1086                                               + s.getStartingLine().trim() );
1087 
1088                        }
1089                        if ( s.getEndingLine() != null )
1090                        {
1091                            s.setEndingLine( getIndentation( sourceSectionType.getIndentationLevel() )
1092                                             + s.getEndingLine().trim() );
1093 
1094                        }
1095 
1096                        if ( sourceSectionType.getHeadTemplate() != null
1097                             && ( !sourceSectionType.isEditable()
1098                                  || s.getHeadContent().toString().trim().length() == 0 ) )
1099                        {
1100                            final StringWriter writer = new StringWriter();
1101                            final Template template = getVelocityTemplate( sourceSectionType.getHeadTemplate() );
1102                            final VelocityContext ctx = getVelocityContext();
1103                            ctx.put( "template", template );
1104                            template.merge( ctx, writer );
1105                            writer.close();
1106                            s.getHeadContent().setLength( 0 );
1107                            s.getHeadContent().append( writer.toString() );
1108                        }
1109 
1110                        if ( sourceSectionType.getTailTemplate() != null
1111                             && ( !sourceSectionType.isEditable()
1112                                  || s.getTailContent().toString().trim().length() == 0 ) )
1113                        {
1114                            final StringWriter writer = new StringWriter();
1115                            final Template template = getVelocityTemplate( sourceSectionType.getTailTemplate() );
1116                            final VelocityContext ctx = getVelocityContext();
1117                            ctx.put( "template", template );
1118                            template.merge( ctx, writer );
1119                            writer.close();
1120                            s.getTailContent().setLength( 0 );
1121                            s.getTailContent().append( writer.toString() );
1122                        }
1123                    }
1124                    else
1125                    {
1126                        if ( isLoggable( Level.WARNING ) )
1127                        {
1128                            if ( this.implementation != null )
1129                            {
1130                                log( Level.WARNING, getMessage(
1131                                    "unknownImplementationSection", this.implementation.getIdentifier(),
1132                                    model.getIdentifier(), s.getName() ), null );
1133 
1134 
1135                            }
1136                            else if ( this.specification != null )
1137                            {
1138                                log( Level.WARNING, getMessage(
1139                                    "unknownSpecificationSection", this.specification.getIdentifier(),
1140                                    model.getIdentifier(), s.getName() ), null );
1141 
1142                            }
1143                        }
1144 
1145                        this.getUnknownSections().add( s );
1146                    }
1147                }
1148            }
1149            catch ( final VelocityException e )
1150            {
1151                // JDK: As of JDK 6, "new IOException( message, cause )".
1152                throw (IOException) new IOException( getMessage( e ) ).initCause( e );
1153            }
1154        }
1155 
1156        private void createSections( final SourceFileType sourceFileType, final SourceSectionsType sourceSectionsType,
1157                                     final Section section ) throws IOException
1158        {
1159            if ( sourceSectionsType != null && section != null )
1160            {
1161                for ( int i = 0, s0 = sourceSectionsType.getSourceSection().size(); i < s0; i++ )
1162                {
1163                    final SourceSectionType sourceSectionType = sourceSectionsType.getSourceSection().get( i );
1164                    Section childSection = section.getSection( sourceSectionType.getName() );
1165 
1166                    if ( childSection == null && !sourceSectionType.isOptional() )
1167                    {
1168                        childSection = this.createSection( StringUtils.defaultString( sourceFileType.getHeadComment() ),
1169                                                           StringUtils.defaultString( sourceFileType.getTailComment() ),
1170                                                           sourceSectionType );
1171 
1172                        section.getSections().add( childSection );
1173 
1174                        if ( isLoggable( Level.FINE ) )
1175                        {
1176                            log( Level.FINE, getMessage(
1177                                "addedSection", sourceFileType.getIdentifier(), childSection.getName() ), null );
1178 
1179                        }
1180 
1181                        this.getAddedSections().add( childSection );
1182                    }
1183 
1184                    this.createSections( sourceFileType, sourceSectionType.getSourceSections(), childSection );
1185                }
1186            }
1187        }
1188 
1189        /**
1190         * Creates a new {@code Section} instance for a given {@code SourceSectionType}.
1191         *
1192         * @param headComment Characters to use to start a comment in the source file.
1193         * @param tailComment Characters to use to end a comment in the source file.
1194         * @param sourceSectionType The {@code SourceSectionType} to create a new {@code Section} instance for.
1195         *
1196         * @return A new {@code Section} instance for {@code sourceSectionType}.
1197         *
1198         * @throws NullPointerException if {@code headComment}, {@code tailComment} or {@code sourceSectionType} is
1199         * {@code null}.
1200         * @throws IOException if creating a new {@code Section} instance fails.
1201         *
1202         * @since 1.2
1203         */
1204        private Section createSection( final String headComment, final String tailComment,
1205                                       final SourceSectionType sourceSectionType ) throws IOException
1206        {
1207            if ( headComment == null )
1208            {
1209                throw new NullPointerException( "headComment" );
1210            }
1211            if ( tailComment == null )
1212            {
1213                throw new NullPointerException( "tailComment" );
1214            }
1215            if ( sourceSectionType == null )
1216            {
1217                throw new NullPointerException( "sourceSectionType" );
1218            }
1219 
1220            final Section s = new Section();
1221            s.setName( sourceSectionType.getName() );
1222 
1223            final StringBuilder head = new StringBuilder( 255 );
1224            head.append( getIndentation( sourceSectionType.getIndentationLevel() ) ).append( headComment );
1225 
1226            s.setStartingLine( head + " SECTION-START[" + sourceSectionType.getName() + ']' + tailComment );
1227            s.setEndingLine( head + " SECTION-END" + tailComment );
1228 
1229            return s;
1230        }
1231 
1232        private void editSourceFile( final File sourcesDirectory ) throws IOException
1233        {
1234            if ( sourcesDirectory == null )
1235            {
1236                throw new NullPointerException( "sourcesDirectory" );
1237            }
1238            if ( !sourcesDirectory.isDirectory() )
1239            {
1240                throw new IOException( getMessage( "directoryNotFound", sourcesDirectory.getAbsolutePath() ) );
1241            }
1242 
1243            final SourceFileType model = this.getSourceFileType();
1244 
1245            if ( model != null && model.getLocation() != null )
1246            {
1247                final File f = new File( sourcesDirectory, model.getLocation() );
1248 
1249                try
1250                {
1251                    String content = "";
1252                    String edited = null;
1253                    boolean creating = false;
1254 
1255                    if ( !f.exists() )
1256                    {
1257                        if ( model.getTemplate() != null )
1258                        {
1259                            final StringWriter writer = new StringWriter();
1260                            final Template template = getVelocityTemplate( model.getTemplate() );
1261                            final VelocityContext ctx = this.getVelocityContext();
1262                            ctx.put( "template", template );
1263                            template.merge( ctx, writer );
1264                            writer.close();
1265                            content = writer.toString();
1266                            creating = true;
1267                        }
1268                    }
1269                    else
1270                    {
1271                        if ( isLoggable( Level.FINER ) )
1272                        {
1273                            log( Level.FINER, getMessage( "reading", f.getAbsolutePath() ), null );
1274                        }
1275 
1276                        content = this.readSourceFile( f );
1277                    }
1278 
1279                    try
1280                    {
1281                        edited = super.edit( content );
1282                    }
1283                    catch ( final IOException e )
1284                    {
1285                        // JDK: As of JDK 6, "new IOException( message, cause )".
1286                        throw (IOException) new IOException( getMessage(
1287                            "failedEditing", f.getAbsolutePath(), getMessage( e ) ) ).initCause( e );
1288 
1289                    }
1290 
1291                    if ( !edited.equals( content ) || edited.length() == 0 )
1292                    {
1293                        if ( !f.getParentFile().exists() && !f.getParentFile().mkdirs() )
1294                        {
1295                            throw new IOException( getMessage(
1296                                "failedCreatingDirectory", f.getParentFile().getAbsolutePath() ) );
1297 
1298                        }
1299 
1300                        if ( isLoggable( Level.INFO ) )
1301                        {
1302                            log( Level.INFO, getMessage(
1303                                creating ? "creating" : "editing", f.getAbsolutePath() ), null );
1304 
1305                        }
1306 
1307                        this.writeSourceFile( f, edited );
1308                    }
1309                    else if ( isLoggable( Level.FINER ) )
1310                    {
1311                        log( Level.FINER, getMessage( "unchanged", f.getAbsolutePath() ), null );
1312                    }
1313                }
1314                catch ( final VelocityException e )
1315                {
1316                    // JDK: As of JDK 6, "new IOException( message, cause )".
1317                    throw (IOException) new IOException( getMessage(
1318                        "failedEditing", f.getAbsolutePath(), getMessage( e ) ) ).initCause( e );
1319 
1320                }
1321            }
1322        }
1323 
1324        private String readSourceFile( final File file ) throws IOException
1325        {
1326            if ( file == null )
1327            {
1328                throw new NullPointerException( "file" );
1329            }
1330 
1331            RandomAccessFile randomAccessFile = null;
1332            FileChannel fileChannel = null;
1333            FileLock fileLock = null;
1334            boolean suppressExceptionOnClose = true;
1335 
1336            //final Charset charset = Charset.forName( getInputEncoding() );
1337            final int length = file.length() > 0L ? Long.valueOf( file.length() ).intValue() : 1;
1338            final ByteBuffer buf = ByteBuffer.allocate( length );
1339            final StringBuilder appendable = new StringBuilder( length );
1340 
1341            try
1342            {
1343                randomAccessFile = new RandomAccessFile( file, "r" );
1344                fileChannel = randomAccessFile.getChannel();
1345                fileLock = fileChannel.lock( 0L, file.length(), true );
1346                fileChannel.position( 0L );
1347 
1348                buf.clear();
1349                int read = fileChannel.read( buf );
1350 
1351                while ( read != -1 )
1352                {
1353                    // JDK: As of JDK 6, new String( byte[], int, int, Charset )
1354                    appendable.append( new String( buf.array(), buf.arrayOffset(), read, getInputEncoding() ) );
1355                    buf.clear();
1356                    read = fileChannel.read( buf );
1357                }
1358 
1359                suppressExceptionOnClose = false;
1360                return appendable.toString();
1361            }
1362            finally
1363            {
1364                this.releaseAndClose( fileLock, fileChannel, randomAccessFile, suppressExceptionOnClose );
1365            }
1366        }
1367 
1368        private void writeSourceFile( final File file, final String content ) throws IOException
1369        {
1370            if ( file == null )
1371            {
1372                throw new NullPointerException( "file" );
1373            }
1374            if ( content == null )
1375            {
1376                throw new NullPointerException( "content" );
1377            }
1378 
1379            RandomAccessFile randomAccessFile = null;
1380            FileChannel fileChannel = null;
1381            FileLock fileLock = null;
1382            boolean suppressExceptionOnClose = true;
1383            final byte[] bytes = content.getBytes( getOutputEncoding() );
1384 
1385            try
1386            {
1387                randomAccessFile = new RandomAccessFile( file, "rw" );
1388                fileChannel = randomAccessFile.getChannel();
1389                fileLock = fileChannel.lock( 0L, bytes.length, false );
1390                fileChannel.truncate( bytes.length );
1391                fileChannel.position( 0L );
1392                fileChannel.write( ByteBuffer.wrap( bytes ) );
1393                fileChannel.force( true );
1394                suppressExceptionOnClose = false;
1395            }
1396            finally
1397            {
1398                this.releaseAndClose( fileLock, fileChannel, randomAccessFile, suppressExceptionOnClose );
1399            }
1400        }
1401 
1402        private void releaseAndClose( final FileLock fileLock, final FileChannel fileChannel,
1403                                      final RandomAccessFile randomAccessFile, final boolean suppressExceptions )
1404            throws IOException
1405        {
1406            try
1407            {
1408                if ( fileLock != null )
1409                {
1410                    fileLock.release();
1411                }
1412            }
1413            catch ( final IOException e )
1414            {
1415                if ( suppressExceptions )
1416                {
1417                    log( Level.SEVERE, null, e );
1418                }
1419                else
1420                {
1421                    throw e;
1422                }
1423            }
1424            finally
1425            {
1426                try
1427                {
1428                    if ( fileChannel != null )
1429                    {
1430                        fileChannel.close();
1431                    }
1432                }
1433                catch ( final IOException e )
1434                {
1435                    if ( suppressExceptions )
1436                    {
1437                        log( Level.SEVERE, null, e );
1438                    }
1439                    else
1440                    {
1441                        throw e;
1442                    }
1443                }
1444                finally
1445                {
1446                    try
1447                    {
1448                        if ( randomAccessFile != null )
1449                        {
1450                            randomAccessFile.close();
1451                        }
1452                    }
1453                    catch ( final IOException e )
1454                    {
1455                        if ( suppressExceptions )
1456                        {
1457                            log( Level.SEVERE, null, e );
1458                        }
1459                        else
1460                        {
1461                            throw e;
1462                        }
1463                    }
1464                }
1465            }
1466        }
1467 
1468    }
1469 
1470}

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