EMMA Coverage Report (generated Wed May 23 02:58:44 CEST 2012)
[all classes][org.jomc.tools]

COVERAGE SUMMARY FOR SOURCE FILE [ClassFileProcessor.java]

nameclass, %method, %block, %line, %
ClassFileProcessor.java100% (1/1)98%  (42/43)76%  (3661/4804)84%  (628.2/751)

COVERAGE BREAKDOWN BY CLASS AND METHOD

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

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