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