ClassFileProcessor.java

  1. /*
  2.  *   Copyright (C) Christian Schulte <cs@schulte.it>, 2005-206
  3.  *   All rights reserved.
  4.  *
  5.  *   Redistribution and use in source and binary forms, with or without
  6.  *   modification, are permitted provided that the following conditions
  7.  *   are met:
  8.  *
  9.  *     o Redistributions of source code must retain the above copyright
  10.  *       notice, this list of conditions and the following disclaimer.
  11.  *
  12.  *     o Redistributions in binary form must reproduce the above copyright
  13.  *       notice, this list of conditions and the following disclaimer in
  14.  *       the documentation and/or other materials provided with the
  15.  *       distribution.
  16.  *
  17.  *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  18.  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  19.  *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  20.  *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  *
  28.  *   $JOMC: ClassFileProcessor.java 5043 2015-05-27 07:03:39Z schulte $
  29.  *
  30.  */
  31. package org.jomc.tools;

  32. import java.io.ByteArrayInputStream;
  33. import java.io.ByteArrayOutputStream;
  34. import java.io.Closeable;
  35. import java.io.File;
  36. import java.io.FileInputStream;
  37. import java.io.IOException;
  38. import java.io.InputStream;
  39. import java.io.RandomAccessFile;
  40. import java.net.URL;
  41. import java.nio.ByteBuffer;
  42. import java.nio.channels.FileChannel;
  43. import java.nio.channels.FileLock;
  44. import java.text.MessageFormat;
  45. import java.util.List;
  46. import java.util.ResourceBundle;
  47. import java.util.logging.Level;
  48. import java.util.zip.GZIPInputStream;
  49. import java.util.zip.GZIPOutputStream;
  50. import javax.xml.bind.JAXBElement;
  51. import javax.xml.bind.JAXBException;
  52. import javax.xml.bind.Marshaller;
  53. import javax.xml.bind.Unmarshaller;
  54. import javax.xml.bind.util.JAXBResult;
  55. import javax.xml.bind.util.JAXBSource;
  56. import javax.xml.transform.Transformer;
  57. import javax.xml.transform.TransformerException;
  58. import javax.xml.validation.Schema;
  59. import org.apache.bcel.classfile.Attribute;
  60. import org.apache.bcel.classfile.ClassParser;
  61. import org.apache.bcel.classfile.Constant;
  62. import org.apache.bcel.classfile.ConstantPool;
  63. import org.apache.bcel.classfile.ConstantUtf8;
  64. import org.apache.bcel.classfile.JavaClass;
  65. import org.apache.bcel.classfile.Unknown;
  66. import org.jomc.model.Dependencies;
  67. import org.jomc.model.Dependency;
  68. import org.jomc.model.Implementation;
  69. import org.jomc.model.Implementations;
  70. import org.jomc.model.Message;
  71. import org.jomc.model.Messages;
  72. import org.jomc.model.ModelObject;
  73. import org.jomc.model.ModelObjectException;
  74. import org.jomc.model.Module;
  75. import org.jomc.model.ObjectFactory;
  76. import org.jomc.model.Properties;
  77. import org.jomc.model.Property;
  78. import org.jomc.model.Specification;
  79. import org.jomc.model.SpecificationReference;
  80. import org.jomc.model.Specifications;
  81. import org.jomc.modlet.ModelContext;
  82. import org.jomc.modlet.ModelException;
  83. import org.jomc.modlet.ModelValidationReport;
  84. import org.jomc.util.ParseException;
  85. import org.jomc.util.TokenMgrError;
  86. import org.jomc.util.VersionParser;

  87. /**
  88.  * Processes class files.
  89.  *
  90.  * <p>
  91.  * <b>Use Cases:</b><br/><ul>
  92.  * <li>{@link #commitModelObjects(org.jomc.modlet.ModelContext, java.io.File) }</li>
  93.  * <li>{@link #commitModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) }</li>
  94.  * <li>{@link #commitModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) }</li>
  95.  * <li>{@link #commitModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) }</li>
  96.  * <li>{@link #validateModelObjects(org.jomc.modlet.ModelContext) }</li>
  97.  * <li>{@link #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext) }</li>
  98.  * <li>{@link #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext) }</li>
  99.  * <li>{@link #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext) }</li>
  100.  * <li>{@link #validateModelObjects(org.jomc.modlet.ModelContext, java.io.File) }</li>
  101.  * <li>{@link #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File) }</li>
  102.  * <li>{@link #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File) }</li>
  103.  * <li>{@link #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File) }</li>
  104.  * <li>{@link #transformModelObjects(org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
  105.  * <li>{@link #transformModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
  106.  * <li>{@link #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
  107.  * <li>{@link #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List) }</li>
  108.  * </ul></p>
  109.  *
  110.  * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
  111.  * @version $JOMC: ClassFileProcessor.java 5043 2015-05-27 07:03:39Z schulte $
  112.  *
  113.  * @see #getModules()
  114.  */
  115. public class ClassFileProcessor extends JomcTool
  116. {

  117.     /**
  118.      * Empty byte array.
  119.      */
  120.     private static final byte[] NO_BYTES =
  121.     {
  122.     };

  123.     /**
  124.      * Creates a new {@code ClassFileProcessor} instance.
  125.      */
  126.     public ClassFileProcessor()
  127.     {
  128.         super();
  129.     }

  130.     /**
  131.      * Creates a new {@code ClassFileProcessor} instance taking a {@code ClassFileProcessor} instance to initialize the
  132.      * instance with.
  133.      *
  134.      * @param tool The instance to initialize the new instance with.
  135.      *
  136.      * @throws NullPointerException if {@code tool} is {@code null}.
  137.      * @throws IOException if copying {@code tool} fails.
  138.      */
  139.     public ClassFileProcessor( final ClassFileProcessor tool ) throws IOException
  140.     {
  141.         super( tool );
  142.     }

  143.     /**
  144.      * Commits model objects of the modules of the instance to class files.
  145.      *
  146.      * @param context The model context to use for committing the model objects.
  147.      * @param classesDirectory The directory holding the class files.
  148.      *
  149.      * @throws NullPointerException if {@code context} or {@code classesDirectory} is {@code null}.
  150.      * @throws IOException if committing model objects fails.
  151.      *
  152.      * @see #commitModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File)
  153.      */
  154.     public final void commitModelObjects( final ModelContext context, final File classesDirectory ) throws IOException
  155.     {
  156.         if ( context == null )
  157.         {
  158.             throw new NullPointerException( "context" );
  159.         }
  160.         if ( classesDirectory == null )
  161.         {
  162.             throw new NullPointerException( "classesDirectory" );
  163.         }

  164.         try
  165.         {
  166.             if ( this.getModules() != null )
  167.             {
  168.                 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
  169.                 m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );

  170.                 this.commitModelObjects( this.getModules().getSpecifications(), this.getModules().getImplementations(),
  171.                                          m, classesDirectory );

  172.             }
  173.             else if ( this.isLoggable( Level.WARNING ) )
  174.             {
  175.                 this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
  176.             }
  177.         }
  178.         catch ( final ModelException e )
  179.         {
  180.             // JDK: As of JDK 6, "new IOException( message, cause )".
  181.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  182.         }
  183.     }

  184.     /**
  185.      * Commits model objects of a given module of the modules of the instance to class files.
  186.      *
  187.      * @param module The module to process.
  188.      * @param context The model context to use for committing the model objects.
  189.      * @param classesDirectory The directory holding the class files.
  190.      *
  191.      * @throws NullPointerException if {@code module}, {@code context} or {@code classesDirectory} is {@code null}.
  192.      * @throws IOException if committing model objects fails.
  193.      *
  194.      * @see #commitModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File)
  195.      * @see #commitModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File)
  196.      */
  197.     public final void commitModelObjects( final Module module, final ModelContext context, final File classesDirectory )
  198.         throws IOException
  199.     {
  200.         if ( module == null )
  201.         {
  202.             throw new NullPointerException( "module" );
  203.         }
  204.         if ( context == null )
  205.         {
  206.             throw new NullPointerException( "context" );
  207.         }
  208.         if ( classesDirectory == null )
  209.         {
  210.             throw new NullPointerException( "classesDirectory" );
  211.         }

  212.         try
  213.         {
  214.             if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
  215.             {
  216.                 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
  217.                 m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );

  218.                 this.commitModelObjects( module.getSpecifications(), module.getImplementations(), m, classesDirectory );
  219.             }
  220.             else if ( this.isLoggable( Level.WARNING ) )
  221.             {
  222.                 this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
  223.             }
  224.         }
  225.         catch ( final ModelException e )
  226.         {
  227.             // JDK: As of JDK 6, "new IOException( message, cause )".
  228.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  229.         }
  230.     }

  231.     /**
  232.      * Commits model objects of a given specification of the modules of the instance to class files.
  233.      *
  234.      * @param specification The specification to process.
  235.      * @param context The model context to use for committing the model objects.
  236.      * @param classesDirectory The directory holding the class files.
  237.      *
  238.      * @throws NullPointerException if {@code specification}, {@code context} or {@code classesDirectory} is
  239.      * {@code null}.
  240.      * @throws IOException if committing model objects fails.
  241.      *
  242.      * @see #commitModelObjects(org.jomc.model.Specification, javax.xml.bind.Marshaller, org.apache.bcel.classfile.JavaClass)
  243.      */
  244.     public final void commitModelObjects( final Specification specification, final ModelContext context,
  245.                                           final File classesDirectory ) throws IOException
  246.     {
  247.         if ( specification == null )
  248.         {
  249.             throw new NullPointerException( "specification" );
  250.         }
  251.         if ( context == null )
  252.         {
  253.             throw new NullPointerException( "context" );
  254.         }
  255.         if ( classesDirectory == null )
  256.         {
  257.             throw new NullPointerException( "classesDirectory" );
  258.         }

  259.         try
  260.         {
  261.             if ( this.getModules() != null
  262.                      && this.getModules().getSpecification( specification.getIdentifier() ) != null )
  263.             {
  264.                 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
  265.                 m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );

  266.                 this.commitModelObjects( specification, m, classesDirectory );
  267.             }
  268.             else if ( this.isLoggable( Level.WARNING ) )
  269.             {
  270.                 this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
  271.             }
  272.         }
  273.         catch ( final ModelException e )
  274.         {
  275.             // JDK: As of JDK 6, "new IOException( message, cause )".
  276.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  277.         }
  278.     }

  279.     /**
  280.      * Commits model objects of a given implementation of the modules of the instance to class files.
  281.      *
  282.      * @param implementation The implementation to process.
  283.      * @param context The model context to use for committing the model objects.
  284.      * @param classesDirectory The directory holding the class files.
  285.      *
  286.      * @throws NullPointerException if {@code implementation}, {@code context} or {@code classesDirectory} is
  287.      * {@code null}.
  288.      * @throws IOException if committing model objects fails.
  289.      *
  290.      * @see #commitModelObjects(org.jomc.model.Implementation, javax.xml.bind.Marshaller, org.apache.bcel.classfile.JavaClass)
  291.      */
  292.     public final void commitModelObjects( final Implementation implementation, final ModelContext context,
  293.                                           final File classesDirectory ) throws IOException
  294.     {
  295.         if ( implementation == null )
  296.         {
  297.             throw new NullPointerException( "implementation" );
  298.         }
  299.         if ( context == null )
  300.         {
  301.             throw new NullPointerException( "context" );
  302.         }
  303.         if ( classesDirectory == null )
  304.         {
  305.             throw new NullPointerException( "classesDirectory" );
  306.         }

  307.         try
  308.         {
  309.             if ( this.getModules() != null
  310.                      && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
  311.             {
  312.                 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
  313.                 m.setSchema( context.createSchema( this.getModel().getIdentifier() ) );

  314.                 this.commitModelObjects( implementation, m, classesDirectory );
  315.             }
  316.             else if ( this.isLoggable( Level.WARNING ) )
  317.             {
  318.                 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
  319.             }
  320.         }
  321.         catch ( final ModelException e )
  322.         {
  323.             // JDK: As of JDK 6, "new IOException( message, cause )".
  324.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  325.         }
  326.     }

  327.     /**
  328.      * Commits model objects of a given specification of the modules of the instance to a given class file.
  329.      *
  330.      * @param specification The specification to process.
  331.      * @param marshaller The marshaller to use for committing the model objects.
  332.      * @param javaClass The java class to commit to.
  333.      *
  334.      * @throws NullPointerException if {@code specification}, {@code marshaller} or {@code javaClass} is {@code null}.
  335.      * @throws IOException if committing model objects fails.
  336.      */
  337.     public void commitModelObjects( final Specification specification, final Marshaller marshaller,
  338.                                     final JavaClass javaClass ) throws IOException
  339.     {
  340.         if ( specification == null )
  341.         {
  342.             throw new NullPointerException( "specification" );
  343.         }
  344.         if ( marshaller == null )
  345.         {
  346.             throw new NullPointerException( "marshaller" );
  347.         }
  348.         if ( javaClass == null )
  349.         {
  350.             throw new NullPointerException( "javaClass" );
  351.         }

  352.         if ( this.getModules() != null
  353.                  && this.getModules().getSpecification( specification.getIdentifier() ) != null )
  354.         {
  355.             this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject(
  356.                                         marshaller, new ObjectFactory().createSpecification( specification ) ) );

  357.         }
  358.         else if ( this.isLoggable( Level.WARNING ) )
  359.         {
  360.             this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
  361.         }
  362.     }

  363.     /**
  364.      * Commits model objects of a given implementation of the modules of the instance to a given class file.
  365.      *
  366.      * @param implementation The implementation to process.
  367.      * @param marshaller The marshaller to use for committing the model objects.
  368.      * @param javaClass The java class to commit to.
  369.      *
  370.      * @throws NullPointerException if {@code implementation}, {@code marshaller} or {@code javaClass} is {@code null}.
  371.      * @throws IOException if committing model objects fails.
  372.      */
  373.     public void commitModelObjects( final Implementation implementation, final Marshaller marshaller,
  374.                                     final JavaClass javaClass ) throws IOException
  375.     {
  376.         if ( implementation == null )
  377.         {
  378.             throw new NullPointerException( "implementation" );
  379.         }
  380.         if ( marshaller == null )
  381.         {
  382.             throw new NullPointerException( "marshaller" );
  383.         }
  384.         if ( javaClass == null )
  385.         {
  386.             throw new NullPointerException( "javaClass" );
  387.         }

  388.         if ( this.getModules() != null
  389.                  && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
  390.         {
  391.             final ObjectFactory of = new ObjectFactory();

  392.             Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() );
  393.             if ( dependencies == null )
  394.             {
  395.                 dependencies = new Dependencies();
  396.             }

  397.             Properties properties = this.getModules().getProperties( implementation.getIdentifier() );
  398.             if ( properties == null )
  399.             {
  400.                 properties = new Properties();
  401.             }

  402.             Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
  403.             if ( messages == null )
  404.             {
  405.                 messages = new Messages();
  406.             }

  407.             Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() );
  408.             if ( specifications == null )
  409.             {
  410.                 specifications = new Specifications();
  411.             }

  412.             for ( int i = 0, s0 = specifications.getReference().size(); i < s0; i++ )
  413.             {
  414.                 final SpecificationReference r = specifications.getReference().get( i );

  415.                 if ( specifications.getSpecification( r.getIdentifier() ) == null && this.isLoggable( Level.WARNING ) )
  416.                 {
  417.                     this.log( Level.WARNING, getMessage( "unresolvedSpecification", r.getIdentifier(),
  418.                                                          implementation.getIdentifier() ), null );

  419.                 }
  420.             }

  421.             for ( int i = 0, s0 = dependencies.getDependency().size(); i < s0; i++ )
  422.             {
  423.                 final Dependency d = dependencies.getDependency().get( i );
  424.                 final Specification s = this.getModules().getSpecification( d.getIdentifier() );

  425.                 if ( s != null )
  426.                 {
  427.                     if ( specifications.getSpecification( s.getIdentifier() ) == null )
  428.                     {
  429.                         specifications.getSpecification().add( s );
  430.                     }
  431.                 }
  432.                 else if ( this.isLoggable( Level.WARNING ) )
  433.                 {
  434.                     this.log( Level.WARNING, getMessage( "unresolvedDependencySpecification", d.getIdentifier(),
  435.                                                          d.getName(), implementation.getIdentifier() ), null );

  436.                 }
  437.             }

  438.             this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject(
  439.                                         marshaller, of.createDependencies( dependencies ) ) );

  440.             this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject(
  441.                                         marshaller, of.createProperties( properties ) ) );

  442.             this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject(
  443.                                         marshaller, of.createMessages( messages ) ) );

  444.             this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject(
  445.                                         marshaller, of.createSpecifications( specifications ) ) );

  446.         }
  447.         else if ( this.isLoggable( Level.WARNING ) )
  448.         {
  449.             this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
  450.         }
  451.     }

  452.     /**
  453.      * Validates model objects of class files of the modules of the instance.
  454.      *
  455.      * @param context The model context to use for validating model objects.
  456.      *
  457.      * @return The report of the validation or {@code null}, if no model objects are found.
  458.      *
  459.      * @throws NullPointerException if {@code context} is {@code null}.
  460.      * @throws IOException if validating model objects fails.
  461.      *
  462.      * @see #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext)
  463.      */
  464.     public final ModelValidationReport validateModelObjects( final ModelContext context ) throws IOException
  465.     {
  466.         if ( context == null )
  467.         {
  468.             throw new NullPointerException( "context" );
  469.         }

  470.         try
  471.         {
  472.             ModelValidationReport report = null;

  473.             if ( this.getModules() != null )
  474.             {
  475.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  476.                 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
  477.                 report = this.validateModelObjects( this.getModules().getSpecifications(),
  478.                                                     this.getModules().getImplementations(), u, context );

  479.             }
  480.             else if ( this.isLoggable( Level.WARNING ) )
  481.             {
  482.                 this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
  483.             }

  484.             return report;
  485.         }
  486.         catch ( final ModelException e )
  487.         {
  488.             // JDK: As of JDK 6, "new IOException( message, cause )".
  489.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  490.         }
  491.     }

  492.     /**
  493.      * Validates model objects of class files of a given module of the modules of the instance.
  494.      *
  495.      * @param module The module to process.
  496.      * @param context The model context to use for validating model objects.
  497.      *
  498.      * @return The report of the validation or {@code null}, if no model objects are found.
  499.      *
  500.      * @throws NullPointerException if {@code module} or {@code context} is {@code null}.
  501.      * @throws IOException if validating model objects fails.
  502.      *
  503.      * @see #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext)
  504.      * @see #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext)
  505.      */
  506.     public final ModelValidationReport validateModelObjects( final Module module, final ModelContext context )
  507.         throws IOException
  508.     {
  509.         if ( module == null )
  510.         {
  511.             throw new NullPointerException( "module" );
  512.         }
  513.         if ( context == null )
  514.         {
  515.             throw new NullPointerException( "context" );
  516.         }

  517.         try
  518.         {
  519.             ModelValidationReport report = null;

  520.             if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
  521.             {
  522.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  523.                 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
  524.                 report = this.validateModelObjects( module.getSpecifications(), module.getImplementations(), u,
  525.                                                     context );

  526.             }
  527.             else if ( this.isLoggable( Level.WARNING ) )
  528.             {
  529.                 this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
  530.             }

  531.             return report;
  532.         }
  533.         catch ( final ModelException e )
  534.         {
  535.             // JDK: As of JDK 6, "new IOException( message, cause )".
  536.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  537.         }
  538.     }

  539.     /**
  540.      * Validates model objects of class files of a given specification of the modules of the instance.
  541.      *
  542.      * @param specification The specification to process.
  543.      * @param context The model context to use for validating model objects.
  544.      *
  545.      * @return The report of the validation or {@code null}, if no model objects are found.
  546.      *
  547.      * @throws NullPointerException if {@code specification} or {@code context} is {@code null}.
  548.      *
  549.      * @throws IOException if validating model objects fails.
  550.      *
  551.      * @see #validateModelObjects(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
  552.      */
  553.     public final ModelValidationReport validateModelObjects( final Specification specification,
  554.                                                              final ModelContext context ) throws IOException
  555.     {
  556.         if ( specification == null )
  557.         {
  558.             throw new NullPointerException( "specification" );
  559.         }
  560.         if ( context == null )
  561.         {
  562.             throw new NullPointerException( "context" );
  563.         }

  564.         try
  565.         {
  566.             ModelValidationReport report = null;

  567.             if ( this.getModules() != null
  568.                      && this.getModules().getSpecification( specification.getIdentifier() ) != null )
  569.             {
  570.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  571.                 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
  572.                 report = this.validateModelObjects( specification, u, context );
  573.             }
  574.             else if ( this.isLoggable( Level.WARNING ) )
  575.             {
  576.                 this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
  577.             }

  578.             return report;
  579.         }
  580.         catch ( final ModelException e )
  581.         {
  582.             // JDK: As of JDK 6, "new IOException( message, cause )".
  583.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  584.         }
  585.     }

  586.     /**
  587.      * Validates model objects of class files of a given implementation of the modules of the instance.
  588.      *
  589.      * @param implementation The implementation to process.
  590.      * @param context The model context to use for validating model objects.
  591.      *
  592.      * @return The report of the validation or {@code null}, if no model objects are found.
  593.      *
  594.      * @throws NullPointerException if {@code implementation} or {@code context} is {@code null}.
  595.      *
  596.      * @throws IOException if validating model objects fails.
  597.      *
  598.      * @see #validateModelObjects(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
  599.      */
  600.     public final ModelValidationReport validateModelObjects( final Implementation implementation,
  601.                                                              final ModelContext context ) throws IOException
  602.     {
  603.         if ( implementation == null )
  604.         {
  605.             throw new NullPointerException( "implementation" );
  606.         }
  607.         if ( context == null )
  608.         {
  609.             throw new NullPointerException( "context" );
  610.         }

  611.         try
  612.         {
  613.             ModelValidationReport report = null;

  614.             if ( this.getModules() != null
  615.                      && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
  616.             {
  617.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  618.                 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
  619.                 report = this.validateModelObjects( implementation, u, context );
  620.             }
  621.             else if ( this.isLoggable( Level.WARNING ) )
  622.             {
  623.                 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
  624.             }

  625.             return report;
  626.         }
  627.         catch ( final ModelException e )
  628.         {
  629.             // JDK: As of JDK 6, "new IOException( message, cause )".
  630.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  631.         }
  632.     }

  633.     /**
  634.      * Validates model objects of class files of the modules of the instance.
  635.      *
  636.      * @param context The model context to use for validating model objects.
  637.      * @param classesDirectory The directory holding the class files.
  638.      *
  639.      * @return The report of the validation or {@code null}, if no model objects are found.
  640.      *
  641.      * @throws NullPointerException if {@code context} or {@code classesDirectory} is {@code null}.
  642.      * @throws IOException if validating model objects fails.
  643.      *
  644.      * @see #validateModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File)
  645.      */
  646.     public final ModelValidationReport validateModelObjects( final ModelContext context, final File classesDirectory )
  647.         throws IOException
  648.     {
  649.         if ( context == null )
  650.         {
  651.             throw new NullPointerException( "context" );
  652.         }
  653.         if ( classesDirectory == null )
  654.         {
  655.             throw new NullPointerException( "classesDirectory" );
  656.         }

  657.         try
  658.         {
  659.             ModelValidationReport report = null;

  660.             if ( this.getModules() != null )
  661.             {
  662.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  663.                 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
  664.                 report = this.validateModelObjects( this.getModules().getSpecifications(),
  665.                                                     this.getModules().getImplementations(), u, classesDirectory );

  666.             }
  667.             else if ( this.isLoggable( Level.WARNING ) )
  668.             {
  669.                 this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
  670.             }

  671.             return report;
  672.         }
  673.         catch ( final ModelException e )
  674.         {
  675.             // JDK: As of JDK 6, "new IOException( message, cause )".
  676.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  677.         }
  678.     }

  679.     /**
  680.      * Validates model objects of class files of a given module of the modules of the instance.
  681.      *
  682.      * @param module The module to process.
  683.      * @param context The model context to use for validating model objects.
  684.      * @param classesDirectory The directory holding the class files.
  685.      *
  686.      * @return The report of the validation or {@code null}, if no model objects are found.
  687.      *
  688.      * @throws NullPointerException if {@code module}, {@code context} or {@code classesDirectory} is {@code null}.
  689.      * @throws IOException if validating model objects fails.
  690.      *
  691.      * @see #validateModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File)
  692.      * @see #validateModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File)
  693.      */
  694.     public final ModelValidationReport validateModelObjects( final Module module, final ModelContext context,
  695.                                                              final File classesDirectory ) throws IOException
  696.     {
  697.         if ( module == null )
  698.         {
  699.             throw new NullPointerException( "module" );
  700.         }
  701.         if ( context == null )
  702.         {
  703.             throw new NullPointerException( "context" );
  704.         }
  705.         if ( classesDirectory == null )
  706.         {
  707.             throw new NullPointerException( "classesDirectory" );
  708.         }

  709.         try
  710.         {
  711.             ModelValidationReport report = null;

  712.             if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
  713.             {
  714.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  715.                 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
  716.                 report = this.validateModelObjects( module.getSpecifications(), module.getImplementations(), u,
  717.                                                     classesDirectory );

  718.             }
  719.             else if ( this.isLoggable( Level.WARNING ) )
  720.             {
  721.                 this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
  722.             }

  723.             return report;
  724.         }
  725.         catch ( final ModelException e )
  726.         {
  727.             // JDK: As of JDK 6, "new IOException( message, cause )".
  728.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  729.         }
  730.     }

  731.     /**
  732.      * Validates model objects of class files of a given specification of the modules of the instance.
  733.      *
  734.      * @param specification The specification to process.
  735.      * @param context The model context to use for validating model objects.
  736.      * @param classesDirectory The directory holding the class files.
  737.      *
  738.      * @return The report of the validation or {@code null}, if no model objects are found.
  739.      *
  740.      * @throws NullPointerException if {@code specification}, {@code context} or {@code classesDirectory} is
  741.      * {@code null}.
  742.      *
  743.      * @throws IOException if validating model objects fails.
  744.      *
  745.      * @see #validateModelObjects(org.jomc.model.Specification, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
  746.      */
  747.     public final ModelValidationReport validateModelObjects( final Specification specification,
  748.                                                              final ModelContext context, final File classesDirectory )
  749.         throws IOException
  750.     {
  751.         if ( specification == null )
  752.         {
  753.             throw new NullPointerException( "specification" );
  754.         }
  755.         if ( context == null )
  756.         {
  757.             throw new NullPointerException( "context" );
  758.         }
  759.         if ( classesDirectory == null )
  760.         {
  761.             throw new NullPointerException( "classesDirectory" );
  762.         }

  763.         try
  764.         {
  765.             ModelValidationReport report = null;

  766.             if ( this.getModules() != null
  767.                      && this.getModules().getSpecification( specification.getIdentifier() ) != null )
  768.             {
  769.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  770.                 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
  771.                 report = this.validateModelObjects( specification, u, classesDirectory );
  772.             }
  773.             else if ( this.isLoggable( Level.WARNING ) )
  774.             {
  775.                 this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
  776.             }

  777.             return report;
  778.         }
  779.         catch ( final ModelException e )
  780.         {
  781.             // JDK: As of JDK 6, "new IOException( message, cause )".
  782.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  783.         }
  784.     }

  785.     /**
  786.      * Validates model objects of class files of a given implementation of the modules of the instance.
  787.      *
  788.      * @param implementation The implementation to process.
  789.      * @param context The model context to use for validating model objects.
  790.      * @param classesDirectory The directory holding the class files.
  791.      *
  792.      * @return The report of the validation or {@code null}, if no model objects are found.
  793.      *
  794.      * @throws NullPointerException if {@code implementation}, {@code context} or {@code classesDirectory} is
  795.      * {@code null}.
  796.      *
  797.      * @throws IOException if validating model objects fails.
  798.      *
  799.      * @see #validateModelObjects(org.jomc.model.Implementation, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass)
  800.      */
  801.     public final ModelValidationReport validateModelObjects( final Implementation implementation,
  802.                                                              final ModelContext context, final File classesDirectory )
  803.         throws IOException
  804.     {
  805.         if ( implementation == null )
  806.         {
  807.             throw new NullPointerException( "implementation" );
  808.         }
  809.         if ( context == null )
  810.         {
  811.             throw new NullPointerException( "context" );
  812.         }
  813.         if ( classesDirectory == null )
  814.         {
  815.             throw new NullPointerException( "classesDirectory" );
  816.         }

  817.         try
  818.         {
  819.             ModelValidationReport report = null;

  820.             if ( this.getModules() != null
  821.                      && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
  822.             {
  823.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  824.                 u.setSchema( context.createSchema( this.getModel().getIdentifier() ) );
  825.                 report = this.validateModelObjects( implementation, u, classesDirectory );
  826.             }
  827.             else if ( this.isLoggable( Level.WARNING ) )
  828.             {
  829.                 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
  830.             }

  831.             return report;
  832.         }
  833.         catch ( final ModelException e )
  834.         {
  835.             // JDK: As of JDK 6, "new IOException( message, cause )".
  836.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  837.         }
  838.     }

  839.     /**
  840.      * Validates model objects of a given specification of the modules of the instance.
  841.      *
  842.      * @param specification The specification to process.
  843.      * @param unmarshaller The unmarshaller to use for validating model objects.
  844.      * @param javaClass The java class to validate.
  845.      *
  846.      * @return The report of the validation or {@code null}, if no model objects are found.
  847.      *
  848.      * @throws NullPointerException if {@code specification}, {@code unmarshaller} or {@code javaClass} is {@code null}.
  849.      * @throws IOException if validating model objects fails.
  850.      */
  851.     public ModelValidationReport validateModelObjects( final Specification specification,
  852.                                                        final Unmarshaller unmarshaller, final JavaClass javaClass )
  853.         throws IOException
  854.     {
  855.         if ( specification == null )
  856.         {
  857.             throw new NullPointerException( "specification" );
  858.         }
  859.         if ( unmarshaller == null )
  860.         {
  861.             throw new NullPointerException( "unmarshaller" );
  862.         }
  863.         if ( javaClass == null )
  864.         {
  865.             throw new NullPointerException( "javaClass" );
  866.         }

  867.         ModelValidationReport report = null;

  868.         if ( this.getModules() != null && this.getModules().getSpecification( specification.getIdentifier() ) != null )
  869.         {
  870.             report = new ModelValidationReport();

  871.             Specification decoded = null;
  872.             final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() );
  873.             if ( bytes != null )
  874.             {
  875.                 decoded = this.decodeModelObject( unmarshaller, bytes, Specification.class );
  876.             }

  877.             if ( decoded != null )
  878.             {
  879.                 if ( decoded.getMultiplicity() != specification.getMultiplicity() )
  880.                 {
  881.                     report.getDetails().add( new ModelValidationReport.Detail(
  882.                         "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage(
  883.                             "illegalMultiplicity", specification.getIdentifier(),
  884.                             specification.getMultiplicity().value(),
  885.                             decoded.getMultiplicity().value() ),
  886.                         new ObjectFactory().createSpecification( specification ) ) );

  887.                 }

  888.                 if ( decoded.getScope() == null
  889.                          ? specification.getScope() != null
  890.                          : !decoded.getScope().equals( specification.getScope() ) )
  891.                 {
  892.                     report.getDetails().add( new ModelValidationReport.Detail(
  893.                         "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage(
  894.                             "illegalScope", specification.getIdentifier(),
  895.                             specification.getScope() == null ? "Multiton" : specification.getScope(),
  896.                             decoded.getScope() == null ? "Multiton" : decoded.getScope() ),
  897.                         new ObjectFactory().createSpecification( specification ) ) );

  898.                 }

  899.                 if ( decoded.getClazz() == null
  900.                          ? specification.getClazz() != null
  901.                          : !decoded.getClazz().equals( specification.getClazz() ) )
  902.                 {
  903.                     report.getDetails().add( new ModelValidationReport.Detail(
  904.                         "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage(
  905.                             "illegalSpecificationClass", decoded.getIdentifier(),
  906.                             specification.getClazz(), decoded.getClazz() ),
  907.                         new ObjectFactory().createSpecification( specification ) ) );

  908.                 }
  909.             }
  910.             else if ( this.isLoggable( Level.WARNING ) )
  911.             {
  912.                 this.log( Level.WARNING, getMessage( "cannotValidateSpecification", specification.getIdentifier(),
  913.                                                      Specification.class.getName() ), null );

  914.             }
  915.         }
  916.         else if ( this.isLoggable( Level.WARNING ) )
  917.         {
  918.             this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
  919.         }

  920.         return report;
  921.     }

  922.     /**
  923.      * Validates model objects of a given implementation of the modules of the instance.
  924.      *
  925.      * @param implementation The implementation to process.
  926.      * @param unmarshaller The unmarshaller to use for validating model objects.
  927.      * @param javaClass The java class to validate.
  928.      *
  929.      * @return The report of the validation or {@code null}, if no model objects are found.
  930.      *
  931.      * @throws NullPointerException if {@code implementation}, {@code unmarshaller} or {@code javaClass} is {@code null}.
  932.      * @throws IOException if validating model objects fails.
  933.      */
  934.     public ModelValidationReport validateModelObjects( final Implementation implementation,
  935.                                                        final Unmarshaller unmarshaller, final JavaClass javaClass )
  936.         throws IOException
  937.     {
  938.         if ( implementation == null )
  939.         {
  940.             throw new NullPointerException( "implementation" );
  941.         }
  942.         if ( unmarshaller == null )
  943.         {
  944.             throw new NullPointerException( "unmarshaller" );
  945.         }
  946.         if ( javaClass == null )
  947.         {
  948.             throw new NullPointerException( "javaClass" );
  949.         }

  950.         try
  951.         {
  952.             ModelValidationReport report = null;

  953.             if ( this.getModules() != null
  954.                      && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
  955.             {
  956.                 report = new ModelValidationReport();
  957.                 Dependencies dependencies = this.getModules().getDependencies( implementation.getIdentifier() );
  958.                 if ( dependencies == null )
  959.                 {
  960.                     dependencies = new Dependencies();
  961.                 }

  962.                 Properties properties = this.getModules().getProperties( implementation.getIdentifier() );
  963.                 if ( properties == null )
  964.                 {
  965.                     properties = new Properties();
  966.                 }

  967.                 Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
  968.                 if ( messages == null )
  969.                 {
  970.                     messages = new Messages();
  971.                 }

  972.                 Specifications specifications = this.getModules().getSpecifications( implementation.getIdentifier() );
  973.                 if ( specifications == null )
  974.                 {
  975.                     specifications = new Specifications();
  976.                 }

  977.                 Dependencies decodedDependencies = null;
  978.                 byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() );
  979.                 if ( bytes != null )
  980.                 {
  981.                     decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class );
  982.                 }

  983.                 Properties decodedProperties = null;
  984.                 bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() );
  985.                 if ( bytes != null )
  986.                 {
  987.                     decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class );
  988.                 }

  989.                 Messages decodedMessages = null;
  990.                 bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() );
  991.                 if ( bytes != null )
  992.                 {
  993.                     decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class );
  994.                 }

  995.                 Specifications decodedSpecifications = null;
  996.                 bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() );
  997.                 if ( bytes != null )
  998.                 {
  999.                     decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class );
  1000.                 }

  1001.                 if ( decodedDependencies != null )
  1002.                 {
  1003.                     for ( int i = 0, s0 = decodedDependencies.getDependency().size(); i < s0; i++ )
  1004.                     {
  1005.                         final Dependency decodedDependency = decodedDependencies.getDependency().get( i );
  1006.                         final Dependency dependency = dependencies.getDependency( decodedDependency.getName() );
  1007.                         final Specification s = this.getModules().getSpecification( decodedDependency.getIdentifier() );

  1008.                         if ( dependency == null )
  1009.                         {
  1010.                             report.getDetails().add( new ModelValidationReport.Detail(
  1011.                                 "CLASS_MISSING_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage(
  1012.                                     "missingDependency", implementation.getIdentifier(), decodedDependency.getName() ),
  1013.                                 new ObjectFactory().createImplementation( implementation ) ) );

  1014.                         }
  1015.                         else if ( decodedDependency.getImplementationName() != null
  1016.                                       && dependency.getImplementationName() == null )
  1017.                         {
  1018.                             report.getDetails().add( new ModelValidationReport.Detail(
  1019.                                 "CLASS_MISSING_DEPENDENCY_IMPLEMENTATION_NAME", Level.SEVERE, getMessage(
  1020.                                     "missingDependencyImplementationName", implementation.getIdentifier(),
  1021.                                     decodedDependency.getName() ),
  1022.                                 new ObjectFactory().createImplementation( implementation ) ) );

  1023.                         }

  1024.                         if ( s != null && s.getVersion() != null && decodedDependency.getVersion() != null
  1025.                                  && VersionParser.compare( decodedDependency.getVersion(), s.getVersion() ) > 0 )
  1026.                         {
  1027.                             final Module moduleOfSpecification =
  1028.                                 this.getModules().getModuleOfSpecification( s.getIdentifier() );

  1029.                             final Module moduleOfImplementation =
  1030.                                 this.getModules().getModuleOfImplementation( implementation.getIdentifier() );

  1031.                             report.getDetails().add( new ModelValidationReport.Detail(
  1032.                                 "CLASS_INCOMPATIBLE_IMPLEMENTATION_DEPENDENCY", Level.SEVERE, getMessage(
  1033.                                     "incompatibleDependency", javaClass.getClassName(),
  1034.                                     moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(),
  1035.                                     s.getIdentifier(),
  1036.                                     moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(),
  1037.                                     decodedDependency.getVersion(), s.getVersion() ),
  1038.                                 new ObjectFactory().createImplementation( implementation ) ) );

  1039.                         }
  1040.                     }
  1041.                 }
  1042.                 else if ( this.isLoggable( Level.WARNING ) )
  1043.                 {
  1044.                     this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
  1045.                                                          Dependencies.class.getName() ), null );

  1046.                 }

  1047.                 if ( decodedProperties != null )
  1048.                 {
  1049.                     for ( int i = 0, s0 = decodedProperties.getProperty().size(); i < s0; i++ )
  1050.                     {
  1051.                         final Property decodedProperty = decodedProperties.getProperty().get( i );
  1052.                         final Property property = properties.getProperty( decodedProperty.getName() );

  1053.                         if ( property == null )
  1054.                         {
  1055.                             report.getDetails().add( new ModelValidationReport.Detail(
  1056.                                 "CLASS_MISSING_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage(
  1057.                                     "missingProperty", implementation.getIdentifier(), decodedProperty.getName() ),
  1058.                                 new ObjectFactory().createImplementation( implementation ) ) );

  1059.                         }
  1060.                         else if ( decodedProperty.getType() == null
  1061.                                       ? property.getType() != null
  1062.                                       : !decodedProperty.getType().equals( property.getType() ) )
  1063.                         {
  1064.                             report.getDetails().add( new ModelValidationReport.Detail(
  1065.                                 "CLASS_ILLEGAL_IMPLEMENTATION_PROPERTY", Level.SEVERE, getMessage(
  1066.                                     "illegalPropertyType", implementation.getIdentifier(), decodedProperty.getName(),
  1067.                                     property.getType() == null ? "<>" : property.getType(),
  1068.                                     decodedProperty.getType() == null ? "<>" : decodedProperty.getType() ),
  1069.                                 new ObjectFactory().createImplementation( implementation ) ) );

  1070.                         }
  1071.                     }
  1072.                 }
  1073.                 else if ( this.isLoggable( Level.WARNING ) )
  1074.                 {
  1075.                     this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
  1076.                                                          Properties.class.getName() ), null );

  1077.                 }

  1078.                 if ( decodedMessages != null )
  1079.                 {
  1080.                     for ( int i = 0, s0 = decodedMessages.getMessage().size(); i < s0; i++ )
  1081.                     {
  1082.                         final Message decodedMessage = decodedMessages.getMessage().get( i );
  1083.                         final Message message = messages.getMessage( decodedMessage.getName() );

  1084.                         if ( message == null )
  1085.                         {
  1086.                             report.getDetails().add( new ModelValidationReport.Detail(
  1087.                                 "CLASS_MISSING_IMPLEMENTATION_MESSAGE", Level.SEVERE, getMessage(
  1088.                                     "missingMessage", implementation.getIdentifier(), decodedMessage.getName() ),
  1089.                                 new ObjectFactory().createImplementation( implementation ) ) );

  1090.                         }
  1091.                     }
  1092.                 }
  1093.                 else if ( this.isLoggable( Level.WARNING ) )
  1094.                 {
  1095.                     this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
  1096.                                                          Messages.class.getName() ), null );

  1097.                 }

  1098.                 if ( decodedSpecifications != null )
  1099.                 {
  1100.                     for ( int i = 0, s0 = decodedSpecifications.getSpecification().size(); i < s0; i++ )
  1101.                     {
  1102.                         final Specification decodedSpecification = decodedSpecifications.getSpecification().get( i );
  1103.                         final Specification specification =
  1104.                             this.getModules().getSpecification( decodedSpecification.getIdentifier() );

  1105.                         if ( specification == null )
  1106.                         {
  1107.                             report.getDetails().add( new ModelValidationReport.Detail(
  1108.                                 "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage(
  1109.                                     "missingSpecification", implementation.getIdentifier(),
  1110.                                     decodedSpecification.getIdentifier() ),
  1111.                                 new ObjectFactory().createImplementation( implementation ) ) );

  1112.                         }
  1113.                         else
  1114.                         {
  1115.                             if ( decodedSpecification.getMultiplicity() != specification.getMultiplicity() )
  1116.                             {
  1117.                                 report.getDetails().add( new ModelValidationReport.Detail(
  1118.                                     "CLASS_ILLEGAL_SPECIFICATION_MULTIPLICITY", Level.SEVERE, getMessage(
  1119.                                         "illegalMultiplicity", specification.getIdentifier(),
  1120.                                         specification.getMultiplicity().value(),
  1121.                                         decodedSpecification.getMultiplicity().value() ),
  1122.                                     new ObjectFactory().createImplementation( implementation ) ) );

  1123.                             }

  1124.                             if ( decodedSpecification.getScope() == null
  1125.                                      ? specification.getScope() != null
  1126.                                      : !decodedSpecification.getScope().equals( specification.getScope() ) )
  1127.                             {
  1128.                                 report.getDetails().add( new ModelValidationReport.Detail(
  1129.                                     "CLASS_ILLEGAL_SPECIFICATION_SCOPE", Level.SEVERE, getMessage(
  1130.                                         "illegalScope", decodedSpecification.getIdentifier(),
  1131.                                         specification.getScope() == null ? "Multiton" : specification.getScope(),
  1132.                                         decodedSpecification.getScope() == null
  1133.                                             ? "Multiton"
  1134.                                             : decodedSpecification.getScope() ),
  1135.                                     new ObjectFactory().createImplementation( implementation ) ) );

  1136.                             }

  1137.                             if ( decodedSpecification.getClazz() == null
  1138.                                      ? specification.getClazz() != null
  1139.                                      : !decodedSpecification.getClazz().equals( specification.getClazz() ) )
  1140.                             {
  1141.                                 report.getDetails().add( new ModelValidationReport.Detail(
  1142.                                     "CLASS_ILLEGAL_SPECIFICATION_CLASS", Level.SEVERE, getMessage(
  1143.                                         "illegalSpecificationClass", decodedSpecification.getIdentifier(),
  1144.                                         specification.getClazz(), decodedSpecification.getClazz() ),
  1145.                                     new ObjectFactory().createImplementation( implementation ) ) );

  1146.                             }
  1147.                         }
  1148.                     }

  1149.                     for ( int i = 0, s0 = decodedSpecifications.getReference().size(); i < s0; i++ )
  1150.                     {
  1151.                         final SpecificationReference decodedReference = decodedSpecifications.getReference().get( i );
  1152.                         final Specification specification =
  1153.                             specifications.getSpecification( decodedReference.getIdentifier() );

  1154.                         if ( specification == null )
  1155.                         {
  1156.                             report.getDetails().add( new ModelValidationReport.Detail(
  1157.                                 "CLASS_MISSING_SPECIFICATION", Level.SEVERE, getMessage(
  1158.                                     "missingSpecification", implementation.getIdentifier(),
  1159.                                     decodedReference.getIdentifier() ),
  1160.                                 new ObjectFactory().createImplementation( implementation ) ) );

  1161.                         }
  1162.                         else if ( decodedReference.getVersion() != null && specification.getVersion() != null
  1163.                                       && VersionParser.compare( decodedReference.getVersion(),
  1164.                                                                 specification.getVersion() ) != 0 )
  1165.                         {
  1166.                             final Module moduleOfSpecification =
  1167.                                 this.getModules().getModuleOfSpecification( decodedReference.getIdentifier() );

  1168.                             final Module moduleOfImplementation =
  1169.                                 this.getModules().getModuleOfImplementation( implementation.getIdentifier() );

  1170.                             report.getDetails().add( new ModelValidationReport.Detail(
  1171.                                 "CLASS_INCOMPATIBLE_IMPLEMENTATION", Level.SEVERE, getMessage(
  1172.                                     "incompatibleImplementation", javaClass.getClassName(),
  1173.                                     moduleOfImplementation == null ? "<>" : moduleOfImplementation.getName(),
  1174.                                     specification.getIdentifier(),
  1175.                                     moduleOfSpecification == null ? "<>" : moduleOfSpecification.getName(),
  1176.                                     decodedReference.getVersion(), specification.getVersion() ),
  1177.                                 new ObjectFactory().createImplementation( implementation ) ) );

  1178.                         }
  1179.                     }
  1180.                 }
  1181.                 else if ( this.isLoggable( Level.WARNING ) )
  1182.                 {
  1183.                     this.log( Level.WARNING, getMessage( "cannotValidateImplementation", implementation.getIdentifier(),
  1184.                                                          Specifications.class.getName() ), null );

  1185.                 }
  1186.             }
  1187.             else if ( this.isLoggable( Level.WARNING ) )
  1188.             {
  1189.                 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
  1190.             }

  1191.             return report;
  1192.         }
  1193.         catch ( final ParseException e )
  1194.         {
  1195.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1196.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  1197.         }
  1198.         catch ( final TokenMgrError e )
  1199.         {
  1200.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1201.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  1202.         }
  1203.     }

  1204.     /**
  1205.      * Transforms model objects of class files of the modules of the instance.
  1206.      *
  1207.      * @param context The model context to use for transforming model objects.
  1208.      * @param classesDirectory The directory holding the class files.
  1209.      * @param transformers The transformers to use for transforming model objects.
  1210.      *
  1211.      * @throws NullPointerException if {@code context}, {@code classesDirectory} or {@code transformers} is
  1212.      * {@code null}.
  1213.      * @throws IOException if transforming model objects fails.
  1214.      *
  1215.      * @see #transformModelObjects(org.jomc.model.Module, org.jomc.modlet.ModelContext, java.io.File, java.util.List)
  1216.      */
  1217.     public final void transformModelObjects( final ModelContext context, final File classesDirectory,
  1218.                                              final List<Transformer> transformers ) throws IOException
  1219.     {
  1220.         if ( context == null )
  1221.         {
  1222.             throw new NullPointerException( "context" );
  1223.         }
  1224.         if ( classesDirectory == null )
  1225.         {
  1226.             throw new NullPointerException( "classesDirectory" );
  1227.         }
  1228.         if ( transformers == null )
  1229.         {
  1230.             throw new NullPointerException( "transformers" );
  1231.         }
  1232.         if ( !classesDirectory.isDirectory() )
  1233.         {
  1234.             throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
  1235.         }

  1236.         try
  1237.         {
  1238.             if ( this.getModules() != null )
  1239.             {
  1240.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  1241.                 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
  1242.                 final Schema s = context.createSchema( this.getModel().getIdentifier() );
  1243.                 u.setSchema( s );
  1244.                 m.setSchema( s );

  1245.                 this.transformModelObjects( this.getModules().getSpecifications(),
  1246.                                             this.getModules().getImplementations(),
  1247.                                             u, m, classesDirectory, transformers );

  1248.             }
  1249.             else if ( this.isLoggable( Level.WARNING ) )
  1250.             {
  1251.                 this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
  1252.             }
  1253.         }
  1254.         catch ( final ModelException e )
  1255.         {
  1256.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1257.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  1258.         }
  1259.     }

  1260.     /**
  1261.      * Transforms model objects of class files of a given module of the modules of the instance.
  1262.      *
  1263.      * @param module The module to process.
  1264.      * @param context The model context to use for transforming model objects.
  1265.      * @param classesDirectory The directory holding the class files.
  1266.      * @param transformers The transformers to use for transforming the model objects.
  1267.      *
  1268.      * @throws NullPointerException if {@code module}, {@code context}, {@code classesDirectory} or {@code transformers}
  1269.      * is {@code null}.
  1270.      * @throws IOException if transforming model objects fails.
  1271.      *
  1272.      * @see #transformModelObjects(org.jomc.model.Specification, org.jomc.modlet.ModelContext, java.io.File, java.util.List)
  1273.      * @see #transformModelObjects(org.jomc.model.Implementation, org.jomc.modlet.ModelContext, java.io.File, java.util.List)
  1274.      */
  1275.     public final void transformModelObjects( final Module module, final ModelContext context,
  1276.                                              final File classesDirectory, final List<Transformer> transformers )
  1277.         throws IOException
  1278.     {
  1279.         if ( module == null )
  1280.         {
  1281.             throw new NullPointerException( "module" );
  1282.         }
  1283.         if ( context == null )
  1284.         {
  1285.             throw new NullPointerException( "context" );
  1286.         }
  1287.         if ( classesDirectory == null )
  1288.         {
  1289.             throw new NullPointerException( "classesDirectory" );
  1290.         }
  1291.         if ( transformers == null )
  1292.         {
  1293.             throw new NullPointerException( "transformers" );
  1294.         }
  1295.         if ( !classesDirectory.isDirectory() )
  1296.         {
  1297.             throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
  1298.         }

  1299.         try
  1300.         {
  1301.             if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
  1302.             {
  1303.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  1304.                 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
  1305.                 final Schema s = context.createSchema( this.getModel().getIdentifier() );
  1306.                 u.setSchema( s );
  1307.                 m.setSchema( s );

  1308.                 this.transformModelObjects( module.getSpecifications(), module.getImplementations(), u, m,
  1309.                                             classesDirectory, transformers );

  1310.             }
  1311.             else if ( this.isLoggable( Level.WARNING ) )
  1312.             {
  1313.                 this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
  1314.             }
  1315.         }
  1316.         catch ( final ModelException e )
  1317.         {
  1318.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1319.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  1320.         }
  1321.     }

  1322.     /**
  1323.      * Transforms model objects of class files of a given specification of the modules of the instance.
  1324.      *
  1325.      * @param specification The specification to process.
  1326.      * @param context The model context to use for transforming model objects.
  1327.      * @param classesDirectory The directory holding the class files.
  1328.      * @param transformers The transformers to use for transforming the model objects.
  1329.      *
  1330.      * @throws NullPointerException if {@code specification}, {@code context}, {@code classesDirectory} or
  1331.      * {@code transformers} is {@code null}.
  1332.      * @throws IOException if transforming model objects fails.
  1333.      *
  1334.      * @see #transformModelObjects(org.jomc.model.Specification, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List)
  1335.      */
  1336.     public final void transformModelObjects( final Specification specification, final ModelContext context,
  1337.                                              final File classesDirectory, final List<Transformer> transformers )
  1338.         throws IOException
  1339.     {
  1340.         if ( specification == null )
  1341.         {
  1342.             throw new NullPointerException( "specification" );
  1343.         }
  1344.         if ( context == null )
  1345.         {
  1346.             throw new NullPointerException( "context" );
  1347.         }
  1348.         if ( classesDirectory == null )
  1349.         {
  1350.             throw new NullPointerException( "classesDirectory" );
  1351.         }
  1352.         if ( transformers == null )
  1353.         {
  1354.             throw new NullPointerException( "transformers" );
  1355.         }
  1356.         if ( !classesDirectory.isDirectory() )
  1357.         {
  1358.             throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
  1359.         }

  1360.         try
  1361.         {
  1362.             if ( this.getModules() != null
  1363.                      && this.getModules().getSpecification( specification.getIdentifier() ) != null )
  1364.             {
  1365.                 final Unmarshaller u = context.createUnmarshaller( this.getModel().getIdentifier() );
  1366.                 final Marshaller m = context.createMarshaller( this.getModel().getIdentifier() );
  1367.                 final Schema s = context.createSchema( this.getModel().getIdentifier() );
  1368.                 u.setSchema( s );
  1369.                 m.setSchema( s );

  1370.                 this.transformModelObjects( specification, m, u, classesDirectory, transformers );
  1371.             }
  1372.             else if ( this.isLoggable( Level.WARNING ) )
  1373.             {
  1374.                 this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
  1375.             }
  1376.         }
  1377.         catch ( final ModelException e )
  1378.         {
  1379.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1380.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  1381.         }
  1382.     }

  1383.     /**
  1384.      * Transforms model objects of class files of a given implementation of the modules of the instance.
  1385.      *
  1386.      * @param implementation The implementation to process.
  1387.      * @param context The model context to use for transforming model objects.
  1388.      * @param classesDirectory The directory holding the class files.
  1389.      * @param transformers The transformers to use for transforming the model objects.
  1390.      *
  1391.      * @throws NullPointerException if {@code implementation}, {@code context}, {@code classesDirectory} or
  1392.      * {@code transformers} is {@code null}.
  1393.      * @throws IOException if transforming model objects fails.
  1394.      *
  1395.      * @see #transformModelObjects(org.jomc.model.Implementation, javax.xml.bind.Marshaller, javax.xml.bind.Unmarshaller, org.apache.bcel.classfile.JavaClass, java.util.List)
  1396.      */
  1397.     public final void transformModelObjects( final Implementation implementation, final ModelContext context,
  1398.                                              final File classesDirectory, final List<Transformer> transformers )
  1399.         throws IOException
  1400.     {
  1401.         if ( implementation == null )
  1402.         {
  1403.             throw new NullPointerException( "implementation" );
  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.         try
  1422.         {
  1423.             if ( this.getModules() != null
  1424.                      && this.getModules().getImplementation( implementation.getIdentifier() ) != 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.                 this.transformModelObjects( implementation, m, u, classesDirectory, transformers );
  1432.             }
  1433.             else if ( this.isLoggable( Level.WARNING ) )
  1434.             {
  1435.                 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
  1436.             }
  1437.         }
  1438.         catch ( final ModelException e )
  1439.         {
  1440.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1441.             throw (IOException) new IOException( getMessage( e ) ).initCause( e );
  1442.         }
  1443.     }

  1444.     /**
  1445.      * Transforms model objects of a given specification of the modules of the instance.
  1446.      *
  1447.      * @param specification The specification to process.
  1448.      * @param marshaller The marshaller to use for transforming model objects.
  1449.      * @param unmarshaller The unmarshaller to use for transforming model objects.
  1450.      * @param javaClass The java class to transform model objects of.
  1451.      * @param transformers The transformers to use for transforming the model objects.
  1452.      *
  1453.      * @throws NullPointerException if {@code specification}, {@code marshaller}, {@code unmarshaller},
  1454.      * {@code javaClass} or {@code transformers} is {@code null}.
  1455.      * @throws IOException if transforming model objects fails.
  1456.      */
  1457.     public void transformModelObjects( final Specification specification, final Marshaller marshaller,
  1458.                                        final Unmarshaller unmarshaller, final JavaClass javaClass,
  1459.                                        final List<Transformer> transformers ) throws IOException
  1460.     {
  1461.         if ( specification == null )
  1462.         {
  1463.             throw new NullPointerException( "specification" );
  1464.         }
  1465.         if ( marshaller == null )
  1466.         {
  1467.             throw new NullPointerException( "marshaller" );
  1468.         }
  1469.         if ( unmarshaller == null )
  1470.         {
  1471.             throw new NullPointerException( "unmarshaller" );
  1472.         }
  1473.         if ( javaClass == null )
  1474.         {
  1475.             throw new NullPointerException( "javaClass" );
  1476.         }
  1477.         if ( transformers == null )
  1478.         {
  1479.             throw new NullPointerException( "transformers" );
  1480.         }

  1481.         try
  1482.         {
  1483.             if ( this.getModules() != null
  1484.                      && this.getModules().getSpecification( specification.getIdentifier() ) != null )
  1485.             {
  1486.                 Specification decodedSpecification = null;
  1487.                 final ObjectFactory objectFactory = new ObjectFactory();
  1488.                 final byte[] bytes = this.getClassfileAttribute( javaClass, Specification.class.getName() );
  1489.                 if ( bytes != null )
  1490.                 {
  1491.                     decodedSpecification = this.decodeModelObject( unmarshaller, bytes, Specification.class );
  1492.                 }

  1493.                 if ( decodedSpecification != null )
  1494.                 {
  1495.                     for ( int i = 0, l = transformers.size(); i < l; i++ )
  1496.                     {
  1497.                         final JAXBSource source =
  1498.                             new JAXBSource( marshaller, objectFactory.createSpecification( decodedSpecification ) );

  1499.                         final JAXBResult result = new JAXBResult( unmarshaller );
  1500.                         transformers.get( i ).transform( source, result );

  1501.                         if ( result.getResult() instanceof JAXBElement<?>
  1502.                                  && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Specification )
  1503.                         {
  1504.                             decodedSpecification = (Specification) ( (JAXBElement<?>) result.getResult() ).getValue();
  1505.                         }
  1506.                         else
  1507.                         {
  1508.                             throw new IOException( getMessage(
  1509.                                 "illegalSpecificationTransformationResult", specification.getIdentifier() ) );

  1510.                         }
  1511.                     }

  1512.                     this.setClassfileAttribute( javaClass, Specification.class.getName(), this.encodeModelObject(
  1513.                                                 marshaller,
  1514.                                                 objectFactory.createSpecification( decodedSpecification ) ) );

  1515.                 }
  1516.             }
  1517.             else if ( this.isLoggable( Level.WARNING ) )
  1518.             {
  1519.                 this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
  1520.             }
  1521.         }
  1522.         catch ( final JAXBException e )
  1523.         {
  1524.             String message = getMessage( e );
  1525.             if ( message == null && e.getLinkedException() != null )
  1526.             {
  1527.                 message = getMessage( e.getLinkedException() );
  1528.             }

  1529.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1530.             throw (IOException) new IOException( message ).initCause( e );
  1531.         }
  1532.         catch ( final TransformerException e )
  1533.         {
  1534.             String message = getMessage( e );
  1535.             if ( message == null && e.getException() != null )
  1536.             {
  1537.                 message = getMessage( e.getException() );
  1538.             }

  1539.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1540.             throw (IOException) new IOException( message ).initCause( e );
  1541.         }
  1542.     }

  1543.     /**
  1544.      * Transforms model objects of a given implementation of the modules of the instance.
  1545.      *
  1546.      * @param implementation The implementation to process.
  1547.      * @param marshaller The marshaller to use for transforming model objects.
  1548.      * @param unmarshaller The unmarshaller to use for transforming model objects.
  1549.      * @param javaClass The java class to transform model object of.
  1550.      * @param transformers The transformers to use for transforming the model objects.
  1551.      *
  1552.      * @throws NullPointerException if {@code implementation}, {@code marshaller}, {@code unmarshaller},
  1553.      * {@code javaClass} or {@code transformers} is {@code null}.
  1554.      * @throws IOException if transforming model objects fails.
  1555.      */
  1556.     public void transformModelObjects( final Implementation implementation, final Marshaller marshaller,
  1557.                                        final Unmarshaller unmarshaller, final JavaClass javaClass,
  1558.                                        final List<Transformer> transformers ) throws IOException
  1559.     {
  1560.         if ( implementation == null )
  1561.         {
  1562.             throw new NullPointerException( "implementation" );
  1563.         }
  1564.         if ( marshaller == null )
  1565.         {
  1566.             throw new NullPointerException( "marshaller" );
  1567.         }
  1568.         if ( unmarshaller == null )
  1569.         {
  1570.             throw new NullPointerException( "unmarshaller" );
  1571.         }
  1572.         if ( javaClass == null )
  1573.         {
  1574.             throw new NullPointerException( "javaClass" );
  1575.         }
  1576.         if ( transformers == null )
  1577.         {
  1578.             throw new NullPointerException( "transformers" );
  1579.         }

  1580.         try
  1581.         {
  1582.             if ( this.getModules() != null
  1583.                      && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
  1584.             {
  1585.                 Dependencies decodedDependencies = null;
  1586.                 byte[] bytes = this.getClassfileAttribute( javaClass, Dependencies.class.getName() );
  1587.                 if ( bytes != null )
  1588.                 {
  1589.                     decodedDependencies = this.decodeModelObject( unmarshaller, bytes, Dependencies.class );
  1590.                 }

  1591.                 Messages decodedMessages = null;
  1592.                 bytes = this.getClassfileAttribute( javaClass, Messages.class.getName() );
  1593.                 if ( bytes != null )
  1594.                 {
  1595.                     decodedMessages = this.decodeModelObject( unmarshaller, bytes, Messages.class );
  1596.                 }

  1597.                 Properties decodedProperties = null;
  1598.                 bytes = this.getClassfileAttribute( javaClass, Properties.class.getName() );
  1599.                 if ( bytes != null )
  1600.                 {
  1601.                     decodedProperties = this.decodeModelObject( unmarshaller, bytes, Properties.class );
  1602.                 }

  1603.                 Specifications decodedSpecifications = null;
  1604.                 bytes = this.getClassfileAttribute( javaClass, Specifications.class.getName() );
  1605.                 if ( bytes != null )
  1606.                 {
  1607.                     decodedSpecifications = this.decodeModelObject( unmarshaller, bytes, Specifications.class );
  1608.                 }

  1609.                 final ObjectFactory of = new ObjectFactory();
  1610.                 for ( int i = 0, l = transformers.size(); i < l; i++ )
  1611.                 {
  1612.                     final Transformer transformer = transformers.get( i );

  1613.                     if ( decodedDependencies != null )
  1614.                     {
  1615.                         final JAXBSource source =
  1616.                             new JAXBSource( marshaller, of.createDependencies( decodedDependencies ) );

  1617.                         final JAXBResult result = new JAXBResult( unmarshaller );
  1618.                         transformer.transform( source, result );

  1619.                         if ( result.getResult() instanceof JAXBElement<?>
  1620.                                  && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Dependencies )
  1621.                         {
  1622.                             decodedDependencies = (Dependencies) ( (JAXBElement<?>) result.getResult() ).getValue();
  1623.                         }
  1624.                         else
  1625.                         {
  1626.                             throw new IOException( getMessage(
  1627.                                 "illegalImplementationTransformationResult", implementation.getIdentifier() ) );

  1628.                         }
  1629.                     }

  1630.                     if ( decodedMessages != null )
  1631.                     {
  1632.                         final JAXBSource source = new JAXBSource( marshaller, of.createMessages( decodedMessages ) );
  1633.                         final JAXBResult result = new JAXBResult( unmarshaller );
  1634.                         transformer.transform( source, result );

  1635.                         if ( result.getResult() instanceof JAXBElement<?>
  1636.                                  && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Messages )
  1637.                         {
  1638.                             decodedMessages = (Messages) ( (JAXBElement<?>) result.getResult() ).getValue();
  1639.                         }
  1640.                         else
  1641.                         {
  1642.                             throw new IOException( getMessage(
  1643.                                 "illegalImplementationTransformationResult", implementation.getIdentifier() ) );

  1644.                         }
  1645.                     }

  1646.                     if ( decodedProperties != null )
  1647.                     {
  1648.                         final JAXBSource source =
  1649.                             new JAXBSource( marshaller, of.createProperties( decodedProperties ) );

  1650.                         final JAXBResult result = new JAXBResult( unmarshaller );
  1651.                         transformer.transform( source, result );

  1652.                         if ( result.getResult() instanceof JAXBElement<?>
  1653.                                  && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Properties )
  1654.                         {
  1655.                             decodedProperties = (Properties) ( (JAXBElement<?>) result.getResult() ).getValue();
  1656.                         }
  1657.                         else
  1658.                         {
  1659.                             throw new IOException( getMessage(
  1660.                                 "illegalImplementationTransformationResult", implementation.getIdentifier() ) );

  1661.                         }
  1662.                     }

  1663.                     if ( decodedSpecifications != null )
  1664.                     {
  1665.                         final JAXBSource source =
  1666.                             new JAXBSource( marshaller, of.createSpecifications( decodedSpecifications ) );

  1667.                         final JAXBResult result = new JAXBResult( unmarshaller );
  1668.                         transformer.transform( source, result );

  1669.                         if ( result.getResult() instanceof JAXBElement<?>
  1670.                                  && ( (JAXBElement<?>) result.getResult() ).getValue() instanceof Specifications )
  1671.                         {
  1672.                             decodedSpecifications = (Specifications) ( (JAXBElement<?>) result.getResult() ).getValue();
  1673.                         }
  1674.                         else
  1675.                         {
  1676.                             throw new IOException( getMessage(
  1677.                                 "illegalImplementationTransformationResult", implementation.getIdentifier() ) );

  1678.                         }
  1679.                     }
  1680.                 }

  1681.                 if ( decodedDependencies != null )
  1682.                 {
  1683.                     this.setClassfileAttribute( javaClass, Dependencies.class.getName(), this.encodeModelObject(
  1684.                                                 marshaller, of.createDependencies( decodedDependencies ) ) );

  1685.                 }

  1686.                 if ( decodedMessages != null )
  1687.                 {
  1688.                     this.setClassfileAttribute( javaClass, Messages.class.getName(), this.encodeModelObject(
  1689.                                                 marshaller, of.createMessages( decodedMessages ) ) );

  1690.                 }

  1691.                 if ( decodedProperties != null )
  1692.                 {
  1693.                     this.setClassfileAttribute( javaClass, Properties.class.getName(), this.encodeModelObject(
  1694.                                                 marshaller, of.createProperties( decodedProperties ) ) );

  1695.                 }

  1696.                 if ( decodedSpecifications != null )
  1697.                 {
  1698.                     this.setClassfileAttribute( javaClass, Specifications.class.getName(), this.encodeModelObject(
  1699.                                                 marshaller, of.createSpecifications( decodedSpecifications ) ) );

  1700.                 }
  1701.             }
  1702.             else if ( this.isLoggable( Level.WARNING ) )
  1703.             {
  1704.                 this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
  1705.             }
  1706.         }
  1707.         catch ( final JAXBException e )
  1708.         {
  1709.             String message = getMessage( e );
  1710.             if ( message == null && e.getLinkedException() != null )
  1711.             {
  1712.                 message = getMessage( e.getLinkedException() );
  1713.             }

  1714.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1715.             throw (IOException) new IOException( message ).initCause( e );
  1716.         }
  1717.         catch ( final TransformerException e )
  1718.         {
  1719.             String message = getMessage( e );
  1720.             if ( message == null && e.getException() != null )
  1721.             {
  1722.                 message = getMessage( e.getException() );
  1723.             }

  1724.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1725.             throw (IOException) new IOException( message ).initCause( e );
  1726.         }
  1727.     }

  1728.     /**
  1729.      * Gets an attribute from a java class.
  1730.      *
  1731.      * @param clazz The java class to get an attribute from.
  1732.      * @param attributeName The name of the attribute to get.
  1733.      *
  1734.      * @return The value of attribute {@code attributeName} of {@code clazz} or {@code null}, if no such attribute
  1735.      * exists.
  1736.      *
  1737.      * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}.
  1738.      * @throws IOException if getting the attribute fails.
  1739.      *
  1740.      * @see JavaClass#getAttributes()
  1741.      */
  1742.     public byte[] getClassfileAttribute( final JavaClass clazz, final String attributeName ) throws IOException
  1743.     {
  1744.         if ( clazz == null )
  1745.         {
  1746.             throw new NullPointerException( "clazz" );
  1747.         }
  1748.         if ( attributeName == null )
  1749.         {
  1750.             throw new NullPointerException( "attributeName" );
  1751.         }

  1752.         final Attribute[] attributes = clazz.getAttributes();

  1753.         for ( int i = attributes.length - 1; i >= 0; i-- )
  1754.         {
  1755.             final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() );

  1756.             if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) )
  1757.             {
  1758.                 final Unknown unknown = (Unknown) attributes[i];
  1759.                 return unknown.getBytes();
  1760.             }
  1761.         }

  1762.         return null;
  1763.     }

  1764.     /**
  1765.      * Adds or updates an attribute in a java class.
  1766.      *
  1767.      * @param clazz The class to update an attribute of.
  1768.      * @param attributeName The name of the attribute to update.
  1769.      * @param data The new data of the attribute to update the {@code clazz} with.
  1770.      *
  1771.      * @throws NullPointerException if {@code clazz} or {@code attributeName} is {@code null}.
  1772.      * @throws IOException if updating the class file fails.
  1773.      *
  1774.      * @see JavaClass#getAttributes()
  1775.      */
  1776.     public void setClassfileAttribute( final JavaClass clazz, final String attributeName, final byte[] data )
  1777.         throws IOException
  1778.     {
  1779.         if ( clazz == null )
  1780.         {
  1781.             throw new NullPointerException( "clazz" );
  1782.         }
  1783.         if ( attributeName == null )
  1784.         {
  1785.             throw new NullPointerException( "attributeName" );
  1786.         }

  1787.         final byte[] attributeData = data != null ? data : NO_BYTES;

  1788.         /*
  1789.          * The JavaTM Virtual Machine Specification - Second Edition - Chapter 4.1
  1790.          *
  1791.          * A Java virtual machine implementation is required to silently ignore any
  1792.          * or all attributes in the attributes table of a ClassFile structure that
  1793.          * it does not recognize. Attributes not defined in this specification are
  1794.          * not allowed to affect the semantics of the class file, but only to
  1795.          * provide additional descriptive information (§4.7.1).
  1796.          */
  1797.         Attribute[] attributes = clazz.getAttributes();

  1798.         int attributeIndex = -1;
  1799.         int nameIndex = -1;

  1800.         for ( int i = attributes.length - 1; i >= 0; i-- )
  1801.         {
  1802.             final Constant constant = clazz.getConstantPool().getConstant( attributes[i].getNameIndex() );

  1803.             if ( constant instanceof ConstantUtf8 && attributeName.equals( ( (ConstantUtf8) constant ).getBytes() ) )
  1804.             {
  1805.                 attributeIndex = i;
  1806.                 nameIndex = attributes[i].getNameIndex();
  1807.             }
  1808.         }

  1809.         if ( nameIndex == -1 )
  1810.         {
  1811.             final Constant[] pool = clazz.getConstantPool().getConstantPool();
  1812.             final Constant[] tmp = new Constant[ pool.length + 1 ];
  1813.             System.arraycopy( pool, 0, tmp, 0, pool.length );
  1814.             tmp[pool.length] = new ConstantUtf8( attributeName );
  1815.             nameIndex = pool.length;
  1816.             clazz.setConstantPool( new ConstantPool( tmp ) );
  1817.         }

  1818.         final Unknown unknown = new Unknown( nameIndex, attributeData.length, attributeData, clazz.getConstantPool() );

  1819.         if ( attributeIndex == -1 )
  1820.         {
  1821.             final Attribute[] tmp = new Attribute[ attributes.length + 1 ];
  1822.             System.arraycopy( attributes, 0, tmp, 0, attributes.length );
  1823.             tmp[attributes.length] = unknown;
  1824.             attributes = tmp;
  1825.         }
  1826.         else
  1827.         {
  1828.             attributes[attributeIndex] = unknown;
  1829.         }

  1830.         clazz.setAttributes( attributes );
  1831.     }

  1832.     /**
  1833.      * Encodes a model object to a byte array.
  1834.      *
  1835.      * @param marshaller The marshaller to use for encoding the object.
  1836.      * @param modelObject The model object to encode.
  1837.      *
  1838.      * @return GZIP compressed XML document of {@code modelObject}.
  1839.      *
  1840.      * @throws NullPointerException if {@code marshaller} or {@code modelObject} is {@code null}.
  1841.      * @throws IOException if encoding {@code modelObject} fails.
  1842.      *
  1843.      * @see #decodeModelObject(javax.xml.bind.Unmarshaller, byte[], java.lang.Class)
  1844.      */
  1845.     public byte[] encodeModelObject( final Marshaller marshaller, final JAXBElement<? extends ModelObject> modelObject )
  1846.         throws IOException
  1847.     {
  1848.         if ( marshaller == null )
  1849.         {
  1850.             throw new NullPointerException( "marshaller" );
  1851.         }
  1852.         if ( modelObject == null )
  1853.         {
  1854.             throw new NullPointerException( "modelObject" );
  1855.         }

  1856.         try
  1857.         {
  1858.             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
  1859.             final GZIPOutputStream out = new GZIPOutputStream( baos );
  1860.             marshaller.marshal( modelObject, out );
  1861.             out.close();
  1862.             return baos.toByteArray();
  1863.         }
  1864.         catch ( final JAXBException e )
  1865.         {
  1866.             String message = getMessage( e );
  1867.             if ( message == null && e.getLinkedException() != null )
  1868.             {
  1869.                 message = getMessage( e.getLinkedException() );
  1870.             }

  1871.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1872.             throw (IOException) new IOException( message ).initCause( e );
  1873.         }
  1874.     }

  1875.     /**
  1876.      * Decodes a model object from a byte array.
  1877.      *
  1878.      * @param unmarshaller The unmarshaller to use for decoding the object.
  1879.      * @param bytes The encoded model object to decode.
  1880.      * @param type The class of the type of the encoded model object.
  1881.      * @param <T> The type of the encoded model object.
  1882.      *
  1883.      * @return Model object decoded from {@code bytes}.
  1884.      *
  1885.      * @throws NullPointerException if {@code unmarshaller}, {@code bytes} or {@code type} is {@code null}.
  1886.      * @throws IOException if decoding {@code bytes} fails.
  1887.      *
  1888.      * @see #encodeModelObject(javax.xml.bind.Marshaller, javax.xml.bind.JAXBElement)
  1889.      */
  1890.     public <T extends ModelObject> T decodeModelObject( final Unmarshaller unmarshaller, final byte[] bytes,
  1891.                                                         final Class<T> type ) throws IOException
  1892.     {
  1893.         if ( unmarshaller == null )
  1894.         {
  1895.             throw new NullPointerException( "unmarshaller" );
  1896.         }
  1897.         if ( bytes == null )
  1898.         {
  1899.             throw new NullPointerException( "bytes" );
  1900.         }
  1901.         if ( type == null )
  1902.         {
  1903.             throw new NullPointerException( "type" );
  1904.         }

  1905.         try
  1906.         {
  1907.             final ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
  1908.             final GZIPInputStream in = new GZIPInputStream( bais );
  1909.             final JAXBElement<T> element = (JAXBElement<T>) unmarshaller.unmarshal( in );
  1910.             in.close();
  1911.             return element.getValue();
  1912.         }
  1913.         catch ( final JAXBException e )
  1914.         {
  1915.             String message = getMessage( e );
  1916.             if ( message == null && e.getLinkedException() != null )
  1917.             {
  1918.                 message = getMessage( e.getLinkedException() );
  1919.             }

  1920.             // JDK: As of JDK 6, "new IOException( message, cause )".
  1921.             throw (IOException) new IOException( message ).initCause( e );
  1922.         }
  1923.     }

  1924.     private void commitModelObjects( final Specifications specifications, final Implementations implementations,
  1925.                                      final Marshaller marshaller, final File classesDirectory )
  1926.         throws IOException, ModelObjectException
  1927.     {
  1928.         if ( specifications != null )
  1929.         {
  1930.             for ( int i = specifications.getSpecification().size() - 1; i >= 0; i-- )
  1931.             {
  1932.                 this.commitModelObjects( specifications.getSpecification().get( i ), marshaller, classesDirectory );
  1933.             }
  1934.         }

  1935.         if ( implementations != null )
  1936.         {
  1937.             for ( int i = implementations.getImplementation().size() - 1; i >= 0; i-- )
  1938.             {
  1939.                 this.commitModelObjects( implementations.getImplementation().get( i ), marshaller, classesDirectory );
  1940.             }
  1941.         }
  1942.     }

  1943.     private void commitModelObjects( final Specification specification, final Marshaller marshaller,
  1944.                                      final File classesDirectory ) throws IOException, ModelObjectException
  1945.     {
  1946.         if ( specification.isClassDeclaration() && specification.getJavaTypeName() != null )
  1947.         {
  1948.             final String classLocation =
  1949.                 specification.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class";

  1950.             final File classFile = new File( classesDirectory, classLocation );

  1951.             if ( !classesDirectory.isDirectory() )
  1952.             {
  1953.                 throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
  1954.             }
  1955.             if ( !classFile.isFile() )
  1956.             {
  1957.                 throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
  1958.             }
  1959.             if ( !( classFile.canRead() && classFile.canWrite() ) )
  1960.             {
  1961.                 throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
  1962.             }

  1963.             if ( this.isLoggable( Level.INFO ) )
  1964.             {
  1965.                 this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null );
  1966.             }

  1967.             final JavaClass javaClass = this.readJavaClass( classFile );
  1968.             this.commitModelObjects( specification, marshaller, javaClass );
  1969.             this.writeJavaClass( javaClass, classFile );
  1970.         }
  1971.     }

  1972.     private void commitModelObjects( final Implementation implementation, final Marshaller marshaller,
  1973.                                      final File classesDirectory ) throws IOException, ModelObjectException
  1974.     {
  1975.         if ( implementation.isClassDeclaration() && implementation.getJavaTypeName() != null )
  1976.         {
  1977.             final String classLocation =
  1978.                 implementation.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class";

  1979.             final File classFile = new File( classesDirectory, classLocation );

  1980.             if ( !classesDirectory.isDirectory() )
  1981.             {
  1982.                 throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
  1983.             }
  1984.             if ( !classFile.isFile() )
  1985.             {
  1986.                 throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
  1987.             }
  1988.             if ( !( classFile.canRead() && classFile.canWrite() ) )
  1989.             {
  1990.                 throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
  1991.             }

  1992.             if ( this.isLoggable( Level.INFO ) )
  1993.             {
  1994.                 this.log( Level.INFO, getMessage( "committing", classFile.getAbsolutePath() ), null );
  1995.             }

  1996.             final JavaClass javaClass = this.readJavaClass( classFile );
  1997.             this.commitModelObjects( implementation, marshaller, javaClass );
  1998.             this.writeJavaClass( javaClass, classFile );
  1999.         }
  2000.     }

  2001.     private ModelValidationReport validateModelObjects( final Specifications specifications,
  2002.                                                         final Implementations implementations,
  2003.                                                         final Unmarshaller unmarshaller, final File classesDirectory )
  2004.         throws IOException, ModelObjectException
  2005.     {
  2006.         final ModelValidationReport report = new ModelValidationReport();

  2007.         if ( specifications != null )
  2008.         {
  2009.             for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ )
  2010.             {
  2011.                 final ModelValidationReport current = this.validateModelObjects(
  2012.                     specifications.getSpecification().get( i ), unmarshaller, classesDirectory );

  2013.                 report.getDetails().addAll( current.getDetails() );
  2014.             }
  2015.         }

  2016.         if ( implementations != null )
  2017.         {
  2018.             for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
  2019.             {
  2020.                 final ModelValidationReport current = this.validateModelObjects(
  2021.                     implementations.getImplementation().get( i ), unmarshaller, classesDirectory );

  2022.                 report.getDetails().addAll( current.getDetails() );
  2023.             }
  2024.         }

  2025.         return report;
  2026.     }

  2027.     private ModelValidationReport validateModelObjects( final Specification specification,
  2028.                                                         final Unmarshaller unmarshaller,
  2029.                                                         final File classesDirectory )
  2030.         throws IOException, ModelObjectException
  2031.     {
  2032.         final ModelValidationReport report = new ModelValidationReport();

  2033.         if ( specification.isClassDeclaration() && specification.getJavaTypeName() != null )
  2034.         {
  2035.             final String classLocation =
  2036.                 specification.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class";

  2037.             final File classFile = new File( classesDirectory, classLocation );

  2038.             if ( !classesDirectory.isDirectory() )
  2039.             {
  2040.                 throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
  2041.             }
  2042.             if ( !classFile.isFile() )
  2043.             {
  2044.                 throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
  2045.             }
  2046.             if ( !classFile.canRead() )
  2047.             {
  2048.                 throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
  2049.             }

  2050.             if ( this.isLoggable( Level.INFO ) )
  2051.             {
  2052.                 this.log( Level.INFO, getMessage( "validating", classFile.getAbsolutePath() ), null );
  2053.             }

  2054.             final JavaClass javaClass = this.readJavaClass( classFile );

  2055.             report.getDetails().addAll(
  2056.                 this.validateModelObjects( specification, unmarshaller, javaClass ).getDetails() );

  2057.         }

  2058.         return report;
  2059.     }

  2060.     private ModelValidationReport validateModelObjects( final Implementation implementation,
  2061.                                                         final Unmarshaller unmarshaller,
  2062.                                                         final File classesDirectory )
  2063.         throws IOException, ModelObjectException
  2064.     {
  2065.         final ModelValidationReport report = new ModelValidationReport();

  2066.         if ( implementation.isClassDeclaration() && implementation.getJavaTypeName() != null )
  2067.         {
  2068.             final String classLocation =
  2069.                 implementation.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class";

  2070.             final File classFile = new File( classesDirectory, classLocation );

  2071.             if ( !classesDirectory.isDirectory() )
  2072.             {
  2073.                 throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
  2074.             }
  2075.             if ( !classFile.isFile() )
  2076.             {
  2077.                 throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
  2078.             }
  2079.             if ( !classFile.canRead() )
  2080.             {
  2081.                 throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
  2082.             }

  2083.             if ( this.isLoggable( Level.INFO ) )
  2084.             {
  2085.                 this.log( Level.INFO, getMessage( "validating", classFile.getAbsolutePath() ), null );
  2086.             }

  2087.             final JavaClass javaClass = this.readJavaClass( classFile );

  2088.             report.getDetails().addAll(
  2089.                 this.validateModelObjects( implementation, unmarshaller, javaClass ).getDetails() );

  2090.         }

  2091.         return report;
  2092.     }

  2093.     private ModelValidationReport validateModelObjects( final Specifications specifications,
  2094.                                                         final Implementations implementations,
  2095.                                                         final Unmarshaller unmarshaller, final ModelContext context )
  2096.         throws IOException, ModelException
  2097.     {
  2098.         final ModelValidationReport report = new ModelValidationReport();

  2099.         if ( specifications != null )
  2100.         {
  2101.             for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ )
  2102.             {
  2103.                 final ModelValidationReport current = this.validateModelObjects(
  2104.                     specifications.getSpecification().get( i ), unmarshaller, context );

  2105.                 report.getDetails().addAll( current.getDetails() );
  2106.             }
  2107.         }

  2108.         if ( implementations != null )
  2109.         {
  2110.             for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
  2111.             {
  2112.                 final ModelValidationReport current = this.validateModelObjects(
  2113.                     implementations.getImplementation().get( i ), unmarshaller, context );

  2114.                 report.getDetails().addAll( current.getDetails() );
  2115.             }
  2116.         }

  2117.         return report;
  2118.     }

  2119.     private ModelValidationReport validateModelObjects( final Specification specification,
  2120.                                                         final Unmarshaller unmarshaller,
  2121.                                                         final ModelContext context ) throws IOException, ModelException
  2122.     {
  2123.         final ModelValidationReport report = new ModelValidationReport();

  2124.         if ( specification.isClassDeclaration() && specification.getJavaTypeName() != null )
  2125.         {
  2126.             final String classLocation =
  2127.                 specification.getJavaTypeName().getClassName().replace( '.', '/' ) + ".class";

  2128.             final URL classUrl = context.findResource( classLocation );

  2129.             if ( classUrl == null )
  2130.             {
  2131.                 throw new IOException( getMessage( "resourceNotFound", classLocation ) );
  2132.             }

  2133.             if ( this.isLoggable( Level.INFO ) )
  2134.             {
  2135.                 this.log( Level.INFO, getMessage( "validatingSpecification", specification.getIdentifier() ), null );
  2136.             }

  2137.             InputStream in = null;
  2138.             JavaClass javaClass = null;
  2139.             boolean suppressExceptionOnClose = true;

  2140.             try
  2141.             {
  2142.                 in = classUrl.openStream();
  2143.                 javaClass = new ClassParser( in, classUrl.toExternalForm() ).parse();
  2144.                 suppressExceptionOnClose = false;
  2145.             }
  2146.             finally
  2147.             {
  2148.                 try
  2149.                 {
  2150.                     if ( in != null )
  2151.                     {
  2152.                         in.close();
  2153.                     }
  2154.                 }
  2155.                 catch ( final IOException e )
  2156.                 {
  2157.                     if ( suppressExceptionOnClose )
  2158.                     {
  2159.                         this.log( Level.SEVERE, getMessage( e ), e );
  2160.                     }
  2161.                     else
  2162.                     {
  2163.                         throw e;
  2164.                     }
  2165.                 }
  2166.             }

  2167.             report.getDetails().addAll(
  2168.                 this.validateModelObjects( specification, unmarshaller, javaClass ).getDetails() );

  2169.         }

  2170.         return report;
  2171.     }

  2172.     private ModelValidationReport validateModelObjects( final Implementation implementation,
  2173.                                                         final Unmarshaller unmarshaller,
  2174.                                                         final ModelContext context ) throws IOException, ModelException
  2175.     {
  2176.         final ModelValidationReport report = new ModelValidationReport();

  2177.         if ( implementation.isClassDeclaration() && implementation.getJavaTypeName() != null )
  2178.         {
  2179.             final String classLocation = implementation.getJavaTypeName().getClassName().replace( '.', '/' ) + ".class";
  2180.             final URL classUrl = context.findResource( classLocation );

  2181.             if ( classUrl == null )
  2182.             {
  2183.                 throw new IOException( getMessage( "resourceNotFound", classLocation ) );
  2184.             }

  2185.             if ( this.isLoggable( Level.INFO ) )
  2186.             {
  2187.                 this.log( Level.INFO, getMessage( "validatingImplementation", implementation.getIdentifier() ), null );
  2188.             }

  2189.             InputStream in = null;
  2190.             JavaClass javaClass = null;
  2191.             boolean suppressExceptionOnClose = true;

  2192.             try
  2193.             {
  2194.                 in = classUrl.openStream();
  2195.                 javaClass = new ClassParser( in, classUrl.toExternalForm() ).parse();
  2196.                 suppressExceptionOnClose = false;
  2197.             }
  2198.             finally
  2199.             {
  2200.                 try
  2201.                 {
  2202.                     if ( in != null )
  2203.                     {
  2204.                         in.close();
  2205.                     }
  2206.                 }
  2207.                 catch ( final IOException e )
  2208.                 {
  2209.                     if ( suppressExceptionOnClose )
  2210.                     {
  2211.                         this.log( Level.SEVERE, getMessage( e ), e );
  2212.                     }
  2213.                     else
  2214.                     {
  2215.                         throw e;
  2216.                     }
  2217.                 }
  2218.             }

  2219.             report.getDetails().addAll(
  2220.                 this.validateModelObjects( implementation, unmarshaller, javaClass ).getDetails() );

  2221.         }

  2222.         return report;
  2223.     }

  2224.     private void transformModelObjects( final Specifications specifications, final Implementations implementations,
  2225.                                         final Unmarshaller unmarshaller, final Marshaller marshaller,
  2226.                                         final File classesDirectory, final List<Transformer> transformers )
  2227.         throws IOException, ModelObjectException
  2228.     {
  2229.         if ( specifications != null )
  2230.         {
  2231.             for ( int i = 0, s0 = specifications.getSpecification().size(); i < s0; i++ )
  2232.             {
  2233.                 this.transformModelObjects( specifications.getSpecification().get( i ), marshaller, unmarshaller,
  2234.                                             classesDirectory, transformers );

  2235.             }
  2236.         }

  2237.         if ( implementations != null )
  2238.         {
  2239.             for ( int i = 0, s0 = implementations.getImplementation().size(); i < s0; i++ )
  2240.             {
  2241.                 this.transformModelObjects( implementations.getImplementation().get( i ), marshaller, unmarshaller,
  2242.                                             classesDirectory, transformers );

  2243.             }
  2244.         }
  2245.     }

  2246.     private void transformModelObjects( final Specification specification, final Marshaller marshaller,
  2247.                                         final Unmarshaller unmarshaller, final File classesDirectory,
  2248.                                         final List<Transformer> transformers ) throws IOException, ModelObjectException
  2249.     {
  2250.         if ( specification.isClassDeclaration() && specification.getJavaTypeName() != null )
  2251.         {
  2252.             final String classLocation =
  2253.                 specification.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class";

  2254.             final File classFile = new File( classesDirectory, classLocation );

  2255.             if ( !classesDirectory.isDirectory() )
  2256.             {
  2257.                 throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
  2258.             }
  2259.             if ( !classFile.isFile() )
  2260.             {
  2261.                 throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
  2262.             }
  2263.             if ( !( classFile.canRead() && classFile.canWrite() ) )
  2264.             {
  2265.                 throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
  2266.             }

  2267.             if ( this.isLoggable( Level.INFO ) )
  2268.             {
  2269.                 this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null );
  2270.             }

  2271.             final JavaClass javaClass = this.readJavaClass( classFile );
  2272.             this.transformModelObjects( specification, marshaller, unmarshaller, javaClass, transformers );
  2273.             this.writeJavaClass( javaClass, classFile );
  2274.         }
  2275.     }

  2276.     private void transformModelObjects( final Implementation implementation, final Marshaller marshaller,
  2277.                                         final Unmarshaller unmarshaller, final File classesDirectory,
  2278.                                         final List<Transformer> transformers ) throws IOException, ModelObjectException
  2279.     {
  2280.         if ( implementation.isClassDeclaration() && implementation.getJavaTypeName() != null )
  2281.         {
  2282.             final String classLocation =
  2283.                 implementation.getJavaTypeName().getClassName().replace( '.', File.separatorChar ) + ".class";

  2284.             final File classFile = new File( classesDirectory, classLocation );

  2285.             if ( !classesDirectory.isDirectory() )
  2286.             {
  2287.                 throw new IOException( getMessage( "directoryNotFound", classesDirectory.getAbsolutePath() ) );
  2288.             }
  2289.             if ( !classFile.isFile() )
  2290.             {
  2291.                 throw new IOException( getMessage( "fileNotFound", classFile.getAbsolutePath() ) );
  2292.             }
  2293.             if ( !( classFile.canRead() && classFile.canWrite() ) )
  2294.             {
  2295.                 throw new IOException( getMessage( "fileAccessDenied", classFile.getAbsolutePath() ) );
  2296.             }

  2297.             if ( this.isLoggable( Level.INFO ) )
  2298.             {
  2299.                 this.log( Level.INFO, getMessage( "transforming", classFile.getAbsolutePath() ), null );
  2300.             }

  2301.             final JavaClass javaClass = this.readJavaClass( classFile );
  2302.             this.transformModelObjects( implementation, marshaller, unmarshaller, javaClass, transformers );
  2303.             this.writeJavaClass( javaClass, classFile );
  2304.         }
  2305.     }

  2306.     private JavaClass readJavaClass( final File classFile ) throws IOException
  2307.     {
  2308.         FileInputStream in = null;
  2309.         FileChannel fileChannel = null;
  2310.         FileLock fileLock = null;
  2311.         boolean suppressExceptionOnClose = true;

  2312.         try
  2313.         {
  2314.             in = new FileInputStream( classFile );
  2315.             fileChannel = in.getChannel();
  2316.             fileLock = fileChannel.lock( 0, classFile.length(), true );

  2317.             final JavaClass javaClass = new ClassParser( in, classFile.getAbsolutePath() ).parse();
  2318.             suppressExceptionOnClose = false;
  2319.             return javaClass;
  2320.         }
  2321.         finally
  2322.         {
  2323.             this.releaseAndClose( fileLock, fileChannel, in, suppressExceptionOnClose );
  2324.         }
  2325.     }

  2326.     private void writeJavaClass( final JavaClass javaClass, final File classFile ) throws IOException
  2327.     {
  2328.         RandomAccessFile randomAccessFile = null;
  2329.         FileChannel fileChannel = null;
  2330.         FileLock fileLock = null;
  2331.         boolean suppressExceptionOnClose = true;

  2332.         final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
  2333.         javaClass.dump( byteStream );
  2334.         byteStream.close();

  2335.         final byte[] bytes = byteStream.toByteArray();

  2336.         try
  2337.         {
  2338.             randomAccessFile = new RandomAccessFile( classFile, "rw" );
  2339.             fileChannel = randomAccessFile.getChannel();
  2340.             fileLock = fileChannel.lock();
  2341.             fileChannel.truncate( bytes.length );
  2342.             fileChannel.position( 0L );
  2343.             fileChannel.write( ByteBuffer.wrap( bytes ) );
  2344.             fileChannel.force( true );
  2345.             suppressExceptionOnClose = false;
  2346.         }
  2347.         finally
  2348.         {
  2349.             this.releaseAndClose( fileLock, fileChannel, randomAccessFile, suppressExceptionOnClose );
  2350.         }
  2351.     }

  2352.     private void releaseAndClose( final FileLock fileLock, final FileChannel fileChannel,
  2353.                                   final Closeable closeable, final boolean suppressExceptions )
  2354.         throws IOException
  2355.     {
  2356.         try
  2357.         {
  2358.             if ( fileLock != null )
  2359.             {
  2360.                 fileLock.release();
  2361.             }
  2362.         }
  2363.         catch ( final IOException e )
  2364.         {
  2365.             if ( suppressExceptions )
  2366.             {
  2367.                 this.log( Level.SEVERE, null, e );
  2368.             }
  2369.             else
  2370.             {
  2371.                 throw e;
  2372.             }
  2373.         }
  2374.         finally
  2375.         {
  2376.             try
  2377.             {
  2378.                 if ( fileChannel != null )
  2379.                 {
  2380.                     fileChannel.close();
  2381.                 }
  2382.             }
  2383.             catch ( final IOException e )
  2384.             {
  2385.                 if ( suppressExceptions )
  2386.                 {
  2387.                     this.log( Level.SEVERE, null, e );
  2388.                 }
  2389.                 else
  2390.                 {
  2391.                     throw e;
  2392.                 }
  2393.             }
  2394.             finally
  2395.             {
  2396.                 try
  2397.                 {
  2398.                     if ( closeable != null )
  2399.                     {
  2400.                         closeable.close();
  2401.                     }
  2402.                 }
  2403.                 catch ( final IOException e )
  2404.                 {
  2405.                     if ( suppressExceptions )
  2406.                     {
  2407.                         this.log( Level.SEVERE, null, e );
  2408.                     }
  2409.                     else
  2410.                     {
  2411.                         throw e;
  2412.                     }
  2413.                 }
  2414.             }
  2415.         }
  2416.     }

  2417.     private static String getMessage( final String key, final Object... arguments )
  2418.     {
  2419.         return MessageFormat.format( ResourceBundle.getBundle(
  2420.             ClassFileProcessor.class.getName().replace( '.', '/' ) ).getString( key ), arguments );

  2421.     }

  2422.     private static String getMessage( final Throwable t )
  2423.     {
  2424.         return t != null
  2425.                    ? t.getMessage() != null && t.getMessage().trim().length() > 0
  2426.                          ? t.getMessage()
  2427.                          : getMessage( t.getCause() )
  2428.                    : null;

  2429.     }

  2430. }