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