EMMA Coverage Report (generated Wed Feb 03 01:24:19 UTC 2010)
[all classes][org.jomc.tools]

COVERAGE SUMMARY FOR SOURCE FILE [JavaClasses.java]

nameclass, %method, %block, %line, %
JavaClasses.java100% (1/1)96%  (23/24)63%  (1880/2967)76%  (389.8/513)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JavaClasses100% (1/1)96%  (23/24)63%  (1880/2967)76%  (389.8/513)
JavaClasses (JavaClasses): void 0%   (0/1)0%   (0/4)0%   (0/2)
validateClasses (Module, Unmarshaller, ClassLoader): ModelValidationReport 100% (1/1)13%  (21/161)20%  (6/30)
validateClasses (Unmarshaller, ClassLoader): ModelValidationReport 100% (1/1)31%  (14/45)40%  (4/10)
validateClasses (Implementation, Unmarshaller, JavaClass): ModelValidationReport 100% (1/1)33%  (295/882)56%  (53.9/96)
validateClasses (Specification, Unmarshaller, JavaClass): ModelValidationReport 100% (1/1)46%  (105/228)83%  (19.2/23)
commitClasses (Implementation, Marshaller, File): void 100% (1/1)67%  (179/268)73%  (32.8/45)
getJavaClass (File): JavaClass 100% (1/1)71%  (15/21)60%  (3/5)
getMessage (String, Object []): String 100% (1/1)72%  (13/18)67%  (2/3)
encodeModelObject (Marshaller, JAXBElement): byte [] 100% (1/1)73%  (32/44)69%  (9/13)
getJavaClass (URL, String): JavaClass 100% (1/1)77%  (20/26)71%  (5/7)
decodeModelObject (Unmarshaller, byte [], Class): ModelObject 100% (1/1)78%  (42/54)73%  (11/15)
getJavaClass (InputStream, String): JavaClass 100% (1/1)82%  (27/33)80%  (8/10)
transformClasses (Specification, Marshaller, Unmarshaller, JavaClass, List): ... 100% (1/1)85%  (100/117)83%  (24/29)
transformClasses (Marshaller, Unmarshaller, File, List): void 100% (1/1)90%  (44/49)91%  (10/11)
getClassfileAttribute (JavaClass, String): byte [] 100% (1/1)91%  (48/53)91%  (10/11)
commitClasses (Specification, Marshaller, File): void 100% (1/1)93%  (82/88)89%  (16/18)
transformClasses (Module, Marshaller, Unmarshaller, File, List): void 100% (1/1)94%  (170/181)92%  (33/36)
transformClasses (Implementation, Marshaller, Unmarshaller, JavaClass, List):... 100% (1/1)94%  (267/284)92%  (58/63)
setClassfileAttribute (JavaClass, String, byte []): void 100% (1/1)96%  (128/133)97%  (28/29)
JavaClasses (): void 100% (1/1)100% (3/3)100% (2/2)
commitClasses (Marshaller, File): void 100% (1/1)100% (33/33)100% (7/7)
commitClasses (Module, Marshaller, File): void 100% (1/1)100% (64/64)100% (13/13)
validateClasses (Module, Unmarshaller, File): ModelValidationReport 100% (1/1)100% (133/133)100% (25/25)
validateClasses (Unmarshaller, File): ModelValidationReport 100% (1/1)100% (45/45)100% (10/10)

1/*
2 *   Copyright (c) 2009 The JOMC Project
3 *   Copyright (c) 2005 Christian Schulte <cs@jomc.org>
4 *   All rights reserved.
5 *
6 *   Redistribution and use in source and binary forms, with or without
7 *   modification, are permitted provided that the following conditions
8 *   are met:
9 *
10 *     o Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *
13 *     o Redistributions in binary form must reproduce the above copyright
14 *       notice, this list of conditions and the following disclaimer in
15 *       the documentation and/or other materials provided with the
16 *       distribution.
17 *
18 *   THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS"
19 *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 *   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 *   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR
22 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 *   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 *   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 *   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 *   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 *   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 *   $Id: JavaClasses.java 1435 2010-01-30 01:52:40Z schulte2005 $
31 *
32 */
33package org.jomc.tools;
34 
35import java.io.ByteArrayInputStream;
36import java.io.ByteArrayOutputStream;
37import java.io.File;
38import java.io.IOException;
39import java.io.InputStream;
40import java.net.URL;
41import java.text.MessageFormat;
42import java.util.List;
43import java.util.ResourceBundle;
44import java.util.logging.Level;
45import java.util.zip.GZIPInputStream;
46import java.util.zip.GZIPOutputStream;
47import javax.xml.bind.JAXBElement;
48import javax.xml.bind.JAXBException;
49import javax.xml.bind.Marshaller;
50import javax.xml.bind.Unmarshaller;
51import javax.xml.bind.util.JAXBResult;
52import javax.xml.bind.util.JAXBSource;
53import javax.xml.transform.Transformer;
54import javax.xml.transform.TransformerException;
55import org.apache.bcel.classfile.Attribute;
56import org.apache.bcel.classfile.ClassParser;
57import org.apache.bcel.classfile.Constant;
58import org.apache.bcel.classfile.ConstantPool;
59import org.apache.bcel.classfile.ConstantUtf8;
60import org.apache.bcel.classfile.JavaClass;
61import org.apache.bcel.classfile.Unknown;
62import org.jomc.model.Dependencies;
63import org.jomc.model.Dependency;
64import org.jomc.model.Implementation;
65import org.jomc.model.Message;
66import org.jomc.model.Messages;
67import org.jomc.model.ModelObject;
68import org.jomc.model.ModelValidationReport;
69import org.jomc.model.Module;
70import org.jomc.model.ObjectFactory;
71import org.jomc.model.Properties;
72import org.jomc.model.Property;
73import org.jomc.model.Specification;
74import org.jomc.model.SpecificationReference;
75import org.jomc.model.Specifications;
76import org.jomc.util.ParseException;
77import org.jomc.util.TokenMgrError;
78import org.jomc.util.VersionParser;
79 
80/**
81 * Manages Java classes.
82 *
83 * <p><b>Use cases</b><br/><ul>
84 * <li>{@link #commitClasses(javax.xml.bind.Marshaller, java.io.File) }</li>
85 * <li>{@link #commitClasses(org.jomc.model.Module, javax.xml.bind.Marshaller, java.io.File) }</li>
86 * <li>{@link #commitClasses(org.jomc.model.Specification, javax.xml.bind.Marshaller, java.io.File) }</li>
87 * <li>{@link #commitClasses(org.jomc.model.Implementation, javax.xml.bind.Marshaller, java.io.File) }</li>
88 * <li>{@link #validateClasses(javax.xml.bind.Unmarshaller, java.io.File) }</li>
89 * <li>{@link #validateClasses(javax.xml.bind.Unmarshaller, java.lang.ClassLoader) }</li>
90 * <li>{@link #validateClasses(org.jomc.model.Module, javax.xml.bind.Unmarshaller, java.io.File) }</li>
91 * <li>{@link #validateClasses(org.jomc.model.Module, javax.xml.bind.Unmarshaller, java.lang.ClassLoader) }</li>
92 * <li>{@link #validateClasses(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass) }</li>
93 * <li>{@link #validateClasses(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass) }</li>
94 * <li>{@link #transformClasses(javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, java.io.File, java.util.List) }</li>
95 * <li>{@link #transformClasses(org.jomc.model.Module, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, java.io.File, java.util.List) }</li>
96 * <li>{@link #transformClasses(org.jomc.model.Specification, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List) }</li>
97 * <li>{@link #transformClasses(org.jomc.model.Implementation, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List) }</li>
98 * </ul></p>
99 *
100 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
101 * @version $Id: JavaClasses.java 1435 2010-01-30 01:52:40Z schulte2005 $
102 *
103 * @see #getModules()
104 */
105public class JavaClasses extends JomcTool
106{
107 
108    /** Creates a new {@code JavaClasses} instance. */
109    public JavaClasses()
110    {
111        super();
112    }
113 
114    /**
115     * Creates a new {@code JavaClasses} instance taking a {@code JavaClasses} instance to initialize the instance with.
116     *
117     * @param tool The instance to initialize the new instance with,
118     */
119    public JavaClasses( final JavaClasses tool )
120    {
121        super( tool );
122    }
123 
124    /**
125     * Commits meta-data of the modules of the instance to compiled Java classes.
126     *
127     * @param marshaller The marshaller to use for committing the classes.
128     * @param classesDirectory The directory holding the compiled class files.
129     *
130     * @throws NullPointerException if {@code marshaller} or {@code classesDirectory} is {@code null}.
131     * @throws ToolException if committing meta-data fails.
132     *
133     * @see #commitClasses(org.jomc.model.Module, javax.xml.bind.Marshaller, java.io.File)
134     */
135    public void commitClasses( final Marshaller marshaller, final File classesDirectory ) throws ToolException
136    {
137        if ( marshaller == null )
138        {
139            throw new NullPointerException( "marshaller" );
140        }
141        if ( classesDirectory == null )
142        {
143            throw new NullPointerException( "classesDirectory" );
144        }
145 
146        for ( Module m : this.getModules().getModule() )
147        {
148            this.commitClasses( m, marshaller, classesDirectory );
149        }
150    }
151 
152    /**
153     * Commits meta-data of a given module of the modules of the instance to compiled Java classes.
154     *
155     * @param module The module to process.
156     * @param marshaller The marshaller to use for committing the classes.
157     * @param classesDirectory The directory holding the compiled class files.
158     *
159     * @throws NullPointerException if {@code module}, {@code marshaller} or {@code classesDirectory} is {@code null}.
160     * @throws ToolException if committing meta-data fails.
161     *
162     * @see #commitClasses(org.jomc.model.Specification, javax.xml.bind.Marshaller, java.io.File)
163     * @see #commitClasses(org.jomc.model.Implementation, javax.xml.bind.Marshaller, java.io.File)
164     */
165    public void commitClasses( final Module module, final Marshaller marshaller, final File classesDirectory )
166        throws ToolException
167    {
168        if ( module == null )
169        {
170            throw new NullPointerException( "module" );
171        }
172        if ( marshaller == null )
173        {
174            throw new NullPointerException( "marshaller" );
175        }
176        if ( classesDirectory == null )
177        {
178            throw new NullPointerException( "classesDirectory" );
179        }
180 
181        if ( module.getSpecifications() != null )
182        {
183            for ( Specification s : module.getSpecifications().getSpecification() )
184            {
185                this.commitClasses( s, marshaller, classesDirectory );
186            }
187        }
188        if ( module.getImplementations() != null )
189        {
190            for ( Implementation i : module.getImplementations().getImplementation() )
191            {
192                this.commitClasses( i, marshaller, classesDirectory );
193            }
194        }
195    }
196 
197    /**
198     * Commits meta-data of a given specification of the modules of the instance to compiled Java classes.
199     *
200     * @param specification The specification to process.
201     * @param marshaller The marshaller to use for committing the classes.
202     * @param classesDirectory The directory holding the compiled class files.
203     *
204     * @throws NullPointerException if {@code specification}, {@code marshaller} or {@code classesDirectory} is
205     * {@code null}.
206     * @throws ToolException if committing meta-data fails.
207     *
208     * @see org.jomc.model.ModelContext#createMarshaller()
209     */
210    public void commitClasses( final Specification specification, final Marshaller marshaller,
211                               final File classesDirectory ) throws ToolException
212    {
213        if ( specification == null )
214        {
215            throw new NullPointerException( "specification" );
216        }
217        if ( marshaller == null )
218        {
219            throw new NullPointerException( "marshaller" );
220        }
221        if ( classesDirectory == null )
222        {
223            throw new NullPointerException( "classesDirectory" );
224        }
225 
226        try
227        {
228            if ( specification.isClassDeclaration() )
229            {
230                final String classLocation = specification.getClazz().replace( '.', File.separatorChar ) + ".class";
231                final File classFile = new File( classesDirectory, classLocation );
232                if ( this.isLoggable( Level.INFO ) )
233                {
234                    this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null );
235                }
236 
237                final JavaClass javaClass = this.getJavaClass( classFile );
238                this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject(
239                    marshaller, new ObjectFactory().createSpecification( specification ) ) );
240 
241                javaClass.dump( classFile );
242            }
243        }
244        catch ( final IOException e )
245        {
246            throw new ToolException( e );
247        }
248    }
249 
250    /**
251     * Commits meta-data of a given implementation of the modules of the instance to compiled Java classes.
252     *
253     * @param implementation The implementation to process.
254     * @param marshaller The marshaller to use for committing the classes.
255     * @param classesDirectory The directory holding the compiled class files.
256     *
257     * @throws NullPointerException if {@code implementation}, {@code marshaller} or {@code classesDirectory} is
258     * {@code null}.
259     * @throws ToolException if committing meta-data fails.
260     *
261     * @see org.jomc.model.ModelContext#createMarshaller()
262     */
263    public void commitClasses( final Implementation implementation, final Marshaller marshaller,
264                               final File classesDirectory ) throws ToolException
265    {
266        if ( implementation == null )
267        {
268            throw new NullPointerException( "implementation" );
269        }
270        if ( marshaller == null )
271        {
272            throw new NullPointerException( "marshaller" );
273        }
274        if ( classesDirectory == null )
275        {
276            throw new NullPointerException( "classesDirectory" );
277        }
278 
279        try
280        {
281            if ( implementation.isClassDeclaration() )
282            {
283                Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() );
284                if ( dependencies == null )
285                {
286                    dependencies = new Dependencies();
287                }
288 
289                Properties properties = this.getModules().getProperties( implementation.getIdentifier() );
290                if ( properties == null )
291                {
292                    properties = new Properties();
293                }
294 
295                Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
296                if ( messages == null )
297                {
298                    messages = new Messages();
299                }
300 
301                Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() );
302                if ( specifications == null )
303                {
304                    specifications = new Specifications();
305                }
306 
307                for ( SpecificationReference r : specifications.getReference() )
308                {
309                    if ( specifications.getSpecification( r.getIdentifier() ) == null &&
310                         this.isLoggable( Level.WARNING ) )
311                    {
312                        this.log( Level.WARNING, getMessage( "unresolvedSpecification", r.getIdentifier(),
313                                                             implementation.getIdentifier() ), null );
314 
315                    }
316                }
317 
318                for ( Dependency d : dependencies.getDependency() )
319                {
320                    final Specification s = this.getModules().getSpecification( d.getIdentifier() );
321 
322                    if ( s != null )
323                    {
324                        if ( specifications.getSpecification( s.getIdentifier() ) == null )
325                        {
326                            specifications.getSpecification().add( s );
327                        }
328                    }
329                    else if ( this.isLoggable( Level.WARNING ) )
330                    {
331                        this.log( Level.WARNING, getMessage( "unresolvedDependencySpecification", d.getIdentifier(),
332                                                             d.getName(), implementation.getIdentifier() ), null );
333 
334                    }
335                }
336 
337                final String classLocation = implementation.getClazz().replace( '.', File.separatorChar ) + ".class";
338                final File classFile = new File( classesDirectory, classLocation );
339 
340                if ( this.isLoggable( Level.INFO ) )
341                {
342                    this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null );
343                }
344 
345                final JavaClass javaClass = this.getJavaClass( classFile );
346                final ObjectFactory of = new ObjectFactory();
347 
348                this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject(
349                    marshaller, of.createDependencies( dependencies ) ) );
350 
351                this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject(
352                    marshaller, of.createProperties( properties ) ) );
353 
354                this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject(
355                    marshaller, of.createMessages( messages ) ) );
356 
357                this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject(
358                    marshaller, of.createSpecifications( specifications ) ) );
359 
360                javaClass.dump( classFile );
361            }
362        }
363        catch ( final IOException e )
364        {
365            throw new ToolException( e );
366        }
367    }
368 
369    /**
370     * Validates compiled Java classes against the modules of the instance.
371     *
372     * @param unmarshaller The unmarshaller to use for validating classes.
373     * @param classesDirectory The directory holding the compiled class files.
374     *
375     * @return The report of the validation.
376     *
377     * @throws NullPointerException if {@code unmarshaller} or {@code classesDirectory} is {@code null}.
378     * @throws ToolException if reading class files fails.
379     *
380     * @see #validateClasses(org.jomc.model.Module, javax.xml.bind.Unmarshaller, java.io.File)
381     */
382    public ModelValidationReport validateClasses( final Unmarshaller unmarshaller, final File classesDirectory )
383        throws ToolException
384    {
385        if ( unmarshaller == null )
386        {
387            throw new NullPointerException( "unmarshaller" );
388        }
389        if ( classesDirectory == null )
390        {
391            throw new NullPointerException( "classesDirectory" );
392        }
393 
394        final ModelValidationReport report = new ModelValidationReport();
395 
396        for ( Module m : this.getModules().getModule() )
397        {
398            final ModelValidationReport current = this.validateClasses( m, unmarshaller, classesDirectory );
399            report.getDetails().addAll( current.getDetails() );
400        }
401 
402        return report;
403    }
404 
405    /**
406     * Validates compiled Java classes against the modules of the instance.
407     *
408     * @param unmarshaller The unmarshaller to use for validating classes.
409     * @param classLoader The class loader to search for classes.
410     *
411     * @return The report of the validation.
412     *
413     * @throws NullPointerException if {@code unmarshaller} or {@code classLoader} is {@code null}.
414     * @throws ToolException if reading class files fails.
415     *
416     * @see #validateClasses(org.jomc.model.Module, javax.xml.bind.Unmarshaller, java.lang.ClassLoader)
417     */
418    public ModelValidationReport validateClasses( final Unmarshaller unmarshaller, final ClassLoader classLoader )
419        throws ToolException
420    {
421        if ( unmarshaller == null )
422        {
423            throw new NullPointerException( "unmarshaller" );
424        }
425        if ( classLoader == null )
426        {
427            throw new NullPointerException( "classLoader" );
428        }
429 
430        final ModelValidationReport report = new ModelValidationReport();
431 
432        for ( Module m : this.getModules().getModule() )
433        {
434            final ModelValidationReport current = this.validateClasses( m, unmarshaller, classLoader );
435            report.getDetails().addAll( current.getDetails() );
436        }
437 
438        return report;
439    }
440 
441    /**
442     * Validates compiled Java classes against a given module of the modules of the instance.
443     *
444     * @param module The module to process.
445     * @param unmarshaller The unmarshaller to use for validating classes.
446     * @param classesDirectory The directory holding the compiled class files.
447     *
448     * @return The report of the validation.
449     *
450     * @throws NullPointerException if {@code module}, {@code unmarshaller} or {@code classesDirectory} is {@code null}.
451     * @throws ToolException if reading class files fails.
452     *
453     * @see #validateClasses(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
454     * @see #validateClasses(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
455     */
456    public ModelValidationReport validateClasses( final Module module, final Unmarshaller unmarshaller,
457                                                  final File classesDirectory ) throws ToolException
458    {
459        if ( module == null )
460        {
461            throw new NullPointerException( "module" );
462        }
463        if ( unmarshaller == null )
464        {
465            throw new NullPointerException( "unmarshaller" );
466        }
467        if ( classesDirectory == null )
468        {
469            throw new NullPointerException( "classesDirectory" );
470        }
471 
472        final ModelValidationReport report = new ModelValidationReport();
473 
474        if ( module.getSpecifications() != null )
475        {
476            for ( Specification s : module.getSpecifications().getSpecification() )
477            {
478                if ( s.isClassDeclaration() )
479                {
480                    final String classLocation = s.getClazz().replace( '.', File.separatorChar ) + ".class";
481                    final File classFile = new File( classesDirectory, classLocation );
482                    final ModelValidationReport current =
483                        this.validateClasses( s, unmarshaller, this.getJavaClass( classFile ) );
484 
485                    report.getDetails().addAll( current.getDetails() );
486                }
487            }
488        }
489 
490        if ( module.getImplementations() != null )
491        {
492            for ( Implementation i : module.getImplementations().getImplementation() )
493            {
494                if ( i.isClassDeclaration() )
495                {
496                    final String classLocation = i.getClazz().replace( '.', File.separatorChar ) + ".class";
497                    final File classFile = new File( classesDirectory, classLocation );
498                    final JavaClass javaClass = this.getJavaClass( classFile );
499                    final ModelValidationReport current =
500                        this.validateClasses( i, unmarshaller, javaClass );
501 
502                    report.getDetails().addAll( current.getDetails() );
503                }
504            }
505        }
506 
507        return report;
508    }
509 
510    /**
511     * Validates compiled Java classes against a given module of the modules of the instance.
512     *
513     * @param module The module to process.
514     * @param unmarshaller The unmarshaller to use for validating classes.
515     * @param classLoader The class loader to search for classes.
516     *
517     * @return The report of the validation.
518     *
519     * @throws NullPointerException if {@code module}, {@code unmarshaller} or {@code classLoader} is {@code null}.
520     * @throws ToolException if reading class files fails.
521     *
522     * @see #validateClasses(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
523     * @see #validateClasses(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
524     */
525    public ModelValidationReport validateClasses( final Module module, final Unmarshaller unmarshaller,
526                                                  final ClassLoader classLoader ) throws ToolException
527    {
528        if ( module == null )
529        {
530            throw new NullPointerException( "module" );
531        }
532        if ( unmarshaller == null )
533        {
534            throw new NullPointerException( "unmarshaller" );
535        }
536        if ( classLoader == null )
537        {
538            throw new NullPointerException( "classLoader" );
539        }
540 
541        final ModelValidationReport report = new ModelValidationReport();
542 
543        if ( module.getSpecifications() != null )
544        {
545            for ( Specification s : module.getSpecifications().getSpecification() )
546            {
547                if ( s.isClassDeclaration() )
548                {
549                    final String classLocation = s.getClazz().replace( '.', '/' ) + ".class";
550                    final URL classUrl = classLoader.getResource( classLocation );
551 
552                    if ( classUrl == null )
553                    {
554                        throw new ToolException( getMessage( "resourceNotFound", classLocation ) );
555                    }
556 
557                    final JavaClass javaClass = this.getJavaClass( classUrl, classLocation );
558                    final ModelValidationReport current =
559                        this.validateClasses( s, unmarshaller, javaClass );
560 
561                    report.getDetails().addAll( current.getDetails() );
562                }
563            }
564        }
565 
566        if ( module.getImplementations() != null )
567        {
568            for ( Implementation i : module.getImplementations().getImplementation() )
569            {
570                if ( i.isClassDeclaration() )
571                {
572                    final String classLocation = i.getClazz().replace( '.', '/' ) + ".class";
573                    final URL classUrl = classLoader.getResource( classLocation );
574 
575                    if ( classUrl == null )
576                    {
577                        throw new ToolException( getMessage( "resourceNotFound", classLocation ) );
578                    }
579 
580                    final JavaClass javaClass = this.getJavaClass( classUrl, classLocation );
581                    final ModelValidationReport current = this.validateClasses( i, unmarshaller, javaClass );
582                    report.getDetails().addAll( current.getDetails() );
583                }
584            }
585        }
586 
587        return report;
588    }
589 
590    /**
591     * Validates compiled Java classes against a given specification of the modules of the instance.
592     *
593     * @param specification The specification to process.
594     * @param unmarshaller The unmarshaller to use for validating classes.
595     * @param javaClass The class to validate.
596     *
597     * @return The report of the validation.
598     *
599     * @throws NullPointerException if {@code specification}, {@code unmarshaller} or {@code javaClass} is {@code null}.
600     * @throws ToolException if reading class files fails.
601     *
602     * @see org.jomc.model.ModelContext#createUnmarshaller()
603     */
604    public ModelValidationReport validateClasses( final Specification specification,
605                                                  final Unmarshaller unmarshaller, final JavaClass javaClass )
606        throws ToolException
607    {
608        if ( specification == null )
609        {
610            throw new NullPointerException( "specification" );
611        }
612        if ( unmarshaller == null )
613        {
614            throw new NullPointerException( "unmarshaller" );
615        }
616        if ( javaClass == null )
617        {
618            throw new NullPointerException( "javaClass" );
619        }
620 
621        if ( this.isLoggable( Level.INFO ) )
622        {
623            this.log( Level.INFO, getMessage( "validatingSpecification", specification.getIdentifier() ), null );
624        }
625 
626        final ModelValidationReport report = new ModelValidationReport();
627 
628        Specification decoded = null;
629        final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() );
630        if ( bytes != null )
631        {
632            decoded = this.decodeModelObject( unmarshaller, bytes, Specification.class );
633        }
634 
635        if ( decoded != null )
636        {
637            if ( decoded.getMultiplicity() != specification.getMultiplicity() )
638            {
639                report.getDetails().add( new ModelValidationReport.Detail(
640                    "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage(
641                    "illegalMultiplicity", specification.getIdentifier(), specification.getMultiplicity().value(),
642                    decoded.getMultiplicity().value() ), new ObjectFactory().createSpecification( specification ) ) );
643 
644            }
645 
646            if ( decoded.getScope() == null
647                 ? specification.getScope() != null
648                 : !decoded.getScope().equals( specification.getScope() ) )
649            {
650                report.getDetails().add( new ModelValidationReport.Detail(
651                    "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage(
652                    "illegalScope", specification.getIdentifier(),
653                    specification.getScope() == null ? "Multiton" : specification.getScope(),
654                    decoded.getScope() == null ? "Multiton" : decoded.getScope() ),
655                    new ObjectFactory().createSpecification( specification ) ) );
656 
657            }
658 
659            if ( decoded.getClazz() == null
660                 ? specification.getClazz() != null
661                 : !decoded.getClazz().equals( specification.getClazz() ) )
662            {
663                report.getDetails().add( new ModelValidationReport.Detail(
664                    "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage(
665                    "illegalSpecificationClass", decoded.getIdentifier(),
666                    specification.getClazz(), decoded.getClazz() ),
667                    new ObjectFactory().createSpecification( specification ) ) );
668 
669            }
670        }
671        else if ( this.isLoggable( Level.WARNING ) )
672        {
673            this.log( Level.WARNING, getMessage( "cannotValidateSpecification", specification.getIdentifier(),
674                                                 Specification.class.getName() ), null );
675 
676        }
677 
678        return report;
679    }
680 
681    /**
682     * Validates compiled Java classes against a given implementation of the modules of the instance.
683     *
684     * @param implementation The implementation to process.
685     * @param unmarshaller The unmarshaller to use for validating classes.
686     * @param javaClass The class to validate.
687     *
688     * @return The report of the validation.
689     *
690     * @throws NullPointerException if {@code implementation}, {@code unmarshaller} or {@code javaClass} is
691     * {@code null}.
692     * @throws ToolException if reading class files fails.
693     *
694     * @see org.jomc.model.ModelContext#createUnmarshaller()
695     */
696    public ModelValidationReport validateClasses( final Implementation implementation,
697                                                  final Unmarshaller unmarshaller, final JavaClass javaClass )
698        throws ToolException
699    {
700        if ( implementation == null )
701        {
702            throw new NullPointerException( "implementation" );
703        }
704        if ( unmarshaller == null )
705        {
706            throw new NullPointerException( "unmarshaller" );
707        }
708        if ( javaClass == null )
709        {
710            throw new NullPointerException( "javaClass" );
711        }
712 
713        if ( this.isLoggable( Level.INFO ) )
714        {
715            this.log( Level.INFO, getMessage( "validatingImplementation", implementation.getIdentifier() ), null );
716        }
717 
718        final ModelValidationReport report = new ModelValidationReport();
719 
720        try
721        {
722            Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() );
723            if ( dependencies == null )
724            {
725                dependencies = new Dependencies();
726            }
727 
728            Properties properties = this.getModules().getProperties( implementation.getIdentifier() );
729            if ( properties == null )
730            {
731                properties = new Properties();
732            }
733 
734            Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
735            if ( messages == null )
736            {
737                messages = new Messages();
738            }
739 
740            Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() );
741            if ( specifications == null )
742            {
743                specifications = new Specifications();
744            }
745 
746            Dependencies decodedDependencies = null;
747            byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() );
748            if ( bytes != null )
749            {
750                decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class );
751            }
752 
753            Properties decodedProperties = null;
754            bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() );
755            if ( bytes != null )
756            {
757                decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class );
758            }
759 
760            Messages decodedMessages = null;
761            bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() );
762            if ( bytes != null )
763            {
764                decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class );
765            }
766 
767            Specifications decodedSpecifications = null;
768            bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() );
769            if ( bytes != null )
770            {
771                decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class );
772            }
773 
774            if ( decodedDependencies != null )
775            {
776                for ( Dependency decodedDependency : decodedDependencies.getDependency() )
777                {
778                    final Dependency dependency = dependencies.getDependency( decodedDependency.getName() );
779 
780                    if ( dependency == null )
781                    {
782                        report.getDetails().add( new ModelValidationReport.Detail(
783                            "CLASS_MISSING_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage(
784                            "missingDependency", implementation.getIdentifier(), decodedDependency.getName() ),
785                            new ObjectFactory().createImplementation( implementation ) ) );
786 
787                    }
788 
789                    final Specification s = this.getModules().getSpecification( decodedDependency.getIdentifier() );
790 
791                    if ( s != null && s.getVersion() != null && decodedDependency.getVersion() != null &&
792                         VersionParser.compare( decodedDependency.getVersion(), s.getVersion() ) > 0 )
793                    {
794                        final Module moduleOfSpecification =
795                            this.getModules().getModuleOfSpecification( s.getIdentifier() );
796 
797                        final Module moduleOfImplementation =
798                            this.getModules().getModuleOfImplementation( implementation.getIdentifier() );
799 
800                        report.getDetails().add( new ModelValidationReport.Detail(
801                            "CLASS_INCOMPATIBLE_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage(
802                            "incompatibleDependency", javaClass.getClassName(),
803                            moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(),
804                            s.getIdentifier(),
805                            moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(),
806                            decodedDependency.getVersion(), s.getVersion() ),
807                            new ObjectFactory().createImplementation( implementation ) ) );
808 
809                    }
810                }
811            }
812            else if ( this.isLoggable( Level.WARNING ) )
813            {
814                this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
815                                                     Dependencies.class.getName() ), null );
816 
817            }
818 
819            if ( decodedProperties != null )
820            {
821                for ( Property decodedProperty : decodedProperties.getProperty() )
822                {
823                    final Property property = properties.getProperty( decodedProperty.getName() );
824 
825                    if ( property == null )
826                    {
827                        report.getDetails().add( new ModelValidationReport.Detail(
828                            "CLASS_MISSING_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage(
829                            "missingProperty", implementation.getIdentifier(), decodedProperty.getName() ),
830                            new ObjectFactory().createImplementation( implementation ) ) );
831 
832                    }
833                    else
834                    {
835                        if ( decodedProperty.getType() == null ? property.getType() != null
836                             : !decodedProperty.getType().equals( property.getType() ) )
837                        {
838                            report.getDetails().add( new ModelValidationReport.Detail(
839                                "CLASS_ILLEGAL_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage(
840                                "illegalPropertyType", implementation.getIdentifier(), decodedProperty.getName(),
841                                property.getType() == null ? "default" : property.getType(),
842                                decodedProperty.getType() == null ? "default" : decodedProperty.getType() ),
843                                new ObjectFactory().createImplementation( implementation ) ) );
844 
845                        }
846                    }
847                }
848            }
849            else if ( this.isLoggable( Level.WARNING ) )
850            {
851                this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
852                                                     Properties.class.getName() ), null );
853 
854            }
855 
856            if ( decodedMessages != null )
857            {
858                for ( Message decodedMessage : decodedMessages.getMessage() )
859                {
860                    final Message message = messages.getMessage( decodedMessage.getName() );
861 
862                    if ( message == null )
863                    {
864                        report.getDetails().add( new ModelValidationReport.Detail(
865                            "CLASS_MISSING_IMPLEMENTATION_MESSAGE", Level.SEVERE, getMessage(
866                            "missingMessage", implementation.getIdentifier(), decodedMessage.getName() ),
867                            new ObjectFactory().createImplementation( implementation ) ) );
868 
869                    }
870                }
871            }
872            else if ( this.isLoggable( Level.WARNING ) )
873            {
874                this.log( Level.WARNING, getMessage( "cannotValidateImplementation",
875                                                     implementation.getIdentifier(), Messages.class.getName() ), null );
876 
877            }
878 
879            if ( decodedSpecifications != null )
880            {
881                for ( Specification decodedSpecification : decodedSpecifications.getSpecification() )
882                {
883                    final Specification specification =
884                        this.getModules().getSpecification( decodedSpecification.getIdentifier() );
885 
886                    if ( specification == null )
887                    {
888                        report.getDetails().add( new ModelValidationReport.Detail(
889                            "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage(
890                            "missingSpecification", implementation.getIdentifier(),
891                            decodedSpecification.getIdentifier() ),
892                            new ObjectFactory().createImplementation( implementation ) ) );
893 
894                    }
895                    else
896                    {
897                        if ( decodedSpecification.getMultiplicity() != specification.getMultiplicity() )
898                        {
899                            report.getDetails().add( new ModelValidationReport.Detail(
900                                "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage(
901                                "illegalMultiplicity", specification.getIdentifier(),
902                                specification.getMultiplicity().value(),
903                                decodedSpecification.getMultiplicity().value() ),
904                                new ObjectFactory().createImplementation( implementation ) ) );
905 
906                        }
907 
908                        if ( decodedSpecification.getScope() == null
909                             ? specification.getScope() != null
910                             : !decodedSpecification.getScope().equals( specification.getScope() ) )
911                        {
912                            report.getDetails().add( new ModelValidationReport.Detail(
913                                "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage(
914                                "illegalScope", decodedSpecification.getIdentifier(),
915                                specification.getScope() == null ? "Multiton" : specification.getScope(),
916                                decodedSpecification.getScope() == null ? "Multiton" : decodedSpecification.getScope() ),
917                                new ObjectFactory().createImplementation( implementation ) ) );
918 
919                        }
920 
921                        if ( decodedSpecification.getClazz() == null ? specification.getClazz() != null
922                             : !decodedSpecification.getClazz().equals( specification.getClazz() ) )
923                        {
924                            report.getDetails().add( new ModelValidationReport.Detail(
925                                "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage(
926                                "illegalSpecificationClass", decodedSpecification.getIdentifier(),
927                                specification.getClazz(), decodedSpecification.getClazz() ),
928                                new ObjectFactory().createImplementation( implementation ) ) );
929 
930                        }
931                    }
932                }
933 
934                for ( SpecificationReference decodedReference : decodedSpecifications.getReference() )
935                {
936                    final Specification specification =
937                        specifications.getSpecification( decodedReference.getIdentifier() );
938 
939                    if ( specification == null )
940                    {
941                        report.getDetails().add( new ModelValidationReport.Detail(
942                            "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage(
943                            "missingSpecification", implementation.getIdentifier(), decodedReference.getIdentifier() ),
944                            new ObjectFactory().createImplementation( implementation ) ) );
945 
946                    }
947                    else if ( decodedReference.getVersion() != null && specification.getVersion() != null &&
948                              VersionParser.compare( decodedReference.getVersion(), specification.getVersion() ) != 0 )
949                    {
950                        final Module moduleOfSpecification =
951                            this.getModules().getModuleOfSpecification( decodedReference.getIdentifier() );
952 
953                        final Module moduleOfImplementation =
954                            this.getModules().getModuleOfImplementation( implementation.getIdentifier() );
955 
956                        report.getDetails().add( new ModelValidationReport.Detail(
957                            "CLASS_INCOMPATIBLE_IMPLEMENTATION", Level.SEVERE, getMessage(
958                            "incompatibleImplementation", javaClass.getClassName(),
959                            moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(),
960                            specification.getIdentifier(),
961                            moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(),
962                            decodedReference.getVersion(), specification.getVersion() ),
963                            new ObjectFactory().createImplementation( implementation ) ) );
964 
965                    }
966                }
967            }
968            else if ( this.isLoggable( Level.WARNING ) )
969            {
970                this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
971                                                     Specifications.class.getName() ), null );
972 
973            }
974 
975            return report;
976        }
977        catch ( final ParseException e )
978        {
979            throw new ToolException( e );
980        }
981        catch ( final TokenMgrError e )
982        {
983            throw new ToolException( e );
984        }
985    }
986 
987    /**
988     * Transforms committed meta-data of compiled Java classes of the modules of the instance.
989     *
990     * @param marshaller The marshaller to use for transforming classes.
991     * @param unmarshaller The unmarshaller to use for transforming classes.
992     * @param classesDirectory The directory holding the compiled class files.
993     * @param transformers The transformers to use for transforming the classes.
994     *
995     * @throws NullPointerException if {@code marshaller}, {@code unmarshaller}, {@code classesDirectory} or
996     * {@code transformers} is {@code null}.
997     * @throws ToolException if accessing class files fails.
998     *
999     * @see #transformClasses(org.jomc.model.Module, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, java.io.File, java.util.List)
1000     */
1001    public void transformClasses( final Marshaller marshaller, final Unmarshaller unmarshaller,
1002                                  final File classesDirectory, final List<Transformer> transformers )
1003        throws ToolException
1004    {
1005        if ( marshaller == null )
1006        {
1007            throw new NullPointerException( "marshaller" );
1008        }
1009        if ( unmarshaller == null )
1010        {
1011            throw new NullPointerException( "unmarshaller" );
1012        }
1013        if ( transformers == null )
1014        {
1015            throw new NullPointerException( "transformers" );
1016        }
1017        if ( classesDirectory == null )
1018        {
1019            throw new NullPointerException( "classesDirectory" );
1020        }
1021 
1022        for ( Module m : this.getModules().getModule() )
1023        {
1024            this.transformClasses( m, marshaller, unmarshaller, classesDirectory, transformers );
1025        }
1026    }
1027 
1028    /**
1029     * Transforms committed meta-data of compiled Java classes of a given module of the modules of the instance.
1030     *
1031     * @param module The module to process.
1032     * @param marshaller The marshaller to use for transforming classes.
1033     * @param unmarshaller The unmarshaller to use for transforming classes.
1034     * @param classesDirectory The directory holding the compiled class files.
1035     * @param transformers The transformers to use for transforming the classes.
1036     *
1037     * @throws NullPointerException if {@code module}, {@code marshaller}, {@code unmarshaller},
1038     * {@code classesDirectory} or {@code transformers} is {@code null}.
1039     * @throws ToolException if accessing class files fails.
1040     *
1041     * @see #transformClasses(org.jomc.model.Specification, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List)
1042     * @see #transformClasses(org.jomc.model.Implementation, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List)
1043     */
1044    public void transformClasses( final Module module, final Marshaller marshaller, final Unmarshaller unmarshaller,
1045                                  final File classesDirectory, final List<Transformer> transformers )
1046        throws ToolException
1047    {
1048        if ( module == null )
1049        {
1050            throw new NullPointerException( "module" );
1051        }
1052        if ( marshaller == null )
1053        {
1054            throw new NullPointerException( "marshaller" );
1055        }
1056        if ( unmarshaller == null )
1057        {
1058            throw new NullPointerException( "unmarshaller" );
1059        }
1060        if ( transformers == null )
1061        {
1062            throw new NullPointerException( "transformers" );
1063        }
1064        if ( classesDirectory == null )
1065        {
1066            throw new NullPointerException( "classesDirectory" );
1067        }
1068 
1069        try
1070        {
1071            if ( module.getSpecifications() != null )
1072            {
1073                for ( Specification s : module.getSpecifications().getSpecification() )
1074                {
1075                    if ( s.isClassDeclaration() )
1076                    {
1077                        final String classLocation = s.getIdentifier().replace( '.', File.separatorChar ) + ".class";
1078                        final File classFile = new File( classesDirectory, classLocation );
1079 
1080                        if ( this.isLoggable( Level.INFO ) )
1081                        {
1082                            this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null );
1083                        }
1084 
1085                        final JavaClass javaClass = this.getJavaClass( classFile );
1086                        this.transformClasses( s, marshaller, unmarshaller, javaClass, transformers );
1087                        javaClass.dump( classFile );
1088                    }
1089                }
1090            }
1091 
1092            if ( module.getImplementations() != null )
1093            {
1094                for ( Implementation i : module.getImplementations().getImplementation() )
1095                {
1096                    if ( i.isClassDeclaration() )
1097                    {
1098                        final String classLocation = i.getClazz().replace( '.', File.separatorChar ) + ".class";
1099                        final File classFile = new File( classesDirectory, classLocation );
1100 
1101                        if ( this.isLoggable( Level.INFO ) )
1102                        {
1103                            this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null );
1104                        }
1105 
1106                        final JavaClass javaClass = this.getJavaClass( classFile );
1107                        this.transformClasses( i, marshaller, unmarshaller, javaClass, transformers );
1108                        javaClass.dump( classFile );
1109                    }
1110                }
1111            }
1112        }
1113        catch ( final IOException e )
1114        {
1115            throw new ToolException( e );
1116        }
1117    }
1118 
1119    /**
1120     * Transforms committed meta-data of compiled Java classes of a given specification of the modules of the instance.
1121     *
1122     * @param specification The specification to process.
1123     * @param marshaller The marshaller to use for transforming classes.
1124     * @param unmarshaller The unmarshaller to use for transforming classes.
1125     * @param javaClass The java class to process.
1126     * @param transformers The transformers to use for transforming the classes.
1127     *
1128     * @throws NullPointerException if {@code specification}, {@code marshaller}, {@code unmarshaller},
1129     * {@code javaClass} or {@code transformers} is {@code null}.
1130     * @throws ToolException if accessing class files fails.
1131     *
1132     * @see org.jomc.model.ModelContext#createMarshaller()
1133     * @see org.jomc.model.ModelContext#createUnmarshaller()
1134     */
1135    public void transformClasses( final Specification specification, final Marshaller marshaller,
1136                                  final Unmarshaller unmarshaller, final JavaClass javaClass,
1137                                  final List<Transformer> transformers ) throws ToolException
1138    {
1139        if ( specification == null )
1140        {
1141            throw new NullPointerException( "specification" );
1142        }
1143        if ( marshaller == null )
1144        {
1145            throw new NullPointerException( "marshaller" );
1146        }
1147        if ( unmarshaller == null )
1148        {
1149            throw new NullPointerException( "unmarshaller" );
1150        }
1151        if ( javaClass == null )
1152        {
1153            throw new NullPointerException( "javaClass" );
1154        }
1155        if ( transformers == null )
1156        {
1157            throw new NullPointerException( "transformers" );
1158        }
1159 
1160        try
1161        {
1162            Specification decodedSpecification = null;
1163            final ObjectFactory objectFactory = new ObjectFactory();
1164            final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() );
1165            if ( bytes != null )
1166            {
1167                decodedSpecification = this.decodeModelObject( unmarshaller, bytes, Specification.class );
1168            }
1169 
1170            if ( decodedSpecification != null )
1171            {
1172                for ( Transformer transformer : transformers )
1173                {
1174                    final JAXBSource source =
1175                        new JAXBSource( marshaller, objectFactory.createSpecification( decodedSpecification ) );
1176 
1177                    final JAXBResult result = new JAXBResult( unmarshaller );
1178                    transformer.transform( source, result );
1179                    decodedSpecification = ( (JAXBElement<Specification>) result.getResult() ).getValue();
1180                }
1181 
1182                this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject(
1183                    marshaller, objectFactory.createSpecification( decodedSpecification ) ) );
1184 
1185            }
1186        }
1187        catch ( final JAXBException e )
1188        {
1189            throw new ToolException( e );
1190        }
1191        catch ( final TransformerException e )
1192        {
1193            throw new ToolException( e );
1194        }
1195    }
1196 
1197    /**
1198     * Transforms committed meta-data of compiled Java classes of a given implementation of the modules of the instance.
1199     *
1200     * @param implementation The implementation to process.
1201     * @param marshaller The marshaller to use for transforming classes.
1202     * @param unmarshaller The unmarshaller to use for transforming classes.
1203     * @param javaClass The java class to process.
1204     * @param transformers The transformers to use for transforming the classes.
1205     *
1206     * @throws NullPointerException if {@code implementation}, {@code marshaller}, {@code unmarshaller},
1207     * {@code javaClass} or {@code transformers} is {@code null}.
1208     * @throws ToolException if accessing class files fails.
1209     *
1210     * @see org.jomc.model.ModelContext#createMarshaller()
1211     * @see org.jomc.model.ModelContext#createUnmarshaller()
1212     */
1213    public void transformClasses( final Implementation implementation, final Marshaller marshaller,
1214                                  final Unmarshaller unmarshaller, final JavaClass javaClass,
1215                                  final List<Transformer> transformers ) throws ToolException
1216    {
1217        if ( implementation == null )
1218        {
1219            throw new NullPointerException( "implementation" );
1220        }
1221        if ( marshaller == null )
1222        {
1223            throw new NullPointerException( "marshaller" );
1224        }
1225        if ( unmarshaller == null )
1226        {
1227            throw new NullPointerException( "unmarshaller" );
1228        }
1229        if ( javaClass == null )
1230        {
1231            throw new NullPointerException( "javaClass" );
1232        }
1233        if ( transformers == null )
1234        {
1235            throw new NullPointerException( "transformers" );
1236        }
1237 
1238        try
1239        {
1240            Dependencies decodedDependencies = null;
1241            byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() );
1242            if ( bytes != null )
1243            {
1244                decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class );
1245            }
1246 
1247            Messages decodedMessages = null;
1248            bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() );
1249            if ( bytes != null )
1250            {
1251                decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class );
1252            }
1253 
1254            Properties decodedProperties = null;
1255            bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() );
1256            if ( bytes != null )
1257            {
1258                decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class );
1259            }
1260 
1261            Specifications decodedSpecifications = null;
1262            bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() );
1263            if ( bytes != null )
1264            {
1265                decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class );
1266            }
1267 
1268            final ObjectFactory of = new ObjectFactory();
1269            for ( Transformer transformer : transformers )
1270            {
1271                if ( decodedDependencies != null )
1272                {
1273                    final JAXBSource source = new JAXBSource( marshaller, of.createDependencies( decodedDependencies ) );
1274                    final JAXBResult result = new JAXBResult( unmarshaller );
1275                    transformer.transform( source, result );
1276                    decodedDependencies = ( (JAXBElement<Dependencies>) result.getResult() ).getValue();
1277                }
1278 
1279                if ( decodedMessages != null )
1280                {
1281                    final JAXBSource source = new JAXBSource( marshaller, of.createMessages( decodedMessages ) );
1282                    final JAXBResult result = new JAXBResult( unmarshaller );
1283                    transformer.transform( source, result );
1284                    decodedMessages = ( (JAXBElement<Messages>) result.getResult() ).getValue();
1285                }
1286 
1287                if ( decodedProperties != null )
1288                {
1289                    final JAXBSource source = new JAXBSource( marshaller, of.createProperties( decodedProperties ) );
1290                    final JAXBResult result = new JAXBResult( unmarshaller );
1291                    transformer.transform( source, result );
1292                    decodedProperties = ( (JAXBElement<Properties>) result.getResult() ).getValue();
1293                }
1294 
1295                if ( decodedSpecifications != null )
1296                {
1297                    final JAXBSource source =
1298                        new JAXBSource( marshaller, of.createSpecifications( decodedSpecifications ) );
1299 
1300                    final JAXBResult result = new JAXBResult( unmarshaller );
1301                    transformer.transform( source, result );
1302                    decodedSpecifications = ( (JAXBElement<Specifications>) result.getResult() ).getValue();
1303                }
1304            }
1305 
1306            if ( decodedDependencies != null )
1307            {
1308                this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject(
1309                    marshaller, of.createDependencies( decodedDependencies ) ) );
1310 
1311            }
1312 
1313            if ( decodedMessages != null )
1314            {
1315                this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject(
1316                    marshaller, of.createMessages( decodedMessages ) ) );
1317 
1318            }
1319 
1320            if ( decodedProperties != null )
1321            {
1322                this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject(
1323                    marshaller, of.createProperties( decodedProperties ) ) );
1324 
1325            }
1326 
1327            if ( decodedSpecifications != null )
1328            {
1329                this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject(
1330                    marshaller, of.createSpecifications( decodedSpecifications ) ) );
1331 
1332            }
1333        }
1334        catch ( final JAXBException e )
1335        {
1336            throw new ToolException( e );
1337        }
1338        catch ( final TransformerException e )
1339        {
1340            throw new ToolException( e );
1341        }
1342    }
1343 
1344    /**
1345     * Parses a class file.
1346     *
1347     * @param classFile The class file to parse.
1348     *
1349     * @return The parsed class file.
1350     *
1351     * @throws NullPointerException if {@code classFile} is {@code null}.
1352     * @throws ToolException if parsing {@code classFile} fails.
1353     *
1354     * @see JavaClass
1355     */
1356    public JavaClass getJavaClass( final File classFile ) throws ToolException
1357    {
1358        if ( classFile == null )
1359        {
1360            throw new NullPointerException( "classFile" );
1361        }
1362 
1363        try
1364        {
1365            return this.getJavaClass( classFile.toURI().toURL(), classFile.getName() );
1366        }
1367        catch ( final IOException e )
1368        {
1369            throw new ToolException( e );
1370        }
1371    }
1372 
1373    /**
1374     * Parses a class file.
1375     *
1376     * @param url The URL of the class file to parse.
1377     * @param className The name of the class at {@code url}.
1378     *
1379     * @return The parsed class file.
1380     *
1381     * @throws NullPointerException if {@code url} or {@code className} is {@code null}.
1382     * @throws ToolException if parsing fails.
1383     *
1384     * @see JavaClass
1385     */
1386    public JavaClass getJavaClass( final URL url, final String className ) throws ToolException
1387    {
1388        if ( url == null )
1389        {
1390            throw new NullPointerException( "url" );
1391        }
1392        if ( className == null )
1393        {
1394            throw new NullPointerException( "className" );
1395        }
1396 
1397        try
1398        {
1399            return this.getJavaClass( url.openStream(), className );
1400        }
1401        catch ( final IOException e )
1402        {
1403            throw new ToolException( e );
1404        }
1405    }
1406 
1407    /**
1408     * Parses a class file.
1409     *
1410     * @param stream The stream to read the class file from.
1411     * @param className The name of the class to read from {@code stream}.
1412     *
1413     * @return The parsed class file.
1414     *
1415     * @throws NullPointerException if {@code stream} or {@code className} is {@code null}.
1416     * @throws ToolException if parsing fails.
1417     *
1418     * @see JavaClass
1419     */
1420    public JavaClass getJavaClass( final InputStream stream, final String className ) throws ToolException
1421    {
1422        if ( stream == null )
1423        {
1424            throw new NullPointerException( "stream" );
1425        }
1426        if ( className == null )
1427        {
1428            throw new NullPointerException( "className" );
1429        }
1430 
1431        try
1432        {
1433            final ClassParser parser = new ClassParser( stream, className );
1434            final JavaClass clazz = parser.parse();
1435            stream.close();
1436            return clazz;
1437        }
1438        catch ( final IOException e )
1439        {
1440            throw new ToolException( e );
1441        }
1442    }
1443 
1444    /**
1445     * Gets an attribute from a java class.
1446     *
1447     * @param clazz The java class to get an attribute from.
1448     * @param attributeName The name of the attribute to get.
1449     *
1450     * @return The value of attribute {@code attributeName} of {@code clazz} or {@code null} if no such attribute
1451     * exists.
1452     *
1453     * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}.
1454     * @throws ToolException if getting the attribute fails.
1455     *
1456     * @see JavaClass#getAttributes()
1457     */
1458    public byte[] getClassfileAttribute( final JavaClass clazz, final String attributeName ) throws ToolException
1459    {
1460        if ( clazz == null )
1461        {
1462            throw new NullPointerException( "clazz" );
1463        }
1464        if ( attributeName == null )
1465        {
1466            throw new NullPointerException( "attributeName" );
1467        }
1468 
1469        final Attribute[] attributes = clazz.getAttributes();
1470 
1471        for ( int i = attributes.length - 1; i >= 0; i-- )
1472        {
1473            final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() );
1474 
1475            if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) )
1476            {
1477                final Unknown unknown = (Unknown) attributes[i];
1478                return unknown.getBytes();
1479            }
1480        }
1481 
1482        return null;
1483    }
1484 
1485    /**
1486     * Adds or updates an attribute in a java class.
1487     *
1488     * @param clazz The class to update.
1489     * @param attributeName The name of the attribute to update.
1490     * @param data The new data of the attribute to update the {@code classFile} with.
1491     *
1492     * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}.
1493     * @throws ToolException if updating the class file fails.
1494     *
1495     * @see JavaClass#getAttributes()
1496     */
1497    public void setClassfileAttribute( final JavaClass clazz, final String attributeName, final byte[] data )
1498        throws ToolException
1499    {
1500        if ( clazz == null )
1501        {
1502            throw new NullPointerException( "clazz" );
1503        }
1504        if ( attributeName == null )
1505        {
1506            throw new NullPointerException( "attributeName" );
1507        }
1508 
1509        /*
1510        The JavaTM Virtual Machine Specification - Second Edition - Chapter 4.1
1511 
1512        A Java virtual machine implementation is required to silently ignore any
1513        or all attributes in the attributes table of a ClassFile structure that
1514        it does not recognize. Attributes not defined in this specification are
1515        not allowed to affect the semantics of the class file, but only to
1516        provide additional descriptive information (§4.7.1).
1517         */
1518        Attribute[] attributes = clazz.getAttributes();
1519 
1520        int attributeIndex = -1;
1521        int nameIndex = -1;
1522 
1523        for ( int i = attributes.length - 1; i >= 0; i-- )
1524        {
1525            final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() );
1526 
1527            if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) )
1528            {
1529                attributeIndex = i;
1530                nameIndex = attributes[i].getNameIndex();
1531            }
1532        }
1533 
1534        if ( nameIndex == -1 )
1535        {
1536            final Constant[] pool = clazz.getConstantPool().getConstantPool();
1537            final Constant[] tmp = new Constant[ pool.length + 1 ];
1538            System.arraycopy( pool, 0, tmp, 0, pool.length );
1539            tmp[pool.length] = new ConstantUtf8( attributeName );
1540            nameIndex = pool.length;
1541            clazz.setConstantPool( new ConstantPool( tmp ) );
1542        }
1543 
1544        final Unknown unknown = new Unknown( nameIndex, data.length, data, clazz.getConstantPool() );
1545 
1546        if ( attributeIndex == -1 )
1547        {
1548            final Attribute[] tmp = new Attribute[ attributes.length + 1 ];
1549            System.arraycopy( attributes, 0, tmp, 0, attributes.length );
1550            tmp[attributes.length] = unknown;
1551            attributes = tmp;
1552        }
1553        else
1554        {
1555            attributes[attributeIndex] = unknown;
1556        }
1557 
1558        clazz.setAttributes( attributes );
1559    }
1560 
1561    /**
1562     * Encodes a model object to a byte array.
1563     *
1564     * @param marshaller The marshaller to use for encoding the object.
1565     * @param modelObject The model object to encode.
1566     *
1567     * @return GZIP compressed XML document for {@code modelObject}.
1568     *
1569     * @throws NullPointerException if {@code marshaller} or {@code modelObject} is {@code null}.
1570     * @throws ToolException if encoding {@code modelObject} fails.
1571     */
1572    public byte[] encodeModelObject( final Marshaller marshaller, final JAXBElement<? extends ModelObject> modelObject )
1573        throws ToolException
1574    {
1575        if ( marshaller == null )
1576        {
1577            throw new NullPointerException( "marshaller" );
1578        }
1579        if ( modelObject == null )
1580        {
1581            throw new NullPointerException( "modelObject" );
1582        }
1583 
1584        try
1585        {
1586            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
1587            final GZIPOutputStream out = new GZIPOutputStream( baos );
1588            marshaller.marshal( modelObject, out );
1589            out.close();
1590            return baos.toByteArray();
1591        }
1592        catch ( final JAXBException e )
1593        {
1594            throw new ToolException( e );
1595        }
1596        catch ( final IOException e )
1597        {
1598            throw new ToolException( e );
1599        }
1600    }
1601 
1602    /**
1603     * Decodes a model object from a byte array.
1604     *
1605     * @param unmarshaller The unmarshaller to use for decoding the object.
1606     * @param bytes The encoded model object to decode.
1607     * @param type The type of the encoded model object.
1608     * @param <T> The type of the decoded model object.
1609     *
1610     * @return Model object decoded from {@code bytes}.
1611     *
1612     * @throws NullPointerException if {@code unmarshaller}, {@code bytes} or {@code type} is {@code null}.
1613     * @throws ToolException if decoding {@code bytes} fails.
1614     */
1615    public <T extends ModelObject> T decodeModelObject( final Unmarshaller unmarshaller, final byte[] bytes,
1616                                                        final Class<T> type ) throws ToolException
1617    {
1618        if ( unmarshaller == null )
1619        {
1620            throw new NullPointerException( "unmarshaller" );
1621        }
1622        if ( bytes == null )
1623        {
1624            throw new NullPointerException( "bytes" );
1625        }
1626        if ( type == null )
1627        {
1628            throw new NullPointerException( "type" );
1629        }
1630 
1631        try
1632        {
1633            final ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
1634            final GZIPInputStream in = new GZIPInputStream( bais );
1635            final JAXBElement<T> element = (JAXBElement<T>) unmarshaller.unmarshal( in );
1636            in.close();
1637            return element.getValue();
1638        }
1639        catch ( final JAXBException e )
1640        {
1641            throw new ToolException( e );
1642        }
1643        catch ( final IOException e )
1644        {
1645            throw new ToolException( e );
1646        }
1647    }
1648 
1649    private static String getMessage( final String key, final Object... arguments )
1650    {
1651        if ( key == null )
1652        {
1653            throw new NullPointerException( "key" );
1654        }
1655 
1656        return MessageFormat.format( ResourceBundle.getBundle( JavaClasses.class.getName().replace( '.', '/' ) ).
1657            getString( key ), arguments );
1658 
1659    }
1660 
1661}

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