001 /*
002 * Copyright (c) 2009 The JOMC Project
003 * Copyright (c) 2005 Christian Schulte <schulte2005@users.sourceforge.net>
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions
008 * are met:
009 *
010 * o Redistributions of source code must retain the above copyright
011 * notice, this list of conditions and the following disclaimer.
012 *
013 * o Redistributions in binary form must reproduce the above copyright
014 * notice, this list of conditions and the following disclaimer in
015 * the documentation and/or other materials provided with the
016 * distribution.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR
022 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
027 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
028 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 *
030 * $Id: ClassFileProcessor.java 2182 2010-06-28 18:52:08Z schulte2005 $
031 *
032 */
033 package org.jomc.tools;
034
035 import java.io.ByteArrayInputStream;
036 import java.io.ByteArrayOutputStream;
037 import java.io.File;
038 import java.io.IOException;
039 import java.io.InputStream;
040 import java.net.URL;
041 import java.text.MessageFormat;
042 import java.util.List;
043 import java.util.ResourceBundle;
044 import java.util.logging.Level;
045 import java.util.zip.GZIPInputStream;
046 import java.util.zip.GZIPOutputStream;
047 import javax.xml.bind.JAXBElement;
048 import javax.xml.bind.JAXBException;
049 import javax.xml.bind.Marshaller;
050 import javax.xml.bind.Unmarshaller;
051 import javax.xml.bind.util.JAXBResult;
052 import javax.xml.bind.util.JAXBSource;
053 import javax.xml.transform.Transformer;
054 import javax.xml.transform.TransformerException;
055 import javax.xml.validation.Schema;
056 import org.apache.bcel.classfile.Attribute;
057 import org.apache.bcel.classfile.ClassParser;
058 import org.apache.bcel.classfile.Constant;
059 import org.apache.bcel.classfile.ConstantPool;
060 import org.apache.bcel.classfile.ConstantUtf8;
061 import org.apache.bcel.classfile.JavaClass;
062 import org.apache.bcel.classfile.Unknown;
063 import org.jomc.model.Dependencies;
064 import org.jomc.model.Dependency;
065 import org.jomc.model.Implementation;
066 import org.jomc.model.Implementations;
067 import org.jomc.model.Message;
068 import org.jomc.model.Messages;
069 import org.jomc.model.ModelObject;
070 import org.jomc.model.Module;
071 import org.jomc.model.ObjectFactory;
072 import org.jomc.model.Properties;
073 import org.jomc.model.Property;
074 import org.jomc.model.Specification;
075 import org.jomc.model.SpecificationReference;
076 import org.jomc.model.Specifications;
077 import org.jomc.modlet.ModelContext;
078 import org.jomc.modlet.ModelException;
079 import org.jomc.modlet.ModelValidationReport;
080 import org.jomc.util.ParseException;
081 import org.jomc.util.TokenMgrError;
082 import org.jomc.util.VersionParser;
083
084 /**
085 * Processes class files.
086 *
087 * <p><b>Use cases</b><br/><ul>
088 * <li>{@link #commitModelObjects(org.jomc.modlet.ModelContext, java.io.File) }</li>
089 * <li>{@link #commitModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) }</li>
090 * <li>{@link #commitModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) }</li>
091 * <li>{@link #commitModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) }</li>
092 * <li>{@link #validateModelObjects(org.jomc.modlet.ModelContext) }</li>
093 * <li>{@link #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext) }</li>
094 * <li>{@link #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext) }</li>
095 * <li>{@link #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext) }</li>
096 * <li>{@link #validateModelObjects(org.jomc.modlet.ModelContext, java.io.File) }</li>
097 * <li>{@link #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) }</li>
098 * <li>{@link #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) }</li>
099 * <li>{@link #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) }</li>
100 * <li>{@link #transformModelObjects(org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
101 * <li>{@link #transformModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
102 * <li>{@link #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
103 * <li>{@link #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
104 * </ul></p>
105 *
106 * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
107 * @version $Id: ClassFileProcessor.java 2182 2010-06-28 18:52:08Z schulte2005 $
108 *
109 * @see #getModules()
110 */
111 public class ClassFileProcessor extends JomcTool
112 {
113
114 /** Empty byte array. */
115 private static final byte[] NO_BYTES =
116 {
117 };
118
119 /** Creates a new {@code ClassFileProcessor} instance. */
120 public ClassFileProcessor()
121 {
122 super();
123 }
124
125 /**
126 * Creates a new {@code ClassFileProcessor} instance taking a {@code ClassFileProcessor} instance to initialize the
127 * instance with.
128 *
129 * @param tool The instance to initialize the new instance with,
130 *
131 * @throws NullPointerException if {@code tool} is {@code null}.
132 * @throws IOException if copying {@code tool} fails.
133 */
134 public ClassFileProcessor( final ClassFileProcessor tool ) throws IOException
135 {
136 super( tool );
137 }
138
139 /**
140 * Commits model objects of the modules of the instance to class files.
141 *
142 * @param context The model context to use for committing the model objects.
143 * @param classesDirectory The directory holding the class files.
144 *
145 * @throws NullPointerException if {@code context} or {@code classesDirectory} is {@code null}.
146 * @throws IOException if committing model objects fails.
147 *
148 * @see #commitModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File)
149 */
150 public final void commitModelObjects( final ModelContext context, final File classesDirectory ) throws IOException
151 {
152 if ( context == null )
153 {
154 throw new NullPointerException( "context" );
155 }
156 if ( classesDirectory == null )
157 {
158 throw new NullPointerException( "classesDirectory" );
159 }
160
161 try
162 {
163 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
164 m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
165
166 this.commitModelObjects( this.getModules().getSpecifications(), this.getModules().getImplementations(), m,
167 classesDirectory );
168
169 }
170 catch ( final ModelException e )
171 {
172 throw (IOException) new IOException( e.getMessage() ).initCause( e );
173 }
174 }
175
176 /**
177 * Commits model objects of a given module of the modules of the instance to class files.
178 *
179 * @param module The module to process.
180 * @param context The model context to use for committing the model objects.
181 * @param classesDirectory The directory holding the class files.
182 *
183 * @throws NullPointerException if {@code module}, {@code context} or {@code classesDirectory} is {@code null}.
184 * @throws IOException if committing model objects fails.
185 *
186 * @see #commitModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File)
187 * @see #commitModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File)
188 */
189 public final void commitModelObjects( final Module module, final ModelContext context, final File classesDirectory )
190 throws IOException
191 {
192 if ( module == null )
193 {
194 throw new NullPointerException( "module" );
195 }
196 if ( context == null )
197 {
198 throw new NullPointerException( "context" );
199 }
200 if ( classesDirectory == null )
201 {
202 throw new NullPointerException( "classesDirectory" );
203 }
204
205 assert this.getModules().getModule( module.getName() ) != null : "Module '" + module.getName() + "' not found.";
206
207 try
208 {
209 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
210 m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
211
212 this.commitModelObjects( module.getSpecifications(), module.getImplementations(), m, classesDirectory );
213 }
214 catch ( final ModelException e )
215 {
216 throw (IOException) new IOException( e.getMessage() ).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 throw (IOException) new IOException( e.getMessage() ).initCause( e );
262 }
263 }
264
265 /**
266 * Commits model objects of a given implementation of the modules of the instance to class files.
267 *
268 * @param implementation The implementation to process.
269 * @param context The model context to use for committing the model objects.
270 * @param classesDirectory The directory holding the class files.
271 *
272 * @throws NullPointerException if {@code implementation}, {@code context} or {@code classesDirectory} is
273 * {@code null}.
274 * @throws IOException if committing model objects fails.
275 *
276 * @see #commitModelObjects(org.jomc.model.Implementation, javax.xml.bind.Marshaller, org.apache.bcel.classfile.JavaClass)
277 */
278 public final void commitModelObjects( final Implementation implementation, final ModelContext context,
279 final File classesDirectory ) throws IOException
280 {
281 if ( implementation == null )
282 {
283 throw new NullPointerException( "implementation" );
284 }
285 if ( context == null )
286 {
287 throw new NullPointerException( "context" );
288 }
289 if ( classesDirectory == null )
290 {
291 throw new NullPointerException( "classesDirectory" );
292 }
293
294 assert this.getModules().getImplementation( implementation.getIdentifier() ) != null :
295 "Implementation '" + implementation.getIdentifier() + "' not found.";
296
297 try
298 {
299 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
300 m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
301
302 this.commitModelObjects( implementation, m, classesDirectory );
303 }
304 catch ( final ModelException e )
305 {
306 throw (IOException) new IOException( e.getMessage() ).initCause( e );
307 }
308 }
309
310 /**
311 * Commits model objects of a given specification of the modules of the instance to a given class file.
312 *
313 * @param specification The specification to process.
314 * @param marshaller The marshaller to use for committing the model objects.
315 * @param javaClass The java class to commit.
316 *
317 * @throws NullPointerException if {@code specification}, {@code marshaller} or {@code javaClass} is {@code null}.
318 * @throws IOException if committing model objects fails.
319 */
320 public void commitModelObjects( final Specification specification, final Marshaller marshaller,
321 final JavaClass javaClass ) throws IOException
322 {
323 if ( specification == null )
324 {
325 throw new NullPointerException( "specification" );
326 }
327 if ( marshaller == null )
328 {
329 throw new NullPointerException( "marshaller" );
330 }
331 if ( javaClass == null )
332 {
333 throw new NullPointerException( "javaClass" );
334 }
335
336 assert this.getModules().getSpecification( specification.getIdentifier() ) != null :
337 "Specification '" + specification.getIdentifier() + "' not found.";
338
339 this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject(
340 marshaller, new ObjectFactory().createSpecification( specification ) ) );
341
342 }
343
344 /**
345 * Commits model objects of a given implementation of the modules of the instance to a given class file.
346 *
347 * @param implementation The implementation to process.
348 * @param marshaller The marshaller to use for committing the model objects.
349 * @param javaClass The java class to commit.
350 *
351 * @throws NullPointerException if {@code implementation}, {@code marshaller} or {@code javaClass} is {@code null}.
352 * @throws IOException if committing model objects fails.
353 */
354 public void commitModelObjects( final Implementation implementation, final Marshaller marshaller,
355 final JavaClass javaClass ) throws IOException
356 {
357 if ( implementation == null )
358 {
359 throw new NullPointerException( "implementation" );
360 }
361 if ( marshaller == null )
362 {
363 throw new NullPointerException( "marshaller" );
364 }
365 if ( javaClass == null )
366 {
367 throw new NullPointerException( "javaClass" );
368 }
369
370 assert this.getModules().getImplementation( implementation.getIdentifier() ) != null :
371 "Implementation '" + implementation.getIdentifier() + "' not found.";
372
373 final ObjectFactory of = new ObjectFactory();
374
375 Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() );
376 if ( dependencies == null )
377 {
378 dependencies = new Dependencies();
379 }
380
381 Properties properties = this.getModules().getProperties( implementation.getIdentifier() );
382 if ( properties == null )
383 {
384 properties = new Properties();
385 }
386
387 Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
388 if ( messages == null )
389 {
390 messages = new Messages();
391 }
392
393 Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() );
394 if ( specifications == null )
395 {
396 specifications = new Specifications();
397 }
398
399 for ( SpecificationReference r : specifications.getReference() )
400 {
401 if ( specifications.getSpecification( r.getIdentifier() ) == null && this.isLoggable( Level.WARNING ) )
402 {
403 this.log( Level.WARNING, getMessage( "unresolvedSpecification", r.getIdentifier(),
404 implementation.getIdentifier() ), null );
405
406 }
407 }
408
409 for ( Dependency d : dependencies.getDependency() )
410 {
411 final Specification s = this.getModules().getSpecification( d.getIdentifier() );
412
413 if ( s != null )
414 {
415 if ( specifications.getSpecification( s.getIdentifier() ) == null )
416 {
417 specifications.getSpecification().add( s );
418 }
419 }
420 else if ( this.isLoggable( Level.WARNING ) )
421 {
422 this.log( Level.WARNING, getMessage( "unresolvedDependencySpecification", d.getIdentifier(),
423 d.getName(), implementation.getIdentifier() ), null );
424
425 }
426 }
427
428 this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject(
429 marshaller, of.createDependencies( dependencies ) ) );
430
431 this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject(
432 marshaller, of.createProperties( properties ) ) );
433
434 this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject(
435 marshaller, of.createMessages( messages ) ) );
436
437 this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject(
438 marshaller, of.createSpecifications( specifications ) ) );
439
440 }
441
442 /**
443 * Validates model objects of class files of the modules of the instance.
444 *
445 * @param context The model context to use for validating model objects.
446 *
447 * @return The report of the validation.
448 *
449 * @throws NullPointerException if {@code context} is {@code null}.
450 * @throws IOException if validating model objects fails.
451 *
452 * @see #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext)
453 */
454 public final ModelValidationReport validateModelObjects( final ModelContext context ) throws IOException
455 {
456 if ( context == null )
457 {
458 throw new NullPointerException( "context" );
459 }
460
461 try
462 {
463 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
464 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
465 return this.validateModelObjects(
466 this.getModules().getSpecifications(), this.getModules().getImplementations(), u,
467 context.getClassLoader() );
468
469 }
470 catch ( final ModelException e )
471 {
472 throw (IOException) new IOException( e.getMessage() ).initCause( e );
473 }
474 }
475
476 /**
477 * Validates model objects of class files of a given module of the modules of the instance.
478 *
479 * @param module The module to process.
480 * @param context The model context to use for validating model objects.
481 *
482 * @return The report of the validation.
483 *
484 * @throws NullPointerException if {@code module} or {@code context} is {@code null}.
485 * @throws IOException if validating model objects fails.
486 *
487 * @see #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext)
488 * @see #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext)
489 */
490 public final ModelValidationReport validateModelObjects( final Module module, final ModelContext context )
491 throws IOException
492 {
493 if ( module == null )
494 {
495 throw new NullPointerException( "module" );
496 }
497 if ( context == null )
498 {
499 throw new NullPointerException( "context" );
500 }
501
502 assert this.getModules().getModule( module.getName() ) != null : "Module '" + module.getName() + "' not found.";
503
504 try
505 {
506 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
507 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
508 return this.validateModelObjects(
509 module.getSpecifications(), module.getImplementations(), u, context.getClassLoader() );
510
511 }
512 catch ( final ModelException e )
513 {
514 throw (IOException) new IOException( e.getMessage() ).initCause( e );
515 }
516 }
517
518 /**
519 * Validates model objects of class files of a given specification of the modules of the instance.
520 *
521 * @param specification The specification to process.
522 * @param context The model context to use for validating model objects.
523 *
524 * @return The report of the validation.
525 *
526 * @throws NullPointerException if {@code specification} or {@code context} is {@code null}.
527 *
528 * @throws IOException if validating model objects fails.
529 *
530 * @see #validateModelObjects(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
531 */
532 public final ModelValidationReport validateModelObjects( final Specification specification,
533 final ModelContext context ) throws IOException
534 {
535 if ( specification == null )
536 {
537 throw new NullPointerException( "specification" );
538 }
539 if ( context == null )
540 {
541 throw new NullPointerException( "context" );
542 }
543
544 assert this.getModules().getSpecification( specification.getIdentifier() ) != null :
545 "Specification '" + specification.getIdentifier() + "' not found.";
546
547 try
548 {
549 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
550 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
551 return this.validateModelObjects( specification, u, context.getClassLoader() );
552 }
553 catch ( final ModelException e )
554 {
555 throw (IOException) new IOException( e.getMessage() ).initCause( e );
556 }
557 }
558
559 /**
560 * Validates model objects of class files of a given implementation of the modules of the instance.
561 *
562 * @param implementation The implementation to process.
563 * @param context The model context to use for validating model objects.
564 *
565 * @return The report of the validation.
566 *
567 * @throws NullPointerException if {@code implementation} or {@code context} is {@code null}.
568 *
569 * @throws IOException if validating model objects fails.
570 *
571 * @see #validateModelObjects(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
572 */
573 public final ModelValidationReport validateModelObjects( final Implementation implementation,
574 final ModelContext context ) throws IOException
575 {
576 if ( implementation == null )
577 {
578 throw new NullPointerException( "implementation" );
579 }
580 if ( context == null )
581 {
582 throw new NullPointerException( "context" );
583 }
584
585 assert this.getModules().getImplementation( implementation.getIdentifier() ) != null :
586 "Implementation '" + implementation.getIdentifier() + "' not found.";
587
588 try
589 {
590 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
591 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
592 return this.validateModelObjects( implementation, u, context.getClassLoader() );
593 }
594 catch ( final ModelException e )
595 {
596 throw (IOException) new IOException( e.getMessage() ).initCause( e );
597 }
598 }
599
600 /**
601 * Validates model objects of class files of the modules of the instance.
602 *
603 * @param context The model context to use for validating model objects.
604 * @param classesDirectory The directory holding the class files.
605 *
606 * @return The report of the validation.
607 *
608 * @throws NullPointerException if {@code context} or {@code classesDirectory} is {@code null}.
609 * @throws IOException if validating model objects fails.
610 *
611 * @see #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File)
612 */
613 public final ModelValidationReport validateModelObjects( final ModelContext context, final File classesDirectory )
614 throws IOException
615 {
616 if ( context == null )
617 {
618 throw new NullPointerException( "context" );
619 }
620 if ( classesDirectory == null )
621 {
622 throw new NullPointerException( "classesDirectory" );
623 }
624
625 try
626 {
627 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
628 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
629 return this.validateModelObjects(
630 this.getModules().getSpecifications(), this.getModules().getImplementations(), u, classesDirectory );
631
632 }
633 catch ( final ModelException e )
634 {
635 throw (IOException) new IOException( e.getMessage() ).initCause( e );
636 }
637 }
638
639 /**
640 * Validates model objects of class files of a given module of the modules of the instance.
641 *
642 * @param module The module to process.
643 * @param context The model context to use for validating model objects.
644 * @param classesDirectory The directory holding the class files.
645 *
646 * @return The report of the validation.
647 *
648 * @throws NullPointerException if {@code module}, {@code context} or {@code classesDirectory} is {@code null}.
649 * @throws IOException if validating model objects fails.
650 *
651 * @see #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File)
652 * @see #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File)
653 */
654 public final ModelValidationReport validateModelObjects( final Module module, final ModelContext context,
655 final File classesDirectory ) throws IOException
656 {
657 if ( module == null )
658 {
659 throw new NullPointerException( "module" );
660 }
661 if ( context == null )
662 {
663 throw new NullPointerException( "context" );
664 }
665 if ( classesDirectory == null )
666 {
667 throw new NullPointerException( "classesDirectory" );
668 }
669
670 assert this.getModules().getModule( module.getName() ) != null : "Module '" + module.getName() + "' not found.";
671
672 try
673 {
674 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
675 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
676 return this.validateModelObjects( module.getSpecifications(), module.getImplementations(), u,
677 classesDirectory );
678
679 }
680 catch ( final ModelException e )
681 {
682 throw (IOException) new IOException( e.getMessage() ).initCause( e );
683 }
684 }
685
686 /**
687 * Validates model objects of class files of a given specification of the modules of the instance.
688 *
689 * @param specification The specification to process.
690 * @param context The model context to use for validating model objects.
691 * @param classesDirectory The directory holding the class files.
692 *
693 * @return The report of the validation.
694 *
695 * @throws NullPointerException if {@code specification}, {@code context} or {@code classesDirectory} is
696 * {@code null}.
697 *
698 * @throws IOException if validating model objects fails.
699 *
700 * @see #validateModelObjects(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
701 */
702 public final ModelValidationReport validateModelObjects( final Specification specification,
703 final ModelContext context, final File classesDirectory )
704 throws IOException
705 {
706 if ( specification == null )
707 {
708 throw new NullPointerException( "specification" );
709 }
710 if ( context == null )
711 {
712 throw new NullPointerException( "context" );
713 }
714 if ( classesDirectory == null )
715 {
716 throw new NullPointerException( "classesDirectory" );
717 }
718
719 assert this.getModules().getSpecification( specification.getIdentifier() ) != null :
720 "Specification '" + specification.getIdentifier() + "' not found.";
721
722 try
723 {
724 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
725 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
726 return this.validateModelObjects( specification, u, classesDirectory );
727 }
728 catch ( final ModelException e )
729 {
730 throw (IOException) new IOException( e.getMessage() ).initCause( e );
731 }
732 }
733
734 /**
735 * Validates model objects of class files of a given implementation of the modules of the instance.
736 *
737 * @param implementation The implementation to process.
738 * @param context The model context to use for validating model objects.
739 * @param classesDirectory The directory holding the class files.
740 *
741 * @return The report of the validation.
742 *
743 * @throws NullPointerException if {@code implementation}, {@code context} or {@code classesDirectory} is
744 * {@code null}.
745 *
746 * @throws IOException if validating model objects fails.
747 *
748 * @see #validateModelObjects(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
749 */
750 public final ModelValidationReport validateModelObjects( final Implementation implementation,
751 final ModelContext context, final File classesDirectory )
752 throws IOException
753 {
754 if ( implementation == null )
755 {
756 throw new NullPointerException( "implementation" );
757 }
758 if ( context == null )
759 {
760 throw new NullPointerException( "context" );
761 }
762 if ( classesDirectory == null )
763 {
764 throw new NullPointerException( "classesDirectory" );
765 }
766
767 assert this.getModules().getImplementation( implementation.getIdentifier() ) != null :
768 "Implementation '" + implementation.getIdentifier() + "' not found.";
769
770 try
771 {
772 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
773 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
774 return this.validateModelObjects( implementation, u, classesDirectory );
775 }
776 catch ( final ModelException e )
777 {
778 throw (IOException) new IOException( e.getMessage() ).initCause( e );
779 }
780 }
781
782 /**
783 * Validates model objects of a given specification of the modules of the instance.
784 *
785 * @param specification The specification to process.
786 * @param unmarshaller The unmarshaller to use for validating model objects.
787 * @param javaClass The java class to validate.
788 *
789 * @return The report of the validation.
790 *
791 * @throws NullPointerException if {@code specification}, {@code unmarshaller} or {@code javaClass} is {@code null}.
792 * @throws IOException if validating model objects fails.
793 */
794 public ModelValidationReport validateModelObjects( final Specification specification,
795 final Unmarshaller unmarshaller, final JavaClass javaClass )
796 throws IOException
797 {
798 if ( specification == null )
799 {
800 throw new NullPointerException( "specification" );
801 }
802 if ( unmarshaller == null )
803 {
804 throw new NullPointerException( "unmarshaller" );
805 }
806 if ( javaClass == null )
807 {
808 throw new NullPointerException( "javaClass" );
809 }
810
811 assert this.getModules().getSpecification( specification.getIdentifier() ) != null :
812 "Specification '" + specification.getIdentifier() + "' not found.";
813
814 final ModelValidationReport report = new ModelValidationReport();
815
816 Specification decoded = null;
817 final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() );
818 if ( bytes != null )
819 {
820 decoded = this.decodeModelObject( unmarshaller, bytes, Specification.class );
821 }
822
823 if ( decoded != null )
824 {
825 if ( decoded.getMultiplicity() != specification.getMultiplicity() )
826 {
827 report.getDetails().add( new ModelValidationReport.Detail(
828 "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage(
829 "illegalMultiplicity", specification.getIdentifier(), specification.getMultiplicity().value(),
830 decoded.getMultiplicity().value() ), new ObjectFactory().createSpecification( specification ) ) );
831
832 }
833
834 if ( decoded.getScope() == null
835 ? specification.getScope() != null
836 : !decoded.getScope().equals( specification.getScope() ) )
837 {
838 report.getDetails().add( new ModelValidationReport.Detail(
839 "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage(
840 "illegalScope", specification.getIdentifier(),
841 specification.getScope() == null ? "Multiton" : specification.getScope(),
842 decoded.getScope() == null ? "Multiton" : decoded.getScope() ),
843 new ObjectFactory().createSpecification( specification ) ) );
844
845 }
846
847 if ( decoded.getClazz() == null
848 ? specification.getClazz() != null
849 : !decoded.getClazz().equals( specification.getClazz() ) )
850 {
851 report.getDetails().add( new ModelValidationReport.Detail(
852 "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage(
853 "illegalSpecificationClass", decoded.getIdentifier(),
854 specification.getClazz(), decoded.getClazz() ),
855 new ObjectFactory().createSpecification( specification ) ) );
856
857 }
858 }
859 else if ( this.isLoggable( Level.WARNING ) )
860 {
861 this.log( Level.WARNING, getMessage( "cannotValidateSpecification", specification.getIdentifier(),
862 Specification.class.getName() ), null );
863
864 }
865
866 return report;
867 }
868
869 /**
870 * Validates model objects of a given implementation of the modules of the instance.
871 *
872 * @param implementation The implementation to process.
873 * @param unmarshaller The unmarshaller to use for validating model objects.
874 * @param javaClass The java class to validate.
875 *
876 * @return The report of the validation.
877 *
878 * @throws NullPointerException if {@code implementation}, {@code unmarshaller} or {@code javaClass} is {@code null}.
879 * @throws IOException if validating model objects fails.
880 */
881 public ModelValidationReport validateModelObjects( final Implementation implementation,
882 final Unmarshaller unmarshaller, final JavaClass javaClass )
883 throws IOException
884 {
885 if ( implementation == null )
886 {
887 throw new NullPointerException( "implementation" );
888 }
889 if ( unmarshaller == null )
890 {
891 throw new NullPointerException( "unmarshaller" );
892 }
893 if ( javaClass == null )
894 {
895 throw new NullPointerException( "javaClass" );
896 }
897
898 assert this.getModules().getImplementation( implementation.getIdentifier() ) != null :
899 "Implementation '" + implementation.getIdentifier() + "' not found.";
900
901 try
902 {
903 final ModelValidationReport report = new ModelValidationReport();
904 Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() );
905 if ( dependencies == null )
906 {
907 dependencies = new Dependencies();
908 }
909
910 Properties properties = this.getModules().getProperties( implementation.getIdentifier() );
911 if ( properties == null )
912 {
913 properties = new Properties();
914 }
915
916 Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
917 if ( messages == null )
918 {
919 messages = new Messages();
920 }
921
922 Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() );
923 if ( specifications == null )
924 {
925 specifications = new Specifications();
926 }
927
928 Dependencies decodedDependencies = null;
929 byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() );
930 if ( bytes != null )
931 {
932 decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class );
933 }
934
935 Properties decodedProperties = null;
936 bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() );
937 if ( bytes != null )
938 {
939 decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class );
940 }
941
942 Messages decodedMessages = null;
943 bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() );
944 if ( bytes != null )
945 {
946 decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class );
947 }
948
949 Specifications decodedSpecifications = null;
950 bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() );
951 if ( bytes != null )
952 {
953 decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class );
954 }
955
956 if ( decodedDependencies != null )
957 {
958 for ( Dependency decodedDependency : decodedDependencies.getDependency() )
959 {
960 final Dependency dependency = dependencies.getDependency( decodedDependency.getName() );
961 final Specification s = this.getModules().getSpecification( decodedDependency.getIdentifier() );
962
963 if ( dependency == null )
964 {
965 report.getDetails().add( new ModelValidationReport.Detail(
966 "CLASS_MISSING_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage(
967 "missingDependency", implementation.getIdentifier(), decodedDependency.getName() ),
968 new ObjectFactory().createImplementation( implementation ) ) );
969
970 }
971 else if ( decodedDependency.getImplementationName() != null
972 && dependency.getImplementationName() == null )
973 {
974 report.getDetails().add( new ModelValidationReport.Detail(
975 "CLASS_MISSING_DEPENDENCY_IMPLEMENTATION_NAME", Level.SEVERE, getMessage(
976 "missingDependencyImplementationName", implementation.getIdentifier(),
977 decodedDependency.getName() ),
978 new ObjectFactory().createImplementation( implementation ) ) );
979
980 }
981
982 if ( s != null && s.getVersion() != null && decodedDependency.getVersion() != null
983 && VersionParser.compare( decodedDependency.getVersion(), s.getVersion() ) > 0 )
984 {
985 final Module moduleOfSpecification =
986 this.getModules().getModuleOfSpecification( s.getIdentifier() );
987
988 final Module moduleOfImplementation =
989 this.getModules().getModuleOfImplementation( implementation.getIdentifier() );
990
991 report.getDetails().add( new ModelValidationReport.Detail(
992 "CLASS_INCOMPATIBLE_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage(
993 "incompatibleDependency", javaClass.getClassName(),
994 moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(),
995 s.getIdentifier(),
996 moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(),
997 decodedDependency.getVersion(), s.getVersion() ),
998 new ObjectFactory().createImplementation( implementation ) ) );
999
1000 }
1001 }
1002 }
1003 else if ( this.isLoggable( Level.WARNING ) )
1004 {
1005 this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
1006 Dependencies.class.getName() ), null );
1007
1008 }
1009
1010 if ( decodedProperties != null )
1011 {
1012 for ( Property decodedProperty : decodedProperties.getProperty() )
1013 {
1014 final Property property = properties.getProperty( decodedProperty.getName() );
1015
1016 if ( property == null )
1017 {
1018 report.getDetails().add( new ModelValidationReport.Detail(
1019 "CLASS_MISSING_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage(
1020 "missingProperty", implementation.getIdentifier(), decodedProperty.getName() ),
1021 new ObjectFactory().createImplementation( implementation ) ) );
1022
1023 }
1024 else if ( decodedProperty.getType() == null
1025 ? property.getType() != null
1026 : !decodedProperty.getType().equals( property.getType() ) )
1027 {
1028 report.getDetails().add( new ModelValidationReport.Detail(
1029 "CLASS_ILLEGAL_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage(
1030 "illegalPropertyType", implementation.getIdentifier(), decodedProperty.getName(),
1031 property.getType() == null ? "<>" : property.getType(),
1032 decodedProperty.getType() == null ? "<>" : decodedProperty.getType() ),
1033 new ObjectFactory().createImplementation( implementation ) ) );
1034
1035 }
1036 }
1037 }
1038 else if ( this.isLoggable( Level.WARNING ) )
1039 {
1040 this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
1041 Properties.class.getName() ), null );
1042
1043 }
1044
1045 if ( decodedMessages != null )
1046 {
1047 for ( Message decodedMessage : decodedMessages.getMessage() )
1048 {
1049 final Message message = messages.getMessage( decodedMessage.getName() );
1050
1051 if ( message == null )
1052 {
1053 report.getDetails().add( new ModelValidationReport.Detail(
1054 "CLASS_MISSING_IMPLEMENTATION_MESSAGE", Level.SEVERE, getMessage(
1055 "missingMessage", implementation.getIdentifier(), decodedMessage.getName() ),
1056 new ObjectFactory().createImplementation( implementation ) ) );
1057
1058 }
1059 }
1060 }
1061 else if ( this.isLoggable( Level.WARNING ) )
1062 {
1063 this.log( Level.WARNING, getMessage( "cannotValidateImplementation",
1064 implementation.getIdentifier(), Messages.class.getName() ), null );
1065
1066 }
1067
1068 if ( decodedSpecifications != null )
1069 {
1070 for ( Specification decodedSpecification : decodedSpecifications.getSpecification() )
1071 {
1072 final Specification specification =
1073 this.getModules().getSpecification( decodedSpecification.getIdentifier() );
1074
1075 if ( specification == null )
1076 {
1077 report.getDetails().add( new ModelValidationReport.Detail(
1078 "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage(
1079 "missingSpecification", implementation.getIdentifier(),
1080 decodedSpecification.getIdentifier() ),
1081 new ObjectFactory().createImplementation( implementation ) ) );
1082
1083 }
1084 else
1085 {
1086 if ( decodedSpecification.getMultiplicity() != specification.getMultiplicity() )
1087 {
1088 report.getDetails().add( new ModelValidationReport.Detail(
1089 "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage(
1090 "illegalMultiplicity", specification.getIdentifier(),
1091 specification.getMultiplicity().value(),
1092 decodedSpecification.getMultiplicity().value() ),
1093 new ObjectFactory().createImplementation( implementation ) ) );
1094
1095 }
1096
1097 if ( decodedSpecification.getScope() == null
1098 ? specification.getScope() != null
1099 : !decodedSpecification.getScope().equals( specification.getScope() ) )
1100 {
1101 report.getDetails().add( new ModelValidationReport.Detail(
1102 "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage(
1103 "illegalScope", decodedSpecification.getIdentifier(),
1104 specification.getScope() == null ? "Multiton" : specification.getScope(),
1105 decodedSpecification.getScope() == null ? "Multiton" : decodedSpecification.getScope() ),
1106 new ObjectFactory().createImplementation( implementation ) ) );
1107
1108 }
1109
1110 if ( decodedSpecification.getClazz() == null
1111 ? specification.getClazz() != null
1112 : !decodedSpecification.getClazz().equals( specification.getClazz() ) )
1113 {
1114 report.getDetails().add( new ModelValidationReport.Detail(
1115 "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage(
1116 "illegalSpecificationClass", decodedSpecification.getIdentifier(),
1117 specification.getClazz(), decodedSpecification.getClazz() ),
1118 new ObjectFactory().createImplementation( implementation ) ) );
1119
1120 }
1121 }
1122 }
1123
1124 for ( SpecificationReference decodedReference : decodedSpecifications.getReference() )
1125 {
1126 final Specification specification =
1127 specifications.getSpecification( decodedReference.getIdentifier() );
1128
1129 if ( specification == null )
1130 {
1131 report.getDetails().add( new ModelValidationReport.Detail(
1132 "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage(
1133 "missingSpecification", implementation.getIdentifier(), decodedReference.getIdentifier() ),
1134 new ObjectFactory().createImplementation( implementation ) ) );
1135
1136 }
1137 else if ( decodedReference.getVersion() != null && specification.getVersion() != null
1138 && VersionParser.compare( decodedReference.getVersion(),
1139 specification.getVersion() ) != 0 )
1140 {
1141 final Module moduleOfSpecification =
1142 this.getModules().getModuleOfSpecification( decodedReference.getIdentifier() );
1143
1144 final Module moduleOfImplementation =
1145 this.getModules().getModuleOfImplementation( implementation.getIdentifier() );
1146
1147 report.getDetails().add( new ModelValidationReport.Detail(
1148 "CLASS_INCOMPATIBLE_IMPLEMENTATION", Level.SEVERE, getMessage(
1149 "incompatibleImplementation", javaClass.getClassName(),
1150 moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(),
1151 specification.getIdentifier(),
1152 moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(),
1153 decodedReference.getVersion(), specification.getVersion() ),
1154 new ObjectFactory().createImplementation( implementation ) ) );
1155
1156 }
1157 }
1158 }
1159 else if ( this.isLoggable( Level.WARNING ) )
1160 {
1161 this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
1162 Specifications.class.getName() ), null );
1163
1164 }
1165
1166 return report;
1167 }
1168 catch ( final ParseException e )
1169 {
1170 throw (IOException) new IOException( e.getMessage() ).initCause( e );
1171 }
1172 catch ( final TokenMgrError e )
1173 {
1174 throw (IOException) new IOException( e.getMessage() ).initCause( e );
1175 }
1176 }
1177
1178 /**
1179 * Transforms model objects of class files of the modules of the instance.
1180 *
1181 * @param context The model context to use for transforming model objects.
1182 * @param classesDirectory The directory holding the class files.
1183 * @param transformers The transformers to use for transforming model objects.
1184 *
1185 * @throws NullPointerException if {@code context}, {@code classesDirectory} or {@code transformers} is
1186 * {@code null}.
1187 * @throws IOException if transforming model objects fails.
1188 *
1189 * @see #transformModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File, java.util.List)
1190 */
1191 public final void transformModelObjects( final ModelContext context, final File classesDirectory,
1192 final List<Transformer> transformers ) throws IOException
1193 {
1194 if ( context == null )
1195 {
1196 throw new NullPointerException( "context" );
1197 }
1198 if ( classesDirectory == null )
1199 {
1200 throw new NullPointerException( "classesDirectory" );
1201 }
1202 if ( transformers == null )
1203 {
1204 throw new NullPointerException( "transformers" );
1205 }
1206
1207 try
1208 {
1209 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
1210 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
1211 final Schema s = context.createSchema( this.getModel().getIdentifier() );
1212 u.setSchema( s );
1213 m.setSchema( s );
1214
1215 this.transformModelObjects( this.getModules().getSpecifications(), this.getModules().getImplementations(),
1216 u, m, classesDirectory, transformers );
1217
1218 }
1219 catch ( final ModelException e )
1220 {
1221 throw (IOException) new IOException( e.getMessage() ).initCause( e );
1222 }
1223 }
1224
1225 /**
1226 * Transforms model objects of class files of a given module of the modules of the instance.
1227 *
1228 * @param module The module to process.
1229 * @param context The model context to use for transforming model objects.
1230 * @param classesDirectory The directory holding the class files.
1231 * @param transformers The transformers to use for transforming the model objects.
1232 *
1233 * @throws NullPointerException if {@code module}, {@code context}, {@code classesDirectory} or {@code transformers}
1234 * is {@code null}.
1235 * @throws IOException if transforming model objects fails.
1236 *
1237 * @see #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List)
1238 * @see #transformModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File, java.util.List)
1239 */
1240 public final void transformModelObjects( final Module module, final ModelContext context,
1241 final File classesDirectory, final List<Transformer> transformers )
1242 throws IOException
1243 {
1244 if ( module == null )
1245 {
1246 throw new NullPointerException( "module" );
1247 }
1248 if ( context == null )
1249 {
1250 throw new NullPointerException( "context" );
1251 }
1252 if ( classesDirectory == null )
1253 {
1254 throw new NullPointerException( "classesDirectory" );
1255 }
1256 if ( transformers == null )
1257 {
1258 throw new NullPointerException( "transformers" );
1259 }
1260
1261 assert this.getModules().getModule( module.getName() ) != null : "Module '" + module.getName() + "' not found.";
1262
1263 try
1264 {
1265 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
1266 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
1267 final Schema s = context.createSchema( this.getModel().getIdentifier() );
1268 u.setSchema( s );
1269 m.setSchema( s );
1270
1271 this.transformModelObjects( module.getSpecifications(), module.getImplementations(), u, m, classesDirectory,
1272 transformers );
1273
1274 }
1275 catch ( final ModelException e )
1276 {
1277 throw (IOException) new IOException( e.getMessage() ).initCause( e );
1278 }
1279 }
1280
1281 /**
1282 * Transforms model objects of class files of a given specification of the modules of the instance.
1283 *
1284 * @param specification The specification to process.
1285 * @param context The model context to use for transforming model objects.
1286 * @param classesDirectory The directory holding the class files.
1287 * @param transformers The transformers to use for transforming the model objects.
1288 *
1289 * @throws NullPointerException if {@code specification}, {@code context}, {@code classesDirectory} or
1290 * {@code transformers} is {@code null}.
1291 * @throws IOException if transforming model objects fails.
1292 *
1293 * @see #transformModelObjects(org.jomc.model.Specification, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List)
1294 */
1295 public final void transformModelObjects( final Specification specification, final ModelContext context,
1296 final File classesDirectory, final List<Transformer> transformers )
1297 throws IOException
1298 {
1299 if ( specification == null )
1300 {
1301 throw new NullPointerException( "specification" );
1302 }
1303 if ( context == null )
1304 {
1305 throw new NullPointerException( "context" );
1306 }
1307 if ( classesDirectory == null )
1308 {
1309 throw new NullPointerException( "classesDirectory" );
1310 }
1311 if ( transformers == null )
1312 {
1313 throw new NullPointerException( "transformers" );
1314 }
1315
1316 assert this.getModules().getSpecification( specification.getIdentifier() ) != null :
1317 "Specification '" + specification.getIdentifier() + "' not found.";
1318
1319 try
1320 {
1321 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
1322 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
1323 final Schema s = context.createSchema( this.getModel().getIdentifier() );
1324 u.setSchema( s );
1325 m.setSchema( s );
1326
1327 this.transformModelObjects( specification, m, u, classesDirectory, transformers );
1328 }
1329 catch ( final ModelException e )
1330 {
1331 throw (IOException) new IOException( e.getMessage() ).initCause( e );
1332 }
1333 }
1334
1335 /**
1336 * Transforms model objects of class files of a given implementation of the modules of the instance.
1337 *
1338 * @param implementation The implementation to process.
1339 * @param context The model context to use for transforming model objects.
1340 * @param classesDirectory The directory holding the class files.
1341 * @param transformers The transformers to use for transforming the model objects.
1342 *
1343 * @throws NullPointerException if {@code implementation}, {@code context}, {@code classesDirectory} or
1344 * {@code transformers} is {@code null}.
1345 * @throws IOException if transforming model objects fails.
1346 *
1347 * @see #transformModelObjects(org.jomc.model.Implementation, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List)
1348 */
1349 public final void transformModelObjects( final Implementation implementation, final ModelContext context,
1350 final File classesDirectory, final List<Transformer> transformers )
1351 throws IOException
1352 {
1353 if ( implementation == null )
1354 {
1355 throw new NullPointerException( "implementation" );
1356 }
1357 if ( context == null )
1358 {
1359 throw new NullPointerException( "context" );
1360 }
1361 if ( classesDirectory == null )
1362 {
1363 throw new NullPointerException( "classesDirectory" );
1364 }
1365 if ( transformers == null )
1366 {
1367 throw new NullPointerException( "transformers" );
1368 }
1369
1370 assert this.getModules().getImplementation( implementation.getIdentifier() ) != null :
1371 "Implementation '" + implementation.getIdentifier() + "' not found.";
1372
1373 try
1374 {
1375 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
1376 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
1377 final Schema s = context.createSchema( this.getModel().getIdentifier() );
1378 u.setSchema( s );
1379 m.setSchema( s );
1380
1381 this.transformModelObjects( implementation, m, u, classesDirectory, transformers );
1382 }
1383 catch ( final ModelException e )
1384 {
1385 throw (IOException) new IOException( e.getMessage() ).initCause( e );
1386 }
1387 }
1388
1389 /**
1390 * Transforms model objects of a given specification of the modules of the instance.
1391 *
1392 * @param specification The specification to process.
1393 * @param marshaller The marshaller to use for transforming model objects.
1394 * @param unmarshaller The unmarshaller to use for transforming model objects.
1395 * @param javaClass The the class file to transform.
1396 * @param transformers The transformers to use for transforming the model objects.
1397 *
1398 * @throws NullPointerException if {@code specification}, {@code marshaller}, {@code unmarshaller},
1399 * {@code javaClass} or {@code transformers} is {@code null}.
1400 * @throws IOException if transforming model objects fails.
1401 */
1402 public void transformModelObjects( final Specification specification, final Marshaller marshaller,
1403 final Unmarshaller unmarshaller, final JavaClass javaClass,
1404 final List<Transformer> transformers ) throws IOException
1405 {
1406 if ( specification == null )
1407 {
1408 throw new NullPointerException( "specification" );
1409 }
1410 if ( marshaller == null )
1411 {
1412 throw new NullPointerException( "marshaller" );
1413 }
1414 if ( unmarshaller == null )
1415 {
1416 throw new NullPointerException( "unmarshaller" );
1417 }
1418 if ( javaClass == null )
1419 {
1420 throw new NullPointerException( "javaClass" );
1421 }
1422 if ( transformers == null )
1423 {
1424 throw new NullPointerException( "transformers" );
1425 }
1426
1427 assert this.getModules().getSpecification( specification.getIdentifier() ) != null :
1428 "Specification '" + specification.getIdentifier() + "' not found.";
1429
1430 try
1431 {
1432 Specification decodedSpecification = null;
1433 final ObjectFactory objectFactory = new ObjectFactory();
1434 final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() );
1435 if ( bytes != null )
1436 {
1437 decodedSpecification = this.decodeModelObject( unmarshaller, bytes, Specification.class );
1438 }
1439
1440 if ( decodedSpecification != null )
1441 {
1442 for ( Transformer transformer : transformers )
1443 {
1444 final JAXBSource source =
1445 new JAXBSource( marshaller, objectFactory.createSpecification( decodedSpecification ) );
1446
1447 final JAXBResult result = new JAXBResult( unmarshaller );
1448 transformer.transform( source, result );
1449 decodedSpecification = ( (JAXBElement<Specification>) result.getResult() ).getValue();
1450 }
1451
1452 this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject(
1453 marshaller, objectFactory.createSpecification( decodedSpecification ) ) );
1454
1455 }
1456 }
1457 catch ( final JAXBException e )
1458 {
1459 String message = e.getMessage();
1460 if ( message == null && e.getLinkedException() != null )
1461 {
1462 message = e.getLinkedException().getMessage();
1463 }
1464
1465 throw (IOException) new IOException( message ).initCause( e );
1466 }
1467 catch ( final TransformerException e )
1468 {
1469 String message = e.getMessage();
1470 if ( message == null && e.getException() != null )
1471 {
1472 message = e.getException().getMessage();
1473 }
1474
1475 throw (IOException) new IOException( message ).initCause( e );
1476 }
1477 }
1478
1479 /**
1480 * Transforms model objects of a given implementation of the modules of the instance.
1481 *
1482 * @param implementation The implementation to process.
1483 * @param marshaller The marshaller to use for transforming model objects.
1484 * @param unmarshaller The unmarshaller to use for transforming model objects.
1485 * @param javaClass The the class file to transform.
1486 * @param transformers The transformers to use for transforming the model objects.
1487 *
1488 * @throws NullPointerException if {@code implementation}, {@code marshaller}, {@code unmarshaller},
1489 * {@code javaClass} or {@code transformers} is {@code null}.
1490 * @throws IOException if transforming model objects fails.
1491 */
1492 public void transformModelObjects( final Implementation implementation, final Marshaller marshaller,
1493 final Unmarshaller unmarshaller, final JavaClass javaClass,
1494 final List<Transformer> transformers ) throws IOException
1495 {
1496 if ( implementation == null )
1497 {
1498 throw new NullPointerException( "implementation" );
1499 }
1500 if ( marshaller == null )
1501 {
1502 throw new NullPointerException( "marshaller" );
1503 }
1504 if ( unmarshaller == null )
1505 {
1506 throw new NullPointerException( "unmarshaller" );
1507 }
1508 if ( javaClass == null )
1509 {
1510 throw new NullPointerException( "javaClass" );
1511 }
1512 if ( transformers == null )
1513 {
1514 throw new NullPointerException( "transformers" );
1515 }
1516
1517 assert this.getModules().getImplementation( implementation.getIdentifier() ) != null :
1518 "Implementation '" + implementation.getIdentifier() + "' not found.";
1519
1520 try
1521 {
1522 Dependencies decodedDependencies = null;
1523 byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() );
1524 if ( bytes != null )
1525 {
1526 decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class );
1527 }
1528
1529 Messages decodedMessages = null;
1530 bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() );
1531 if ( bytes != null )
1532 {
1533 decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class );
1534 }
1535
1536 Properties decodedProperties = null;
1537 bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() );
1538 if ( bytes != null )
1539 {
1540 decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class );
1541 }
1542
1543 Specifications decodedSpecifications = null;
1544 bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() );
1545 if ( bytes != null )
1546 {
1547 decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class );
1548 }
1549
1550 final ObjectFactory of = new ObjectFactory();
1551 for ( Transformer transformer : transformers )
1552 {
1553 if ( decodedDependencies != null )
1554 {
1555 final JAXBSource source = new JAXBSource( marshaller,
1556 of.createDependencies( decodedDependencies ) );
1557 final JAXBResult result = new JAXBResult( unmarshaller );
1558 transformer.transform( source, result );
1559 decodedDependencies = ( (JAXBElement<Dependencies>) result.getResult() ).getValue();
1560 }
1561
1562 if ( decodedMessages != null )
1563 {
1564 final JAXBSource source = new JAXBSource( marshaller, of.createMessages( decodedMessages ) );
1565 final JAXBResult result = new JAXBResult( unmarshaller );
1566 transformer.transform( source, result );
1567 decodedMessages = ( (JAXBElement<Messages>) result.getResult() ).getValue();
1568 }
1569
1570 if ( decodedProperties != null )
1571 {
1572 final JAXBSource source = new JAXBSource( marshaller, of.createProperties( decodedProperties ) );
1573 final JAXBResult result = new JAXBResult( unmarshaller );
1574 transformer.transform( source, result );
1575 decodedProperties = ( (JAXBElement<Properties>) result.getResult() ).getValue();
1576 }
1577
1578 if ( decodedSpecifications != null )
1579 {
1580 final JAXBSource source =
1581 new JAXBSource( marshaller, of.createSpecifications( decodedSpecifications ) );
1582
1583 final JAXBResult result = new JAXBResult( unmarshaller );
1584 transformer.transform( source, result );
1585 decodedSpecifications = ( (JAXBElement<Specifications>) result.getResult() ).getValue();
1586 }
1587 }
1588
1589 if ( decodedDependencies != null )
1590 {
1591 this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject(
1592 marshaller, of.createDependencies( decodedDependencies ) ) );
1593
1594 }
1595
1596 if ( decodedMessages != null )
1597 {
1598 this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject(
1599 marshaller, of.createMessages( decodedMessages ) ) );
1600
1601 }
1602
1603 if ( decodedProperties != null )
1604 {
1605 this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject(
1606 marshaller, of.createProperties( decodedProperties ) ) );
1607
1608 }
1609
1610 if ( decodedSpecifications != null )
1611 {
1612 this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject(
1613 marshaller, of.createSpecifications( decodedSpecifications ) ) );
1614
1615 }
1616 }
1617 catch ( final JAXBException e )
1618 {
1619 String message = e.getMessage();
1620 if ( message == null && e.getLinkedException() != null )
1621 {
1622 message = e.getLinkedException().getMessage();
1623 }
1624
1625 throw (IOException) new IOException( message ).initCause( e );
1626 }
1627 catch ( final TransformerException e )
1628 {
1629 String message = e.getMessage();
1630 if ( message == null && e.getException() != null )
1631 {
1632 message = e.getException().getMessage();
1633 }
1634
1635 throw (IOException) new IOException( message ).initCause( e );
1636 }
1637 }
1638
1639 /**
1640 * Gets an attribute from a java class.
1641 *
1642 * @param clazz The java class to get an attribute from.
1643 * @param attributeName The name of the attribute to get.
1644 *
1645 * @return The value of attribute {@code attributeName} of {@code clazz} or {@code null} if no such attribute
1646 * exists.
1647 *
1648 * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}.
1649 * @throws IOException if getting the attribute fails.
1650 *
1651 * @see JavaClass#getAttributes()
1652 */
1653 public byte[] getClassfileAttribute( final JavaClass clazz, final String attributeName ) throws IOException
1654 {
1655 if ( clazz == null )
1656 {
1657 throw new NullPointerException( "clazz" );
1658 }
1659 if ( attributeName == null )
1660 {
1661 throw new NullPointerException( "attributeName" );
1662 }
1663
1664 final Attribute[] attributes = clazz.getAttributes();
1665
1666 for ( int i = attributes.length - 1; i >= 0; i-- )
1667 {
1668 final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() );
1669
1670 if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) )
1671 {
1672 final Unknown unknown = (Unknown) attributes[i];
1673 return unknown.getBytes();
1674 }
1675 }
1676
1677 return null;
1678 }
1679
1680 /**
1681 * Adds or updates an attribute in a java class.
1682 *
1683 * @param clazz The class to update.
1684 * @param attributeName The name of the attribute to update.
1685 * @param data The new data of the attribute to update the {@code classFile} with.
1686 *
1687 * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}.
1688 * @throws IOException if updating the class file fails.
1689 *
1690 * @see JavaClass#getAttributes()
1691 */
1692 public void setClassfileAttribute( final JavaClass clazz, final String attributeName, final byte[] data )
1693 throws IOException
1694 {
1695 if ( clazz == null )
1696 {
1697 throw new NullPointerException( "clazz" );
1698 }
1699 if ( attributeName == null )
1700 {
1701 throw new NullPointerException( "attributeName" );
1702 }
1703
1704 final byte[] attributeData = data != null ? data : NO_BYTES;
1705
1706 /*
1707 The JavaTM Virtual Machine Specification - Second Edition - Chapter 4.1
1708
1709 A Java virtual machine implementation is required to silently ignore any
1710 or all attributes in the attributes table of a ClassFile structure that
1711 it does not recognize. Attributes not defined in this specification are
1712 not allowed to affect the semantics of the class file, but only to
1713 provide additional descriptive information (§4.7.1).
1714 */
1715 Attribute[] attributes = clazz.getAttributes();
1716
1717 int attributeIndex = -1;
1718 int nameIndex = -1;
1719
1720 for ( int i = attributes.length - 1; i >= 0; i-- )
1721 {
1722 final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() );
1723
1724 if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) )
1725 {
1726 attributeIndex = i;
1727 nameIndex = attributes[i].getNameIndex();
1728 }
1729 }
1730
1731 if ( nameIndex == -1 )
1732 {
1733 final Constant[] pool = clazz.getConstantPool().getConstantPool();
1734 final Constant[] tmp = new Constant[ pool.length + 1 ];
1735 System.arraycopy( pool, 0, tmp, 0, pool.length );
1736 tmp[pool.length] = new ConstantUtf8( attributeName );
1737 nameIndex = pool.length;
1738 clazz.setConstantPool( new ConstantPool( tmp ) );
1739 }
1740
1741 final Unknown unknown = new Unknown( nameIndex, attributeData.length, attributeData, clazz.getConstantPool() );
1742
1743 if ( attributeIndex == -1 )
1744 {
1745 final Attribute[] tmp = new Attribute[ attributes.length + 1 ];
1746 System.arraycopy( attributes, 0, tmp, 0, attributes.length );
1747 tmp[attributes.length] = unknown;
1748 attributes = tmp;
1749 }
1750 else
1751 {
1752 attributes[attributeIndex] = unknown;
1753 }
1754
1755 clazz.setAttributes( attributes );
1756 }
1757
1758 /**
1759 * Encodes a model object to a byte array.
1760 *
1761 * @param marshaller The marshaller to use for encoding the object.
1762 * @param modelObject The model object to encode.
1763 *
1764 * @return GZIP compressed XML document for {@code modelObject}.
1765 *
1766 * @throws NullPointerException if {@code marshaller} or {@code modelObject} is {@code null}.
1767 * @throws IOException if encoding {@code modelObject} fails.
1768 */
1769 public byte[] encodeModelObject( final Marshaller marshaller, final JAXBElement<? extends ModelObject> modelObject )
1770 throws IOException
1771 {
1772 if ( marshaller == null )
1773 {
1774 throw new NullPointerException( "marshaller" );
1775 }
1776 if ( modelObject == null )
1777 {
1778 throw new NullPointerException( "modelObject" );
1779 }
1780
1781 try
1782 {
1783 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
1784 final GZIPOutputStream out = new GZIPOutputStream( baos );
1785 marshaller.marshal( modelObject, out );
1786 out.close();
1787 return baos.toByteArray();
1788 }
1789 catch ( final JAXBException e )
1790 {
1791 String message = e.getMessage();
1792 if ( message == null && e.getLinkedException() != null )
1793 {
1794 message = e.getLinkedException().getMessage();
1795 }
1796
1797 throw (IOException) new IOException( message ).initCause( e );
1798 }
1799 }
1800
1801 /**
1802 * Decodes a model object from a byte array.
1803 *
1804 * @param unmarshaller The unmarshaller to use for decoding the object.
1805 * @param bytes The encoded model object to decode.
1806 * @param type The type of the encoded model object.
1807 * @param <T> The type of the decoded model object.
1808 *
1809 * @return Model object decoded from {@code bytes}.
1810 *
1811 * @throws NullPointerException if {@code unmarshaller}, {@code bytes} or {@code type} is {@code null}.
1812 * @throws IOException if decoding {@code bytes} fails.
1813 */
1814 public <T extends ModelObject> T decodeModelObject( final Unmarshaller unmarshaller, final byte[] bytes,
1815 final Class<T> type ) throws IOException
1816 {
1817 if ( unmarshaller == null )
1818 {
1819 throw new NullPointerException( "unmarshaller" );
1820 }
1821 if ( bytes == null )
1822 {
1823 throw new NullPointerException( "bytes" );
1824 }
1825 if ( type == null )
1826 {
1827 throw new NullPointerException( "type" );
1828 }
1829
1830 try
1831 {
1832 final ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
1833 final GZIPInputStream in = new GZIPInputStream( bais );
1834 final JAXBElement<T> element = (JAXBElement<T>) unmarshaller.unmarshal( in );
1835 in.close();
1836 return element.getValue();
1837 }
1838 catch ( final JAXBException e )
1839 {
1840 String message = e.getMessage();
1841 if ( message == null && e.getLinkedException() != null )
1842 {
1843 message = e.getLinkedException().getMessage();
1844 }
1845
1846 throw (IOException) new IOException( message ).initCause( e );
1847 }
1848 }
1849
1850 private void commitModelObjects( final Specifications specifications, final Implementations implementations,
1851 final Marshaller marshaller, final File classesDirectory ) throws IOException
1852 {
1853 if ( specifications != null )
1854 {
1855 for ( Specification s : specifications.getSpecification() )
1856 {
1857 this.commitModelObjects( s, marshaller, classesDirectory );
1858 }
1859 }
1860
1861 if ( implementations != null )
1862 {
1863 for ( Implementation i : implementations.getImplementation() )
1864 {
1865 this.commitModelObjects( i, marshaller, classesDirectory );
1866 }
1867 }
1868 }
1869
1870 private void commitModelObjects( final Specification specification, final Marshaller marshaller,
1871 final File classesDirectory ) throws IOException
1872 {
1873 if ( specification.isClassDeclaration() )
1874 {
1875 final String classLocation = specification.getClazz().replace( '.', File.separatorChar ) + ".class";
1876 final File classFile = new File( classesDirectory, classLocation );
1877
1878 if ( this.isLoggable( Level.INFO ) )
1879 {
1880 this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null );
1881 }
1882
1883 final JavaClass javaClass = new ClassParser( classFile.getAbsolutePath() ).parse();
1884 this.commitModelObjects( specification, marshaller, javaClass );
1885 javaClass.dump( classFile );
1886 }
1887 }
1888
1889 private void commitModelObjects( final Implementation implementation, final Marshaller marshaller,
1890 final File classesDirectory ) throws IOException
1891 {
1892 if ( implementation.isClassDeclaration() )
1893 {
1894 final String classLocation = implementation.getClazz().replace( '.', File.separatorChar ) + ".class";
1895 final File classFile = new File( classesDirectory, classLocation );
1896
1897 if ( this.isLoggable( Level.INFO ) )
1898 {
1899 this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null );
1900 }
1901
1902 final JavaClass javaClass = new ClassParser( classFile.getAbsolutePath() ).parse();
1903 this.commitModelObjects( implementation, marshaller, javaClass );
1904 javaClass.dump( classFile );
1905 }
1906 }
1907
1908 private ModelValidationReport validateModelObjects( final Specifications specifications,
1909 final Implementations implementations,
1910 final Unmarshaller unmarshaller, final File classesDirectory )
1911 throws IOException
1912 {
1913 final ModelValidationReport report = new ModelValidationReport();
1914
1915 if ( specifications != null )
1916 {
1917 for ( Specification s : specifications.getSpecification() )
1918 {
1919 final ModelValidationReport current = this.validateModelObjects( s, unmarshaller, classesDirectory );
1920 report.getDetails().addAll( current.getDetails() );
1921 }
1922 }
1923
1924 if ( implementations != null )
1925 {
1926 for ( Implementation i : implementations.getImplementation() )
1927 {
1928 final ModelValidationReport current = this.validateModelObjects( i, unmarshaller, classesDirectory );
1929 report.getDetails().addAll( current.getDetails() );
1930 }
1931 }
1932
1933 return report;
1934 }
1935
1936 private ModelValidationReport validateModelObjects( final Specification specification,
1937 final Unmarshaller unmarshaller,
1938 final File classesDirectory ) throws IOException
1939 {
1940 final ModelValidationReport report = new ModelValidationReport();
1941
1942 if ( specification.isClassDeclaration() )
1943 {
1944 final String classLocation = specification.getClazz().replace( '.', File.separatorChar ) + ".class";
1945 final File classFile = new File( classesDirectory, classLocation );
1946
1947 if ( this.isLoggable( Level.INFO ) )
1948 {
1949 this.log( Level.INFO, getMessage( "validating", classFile.getAbsolutePath() ), null );
1950 }
1951
1952 final ModelValidationReport current = this.validateModelObjects(
1953 specification, unmarshaller, new ClassParser( classFile.getAbsolutePath() ).parse() );
1954
1955 report.getDetails().addAll( current.getDetails() );
1956 }
1957
1958 return report;
1959 }
1960
1961 private ModelValidationReport validateModelObjects( final Implementation implementation,
1962 final Unmarshaller unmarshaller,
1963 final File classesDirectory ) throws IOException
1964 {
1965 final ModelValidationReport report = new ModelValidationReport();
1966
1967 if ( implementation.isClassDeclaration() )
1968 {
1969 final String classLocation = implementation.getClazz().replace( '.', File.separatorChar ) + ".class";
1970 final File classFile = new File( classesDirectory, classLocation );
1971
1972 if ( this.isLoggable( Level.INFO ) )
1973 {
1974 this.log( Level.INFO, getMessage( "validating", classFile.getAbsolutePath() ), null );
1975 }
1976
1977 final ModelValidationReport current = this.validateModelObjects(
1978 implementation, unmarshaller, new ClassParser( classFile.getAbsolutePath() ).parse() );
1979
1980 report.getDetails().addAll( current.getDetails() );
1981 }
1982
1983 return report;
1984 }
1985
1986 private ModelValidationReport validateModelObjects( final Specifications specifications,
1987 final Implementations implementations,
1988 final Unmarshaller unmarshaller, final ClassLoader classLoader )
1989 throws IOException
1990 {
1991 final ModelValidationReport report = new ModelValidationReport();
1992
1993 if ( specifications != null )
1994 {
1995 for ( Specification s : specifications.getSpecification() )
1996 {
1997 final ModelValidationReport current = this.validateModelObjects( s, unmarshaller, classLoader );
1998 report.getDetails().addAll( current.getDetails() );
1999 }
2000 }
2001
2002 if ( implementations != null )
2003 {
2004 for ( Implementation i : implementations.getImplementation() )
2005 {
2006 final ModelValidationReport current = this.validateModelObjects( i, unmarshaller, classLoader );
2007 report.getDetails().addAll( current.getDetails() );
2008 }
2009 }
2010
2011 return report;
2012 }
2013
2014 private ModelValidationReport validateModelObjects( final Specification specification,
2015 final Unmarshaller unmarshaller,
2016 final ClassLoader classLoader ) throws IOException
2017 {
2018 final ModelValidationReport report = new ModelValidationReport();
2019
2020 if ( specification.isClassDeclaration() )
2021 {
2022 final String classLocation = specification.getClazz().replace( '.', '/' ) + ".class";
2023
2024 if ( this.isLoggable( Level.INFO ) )
2025 {
2026 this.log( Level.INFO, getMessage( "validatingSpecification", specification.getIdentifier() ), null );
2027 }
2028
2029 final URL classUrl = classLoader.getResource( classLocation );
2030
2031 if ( classUrl == null )
2032 {
2033 throw new IOException( getMessage( "resourceNotFound", classLocation ) );
2034 }
2035
2036 InputStream in = null;
2037 JavaClass javaClass = null;
2038
2039 try
2040 {
2041 in = classUrl.openStream();
2042 javaClass = new ClassParser( in, classUrl.toExternalForm() ).parse();
2043 }
2044 finally
2045 {
2046 if ( in != null )
2047 {
2048 in.close();
2049 }
2050 }
2051
2052 final ModelValidationReport current = this.validateModelObjects( specification, unmarshaller, javaClass );
2053 report.getDetails().addAll( current.getDetails() );
2054 }
2055
2056 return report;
2057 }
2058
2059 private ModelValidationReport validateModelObjects( final Implementation implementation,
2060 final Unmarshaller unmarshaller,
2061 final ClassLoader classLoader ) throws IOException
2062 {
2063 final ModelValidationReport report = new ModelValidationReport();
2064
2065 if ( implementation.isClassDeclaration() )
2066 {
2067 final String classLocation = implementation.getClazz().replace( '.', '/' ) + ".class";
2068
2069 if ( this.isLoggable( Level.INFO ) )
2070 {
2071 this.log( Level.INFO, getMessage( "validatingImplementation", implementation.getIdentifier() ), null );
2072 }
2073
2074 final URL classUrl = classLoader.getResource( classLocation );
2075
2076 if ( classUrl == null )
2077 {
2078 throw new IOException( getMessage( "resourceNotFound", classLocation ) );
2079 }
2080
2081 InputStream in = null;
2082 JavaClass javaClass = null;
2083
2084 try
2085 {
2086 in = classUrl.openStream();
2087 javaClass = new ClassParser( in, classUrl.toExternalForm() ).parse();
2088 }
2089 finally
2090 {
2091 if ( in != null )
2092 {
2093 in.close();
2094 }
2095 }
2096
2097 final ModelValidationReport current = this.validateModelObjects( implementation, unmarshaller, javaClass );
2098 report.getDetails().addAll( current.getDetails() );
2099 }
2100
2101 return report;
2102 }
2103
2104 private void transformModelObjects( final Specifications specifications, final Implementations implementations,
2105 final Unmarshaller unmarshaller, final Marshaller marshaller,
2106 final File classesDirectory, final List<Transformer> transformers )
2107 throws IOException
2108 {
2109 if ( specifications != null )
2110 {
2111 for ( Specification s : specifications.getSpecification() )
2112 {
2113 this.transformModelObjects( s, marshaller, unmarshaller, classesDirectory, transformers );
2114 }
2115 }
2116
2117 if ( implementations != null )
2118 {
2119 for ( Implementation i : implementations.getImplementation() )
2120 {
2121 this.transformModelObjects( i, marshaller, unmarshaller, classesDirectory, transformers );
2122 }
2123 }
2124 }
2125
2126 private void transformModelObjects( final Specification specification, final Marshaller marshaller,
2127 final Unmarshaller unmarshaller, final File classesDirectory,
2128 final List<Transformer> transformers ) throws IOException
2129 {
2130 if ( specification.isClassDeclaration() )
2131 {
2132 final String classLocation = specification.getClazz().replace( '.', File.separatorChar ) + ".class";
2133 final File classFile = new File( classesDirectory, classLocation );
2134
2135 if ( this.isLoggable( Level.INFO ) )
2136 {
2137 this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null );
2138 }
2139
2140 final JavaClass javaClass = new ClassParser( classFile.getAbsolutePath() ).parse();
2141 this.transformModelObjects( specification, marshaller, unmarshaller, javaClass, transformers );
2142 javaClass.dump( classFile );
2143 }
2144 }
2145
2146 private void transformModelObjects( final Implementation implementation, final Marshaller marshaller,
2147 final Unmarshaller unmarshaller, final File classesDirectory,
2148 final List<Transformer> transformers ) throws IOException
2149 {
2150 if ( implementation.isClassDeclaration() )
2151 {
2152 final String classLocation = implementation.getClazz().replace( '.', File.separatorChar ) + ".class";
2153 final File classFile = new File( classesDirectory, classLocation );
2154
2155 if ( this.isLoggable( Level.INFO ) )
2156 {
2157 this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null );
2158 }
2159
2160 final JavaClass javaClass = new ClassParser( classFile.getAbsolutePath() ).parse();
2161 this.transformModelObjects( implementation, marshaller, unmarshaller, javaClass, transformers );
2162 javaClass.dump( classFile );
2163 }
2164 }
2165
2166 private static String getMessage( final String key, final Object... arguments )
2167 {
2168 return MessageFormat.format( ResourceBundle.getBundle( ClassFileProcessor.class.getName().replace( '.', '/' ) ).
2169 getString( key ), arguments );
2170
2171 }
2172
2173 }