EMMA Coverage Report (generated Tue Nov 18 06:49:09 CET 2014)
[all classes][org.jomc.tools]

COVERAGE SUMMARY FOR SOURCE FILE [ClassFileProcessor.java]

nameclass, %method, %block, %line, %
ClassFileProcessor.java100% (1/1)98%  (45/46)80%  (4263/5358)85%  (757/889)

COVERAGE BREAKDOWN BY CLASS AND METHOD

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

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