EMMA Coverage Report (generated Mon Apr 22 06:35:53 CEST 2013)
[all classes][org.jomc.tools]

COVERAGE SUMMARY FOR SOURCE FILE [ClassFileProcessor.java]

nameclass, %method, %block, %line, %
ClassFileProcessor.java100% (1/1)98%  (45/46)79%  (4231/5326)85%  (757/889)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ClassFileProcessor100% (1/1)98%  (45/46)79%  (4231/5326)85%  (757/889)
getMessage (Throwable): String 0%   (0/1)0%   (0/19)0%   (0/1)
releaseAndClose (FileLock, FileChannel, Closeable, boolean): void 100% (1/1)7%   (15/225)18%  (4.4/24)
encodeModelObject (Marshaller, JAXBElement): byte [] 100% (1/1)60%  (32/53)64%  (9/14)
decodeModelObject (Unmarshaller, byte [], Class): ModelObject 100% (1/1)67%  (42/63)69%  (11/16)
validateModelObjects (Implementation, Unmarshaller, JavaClass): ModelValidati... 100% (1/1)71%  (684/962)83%  (84/101)
validateModelObjects (Implementation, Unmarshaller, ModelContext): ModelValid... 100% (1/1)73%  (91/124)70%  (17.6/25)
validateModelObjects (Specification, Unmarshaller, ModelContext): ModelValida... 100% (1/1)73%  (91/124)70%  (17.6/25)
commitModelObjects (Implementation, Marshaller, JavaClass): void 100% (1/1)74%  (187/252)82%  (32.7/40)
transformModelObjects (Implementation, Marshaller, Unmarshaller, File, List):... 100% (1/1)75%  (80/106)87%  (13/15)
transformModelObjects (Specification, Marshaller, Unmarshaller, File, List): ... 100% (1/1)75%  (80/106)87%  (13/15)
transformModelObjects (Specification, Marshaller, Unmarshaller, JavaClass, Li... 100% (1/1)79%  (158/200)75%  (30/40)
validateModelObjects (Specification, Unmarshaller, JavaClass): ModelValidatio... 100% (1/1)80%  (192/240)93%  (24.1/26)
readJavaClass (File): JavaClass 100% (1/1)83%  (43/52)98%  (10.8/11)
validateModelObjects (ModelContext): ModelValidationReport 100% (1/1)85%  (57/67)85%  (11/13)
commitModelObjects (ModelContext, File): void 100% (1/1)86%  (61/71)87%  (13/15)
validateModelObjects (Implementation, ModelContext): ModelValidationReport 100% (1/1)86%  (64/74)87%  (13/15)
validateModelObjects (ModelContext, File): ModelValidationReport 100% (1/1)86%  (64/74)87%  (13/15)
validateModelObjects (Specification, ModelContext): ModelValidationReport 100% (1/1)86%  (64/74)87%  (13/15)
writeJavaClass (JavaClass, File): void 100% (1/1)87%  (60/69)99%  (18.9/19)
validateModelObjects (Module, ModelContext): ModelValidationReport 100% (1/1)87%  (67/77)87%  (13/15)
commitModelObjects (Implementation, ModelContext, File): void 100% (1/1)87%  (68/78)88%  (15/17)
commitModelObjects (Specification, ModelContext, File): void 100% (1/1)87%  (68/78)88%  (15/17)
commitModelObjects (Implementation, Marshaller, File): void 100% (1/1)88%  (91/104)93%  (14/15)
commitModelObjects (Specification, Marshaller, File): void 100% (1/1)88%  (91/104)93%  (14/15)
commitModelObjects (Module, ModelContext, File): void 100% (1/1)88%  (71/81)88%  (15/17)
validateModelObjects (Implementation, ModelContext, File): ModelValidationReport 100% (1/1)88%  (71/81)88%  (15/17)
validateModelObjects (Specification, ModelContext, File): ModelValidationReport 100% (1/1)88%  (71/81)88%  (15/17)
validateModelObjects (Implementation, Unmarshaller, File): ModelValidationReport 100% (1/1)88%  (94/107)93%  (14/15)
validateModelObjects (Specification, Unmarshaller, File): ModelValidationReport 100% (1/1)88%  (94/107)93%  (14/15)
validateModelObjects (Module, ModelContext, File): ModelValidationReport 100% (1/1)88%  (74/84)88%  (15/17)
transformModelObjects (Implementation, Marshaller, Unmarshaller, JavaClass, L... 100% (1/1)90%  (399/441)88%  (71/81)
transformModelObjects (ModelContext, File, List): void 100% (1/1)91%  (97/107)91%  (20/22)
transformModelObjects (Implementation, ModelContext, File, List): void 100% (1/1)91%  (104/114)92%  (22/24)
transformModelObjects (Specification, ModelContext, File, List): void 100% (1/1)91%  (104/114)92%  (22/24)
transformModelObjects (Module, ModelContext, File, List): void 100% (1/1)91%  (107/117)92%  (22/24)
setClassfileAttribute (JavaClass, String, byte []): void 100% (1/1)99%  (138/139)100% (29.9/30)
<static initializer> 100% (1/1)100% (4/4)100% (1/1)
ClassFileProcessor (): void 100% (1/1)100% (3/3)100% (2/2)
ClassFileProcessor (ClassFileProcessor): void 100% (1/1)100% (4/4)100% (2/2)
commitModelObjects (Specification, Marshaller, JavaClass): void 100% (1/1)100% (62/62)100% (11/11)
commitModelObjects (Specifications, Implementations, Marshaller, File): void 100% (1/1)100% (43/43)100% (7/7)
getClassfileAttribute (JavaClass, String): byte [] 100% (1/1)100% (53/53)100% (11/11)
getMessage (String, Object []): String 100% (1/1)100% (11/11)100% (1/1)
transformModelObjects (Specifications, Implementations, Unmarshaller, Marshal... 100% (1/1)100% (49/49)100% (7/7)
validateModelObjects (Specifications, Implementations, Unmarshaller, File): M... 100% (1/1)100% (64/64)100% (10/10)
validateModelObjects (Specifications, Implementations, Unmarshaller, ModelCon... 100% (1/1)100% (64/64)100% (10/10)

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: ClassFileProcessor.java 4760 2013-04-08 17:56:26Z schulte $
29 *
30 */
31package org.jomc.tools;
32 
33import java.io.ByteArrayInputStream;
34import java.io.ByteArrayOutputStream;
35import java.io.Closeable;
36import java.io.File;
37import java.io.FileInputStream;
38import java.io.IOException;
39import java.io.InputStream;
40import java.io.RandomAccessFile;
41import java.net.URL;
42import java.nio.ByteBuffer;
43import java.nio.channels.FileChannel;
44import java.nio.channels.FileLock;
45import java.text.MessageFormat;
46import java.util.List;
47import java.util.ResourceBundle;
48import java.util.logging.Level;
49import java.util.zip.GZIPInputStream;
50import java.util.zip.GZIPOutputStream;
51import javax.xml.bind.JAXBElement;
52import javax.xml.bind.JAXBException;
53import javax.xml.bind.Marshaller;
54import javax.xml.bind.Unmarshaller;
55import javax.xml.bind.util.JAXBResult;
56import javax.xml.bind.util.JAXBSource;
57import javax.xml.transform.Transformer;
58import javax.xml.transform.TransformerException;
59import javax.xml.validation.Schema;
60import org.apache.bcel.classfile.Attribute;
61import org.apache.bcel.classfile.ClassParser;
62import org.apache.bcel.classfile.Constant;
63import org.apache.bcel.classfile.ConstantPool;
64import org.apache.bcel.classfile.ConstantUtf8;
65import org.apache.bcel.classfile.JavaClass;
66import org.apache.bcel.classfile.Unknown;
67import org.jomc.model.Dependencies;
68import org.jomc.model.Dependency;
69import org.jomc.model.Implementation;
70import org.jomc.model.Implementations;
71import org.jomc.model.Message;
72import org.jomc.model.Messages;
73import org.jomc.model.ModelObject;
74import org.jomc.model.Module;
75import org.jomc.model.ObjectFactory;
76import org.jomc.model.Properties;
77import org.jomc.model.Property;
78import org.jomc.model.Specification;
79import org.jomc.model.SpecificationReference;
80import org.jomc.model.Specifications;
81import org.jomc.modlet.ModelContext;
82import org.jomc.modlet.ModelException;
83import org.jomc.modlet.ModelValidationReport;
84import org.jomc.util.ParseException;
85import org.jomc.util.TokenMgrError;
86import org.jomc.util.VersionParser;
87 
88/**
89 * Processes class files.
90 *
91 * <p><b>Use Cases:</b><br/><ul>
92 * <li>{@link #commitModelObjects(org.jomc.modlet.ModelContext, java.io.File) }</li>
93 * <li>{@link #commitModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) }</li>
94 * <li>{@link #commitModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) }</li>
95 * <li>{@link #commitModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) }</li>
96 * <li>{@link #validateModelObjects(org.jomc.modlet.ModelContext) }</li>
97 * <li>{@link #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext) }</li>
98 * <li>{@link #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext) }</li>
99 * <li>{@link #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext) }</li>
100 * <li>{@link #validateModelObjects(org.jomc.modlet.ModelContext, java.io.File) }</li>
101 * <li>{@link #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) }</li>
102 * <li>{@link #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) }</li>
103 * <li>{@link #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) }</li>
104 * <li>{@link #transformModelObjects(org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
105 * <li>{@link #transformModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
106 * <li>{@link #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
107 * <li>{@link #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
108 * </ul></p>
109 *
110 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
111 * @version $JOMC: ClassFileProcessor.java 4760 2013-04-08 17:56:26Z schulte $
112 *
113 * @see #getModules()
114 */
115public class ClassFileProcessor extends JomcTool
116{
117 
118    /** Empty byte array. */
119    private static final byte[] NO_BYTES =
120    {
121    };
122 
123    /** Creates a new {@code ClassFileProcessor} instance. */
124    public ClassFileProcessor()
125    {
126        super();
127    }
128 
129    /**
130     * Creates a new {@code ClassFileProcessor} instance taking a {@code ClassFileProcessor} instance to initialize the
131     * instance with.
132     *
133     * @param tool The instance to initialize the new instance with.
134     *
135     * @throws NullPointerException if {@code tool} is {@code null}.
136     * @throws IOException if copying {@code tool} fails.
137     */
138    public ClassFileProcessor( final ClassFileProcessor tool ) throws IOException
139    {
140        super( tool );
141    }
142 
143    /**
144     * Commits model objects of the modules of the instance to class files.
145     *
146     * @param context The model context to use for committing the model objects.
147     * @param classesDirectory The directory holding the class files.
148     *
149     * @throws NullPointerException if {@code context} or {@code classesDirectory} is {@code null}.
150     * @throws IOException if committing model objects fails.
151     *
152     * @see #commitModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File)
153     */
154    public final void commitModelObjects( final ModelContext context, final File classesDirectory ) throws IOException
155    {
156        if ( context == null )
157        {
158            throw new NullPointerException( "context" );
159        }
160        if ( classesDirectory == null )
161        {
162            throw new NullPointerException( "classesDirectory" );
163        }
164 
165        try
166        {
167            if ( this.getModules() != null )
168            {
169                final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
170                m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
171 
172                this.commitModelObjects( this.getModules().getSpecifications(), this.getModules().getImplementations(),
173                                         m, classesDirectory );
174 
175            }
176            else if ( this.isLoggable( Level.WARNING ) )
177            {
178                this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
179            }
180        }
181        catch ( final ModelException e )
182        {
183            // JDK: As of JDK 6, "new IOException( message, cause )".
184            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
185        }
186    }
187 
188    /**
189     * Commits model objects of a given module of the modules of the instance to class files.
190     *
191     * @param module The module to process.
192     * @param context The model context to use for committing the model objects.
193     * @param classesDirectory The directory holding the class files.
194     *
195     * @throws NullPointerException if {@code module}, {@code context} or {@code classesDirectory} is {@code null}.
196     * @throws IOException if committing model objects fails.
197     *
198     * @see #commitModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File)
199     * @see #commitModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File)
200     */
201    public final void commitModelObjects( final Module module, final ModelContext context, final File classesDirectory )
202        throws IOException
203    {
204        if ( module == null )
205        {
206            throw new NullPointerException( "module" );
207        }
208        if ( context == null )
209        {
210            throw new NullPointerException( "context" );
211        }
212        if ( classesDirectory == null )
213        {
214            throw new NullPointerException( "classesDirectory" );
215        }
216 
217        try
218        {
219            if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
220            {
221                final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
222                m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
223 
224                this.commitModelObjects( module.getSpecifications(), module.getImplementations(), m, classesDirectory );
225            }
226            else if ( this.isLoggable( Level.WARNING ) )
227            {
228                this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
229            }
230        }
231        catch ( final ModelException e )
232        {
233            // JDK: As of JDK 6, "new IOException( message, cause )".
234            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
235        }
236    }
237 
238    /**
239     * Commits model objects of a given specification of the modules of the instance to class files.
240     *
241     * @param specification The specification to process.
242     * @param context The model context to use for committing the model objects.
243     * @param classesDirectory The directory holding the class files.
244     *
245     * @throws NullPointerException if {@code specification}, {@code context} or {@code classesDirectory} is
246     * {@code null}.
247     * @throws IOException if committing model objects fails.
248     *
249     * @see #commitModelObjects(org.jomc.model.Specification, javax.xml.bind.Marshaller, org.apache.bcel.classfile.JavaClass)
250     */
251    public final void commitModelObjects( final Specification specification, final ModelContext context,
252                                          final File classesDirectory ) throws IOException
253    {
254        if ( specification == null )
255        {
256            throw new NullPointerException( "specification" );
257        }
258        if ( context == null )
259        {
260            throw new NullPointerException( "context" );
261        }
262        if ( classesDirectory == null )
263        {
264            throw new NullPointerException( "classesDirectory" );
265        }
266 
267        try
268        {
269            if ( this.getModules() != null
270                 && this.getModules().getSpecification( specification.getIdentifier() ) != null )
271            {
272                final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
273                m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
274 
275                this.commitModelObjects( specification, m, classesDirectory );
276            }
277            else if ( this.isLoggable( Level.WARNING ) )
278            {
279                this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
280            }
281        }
282        catch ( final ModelException e )
283        {
284            // JDK: As of JDK 6, "new IOException( message, cause )".
285            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
286        }
287    }
288 
289    /**
290     * Commits model objects of a given implementation of the modules of the instance to class files.
291     *
292     * @param implementation The implementation to process.
293     * @param context The model context to use for committing the model objects.
294     * @param classesDirectory The directory holding the class files.
295     *
296     * @throws NullPointerException if {@code implementation}, {@code context} or {@code classesDirectory} is
297     * {@code null}.
298     * @throws IOException if committing model objects fails.
299     *
300     * @see #commitModelObjects(org.jomc.model.Implementation, javax.xml.bind.Marshaller, org.apache.bcel.classfile.JavaClass)
301     */
302    public final void commitModelObjects( final Implementation implementation, final ModelContext context,
303                                          final File classesDirectory ) throws IOException
304    {
305        if ( implementation == null )
306        {
307            throw new NullPointerException( "implementation" );
308        }
309        if ( context == null )
310        {
311            throw new NullPointerException( "context" );
312        }
313        if ( classesDirectory == null )
314        {
315            throw new NullPointerException( "classesDirectory" );
316        }
317 
318        try
319        {
320            if ( this.getModules() != null
321                 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
322            {
323                final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
324                m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
325 
326                this.commitModelObjects( implementation, m, classesDirectory );
327            }
328            else if ( this.isLoggable( Level.WARNING ) )
329            {
330                this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
331            }
332        }
333        catch ( final ModelException e )
334        {
335            // JDK: As of JDK 6, "new IOException( message, cause )".
336            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
337        }
338    }
339 
340    /**
341     * Commits model objects of a given specification of the modules of the instance to a given class file.
342     *
343     * @param specification The specification to process.
344     * @param marshaller The marshaller to use for committing the model objects.
345     * @param javaClass The java class to commit to.
346     *
347     * @throws NullPointerException if {@code specification}, {@code marshaller} or {@code javaClass} is {@code null}.
348     * @throws IOException if committing model objects fails.
349     */
350    public void commitModelObjects( final Specification specification, final Marshaller marshaller,
351                                    final JavaClass javaClass ) throws IOException
352    {
353        if ( specification == null )
354        {
355            throw new NullPointerException( "specification" );
356        }
357        if ( marshaller == null )
358        {
359            throw new NullPointerException( "marshaller" );
360        }
361        if ( javaClass == null )
362        {
363            throw new NullPointerException( "javaClass" );
364        }
365 
366        if ( this.getModules() != null
367             && this.getModules().getSpecification( specification.getIdentifier() ) != null )
368        {
369            this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject(
370                marshaller, new ObjectFactory().createSpecification( specification ) ) );
371 
372        }
373        else if ( this.isLoggable( Level.WARNING ) )
374        {
375            this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
376        }
377    }
378 
379    /**
380     * Commits model objects of a given implementation of the modules of the instance to a given class file.
381     *
382     * @param implementation The implementation to process.
383     * @param marshaller The marshaller to use for committing the model objects.
384     * @param javaClass The java class to commit to.
385     *
386     * @throws NullPointerException if {@code implementation}, {@code marshaller} or {@code javaClass} is {@code null}.
387     * @throws IOException if committing model objects fails.
388     */
389    public void commitModelObjects( final Implementation implementation, final Marshaller marshaller,
390                                    final JavaClass javaClass ) throws IOException
391    {
392        if ( implementation == null )
393        {
394            throw new NullPointerException( "implementation" );
395        }
396        if ( marshaller == null )
397        {
398            throw new NullPointerException( "marshaller" );
399        }
400        if ( javaClass == null )
401        {
402            throw new NullPointerException( "javaClass" );
403        }
404 
405        if ( this.getModules() != null
406             && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
407        {
408            final ObjectFactory of = new ObjectFactory();
409 
410            Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() );
411            if ( dependencies == null )
412            {
413                dependencies = new Dependencies();
414            }
415 
416            Properties properties = this.getModules().getProperties( implementation.getIdentifier() );
417            if ( properties == null )
418            {
419                properties = new Properties();
420            }
421 
422            Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
423            if ( messages == null )
424            {
425                messages = new Messages();
426            }
427 
428            Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() );
429            if ( specifications == null )
430            {
431                specifications = new Specifications();
432            }
433 
434            for ( int i = 0, s0 = specifications.getReference().size(); i < s0; i++ )
435            {
436                final SpecificationReference r = specifications.getReference().get( i );
437 
438                if ( specifications.getSpecification( r.getIdentifier() ) == null && this.isLoggable( Level.WARNING ) )
439                {
440                    this.log( Level.WARNING, getMessage( "unresolvedSpecification", r.getIdentifier(),
441                                                         implementation.getIdentifier() ), null );
442 
443                }
444            }
445 
446            for ( int i = 0, s0 = dependencies.getDependency().size(); i < s0; i++ )
447            {
448                final Dependency d = dependencies.getDependency().get( i );
449                final Specification s = this.getModules().getSpecification( d.getIdentifier() );
450 
451                if ( s != null )
452                {
453                    if ( specifications.getSpecification( s.getIdentifier() ) == null )
454                    {
455                        specifications.getSpecification().add( s );
456                    }
457                }
458                else if ( this.isLoggable( Level.WARNING ) )
459                {
460                    this.log( Level.WARNING, getMessage( "unresolvedDependencySpecification", d.getIdentifier(),
461                                                         d.getName(), implementation.getIdentifier() ), null );
462 
463                }
464            }
465 
466            this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject(
467                marshaller, of.createDependencies( dependencies ) ) );
468 
469            this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject(
470                marshaller, of.createProperties( properties ) ) );
471 
472            this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject(
473                marshaller, of.createMessages( messages ) ) );
474 
475            this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject(
476                marshaller, of.createSpecifications( specifications ) ) );
477 
478        }
479        else if ( this.isLoggable( Level.WARNING ) )
480        {
481            this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
482        }
483    }
484 
485    /**
486     * Validates model objects of class files of the modules of the instance.
487     *
488     * @param context The model context to use for validating model objects.
489     *
490     * @return The report of the validation or {@code null}, if no model objects are found.
491     *
492     * @throws NullPointerException if {@code context} is {@code null}.
493     * @throws IOException if validating model objects fails.
494     *
495     * @see #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext)
496     */
497    public final ModelValidationReport validateModelObjects( final ModelContext context ) throws IOException
498    {
499        if ( context == null )
500        {
501            throw new NullPointerException( "context" );
502        }
503 
504        try
505        {
506            ModelValidationReport report = null;
507 
508            if ( this.getModules() != null )
509            {
510                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
511                u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
512                report = this.validateModelObjects( this.getModules().getSpecifications(),
513                                                    this.getModules().getImplementations(), u, context );
514 
515            }
516            else if ( this.isLoggable( Level.WARNING ) )
517            {
518                this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
519            }
520 
521            return report;
522        }
523        catch ( final ModelException e )
524        {
525            // JDK: As of JDK 6, "new IOException( message, cause )".
526            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
527        }
528    }
529 
530    /**
531     * Validates model objects of class files of a given module of the modules of the instance.
532     *
533     * @param module The module to process.
534     * @param context The model context to use for validating model objects.
535     *
536     * @return The report of the validation or {@code null}, if no model objects are found.
537     *
538     * @throws NullPointerException if {@code module} or {@code context} is {@code null}.
539     * @throws IOException if validating model objects fails.
540     *
541     * @see #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext)
542     * @see #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext)
543     */
544    public final ModelValidationReport validateModelObjects( final Module module, final ModelContext context )
545        throws IOException
546    {
547        if ( module == null )
548        {
549            throw new NullPointerException( "module" );
550        }
551        if ( context == null )
552        {
553            throw new NullPointerException( "context" );
554        }
555 
556        try
557        {
558            ModelValidationReport report = null;
559 
560            if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
561            {
562                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
563                u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
564                report = this.validateModelObjects( module.getSpecifications(), module.getImplementations(), u,
565                                                    context );
566 
567            }
568            else if ( this.isLoggable( Level.WARNING ) )
569            {
570                this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
571            }
572 
573            return report;
574        }
575        catch ( final ModelException e )
576        {
577            // JDK: As of JDK 6, "new IOException( message, cause )".
578            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
579        }
580    }
581 
582    /**
583     * Validates model objects of class files of a given specification of the modules of the instance.
584     *
585     * @param specification The specification to process.
586     * @param context The model context to use for validating model objects.
587     *
588     * @return The report of the validation or {@code null}, if no model objects are found.
589     *
590     * @throws NullPointerException if {@code specification} or {@code context} is {@code null}.
591     *
592     * @throws IOException if validating model objects fails.
593     *
594     * @see #validateModelObjects(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
595     */
596    public final ModelValidationReport validateModelObjects( final Specification specification,
597                                                             final ModelContext context ) throws IOException
598    {
599        if ( specification == null )
600        {
601            throw new NullPointerException( "specification" );
602        }
603        if ( context == null )
604        {
605            throw new NullPointerException( "context" );
606        }
607 
608        try
609        {
610            ModelValidationReport report = null;
611 
612            if ( this.getModules() != null
613                 && this.getModules().getSpecification( specification.getIdentifier() ) != null )
614            {
615                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
616                u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
617                report = this.validateModelObjects( specification, u, context );
618            }
619            else if ( this.isLoggable( Level.WARNING ) )
620            {
621                this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
622            }
623 
624            return report;
625        }
626        catch ( final ModelException e )
627        {
628            // JDK: As of JDK 6, "new IOException( message, cause )".
629            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
630        }
631    }
632 
633    /**
634     * Validates model objects of class files of a given implementation of the modules of the instance.
635     *
636     * @param implementation The implementation to process.
637     * @param context The model context to use for validating model objects.
638     *
639     * @return The report of the validation or {@code null}, if no model objects are found.
640     *
641     * @throws NullPointerException if {@code implementation} or {@code context} is {@code null}.
642     *
643     * @throws IOException if validating model objects fails.
644     *
645     * @see #validateModelObjects(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
646     */
647    public final ModelValidationReport validateModelObjects( final Implementation implementation,
648                                                             final ModelContext context ) throws IOException
649    {
650        if ( implementation == null )
651        {
652            throw new NullPointerException( "implementation" );
653        }
654        if ( context == null )
655        {
656            throw new NullPointerException( "context" );
657        }
658 
659        try
660        {
661            ModelValidationReport report = null;
662 
663            if ( this.getModules() != null
664                 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
665            {
666                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
667                u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
668                report = this.validateModelObjects( implementation, u, context );
669            }
670            else if ( this.isLoggable( Level.WARNING ) )
671            {
672                this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
673            }
674 
675            return report;
676        }
677        catch ( final ModelException e )
678        {
679            // JDK: As of JDK 6, "new IOException( message, cause )".
680            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
681        }
682    }
683 
684    /**
685     * Validates model objects of class files of the modules of the instance.
686     *
687     * @param context The model context to use for validating model objects.
688     * @param classesDirectory The directory holding the class files.
689     *
690     * @return The report of the validation or {@code null}, if no model objects are found.
691     *
692     * @throws NullPointerException if {@code context} or {@code classesDirectory} is {@code null}.
693     * @throws IOException if validating model objects fails.
694     *
695     * @see #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File)
696     */
697    public final ModelValidationReport validateModelObjects( final ModelContext context, final File classesDirectory )
698        throws IOException
699    {
700        if ( context == null )
701        {
702            throw new NullPointerException( "context" );
703        }
704        if ( classesDirectory == null )
705        {
706            throw new NullPointerException( "classesDirectory" );
707        }
708 
709        try
710        {
711            ModelValidationReport report = null;
712 
713            if ( this.getModules() != null )
714            {
715                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
716                u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
717                report = this.validateModelObjects( this.getModules().getSpecifications(),
718                                                    this.getModules().getImplementations(), u, classesDirectory );
719 
720            }
721            else if ( this.isLoggable( Level.WARNING ) )
722            {
723                this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
724            }
725 
726            return report;
727        }
728        catch ( final ModelException e )
729        {
730            // JDK: As of JDK 6, "new IOException( message, cause )".
731            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
732        }
733    }
734 
735    /**
736     * Validates model objects of class files of a given module of the modules of the instance.
737     *
738     * @param module The module to process.
739     * @param context The model context to use for validating model objects.
740     * @param classesDirectory The directory holding the class files.
741     *
742     * @return The report of the validation or {@code null}, if no model objects are found.
743     *
744     * @throws NullPointerException if {@code module}, {@code context} or {@code classesDirectory} is {@code null}.
745     * @throws IOException if validating model objects fails.
746     *
747     * @see #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File)
748     * @see #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File)
749     */
750    public final ModelValidationReport validateModelObjects( final Module module, final ModelContext context,
751                                                             final File classesDirectory ) throws IOException
752    {
753        if ( module == null )
754        {
755            throw new NullPointerException( "module" );
756        }
757        if ( context == null )
758        {
759            throw new NullPointerException( "context" );
760        }
761        if ( classesDirectory == null )
762        {
763            throw new NullPointerException( "classesDirectory" );
764        }
765 
766        try
767        {
768            ModelValidationReport report = null;
769 
770            if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
771            {
772                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
773                u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
774                report = this.validateModelObjects( module.getSpecifications(), module.getImplementations(), u,
775                                                    classesDirectory );
776 
777            }
778            else if ( this.isLoggable( Level.WARNING ) )
779            {
780                this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
781            }
782 
783            return report;
784        }
785        catch ( final ModelException e )
786        {
787            // JDK: As of JDK 6, "new IOException( message, cause )".
788            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
789        }
790    }
791 
792    /**
793     * Validates model objects of class files of a given specification of the modules of the instance.
794     *
795     * @param specification The specification to process.
796     * @param context The model context to use for validating model objects.
797     * @param classesDirectory The directory holding the class files.
798     *
799     * @return The report of the validation or {@code null}, if no model objects are found.
800     *
801     * @throws NullPointerException if {@code specification}, {@code context} or {@code classesDirectory} is
802     * {@code null}.
803     *
804     * @throws IOException if validating model objects fails.
805     *
806     * @see #validateModelObjects(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
807     */
808    public final ModelValidationReport validateModelObjects( final Specification specification,
809                                                             final ModelContext context, final File classesDirectory )
810        throws IOException
811    {
812        if ( specification == null )
813        {
814            throw new NullPointerException( "specification" );
815        }
816        if ( context == null )
817        {
818            throw new NullPointerException( "context" );
819        }
820        if ( classesDirectory == null )
821        {
822            throw new NullPointerException( "classesDirectory" );
823        }
824 
825        try
826        {
827            ModelValidationReport report = null;
828 
829            if ( this.getModules() != null
830                 && this.getModules().getSpecification( specification.getIdentifier() ) != null )
831            {
832                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
833                u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
834                report = this.validateModelObjects( specification, u, classesDirectory );
835            }
836            else if ( this.isLoggable( Level.WARNING ) )
837            {
838                this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
839            }
840 
841            return report;
842        }
843        catch ( final ModelException e )
844        {
845            // JDK: As of JDK 6, "new IOException( message, cause )".
846            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
847        }
848    }
849 
850    /**
851     * Validates model objects of class files of a given implementation of the modules of the instance.
852     *
853     * @param implementation The implementation to process.
854     * @param context The model context to use for validating model objects.
855     * @param classesDirectory The directory holding the class files.
856     *
857     * @return The report of the validation or {@code null}, if no model objects are found.
858     *
859     * @throws NullPointerException if {@code implementation}, {@code context} or {@code classesDirectory} is
860     * {@code null}.
861     *
862     * @throws IOException if validating model objects fails.
863     *
864     * @see #validateModelObjects(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
865     */
866    public final ModelValidationReport validateModelObjects( final Implementation implementation,
867                                                             final ModelContext context, final File classesDirectory )
868        throws IOException
869    {
870        if ( implementation == null )
871        {
872            throw new NullPointerException( "implementation" );
873        }
874        if ( context == null )
875        {
876            throw new NullPointerException( "context" );
877        }
878        if ( classesDirectory == null )
879        {
880            throw new NullPointerException( "classesDirectory" );
881        }
882 
883        try
884        {
885            ModelValidationReport report = null;
886 
887            if ( this.getModules() != null
888                 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
889            {
890                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
891                u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
892                report = this.validateModelObjects( implementation, u, classesDirectory );
893            }
894            else if ( this.isLoggable( Level.WARNING ) )
895            {
896                this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
897            }
898 
899            return report;
900        }
901        catch ( final ModelException e )
902        {
903            // JDK: As of JDK 6, "new IOException( message, cause )".
904            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
905        }
906    }
907 
908    /**
909     * Validates model objects of a given specification of the modules of the instance.
910     *
911     * @param specification The specification to process.
912     * @param unmarshaller The unmarshaller to use for validating model objects.
913     * @param javaClass The java class to validate.
914     *
915     * @return The report of the validation or {@code null}, if no model objects are found.
916     *
917     * @throws NullPointerException if {@code specification}, {@code unmarshaller} or {@code javaClass} is {@code null}.
918     * @throws IOException if validating model objects fails.
919     */
920    public ModelValidationReport validateModelObjects( final Specification specification,
921                                                       final Unmarshaller unmarshaller, final JavaClass javaClass )
922        throws IOException
923    {
924        if ( specification == null )
925        {
926            throw new NullPointerException( "specification" );
927        }
928        if ( unmarshaller == null )
929        {
930            throw new NullPointerException( "unmarshaller" );
931        }
932        if ( javaClass == null )
933        {
934            throw new NullPointerException( "javaClass" );
935        }
936 
937        ModelValidationReport report = null;
938 
939        if ( this.getModules() != null && this.getModules().getSpecification( specification.getIdentifier() ) != null )
940        {
941            report = new ModelValidationReport();
942 
943            Specification decoded = null;
944            final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() );
945            if ( bytes != null )
946            {
947                decoded = this.decodeModelObject( unmarshaller, bytes, Specification.class );
948            }
949 
950            if ( decoded != null )
951            {
952                if ( decoded.getMultiplicity() != specification.getMultiplicity() )
953                {
954                    report.getDetails().add( new ModelValidationReport.Detail(
955                        "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage(
956                        "illegalMultiplicity", specification.getIdentifier(), specification.getMultiplicity().value(),
957                        decoded.getMultiplicity().value() ),
958                        new ObjectFactory().createSpecification( specification ) ) );
959 
960                }
961 
962                if ( decoded.getScope() == null
963                     ? specification.getScope() != null
964                     : !decoded.getScope().equals( specification.getScope() ) )
965                {
966                    report.getDetails().add( new ModelValidationReport.Detail(
967                        "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage(
968                        "illegalScope", specification.getIdentifier(),
969                        specification.getScope() == null ? "Multiton" : specification.getScope(),
970                        decoded.getScope() == null ? "Multiton" : decoded.getScope() ),
971                        new ObjectFactory().createSpecification( specification ) ) );
972 
973                }
974 
975                if ( decoded.getClazz() == null
976                     ? specification.getClazz() != null
977                     : !decoded.getClazz().equals( specification.getClazz() ) )
978                {
979                    report.getDetails().add( new ModelValidationReport.Detail(
980                        "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage(
981                        "illegalSpecificationClass", decoded.getIdentifier(),
982                        specification.getClazz(), decoded.getClazz() ),
983                        new ObjectFactory().createSpecification( specification ) ) );
984 
985                }
986            }
987            else if ( this.isLoggable( Level.WARNING ) )
988            {
989                this.log( Level.WARNING, getMessage( "cannotValidateSpecification", specification.getIdentifier(),
990                                                     Specification.class.getName() ), null );
991 
992            }
993        }
994        else if ( this.isLoggable( Level.WARNING ) )
995        {
996            this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
997        }
998 
999        return report;
1000    }
1001 
1002    /**
1003     * Validates model objects of a given implementation of the modules of the instance.
1004     *
1005     * @param implementation The implementation to process.
1006     * @param unmarshaller The unmarshaller to use for validating model objects.
1007     * @param javaClass The java class to validate.
1008     *
1009     * @return The report of the validation or {@code null}, if no model objects are found.
1010     *
1011     * @throws NullPointerException if {@code implementation}, {@code unmarshaller} or {@code javaClass} is {@code null}.
1012     * @throws IOException if validating model objects fails.
1013     */
1014    public ModelValidationReport validateModelObjects( final Implementation implementation,
1015                                                       final Unmarshaller unmarshaller, final JavaClass javaClass )
1016        throws IOException
1017    {
1018        if ( implementation == null )
1019        {
1020            throw new NullPointerException( "implementation" );
1021        }
1022        if ( unmarshaller == null )
1023        {
1024            throw new NullPointerException( "unmarshaller" );
1025        }
1026        if ( javaClass == null )
1027        {
1028            throw new NullPointerException( "javaClass" );
1029        }
1030 
1031        try
1032        {
1033            ModelValidationReport report = null;
1034 
1035            if ( this.getModules() != null
1036                 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
1037            {
1038                report = new ModelValidationReport();
1039                Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() );
1040                if ( dependencies == null )
1041                {
1042                    dependencies = new Dependencies();
1043                }
1044 
1045                Properties properties = this.getModules().getProperties( implementation.getIdentifier() );
1046                if ( properties == null )
1047                {
1048                    properties = new Properties();
1049                }
1050 
1051                Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
1052                if ( messages == null )
1053                {
1054                    messages = new Messages();
1055                }
1056 
1057                Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() );
1058                if ( specifications == null )
1059                {
1060                    specifications = new Specifications();
1061                }
1062 
1063                Dependencies decodedDependencies = null;
1064                byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() );
1065                if ( bytes != null )
1066                {
1067                    decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class );
1068                }
1069 
1070                Properties decodedProperties = null;
1071                bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() );
1072                if ( bytes != null )
1073                {
1074                    decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class );
1075                }
1076 
1077                Messages decodedMessages = null;
1078                bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() );
1079                if ( bytes != null )
1080                {
1081                    decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class );
1082                }
1083 
1084                Specifications decodedSpecifications = null;
1085                bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() );
1086                if ( bytes != null )
1087                {
1088                    decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class );
1089                }
1090 
1091                if ( decodedDependencies != null )
1092                {
1093                    for ( int i = 0, s0 = decodedDependencies.getDependency().size(); i < s0; i++ )
1094                    {
1095                        final Dependency decodedDependency = decodedDependencies.getDependency().get( i );
1096                        final Dependency dependency = dependencies.getDependency( decodedDependency.getName() );
1097                        final Specification s = this.getModules().getSpecification( decodedDependency.getIdentifier() );
1098 
1099                        if ( dependency == null )
1100                        {
1101                            report.getDetails().add( new ModelValidationReport.Detail(
1102                                "CLASS_MISSING_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage(
1103                                "missingDependency", implementation.getIdentifier(), decodedDependency.getName() ),
1104                                new ObjectFactory().createImplementation( implementation ) ) );
1105 
1106                        }
1107                        else if ( decodedDependency.getImplementationName() != null
1108                                  && dependency.getImplementationName() == null )
1109                        {
1110                            report.getDetails().add( new ModelValidationReport.Detail(
1111                                "CLASS_MISSING_DEPENDENCY_IMPLEMENTATION_NAME", Level.SEVERE, getMessage(
1112                                "missingDependencyImplementationName", implementation.getIdentifier(),
1113                                decodedDependency.getName() ),
1114                                new ObjectFactory().createImplementation( implementation ) ) );
1115 
1116                        }
1117 
1118                        if ( s != null && s.getVersion() != null && decodedDependency.getVersion() != null
1119                             && VersionParser.compare( decodedDependency.getVersion(), s.getVersion() ) > 0 )
1120                        {
1121                            final Module moduleOfSpecification =
1122                                this.getModules().getModuleOfSpecification( s.getIdentifier() );
1123 
1124                            final Module moduleOfImplementation =
1125                                this.getModules().getModuleOfImplementation( implementation.getIdentifier() );
1126 
1127                            report.getDetails().add( new ModelValidationReport.Detail(
1128                                "CLASS_INCOMPATIBLE_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage(
1129                                "incompatibleDependency", javaClass.getClassName(),
1130                                moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(),
1131                                s.getIdentifier(),
1132                                moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(),
1133                                decodedDependency.getVersion(), s.getVersion() ),
1134                                new ObjectFactory().createImplementation( implementation ) ) );
1135 
1136                        }
1137                    }
1138                }
1139                else if ( this.isLoggable( Level.WARNING ) )
1140                {
1141                    this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
1142                                                         Dependencies.class.getName() ), null );
1143 
1144                }
1145 
1146                if ( decodedProperties != null )
1147                {
1148                    for ( int i = 0, s0 = decodedProperties.getProperty().size(); i < s0; i++ )
1149                    {
1150                        final Property decodedProperty = decodedProperties.getProperty().get( i );
1151                        final Property property = properties.getProperty( decodedProperty.getName() );
1152 
1153                        if ( property == null )
1154                        {
1155                            report.getDetails().add( new ModelValidationReport.Detail(
1156                                "CLASS_MISSING_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage(
1157                                "missingProperty", implementation.getIdentifier(), decodedProperty.getName() ),
1158                                new ObjectFactory().createImplementation( implementation ) ) );
1159 
1160                        }
1161                        else if ( decodedProperty.getType() == null
1162                                  ? property.getType() != null
1163                                  : !decodedProperty.getType().equals( property.getType() ) )
1164                        {
1165                            report.getDetails().add( new ModelValidationReport.Detail(
1166                                "CLASS_ILLEGAL_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage(
1167                                "illegalPropertyType", implementation.getIdentifier(), decodedProperty.getName(),
1168                                property.getType() == null ? "<>" : property.getType(),
1169                                decodedProperty.getType() == null ? "<>" : decodedProperty.getType() ),
1170                                new ObjectFactory().createImplementation( implementation ) ) );
1171 
1172                        }
1173                    }
1174                }
1175                else if ( this.isLoggable( Level.WARNING ) )
1176                {
1177                    this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
1178                                                         Properties.class.getName() ), null );
1179 
1180                }
1181 
1182                if ( decodedMessages != null )
1183                {
1184                    for ( int i = 0, s0 = decodedMessages.getMessage().size(); i < s0; i++ )
1185                    {
1186                        final Message decodedMessage = decodedMessages.getMessage().get( i );
1187                        final Message message = messages.getMessage( decodedMessage.getName() );
1188 
1189                        if ( message == null )
1190                        {
1191                            report.getDetails().add( new ModelValidationReport.Detail(
1192                                "CLASS_MISSING_IMPLEMENTATION_MESSAGE", Level.SEVERE, getMessage(
1193                                "missingMessage", implementation.getIdentifier(), decodedMessage.getName() ),
1194                                new ObjectFactory().createImplementation( implementation ) ) );
1195 
1196                        }
1197                    }
1198                }
1199                else if ( this.isLoggable( Level.WARNING ) )
1200                {
1201                    this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
1202                                                         Messages.class.getName() ), null );
1203 
1204                }
1205 
1206                if ( decodedSpecifications != null )
1207                {
1208                    for ( int i = 0, s0 = decodedSpecifications.getSpecification().size(); i < s0; i++ )
1209                    {
1210                        final Specification decodedSpecification = decodedSpecifications.getSpecification().get( i );
1211                        final Specification specification =
1212                            this.getModules().getSpecification( decodedSpecification.getIdentifier() );
1213 
1214                        if ( specification == null )
1215                        {
1216                            report.getDetails().add( new ModelValidationReport.Detail(
1217                                "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage(
1218                                "missingSpecification", implementation.getIdentifier(),
1219                                decodedSpecification.getIdentifier() ),
1220                                new ObjectFactory().createImplementation( implementation ) ) );
1221 
1222                        }
1223                        else
1224                        {
1225                            if ( decodedSpecification.getMultiplicity() != specification.getMultiplicity() )
1226                            {
1227                                report.getDetails().add( new ModelValidationReport.Detail(
1228                                    "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage(
1229                                    "illegalMultiplicity", specification.getIdentifier(),
1230                                    specification.getMultiplicity().value(),
1231                                    decodedSpecification.getMultiplicity().value() ),
1232                                    new ObjectFactory().createImplementation( implementation ) ) );
1233 
1234                            }
1235 
1236                            if ( decodedSpecification.getScope() == null
1237                                 ? specification.getScope() != null
1238                                 : !decodedSpecification.getScope().equals( specification.getScope() ) )
1239                            {
1240                                report.getDetails().add( new ModelValidationReport.Detail(
1241                                    "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage(
1242                                    "illegalScope", decodedSpecification.getIdentifier(),
1243                                    specification.getScope() == null ? "Multiton" : specification.getScope(),
1244                                    decodedSpecification.getScope() == null ? "Multiton"
1245                                    : decodedSpecification.getScope() ),
1246                                    new ObjectFactory().createImplementation( implementation ) ) );
1247 
1248                            }
1249 
1250                            if ( decodedSpecification.getClazz() == null
1251                                 ? specification.getClazz() != null
1252                                 : !decodedSpecification.getClazz().equals( specification.getClazz() ) )
1253                            {
1254                                report.getDetails().add( new ModelValidationReport.Detail(
1255                                    "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage(
1256                                    "illegalSpecificationClass", decodedSpecification.getIdentifier(),
1257                                    specification.getClazz(), decodedSpecification.getClazz() ),
1258                                    new ObjectFactory().createImplementation( implementation ) ) );
1259 
1260                            }
1261                        }
1262                    }
1263 
1264                    for ( int i = 0, s0 = decodedSpecifications.getReference().size(); i < s0; i++ )
1265                    {
1266                        final SpecificationReference decodedReference = decodedSpecifications.getReference().get( i );
1267                        final Specification specification =
1268                            specifications.getSpecification( decodedReference.getIdentifier() );
1269 
1270                        if ( specification == null )
1271                        {
1272                            report.getDetails().add( new ModelValidationReport.Detail(
1273                                "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage(
1274                                "missingSpecification", implementation.getIdentifier(),
1275                                decodedReference.getIdentifier() ),
1276                                new ObjectFactory().createImplementation( implementation ) ) );
1277 
1278                        }
1279                        else if ( decodedReference.getVersion() != null && specification.getVersion() != null
1280                                  && VersionParser.compare( decodedReference.getVersion(),
1281                                                            specification.getVersion() ) != 0 )
1282                        {
1283                            final Module moduleOfSpecification =
1284                                this.getModules().getModuleOfSpecification( decodedReference.getIdentifier() );
1285 
1286                            final Module moduleOfImplementation =
1287                                this.getModules().getModuleOfImplementation( implementation.getIdentifier() );
1288 
1289                            report.getDetails().add( new ModelValidationReport.Detail(
1290                                "CLASS_INCOMPATIBLE_IMPLEMENTATION", Level.SEVERE, getMessage(
1291                                "incompatibleImplementation", javaClass.getClassName(),
1292                                moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(),
1293                                specification.getIdentifier(),
1294                                moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(),
1295                                decodedReference.getVersion(), specification.getVersion() ),
1296                                new ObjectFactory().createImplementation( implementation ) ) );
1297 
1298                        }
1299                    }
1300                }
1301                else if ( this.isLoggable( Level.WARNING ) )
1302                {
1303                    this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
1304                                                         Specifications.class.getName() ), null );
1305 
1306                }
1307            }
1308            else if ( this.isLoggable( Level.WARNING ) )
1309            {
1310                this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
1311            }
1312 
1313            return report;
1314        }
1315        catch ( final ParseException e )
1316        {
1317            // JDK: As of JDK 6, "new IOException( message, cause )".
1318            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
1319        }
1320        catch ( final TokenMgrError e )
1321        {
1322            // JDK: As of JDK 6, "new IOException( message, cause )".
1323            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
1324        }
1325    }
1326 
1327    /**
1328     * Transforms model objects of class files of the modules of the instance.
1329     *
1330     * @param context The model context to use for transforming model objects.
1331     * @param classesDirectory The directory holding the class files.
1332     * @param transformers The transformers to use for transforming model objects.
1333     *
1334     * @throws NullPointerException if {@code context}, {@code classesDirectory} or {@code transformers} is
1335     * {@code null}.
1336     * @throws IOException if transforming model objects fails.
1337     *
1338     * @see #transformModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File, java.util.List)
1339     */
1340    public final void transformModelObjects( final ModelContext context, final File classesDirectory,
1341                                             final List<Transformer> transformers ) throws IOException
1342    {
1343        if ( context == null )
1344        {
1345            throw new NullPointerException( "context" );
1346        }
1347        if ( classesDirectory == null )
1348        {
1349            throw new NullPointerException( "classesDirectory" );
1350        }
1351        if ( transformers == null )
1352        {
1353            throw new NullPointerException( "transformers" );
1354        }
1355        if ( !classesDirectory.isDirectory() )
1356        {
1357            throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
1358        }
1359 
1360        try
1361        {
1362            if ( this.getModules() != null )
1363            {
1364                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
1365                final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
1366                final Schema s = context.createSchema( this.getModel().getIdentifier() );
1367                u.setSchema( s );
1368                m.setSchema( s );
1369 
1370                this.transformModelObjects( this.getModules().getSpecifications(),
1371                                            this.getModules().getImplementations(),
1372                                            u, m, classesDirectory, transformers );
1373 
1374            }
1375            else if ( this.isLoggable( Level.WARNING ) )
1376            {
1377                this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
1378            }
1379        }
1380        catch ( final ModelException e )
1381        {
1382            // JDK: As of JDK 6, "new IOException( message, cause )".
1383            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
1384        }
1385    }
1386 
1387    /**
1388     * Transforms model objects of class files of a given module of the modules of the instance.
1389     *
1390     * @param module The module to process.
1391     * @param context The model context to use for transforming model objects.
1392     * @param classesDirectory The directory holding the class files.
1393     * @param transformers The transformers to use for transforming the model objects.
1394     *
1395     * @throws NullPointerException if {@code module}, {@code context}, {@code classesDirectory} or {@code transformers}
1396     * is {@code null}.
1397     * @throws IOException if transforming model objects fails.
1398     *
1399     * @see #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List)
1400     * @see #transformModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File, java.util.List)
1401     */
1402    public final void transformModelObjects( final Module module, final ModelContext context,
1403                                             final File classesDirectory, final List<Transformer> transformers )
1404        throws IOException
1405    {
1406        if ( module == null )
1407        {
1408            throw new NullPointerException( "module" );
1409        }
1410        if ( context == null )
1411        {
1412            throw new NullPointerException( "context" );
1413        }
1414        if ( classesDirectory == null )
1415        {
1416            throw new NullPointerException( "classesDirectory" );
1417        }
1418        if ( transformers == null )
1419        {
1420            throw new NullPointerException( "transformers" );
1421        }
1422        if ( !classesDirectory.isDirectory() )
1423        {
1424            throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
1425        }
1426 
1427        try
1428        {
1429            if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
1430            {
1431                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
1432                final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
1433                final Schema s = context.createSchema( this.getModel().getIdentifier() );
1434                u.setSchema( s );
1435                m.setSchema( s );
1436 
1437                this.transformModelObjects( module.getSpecifications(), module.getImplementations(), u, m,
1438                                            classesDirectory, transformers );
1439 
1440            }
1441            else if ( this.isLoggable( Level.WARNING ) )
1442            {
1443                this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
1444            }
1445        }
1446        catch ( final ModelException e )
1447        {
1448            // JDK: As of JDK 6, "new IOException( message, cause )".
1449            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
1450        }
1451    }
1452 
1453    /**
1454     * Transforms model objects of class files of a given specification of the modules of the instance.
1455     *
1456     * @param specification The specification to process.
1457     * @param context The model context to use for transforming model objects.
1458     * @param classesDirectory The directory holding the class files.
1459     * @param transformers The transformers to use for transforming the model objects.
1460     *
1461     * @throws NullPointerException if {@code specification}, {@code context}, {@code classesDirectory} or
1462     * {@code transformers} is {@code null}.
1463     * @throws IOException if transforming model objects fails.
1464     *
1465     * @see #transformModelObjects(org.jomc.model.Specification, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List)
1466     */
1467    public final void transformModelObjects( final Specification specification, final ModelContext context,
1468                                             final File classesDirectory, final List<Transformer> transformers )
1469        throws IOException
1470    {
1471        if ( specification == null )
1472        {
1473            throw new NullPointerException( "specification" );
1474        }
1475        if ( context == null )
1476        {
1477            throw new NullPointerException( "context" );
1478        }
1479        if ( classesDirectory == null )
1480        {
1481            throw new NullPointerException( "classesDirectory" );
1482        }
1483        if ( transformers == null )
1484        {
1485            throw new NullPointerException( "transformers" );
1486        }
1487        if ( !classesDirectory.isDirectory() )
1488        {
1489            throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
1490        }
1491 
1492        try
1493        {
1494            if ( this.getModules() != null
1495                 && this.getModules().getSpecification( specification.getIdentifier() ) != null )
1496            {
1497                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
1498                final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
1499                final Schema s = context.createSchema( this.getModel().getIdentifier() );
1500                u.setSchema( s );
1501                m.setSchema( s );
1502 
1503                this.transformModelObjects( specification, m, u, classesDirectory, transformers );
1504            }
1505            else if ( this.isLoggable( Level.WARNING ) )
1506            {
1507                this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
1508            }
1509        }
1510        catch ( final ModelException e )
1511        {
1512            // JDK: As of JDK 6, "new IOException( message, cause )".
1513            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
1514        }
1515    }
1516 
1517    /**
1518     * Transforms model objects of class files of a given implementation of the modules of the instance.
1519     *
1520     * @param implementation The implementation to process.
1521     * @param context The model context to use for transforming model objects.
1522     * @param classesDirectory The directory holding the class files.
1523     * @param transformers The transformers to use for transforming the model objects.
1524     *
1525     * @throws NullPointerException if {@code implementation}, {@code context}, {@code classesDirectory} or
1526     * {@code transformers} is {@code null}.
1527     * @throws IOException if transforming model objects fails.
1528     *
1529     * @see #transformModelObjects(org.jomc.model.Implementation, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List)
1530     */
1531    public final void transformModelObjects( final Implementation implementation, final ModelContext context,
1532                                             final File classesDirectory, final List<Transformer> transformers )
1533        throws IOException
1534    {
1535        if ( implementation == null )
1536        {
1537            throw new NullPointerException( "implementation" );
1538        }
1539        if ( context == null )
1540        {
1541            throw new NullPointerException( "context" );
1542        }
1543        if ( classesDirectory == null )
1544        {
1545            throw new NullPointerException( "classesDirectory" );
1546        }
1547        if ( transformers == null )
1548        {
1549            throw new NullPointerException( "transformers" );
1550        }
1551        if ( !classesDirectory.isDirectory() )
1552        {
1553            throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
1554        }
1555 
1556        try
1557        {
1558            if ( this.getModules() != null
1559                 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
1560            {
1561                final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
1562                final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
1563                final Schema s = context.createSchema( this.getModel().getIdentifier() );
1564                u.setSchema( s );
1565                m.setSchema( s );
1566 
1567                this.transformModelObjects( implementation, m, u, classesDirectory, transformers );
1568            }
1569            else if ( this.isLoggable( Level.WARNING ) )
1570            {
1571                this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
1572            }
1573        }
1574        catch ( final ModelException e )
1575        {
1576            // JDK: As of JDK 6, "new IOException( message, cause )".
1577            throw (IOException) new IOException( getMessage( e ) ).initCause( e );
1578        }
1579    }
1580 
1581    /**
1582     * Transforms model objects of a given specification of the modules of the instance.
1583     *
1584     * @param specification The specification to process.
1585     * @param marshaller The marshaller to use for transforming model objects.
1586     * @param unmarshaller The unmarshaller to use for transforming model objects.
1587     * @param javaClass The java class to transform model objects of.
1588     * @param transformers The transformers to use for transforming the model objects.
1589     *
1590     * @throws NullPointerException if {@code specification}, {@code marshaller}, {@code unmarshaller},
1591     * {@code javaClass} or {@code transformers} is {@code null}.
1592     * @throws IOException if transforming model objects fails.
1593     */
1594    public void transformModelObjects( final Specification specification, final Marshaller marshaller,
1595                                       final Unmarshaller unmarshaller, final JavaClass javaClass,
1596                                       final List<Transformer> transformers ) throws IOException
1597    {
1598        if ( specification == null )
1599        {
1600            throw new NullPointerException( "specification" );
1601        }
1602        if ( marshaller == null )
1603        {
1604            throw new NullPointerException( "marshaller" );
1605        }
1606        if ( unmarshaller == null )
1607        {
1608            throw new NullPointerException( "unmarshaller" );
1609        }
1610        if ( javaClass == null )
1611        {
1612            throw new NullPointerException( "javaClass" );
1613        }
1614        if ( transformers == null )
1615        {
1616            throw new NullPointerException( "transformers" );
1617        }
1618 
1619        try
1620        {
1621            if ( this.getModules() != null
1622                 && this.getModules().getSpecification( specification.getIdentifier() ) != null )
1623            {
1624                Specification decodedSpecification = null;
1625                final ObjectFactory objectFactory = new ObjectFactory();
1626                final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() );
1627                if ( bytes != null )
1628                {
1629                    decodedSpecification = this.decodeModelObject( unmarshaller, bytes, Specification.class );
1630                }
1631 
1632                if ( decodedSpecification != null )
1633                {
1634                    for ( int i = 0, l = transformers.size(); i < l; i++ )
1635                    {
1636                        final JAXBSource source =
1637                            new JAXBSource( marshaller, objectFactory.createSpecification( decodedSpecification ) );
1638 
1639                        final JAXBResult result = new JAXBResult( unmarshaller );
1640                        transformers.get( i ).transform( source, result );
1641 
1642                        if ( result.getResult() instanceof JAXBElement<?>
1643                             && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Specification )
1644                        {
1645                            decodedSpecification = (Specification) ( (JAXBElement<?>) result.getResult() ).getValue();
1646                        }
1647                        else
1648                        {
1649                            throw new IOException( getMessage(
1650                                "illegalSpecificationTransformationResult", specification.getIdentifier() ) );
1651 
1652                        }
1653                    }
1654 
1655                    this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject(
1656                        marshaller, objectFactory.createSpecification( decodedSpecification ) ) );
1657 
1658                }
1659            }
1660            else if ( this.isLoggable( Level.WARNING ) )
1661            {
1662                this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
1663            }
1664        }
1665        catch ( final JAXBException e )
1666        {
1667            String message = getMessage( e );
1668            if ( message == null && e.getLinkedException() != null )
1669            {
1670                message = getMessage( e.getLinkedException() );
1671            }
1672 
1673            // JDK: As of JDK 6, "new IOException( message, cause )".
1674            throw (IOException) new IOException( message ).initCause( e );
1675        }
1676        catch ( final TransformerException e )
1677        {
1678            String message = getMessage( e );
1679            if ( message == null && e.getException() != null )
1680            {
1681                message = getMessage( e.getException() );
1682            }
1683 
1684            // JDK: As of JDK 6, "new IOException( message, cause )".
1685            throw (IOException) new IOException( message ).initCause( e );
1686        }
1687    }
1688 
1689    /**
1690     * Transforms model objects of a given implementation of the modules of the instance.
1691     *
1692     * @param implementation The implementation to process.
1693     * @param marshaller The marshaller to use for transforming model objects.
1694     * @param unmarshaller The unmarshaller to use for transforming model objects.
1695     * @param javaClass The java class to transform model object of.
1696     * @param transformers The transformers to use for transforming the model objects.
1697     *
1698     * @throws NullPointerException if {@code implementation}, {@code marshaller}, {@code unmarshaller},
1699     * {@code javaClass} or {@code transformers} is {@code null}.
1700     * @throws IOException if transforming model objects fails.
1701     */
1702    public void transformModelObjects( final Implementation implementation, final Marshaller marshaller,
1703                                       final Unmarshaller unmarshaller, final JavaClass javaClass,
1704                                       final List<Transformer> transformers ) throws IOException
1705    {
1706        if ( implementation == null )
1707        {
1708            throw new NullPointerException( "implementation" );
1709        }
1710        if ( marshaller == null )
1711        {
1712            throw new NullPointerException( "marshaller" );
1713        }
1714        if ( unmarshaller == null )
1715        {
1716            throw new NullPointerException( "unmarshaller" );
1717        }
1718        if ( javaClass == null )
1719        {
1720            throw new NullPointerException( "javaClass" );
1721        }
1722        if ( transformers == null )
1723        {
1724            throw new NullPointerException( "transformers" );
1725        }
1726 
1727        try
1728        {
1729            if ( this.getModules() != null
1730                 && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
1731            {
1732                Dependencies decodedDependencies = null;
1733                byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() );
1734                if ( bytes != null )
1735                {
1736                    decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class );
1737                }
1738 
1739                Messages decodedMessages = null;
1740                bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() );
1741                if ( bytes != null )
1742                {
1743                    decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class );
1744                }
1745 
1746                Properties decodedProperties = null;
1747                bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() );
1748                if ( bytes != null )
1749                {
1750                    decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class );
1751                }
1752 
1753                Specifications decodedSpecifications = null;
1754                bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() );
1755                if ( bytes != null )
1756                {
1757                    decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class );
1758                }
1759 
1760                final ObjectFactory of = new ObjectFactory();
1761                for ( int i = 0, l = transformers.size(); i < l; i++ )
1762                {
1763                    final Transformer transformer = transformers.get( i );
1764 
1765                    if ( decodedDependencies != null )
1766                    {
1767                        final JAXBSource source =
1768                            new JAXBSource( marshaller, of.createDependencies( decodedDependencies ) );
1769 
1770                        final JAXBResult result = new JAXBResult( unmarshaller );
1771                        transformer.transform( source, result );
1772 
1773                        if ( result.getResult() instanceof JAXBElement<?>
1774                             && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Dependencies )
1775                        {
1776                            decodedDependencies = (Dependencies) ( (JAXBElement<?>) result.getResult() ).getValue();
1777                        }
1778                        else
1779                        {
1780                            throw new IOException( getMessage(
1781                                "illegalImplementationTransformationResult", implementation.getIdentifier() ) );
1782 
1783                        }
1784                    }
1785 
1786                    if ( decodedMessages != null )
1787                    {
1788                        final JAXBSource source = new JAXBSource( marshaller, of.createMessages( decodedMessages ) );
1789                        final JAXBResult result = new JAXBResult( unmarshaller );
1790                        transformer.transform( source, result );
1791 
1792                        if ( result.getResult() instanceof JAXBElement<?>
1793                             && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Messages )
1794                        {
1795                            decodedMessages = (Messages) ( (JAXBElement<?>) result.getResult() ).getValue();
1796                        }
1797                        else
1798                        {
1799                            throw new IOException( getMessage(
1800                                "illegalImplementationTransformationResult", implementation.getIdentifier() ) );
1801 
1802                        }
1803                    }
1804 
1805                    if ( decodedProperties != null )
1806                    {
1807                        final JAXBSource source = new JAXBSource( marshaller, of.createProperties( decodedProperties ) );
1808                        final JAXBResult result = new JAXBResult( unmarshaller );
1809                        transformer.transform( source, result );
1810 
1811                        if ( result.getResult() instanceof JAXBElement<?>
1812                             && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Properties )
1813                        {
1814                            decodedProperties = (Properties) ( (JAXBElement<?>) result.getResult() ).getValue();
1815                        }
1816                        else
1817                        {
1818                            throw new IOException( getMessage(
1819                                "illegalImplementationTransformationResult", implementation.getIdentifier() ) );
1820 
1821                        }
1822                    }
1823 
1824                    if ( decodedSpecifications != null )
1825                    {
1826                        final JAXBSource source =
1827                            new JAXBSource( marshaller, of.createSpecifications( decodedSpecifications ) );
1828 
1829                        final JAXBResult result = new JAXBResult( unmarshaller );
1830                        transformer.transform( source, result );
1831 
1832                        if ( result.getResult() instanceof JAXBElement<?>
1833                             && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Specifications )
1834                        {
1835                            decodedSpecifications = (Specifications) ( (JAXBElement<?>) result.getResult() ).getValue();
1836                        }
1837                        else
1838                        {
1839                            throw new IOException( getMessage(
1840                                "illegalImplementationTransformationResult", implementation.getIdentifier() ) );
1841 
1842                        }
1843                    }
1844                }
1845 
1846                if ( decodedDependencies != null )
1847                {
1848                    this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject(
1849                        marshaller, of.createDependencies( decodedDependencies ) ) );
1850 
1851                }
1852 
1853                if ( decodedMessages != null )
1854                {
1855                    this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject(
1856                        marshaller, of.createMessages( decodedMessages ) ) );
1857 
1858                }
1859 
1860                if ( decodedProperties != null )
1861                {
1862                    this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject(
1863                        marshaller, of.createProperties( decodedProperties ) ) );
1864 
1865                }
1866 
1867                if ( decodedSpecifications != null )
1868                {
1869                    this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject(
1870                        marshaller, of.createSpecifications( decodedSpecifications ) ) );
1871 
1872                }
1873            }
1874            else if ( this.isLoggable( Level.WARNING ) )
1875            {
1876                this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
1877            }
1878        }
1879        catch ( final JAXBException e )
1880        {
1881            String message = getMessage( e );
1882            if ( message == null && e.getLinkedException() != null )
1883            {
1884                message = getMessage( e.getLinkedException() );
1885            }
1886 
1887            // JDK: As of JDK 6, "new IOException( message, cause )".
1888            throw (IOException) new IOException( message ).initCause( e );
1889        }
1890        catch ( final TransformerException e )
1891        {
1892            String message = getMessage( e );
1893            if ( message == null && e.getException() != null )
1894            {
1895                message = getMessage( e.getException() );
1896            }
1897 
1898            // JDK: As of JDK 6, "new IOException( message, cause )".
1899            throw (IOException) new IOException( message ).initCause( e );
1900        }
1901    }
1902 
1903    /**
1904     * Gets an attribute from a java class.
1905     *
1906     * @param clazz The java class to get an attribute from.
1907     * @param attributeName The name of the attribute to get.
1908     *
1909     * @return The value of attribute {@code attributeName} of {@code clazz} or {@code null}, if no such attribute
1910     * exists.
1911     *
1912     * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}.
1913     * @throws IOException if getting the attribute fails.
1914     *
1915     * @see JavaClass#getAttributes()
1916     */
1917    public byte[] getClassfileAttribute( final JavaClass clazz, final String attributeName ) throws IOException
1918    {
1919        if ( clazz == null )
1920        {
1921            throw new NullPointerException( "clazz" );
1922        }
1923        if ( attributeName == null )
1924        {
1925            throw new NullPointerException( "attributeName" );
1926        }
1927 
1928        final Attribute[] attributes = clazz.getAttributes();
1929 
1930        for ( int i = attributes.length - 1; i >= 0; i-- )
1931        {
1932            final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() );
1933 
1934            if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) )
1935            {
1936                final Unknown unknown = (Unknown) attributes[i];
1937                return unknown.getBytes();
1938            }
1939        }
1940 
1941        return null;
1942    }
1943 
1944    /**
1945     * Adds or updates an attribute in a java class.
1946     *
1947     * @param clazz The class to update an attribute of.
1948     * @param attributeName The name of the attribute to update.
1949     * @param data The new data of the attribute to update the {@code clazz} with.
1950     *
1951     * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}.
1952     * @throws IOException if updating the class file fails.
1953     *
1954     * @see JavaClass#getAttributes()
1955     */
1956    public void setClassfileAttribute( final JavaClass clazz, final String attributeName, final byte[] data )
1957        throws IOException
1958    {
1959        if ( clazz == null )
1960        {
1961            throw new NullPointerException( "clazz" );
1962        }
1963        if ( attributeName == null )
1964        {
1965            throw new NullPointerException( "attributeName" );
1966        }
1967 
1968        final byte[] attributeData = data != null ? data : NO_BYTES;
1969 
1970        /*
1971         The JavaTM Virtual Machine Specification - Second Edition - Chapter 4.1
1972 
1973         A Java virtual machine implementation is required to silently ignore any
1974         or all attributes in the attributes table of a ClassFile structure that
1975         it does not recognize. Attributes not defined in this specification are
1976         not allowed to affect the semantics of the class file, but only to
1977         provide additional descriptive information (§4.7.1).
1978         */
1979        Attribute[] attributes = clazz.getAttributes();
1980 
1981        int attributeIndex = -1;
1982        int nameIndex = -1;
1983 
1984        for ( int i = attributes.length - 1; i >= 0; i-- )
1985        {
1986            final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() );
1987 
1988            if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) )
1989            {
1990                attributeIndex = i;
1991                nameIndex = attributes[i].getNameIndex();
1992            }
1993        }
1994 
1995        if ( nameIndex == -1 )
1996        {
1997            final Constant[] pool = clazz.getConstantPool().getConstantPool();
1998            final Constant[] tmp = new Constant[ pool.length + 1 ];
1999            System.arraycopy( pool, 0, tmp, 0, pool.length );
2000            tmp[pool.length] = new ConstantUtf8( attributeName );
2001            nameIndex = pool.length;
2002            clazz.setConstantPool( new ConstantPool( tmp ) );
2003        }
2004 
2005        final Unknown unknown = new Unknown( nameIndex, attributeData.length, attributeData, clazz.getConstantPool() );
2006 
2007        if ( attributeIndex == -1 )
2008        {
2009            final Attribute[] tmp = new Attribute[ attributes.length + 1 ];
2010            System.arraycopy( attributes, 0, tmp, 0, attributes.length );
2011            tmp[attributes.length] = unknown;
2012            attributes = tmp;
2013        }
2014        else
2015        {
2016            attributes[attributeIndex] = unknown;
2017        }
2018 
2019        clazz.setAttributes( attributes );
2020    }
2021 
2022    /**
2023     * Encodes a model object to a byte array.
2024     *
2025     * @param marshaller The marshaller to use for encoding the object.
2026     * @param modelObject The model object to encode.
2027     *
2028     * @return GZIP compressed XML document of {@code modelObject}.
2029     *
2030     * @throws NullPointerException if {@code marshaller} or {@code modelObject} is {@code null}.
2031     * @throws IOException if encoding {@code modelObject} fails.
2032     *
2033     * @see #decodeModelObject(javax.xml.bind.Unmarshaller, byte[], java.lang.Class)
2034     */
2035    public byte[] encodeModelObject( final Marshaller marshaller, final JAXBElement<? extends ModelObject> modelObject )
2036        throws IOException
2037    {
2038        if ( marshaller == null )
2039        {
2040            throw new NullPointerException( "marshaller" );
2041        }
2042        if ( modelObject == null )
2043        {
2044            throw new NullPointerException( "modelObject" );
2045        }
2046 
2047        try
2048        {
2049            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2050            final GZIPOutputStream out = new GZIPOutputStream( baos );
2051            marshaller.marshal( modelObject, out );
2052            out.close();
2053            return baos.toByteArray();
2054        }
2055        catch ( final JAXBException e )
2056        {
2057            String message = getMessage( e );
2058            if ( message == null && e.getLinkedException() != null )
2059            {
2060                message = getMessage( e.getLinkedException() );
2061            }
2062 
2063            // JDK: As of JDK 6, "new IOException( message, cause )".
2064            throw (IOException) new IOException( message ).initCause( e );
2065        }
2066    }
2067 
2068    /**
2069     * Decodes a model object from a byte array.
2070     *
2071     * @param unmarshaller The unmarshaller to use for decoding the object.
2072     * @param bytes The encoded model object to decode.
2073     * @param type The class of the type of the encoded model object.
2074     * @param <T> The type of the encoded model object.
2075     *
2076     * @return Model object decoded from {@code bytes}.
2077     *
2078     * @throws NullPointerException if {@code unmarshaller}, {@code bytes} or {@code type} is {@code null}.
2079     * @throws IOException if decoding {@code bytes} fails.
2080     *
2081     * @see #encodeModelObject(javax.xml.bind.Marshaller, javax.xml.bind.JAXBElement)
2082     */
2083    public <T extends ModelObject> T decodeModelObject( final Unmarshaller unmarshaller, final byte[] bytes,
2084                                                        final Class<T> type ) throws IOException
2085    {
2086        if ( unmarshaller == null )
2087        {
2088            throw new NullPointerException( "unmarshaller" );
2089        }
2090        if ( bytes == null )
2091        {
2092            throw new NullPointerException( "bytes" );
2093        }
2094        if ( type == null )
2095        {
2096            throw new NullPointerException( "type" );
2097        }
2098 
2099        try
2100        {
2101            final ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
2102            final GZIPInputStream in = new GZIPInputStream( bais );
2103            final JAXBElement<T> element = (JAXBElement<T>) unmarshaller.unmarshal( in );
2104            in.close();
2105            return element.getValue();
2106        }
2107        catch ( final JAXBException e )
2108        {
2109            String message = getMessage( e );
2110            if ( message == null && e.getLinkedException() != null )
2111            {
2112                message = getMessage( e.getLinkedException() );
2113            }
2114 
2115            // JDK: As of JDK 6, "new IOException( message, cause )".
2116            throw (IOException) new IOException( message ).initCause( e );
2117        }
2118    }
2119 
2120    private void commitModelObjects( final Specifications specifications, final Implementations implementations,
2121                                     final Marshaller marshaller, final File classesDirectory ) throws IOException
2122    {
2123        if ( specifications != null )
2124        {
2125            for ( int i = specifications.getSpecification().size() - 1; i >= 0; i-- )
2126            {
2127                this.commitModelObjects( specifications.getSpecification().get( i ), marshaller, classesDirectory );
2128            }
2129        }
2130 
2131        if ( implementations != null )
2132        {
2133            for ( int i = implementations.getImplementation().size() - 1; i >= 0; i-- )
2134            {
2135                this.commitModelObjects( implementations.getImplementation().get( i ), marshaller, classesDirectory );
2136            }
2137        }
2138    }
2139 
2140    private void commitModelObjects( final Specification specification, final Marshaller marshaller,
2141                                     final File classesDirectory ) throws IOException
2142    {
2143        if ( specification.isClassDeclaration() )
2144        {
2145            final String classLocation = specification.getClazz().replace( '.', File.separatorChar ) + ".class";
2146            final File classFile = new File( classesDirectory, classLocation );
2147 
2148            if ( !classesDirectory.isDirectory() )
2149            {
2150                throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
2151            }
2152            if ( !classFile.isFile() )
2153            {
2154                throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
2155            }
2156            if ( !( classFile.canRead() && classFile.canWrite() ) )
2157            {
2158                throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
2159            }
2160 
2161            if ( this.isLoggable( Level.INFO ) )
2162            {
2163                this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null );
2164            }
2165 
2166            final JavaClass javaClass = this.readJavaClass( classFile );
2167            this.commitModelObjects( specification, marshaller, javaClass );
2168            this.writeJavaClass( javaClass, classFile );
2169        }
2170    }
2171 
2172    private void commitModelObjects( final Implementation implementation, final Marshaller marshaller,
2173                                     final File classesDirectory ) throws IOException
2174    {
2175        if ( implementation.isClassDeclaration() )
2176        {
2177            final String classLocation = implementation.getClazz().replace( '.', File.separatorChar ) + ".class";
2178            final File classFile = new File( classesDirectory, classLocation );
2179 
2180            if ( !classesDirectory.isDirectory() )
2181            {
2182                throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
2183            }
2184            if ( !classFile.isFile() )
2185            {
2186                throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
2187            }
2188            if ( !( classFile.canRead() && classFile.canWrite() ) )
2189            {
2190                throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
2191            }
2192 
2193            if ( this.isLoggable( Level.INFO ) )
2194            {
2195                this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null );
2196            }
2197 
2198            final JavaClass javaClass = this.readJavaClass( classFile );
2199            this.commitModelObjects( implementation, marshaller, javaClass );
2200            this.writeJavaClass( javaClass, classFile );
2201        }
2202    }
2203 
2204    private ModelValidationReport validateModelObjects( final Specifications specifications,
2205                                                        final Implementations implementations,
2206                                                        final Unmarshaller unmarshaller, final File classesDirectory )
2207        throws IOException
2208    {
2209        final ModelValidationReport report = new ModelValidationReport();
2210 
2211        if ( specifications != null )
2212        {
2213            for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ )
2214            {
2215                final ModelValidationReport current = this.validateModelObjects(
2216                    specifications.getSpecification().get( i ), unmarshaller, classesDirectory );
2217 
2218                report.getDetails().addAll( current.getDetails() );
2219            }
2220        }
2221 
2222        if ( implementations != null )
2223        {
2224            for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
2225            {
2226                final ModelValidationReport current = this.validateModelObjects(
2227                    implementations.getImplementation().get( i ), unmarshaller, classesDirectory );
2228 
2229                report.getDetails().addAll( current.getDetails() );
2230            }
2231        }
2232 
2233        return report;
2234    }
2235 
2236    private ModelValidationReport validateModelObjects( final Specification specification,
2237                                                        final Unmarshaller unmarshaller,
2238                                                        final File classesDirectory ) throws IOException
2239    {
2240        final ModelValidationReport report = new ModelValidationReport();
2241 
2242        if ( specification.isClassDeclaration() )
2243        {
2244            final String classLocation = specification.getClazz().replace( '.', File.separatorChar ) + ".class";
2245            final File classFile = new File( classesDirectory, classLocation );
2246 
2247            if ( !classesDirectory.isDirectory() )
2248            {
2249                throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
2250            }
2251            if ( !classFile.isFile() )
2252            {
2253                throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
2254            }
2255            if ( !classFile.canRead() )
2256            {
2257                throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
2258            }
2259 
2260            if ( this.isLoggable( Level.INFO ) )
2261            {
2262                this.log( Level.INFO, getMessage( "validating", classFile.getAbsolutePath() ), null );
2263            }
2264 
2265            final JavaClass javaClass = this.readJavaClass( classFile );
2266 
2267            report.getDetails().addAll(
2268                this.validateModelObjects( specification, unmarshaller, javaClass ).getDetails() );
2269 
2270        }
2271 
2272        return report;
2273    }
2274 
2275    private ModelValidationReport validateModelObjects( final Implementation implementation,
2276                                                        final Unmarshaller unmarshaller,
2277                                                        final File classesDirectory ) throws IOException
2278    {
2279        final ModelValidationReport report = new ModelValidationReport();
2280 
2281        if ( implementation.isClassDeclaration() )
2282        {
2283            final String classLocation = implementation.getClazz().replace( '.', File.separatorChar ) + ".class";
2284            final File classFile = new File( classesDirectory, classLocation );
2285 
2286            if ( !classesDirectory.isDirectory() )
2287            {
2288                throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
2289            }
2290            if ( !classFile.isFile() )
2291            {
2292                throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
2293            }
2294            if ( !classFile.canRead() )
2295            {
2296                throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
2297            }
2298 
2299            if ( this.isLoggable( Level.INFO ) )
2300            {
2301                this.log( Level.INFO, getMessage( "validating", classFile.getAbsolutePath() ), null );
2302            }
2303 
2304            final JavaClass javaClass = this.readJavaClass( classFile );
2305 
2306            report.getDetails().addAll(
2307                this.validateModelObjects( implementation, unmarshaller, javaClass ).getDetails() );
2308 
2309        }
2310 
2311        return report;
2312    }
2313 
2314    private ModelValidationReport validateModelObjects( final Specifications specifications,
2315                                                        final Implementations implementations,
2316                                                        final Unmarshaller unmarshaller, final ModelContext context )
2317        throws IOException, ModelException
2318    {
2319        final ModelValidationReport report = new ModelValidationReport();
2320 
2321        if ( specifications != null )
2322        {
2323            for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ )
2324            {
2325                final ModelValidationReport current = this.validateModelObjects(
2326                    specifications.getSpecification().get( i ), unmarshaller, context );
2327 
2328                report.getDetails().addAll( current.getDetails() );
2329            }
2330        }
2331 
2332        if ( implementations != null )
2333        {
2334            for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
2335            {
2336                final ModelValidationReport current = this.validateModelObjects(
2337                    implementations.getImplementation().get( i ), unmarshaller, context );
2338 
2339                report.getDetails().addAll( current.getDetails() );
2340            }
2341        }
2342 
2343        return report;
2344    }
2345 
2346    private ModelValidationReport validateModelObjects( final Specification specification,
2347                                                        final Unmarshaller unmarshaller,
2348                                                        final ModelContext context ) throws IOException, ModelException
2349    {
2350        final ModelValidationReport report = new ModelValidationReport();
2351 
2352        if ( specification.isClassDeclaration() )
2353        {
2354            final String classLocation = specification.getClazz().replace( '.', '/' ) + ".class";
2355 
2356            final URL classUrl = context.findResource( classLocation );
2357 
2358            if ( classUrl == null )
2359            {
2360                throw new IOException( getMessage( "resourceNotFound", classLocation ) );
2361            }
2362 
2363            if ( this.isLoggable( Level.INFO ) )
2364            {
2365                this.log( Level.INFO, getMessage( "validatingSpecification", specification.getIdentifier() ), null );
2366            }
2367 
2368            InputStream in = null;
2369            JavaClass javaClass = null;
2370            boolean suppressExceptionOnClose = true;
2371 
2372            try
2373            {
2374                in = classUrl.openStream();
2375                javaClass = new ClassParser( in, classUrl.toExternalForm() ).parse();
2376                suppressExceptionOnClose = false;
2377            }
2378            finally
2379            {
2380                try
2381                {
2382                    if ( in != null )
2383                    {
2384                        in.close();
2385                    }
2386                }
2387                catch ( final IOException e )
2388                {
2389                    if ( suppressExceptionOnClose )
2390                    {
2391                        this.log( Level.SEVERE, getMessage( e ), e );
2392                    }
2393                    else
2394                    {
2395                        throw e;
2396                    }
2397                }
2398            }
2399 
2400            report.getDetails().addAll(
2401                this.validateModelObjects( specification, unmarshaller, javaClass ).getDetails() );
2402 
2403        }
2404 
2405        return report;
2406    }
2407 
2408    private ModelValidationReport validateModelObjects( final Implementation implementation,
2409                                                        final Unmarshaller unmarshaller,
2410                                                        final ModelContext context ) throws IOException, ModelException
2411    {
2412        final ModelValidationReport report = new ModelValidationReport();
2413 
2414        if ( implementation.isClassDeclaration() )
2415        {
2416            final String classLocation = implementation.getClazz().replace( '.', '/' ) + ".class";
2417 
2418            final URL classUrl = context.findResource( classLocation );
2419 
2420            if ( classUrl == null )
2421            {
2422                throw new IOException( getMessage( "resourceNotFound", classLocation ) );
2423            }
2424 
2425            if ( this.isLoggable( Level.INFO ) )
2426            {
2427                this.log( Level.INFO, getMessage( "validatingImplementation", implementation.getIdentifier() ), null );
2428            }
2429 
2430            InputStream in = null;
2431            JavaClass javaClass = null;
2432            boolean suppressExceptionOnClose = true;
2433 
2434            try
2435            {
2436                in = classUrl.openStream();
2437                javaClass = new ClassParser( in, classUrl.toExternalForm() ).parse();
2438                suppressExceptionOnClose = false;
2439            }
2440            finally
2441            {
2442                try
2443                {
2444                    if ( in != null )
2445                    {
2446                        in.close();
2447                    }
2448                }
2449                catch ( final IOException e )
2450                {
2451                    if ( suppressExceptionOnClose )
2452                    {
2453                        this.log( Level.SEVERE, getMessage( e ), e );
2454                    }
2455                    else
2456                    {
2457                        throw e;
2458                    }
2459                }
2460            }
2461 
2462            report.getDetails().addAll(
2463                this.validateModelObjects( implementation, unmarshaller, javaClass ).getDetails() );
2464 
2465        }
2466 
2467        return report;
2468    }
2469 
2470    private void transformModelObjects( final Specifications specifications, final Implementations implementations,
2471                                        final Unmarshaller unmarshaller, final Marshaller marshaller,
2472                                        final File classesDirectory, final List<Transformer> transformers )
2473        throws IOException
2474    {
2475        if ( specifications != null )
2476        {
2477            for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ )
2478            {
2479                this.transformModelObjects( specifications.getSpecification().get( i ), marshaller, unmarshaller,
2480                                            classesDirectory, transformers );
2481 
2482            }
2483        }
2484 
2485        if ( implementations != null )
2486        {
2487            for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
2488            {
2489                this.transformModelObjects( implementations.getImplementation().get( i ), marshaller, unmarshaller,
2490                                            classesDirectory, transformers );
2491 
2492            }
2493        }
2494    }
2495 
2496    private void transformModelObjects( final Specification specification, final Marshaller marshaller,
2497                                        final Unmarshaller unmarshaller, final File classesDirectory,
2498                                        final List<Transformer> transformers ) throws IOException
2499    {
2500        if ( specification.isClassDeclaration() )
2501        {
2502            final String classLocation = specification.getClazz().replace( '.', File.separatorChar ) + ".class";
2503            final File classFile = new File( classesDirectory, classLocation );
2504 
2505            if ( !classesDirectory.isDirectory() )
2506            {
2507                throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
2508            }
2509            if ( !classFile.isFile() )
2510            {
2511                throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
2512            }
2513            if ( !( classFile.canRead() && classFile.canWrite() ) )
2514            {
2515                throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
2516            }
2517 
2518            if ( this.isLoggable( Level.INFO ) )
2519            {
2520                this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null );
2521            }
2522 
2523            final JavaClass javaClass = this.readJavaClass( classFile );
2524            this.transformModelObjects( specification, marshaller, unmarshaller, javaClass, transformers );
2525            this.writeJavaClass( javaClass, classFile );
2526        }
2527    }
2528 
2529    private void transformModelObjects( final Implementation implementation, final Marshaller marshaller,
2530                                        final Unmarshaller unmarshaller, final File classesDirectory,
2531                                        final List<Transformer> transformers ) throws IOException
2532    {
2533        if ( implementation.isClassDeclaration() )
2534        {
2535            final String classLocation = implementation.getClazz().replace( '.', File.separatorChar ) + ".class";
2536            final File classFile = new File( classesDirectory, classLocation );
2537 
2538            if ( !classesDirectory.isDirectory() )
2539            {
2540                throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
2541            }
2542            if ( !classFile.isFile() )
2543            {
2544                throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
2545            }
2546            if ( !( classFile.canRead() && classFile.canWrite() ) )
2547            {
2548                throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
2549            }
2550 
2551            if ( this.isLoggable( Level.INFO ) )
2552            {
2553                this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null );
2554            }
2555 
2556            final JavaClass javaClass = this.readJavaClass( classFile );
2557            this.transformModelObjects( implementation, marshaller, unmarshaller, javaClass, transformers );
2558            this.writeJavaClass( javaClass, classFile );
2559        }
2560    }
2561 
2562    private JavaClass readJavaClass( final File classFile ) throws IOException
2563    {
2564        FileInputStream in = null;
2565        FileChannel fileChannel = null;
2566        FileLock fileLock = null;
2567        boolean suppressExceptionOnClose = true;
2568 
2569        try
2570        {
2571            in = new FileInputStream( classFile );
2572            fileChannel = in.getChannel();
2573            fileLock = fileChannel.lock( 0, classFile.length(), true );
2574 
2575            final JavaClass javaClass = new ClassParser( in, classFile.getAbsolutePath() ).parse();
2576            suppressExceptionOnClose = false;
2577            return javaClass;
2578        }
2579        finally
2580        {
2581            this.releaseAndClose( fileLock, fileChannel, in, suppressExceptionOnClose );
2582        }
2583    }
2584 
2585    private void writeJavaClass( final JavaClass javaClass, final File classFile ) throws IOException
2586    {
2587        RandomAccessFile randomAccessFile = null;
2588        FileChannel fileChannel = null;
2589        FileLock fileLock = null;
2590        boolean suppressExceptionOnClose = true;
2591 
2592        final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
2593        javaClass.dump( byteStream );
2594        byteStream.close();
2595 
2596        final byte[] bytes = byteStream.toByteArray();
2597 
2598        try
2599        {
2600            randomAccessFile = new RandomAccessFile( classFile, "rw" );
2601            fileChannel = randomAccessFile.getChannel();
2602            fileLock = fileChannel.lock();
2603            fileChannel.truncate( bytes.length );
2604            fileChannel.position( 0L );
2605            fileChannel.write( ByteBuffer.wrap( bytes ) );
2606            fileChannel.force( true );
2607            suppressExceptionOnClose = false;
2608        }
2609        finally
2610        {
2611            this.releaseAndClose( fileLock, fileChannel, randomAccessFile, suppressExceptionOnClose );
2612        }
2613    }
2614 
2615    private void releaseAndClose( final FileLock fileLock, final FileChannel fileChannel,
2616                                  final Closeable closeable, final boolean suppressExceptions )
2617        throws IOException
2618    {
2619        try
2620        {
2621            if ( fileLock != null )
2622            {
2623                fileLock.release();
2624            }
2625        }
2626        catch ( final IOException e )
2627        {
2628            if ( suppressExceptions )
2629            {
2630                this.log( Level.SEVERE, null, e );
2631            }
2632            else
2633            {
2634                throw e;
2635            }
2636        }
2637        finally
2638        {
2639            try
2640            {
2641                if ( fileChannel != null )
2642                {
2643                    fileChannel.close();
2644                }
2645            }
2646            catch ( final IOException e )
2647            {
2648                if ( suppressExceptions )
2649                {
2650                    this.log( Level.SEVERE, null, e );
2651                }
2652                else
2653                {
2654                    throw e;
2655                }
2656            }
2657            finally
2658            {
2659                try
2660                {
2661                    if ( closeable != null )
2662                    {
2663                        closeable.close();
2664                    }
2665                }
2666                catch ( final IOException e )
2667                {
2668                    if ( suppressExceptions )
2669                    {
2670                        this.log( Level.SEVERE, null, e );
2671                    }
2672                    else
2673                    {
2674                        throw e;
2675                    }
2676                }
2677            }
2678        }
2679    }
2680 
2681    private static String getMessage( final String key, final Object... arguments )
2682    {
2683        return MessageFormat.format( ResourceBundle.getBundle(
2684            ClassFileProcessor.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
2685 
2686    }
2687 
2688    private static String getMessage( final Throwable t )
2689    {
2690        return t != null
2691               ? t.getMessage() != null && t.getMessage().trim().length() > 0
2692                 ? t.getMessage()
2693                 : getMessage( t.getCause() )
2694               : null;
2695 
2696    }
2697 
2698}

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